1 // timer.cxx - An implementation of the Timer for the
2 // Toshiba Media Processor (MeP). -*- C++ -*-
4 // Copyright (C) 2002, 2003 Red Hat.
5 // This file is part of SID and is licensed under the GPL.
6 // See the file COPYING.SID for conditions for redistribution.
12 mep_timer_channel::mep_timer_channel (mep_timer &o,
13 control_register_bus<big_int_4> &b,
14 sidutil::output_pin &p,
21 // Ctrl regs and fields. Fields with undefined initial values
22 // are not initialized.
24 cnt (& control_bus, 0x0, 0xffffffff, true, true, this,
25 & mep_timer_channel::set_cnt, & mep_timer_channel::get_cnt),
27 cmp (& control_bus, 0x1, 0xffffffff, true, true, this,
28 & mep_timer_channel::set_cmp, & mep_timer_channel::get_cmp),
30 ten (& control_bus, 0x2, 0xffffffff, true, true, this,
31 & mep_timer_channel::set_ten, & mep_timer_channel::get_ten),
35 tcr (& control_bus, 0x3, 0xffffffff, true, true, this,
36 & mep_timer_channel::set_tcr, & mep_timer_channel::get_tcr),
38 tis (& control_bus, 0x4, 0xffffffff, true, true, this,
39 & mep_timer_channel::set_tis, & mep_timer_channel::get_tis),
41 tcd (& control_bus, 0x5, 0xffffffff, true, true, this,
42 & mep_timer_channel::set_tcd, & mep_timer_channel::get_tcd),
48 mep_timer_channel::set_ten_ten (unsigned ten)
52 // Setting this bit when it is already set has no effect.
58 // If cmp_cmp and cnt_cnt are both 0, then indicate a timeout
59 // immediately, otherwise activate the timer.
60 if (get_cmp_cmp () == 0 && get_cnt_cnt () == 0)
67 // Activate the timer.
68 if (owner.activate ())
70 // Perform one tick right away
77 // Bit being cleared, or init failed.
82 mep_timer_channel::set_tis_tis (unsigned tis)
84 // We are clearing tis_tis in interval mode
85 if (tis_tis && ! tis && get_tcr_tmd () == 0)
87 // If counter matches the compare register, then there is no effect
88 // since the timer immediately times out again. See MeP Media Engine
89 // User's Manual, section 6.4.1, item (3).
90 if (get_cnt_cnt () == get_cmp_cmp ())
93 // Clear any pending interrupt
94 if (owner.debug_burst)
95 cout << " clearing interrupt pin while clearing tis_tis" << endl;
96 interrupt_pin.drive (0);
98 // If we setting tis_tis to 1, generate an interrupt if tcr_tie
100 else if (tis && get_tcr_tie ())
104 if (owner.debug_burst)
105 cout << " driving nmi pin while setting tis_tis" << endl;
110 if (owner.debug_burst)
111 cout << " driving interrupt pin while setting tis_tis" << endl;
112 interrupt_pin.drive (1);
120 mep_timer_channel::set_tcr_tie (unsigned tie)
122 // If we are changing tie_tie from 0 to 1 in interval mode and tis_tis is
123 // set, generate an interrupt.
124 if (! tcr_tie && tie && get_tcr_tmd () == 0 && get_tis_tis ())
126 if (owner.debug_burst)
127 cout << " driving interrupt pin while setting tcr_tie" << endl;
128 interrupt_pin.drive (1);
135 mep_timer_channel::tick ()
137 // If not active, then nothing to do
138 if (! get_ten_ten ())
139 return 0; // not active
141 if (owner.debug_burst)
142 cout << "channel " << channel_num << " is active" << endl;
144 // Only increment the counter if the divisor has been exceeded
146 if (ticks < tick_limit ())
148 if (owner.debug_burst)
149 cout << " ticks== 0x" << hex << ticks
150 << " limit== 0x" << tick_limit () << dec << endl;
151 return 1; // still active
155 // Increment the counter
156 sid::big_int_4 cnt = get_cnt_cnt () + 1;
159 if (owner.debug_burst)
160 cout << " cnt is " << hex << cnt << dec << endl;
162 // See if we have timed out
163 if (cnt != get_cmp_cmp ())
164 return 1; // still active
169 return get_ten_ten (); // still active?
173 mep_timer_channel::timeout ()
175 if (owner.debug_burst)
176 cout << " timeout" << endl;
178 // Signal the interrupt, if requested
181 // Check for auto counter reset.
182 if (! get_tcr_tai ())
184 if (owner.debug_burst)
185 cout << " no auto reset. Channel now inactive. cnt is "
186 << hex << get_cnt_cnt () << dec << endl;
187 // No auto reset. Timer becomes inactive.
192 // Reset the counter.
194 if (owner.debug_burst)
195 cout << " auto reset" << endl;
197 if (owner.debug_burst)
198 cout << " channel remains active" << endl;
201 mep_timer::mep_timer ()
205 sched ("burst", this, & mep_timer::do_one_burst),
208 // Allocate and assign a control bus and an interrupt pin for
210 for (int i = 0; i < max_channels; ++i)
213 channel_ctrl_bus[i] = new control_register_bus<big_int_4> ();
214 add_bus ("control-regs-" + make_numeric_attribute (i),
215 channel_ctrl_bus[i]);
216 interrupt_pin[i] = new sidutil::output_pin ();
217 add_pin ("interrupt-" + make_numeric_attribute (i), interrupt_pin[i]);
219 add_pin ("nmi", & nmi_pin);
221 // Set up the default configuration.
222 add_attribute_notify ("num-channels", & num_channels, this,
223 & mep_timer::num_channels_set, "setting");
224 set_attribute_value ("num-channels", "1");
227 // Called after the dcr attribute is set to alter the configuration
230 mep_timer::num_channels_set ()
232 // Allocate the requested number of channels
233 for (int i = 0; i < num_channels; ++i)
235 if (channels[i] != NULL)
236 continue; // already allocated
237 assert (channel_ctrl_bus[i]);
238 assert (interrupt_pin[i]);
239 channels[i] = new mep_timer_channel (*this, *channel_ctrl_bus[i],
240 *interrupt_pin[i], i);
245 mep_timer::activate () throw ()
248 return true; // all is ok
250 // Schedule the transfer with the scheduler.
252 sched.schedule_regular (begin_wait);
253 return true; // all is ok
257 mep_timer::do_one_burst () throw ()
260 cout << "------------------------" << endl;
262 bool active_channels = false;
263 for (int i = 0; i < num_channels; ++i)
265 assert (channels[i]);
266 bool still_active = channels[i]->tick ();
269 active_channels = true;
272 if (! active_channels)
280 mep_timer::signal_nmi ()