OSDN Git Service

Support for Toshiba MeP.
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / families / mep / timer.cxx
1 // timer.cxx - An implementation of the Timer for the
2 // Toshiba Media Processor (MeP). -*- C++ -*-
3
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.
7
8 #include "timer.h"
9
10 using namespace std;
11
12 mep_timer_channel::mep_timer_channel (mep_timer &o,
13                                       control_register_bus<big_int_4> &b,
14                                       sidutil::output_pin &p,
15                                       unsigned c)
16   :
17   owner (o),
18   control_bus (b),
19   interrupt_pin (p),
20   channel_num (c),
21   // Ctrl regs and fields. Fields with undefined initial values
22   // are not initialized.
23   cnt_cnt (0x1),
24   cnt (& control_bus, 0x0, 0xffffffff, true, true, this,
25        & mep_timer_channel::set_cnt, & mep_timer_channel::get_cnt),
26   cmp_cmp (0),
27   cmp (& control_bus, 0x1, 0xffffffff, true, true, this,
28        & mep_timer_channel::set_cmp, & mep_timer_channel::get_cmp),
29   ten_ten (0),
30   ten (& control_bus, 0x2, 0xffffffff, true, true, this,
31        & mep_timer_channel::set_ten, & mep_timer_channel::get_ten),
32   tcr_tai (0),
33   tcr_tmd (0),
34   tcr_tie (0),
35   tcr (& control_bus, 0x3, 0xffffffff, true, true, this,
36        & mep_timer_channel::set_tcr, & mep_timer_channel::get_tcr),
37   tis_tis (0),
38   tis (& control_bus, 0x4, 0xffffffff, true, true, this,
39        & mep_timer_channel::set_tis, & mep_timer_channel::get_tis),
40   tcd_tcd (0),
41   tcd (& control_bus, 0x5, 0xffffffff, true, true, this,
42        & mep_timer_channel::set_tcd, & mep_timer_channel::get_tcd),
43   ticks (0)
44 {
45 }
46
47 void
48 mep_timer_channel::set_ten_ten (unsigned ten)
49 {
50   if (ten)
51     {
52       // Setting this bit when it is already set has no effect.
53       if (ten_ten)
54         return;
55
56       ten_ten = 1;
57
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)
61         {
62           timeout ();
63           if (! ten_ten)
64             return;
65         }
66          
67       // Activate the timer.
68       if (owner.activate ())
69         {
70           // Perform one tick right away
71           ticks = 0;
72           tick ();
73           return;
74         }
75     }
76
77   // Bit being cleared, or init failed.
78   ten_ten = 0;
79 }
80
81 void
82 mep_timer_channel::set_tis_tis (unsigned tis)
83 {
84   // We are clearing tis_tis in interval mode
85   if (tis_tis && ! tis && get_tcr_tmd () == 0)
86     {
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 ())
91         return;
92
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);
97     }
98   // If we setting tis_tis to 1, generate an interrupt if tcr_tie
99   // is also set.
100   else if (tis && get_tcr_tie ())
101     {
102       if (get_tcr_tmd ())
103         {
104           if (owner.debug_burst)
105             cout << "  driving nmi pin while setting tis_tis" << endl;
106           owner.signal_nmi ();
107         }
108       else
109         {
110           if (owner.debug_burst)
111             cout << "  driving interrupt pin while setting tis_tis" << endl;
112           interrupt_pin.drive (1);
113         }
114     }
115
116   tis_tis = tis;
117 }
118
119 void
120 mep_timer_channel::set_tcr_tie (unsigned tie)
121 {
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 ())
125     {
126       if (owner.debug_burst)
127         cout << "  driving interrupt pin while setting tcr_tie" << endl;
128       interrupt_pin.drive (1);
129     }
130
131   tcr_tie = tie;
132 }
133
134 int
135 mep_timer_channel::tick ()
136 {
137   // If not active, then nothing to do
138   if (! get_ten_ten ())
139     return 0; // not active
140
141   if (owner.debug_burst)
142     cout << "channel " << channel_num << " is active" << endl;
143
144   // Only increment the counter if the divisor has been exceeded
145   ++ticks;
146   if (ticks < tick_limit ())
147     {
148       if (owner.debug_burst)
149         cout << "  ticks== 0x" << hex << ticks
150              << " limit== 0x" << tick_limit () << dec << endl;
151       return 1; // still active
152     }
153   ticks = 0;
154
155   // Increment the counter
156   sid::big_int_4 cnt = get_cnt_cnt () + 1;
157   set_cnt_cnt (cnt);
158
159   if (owner.debug_burst)
160     cout << "  cnt is " << hex << cnt << dec << endl;
161
162   // See if we have timed out
163   if (cnt != get_cmp_cmp ())
164     return 1; // still active
165
166   // we have timed out
167   timeout ();
168
169   return get_ten_ten (); // still active?
170 }
171
172 void
173 mep_timer_channel::timeout ()
174 {
175   if (owner.debug_burst)
176     cout << "  timeout" << endl;
177
178   // Signal the interrupt, if requested
179   set_tis_tis (1);
180
181   // Check for auto counter reset.
182   if (! get_tcr_tai ())
183     {
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.
188       set_ten_ten (0);
189       return;
190     }
191
192   // Reset the counter.
193   set_cnt_cnt (1);
194   if (owner.debug_burst)
195     cout << "  auto reset" << endl;
196
197   if (owner.debug_burst)
198     cout << "  channel remains active" << endl;
199 }
200
201 mep_timer::mep_timer ()
202   :
203   active (false),
204   num_channels (1),
205   sched ("burst", this, & mep_timer::do_one_burst),
206   nmi_pin ()
207 {
208   // Allocate and assign  a control bus and an interrupt pin for
209   // each channel.
210   for (int i = 0; i < max_channels; ++i)
211     {
212       channels[i] = NULL;
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]);
218     }
219   add_pin ("nmi", & nmi_pin);
220
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");
225 }
226
227 // Called after the dcr attribute is set to alter the configuration
228 // accordingly.
229 void
230 mep_timer::num_channels_set ()
231 {
232   // Allocate the requested number of channels
233   for (int i = 0; i < num_channels; ++i)
234     {
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);
241     }
242 }
243
244 bool
245 mep_timer::activate () throw ()
246 {
247   if (active)
248     return true; // all is ok
249
250   // Schedule the transfer with the scheduler.
251   active = true;
252   sched.schedule_regular (begin_wait);  
253   return true; // all is ok
254 }
255
256 void
257 mep_timer::do_one_burst () throw ()
258 {
259   if (debug_burst)
260     cout << "------------------------" << endl;
261
262   bool active_channels = false;
263   for (int i = 0; i < num_channels; ++i)
264     {
265       assert (channels[i]);
266       bool still_active = channels[i]->tick ();
267
268       if (still_active)
269         active_channels = true;
270     }
271
272   if (! active_channels)
273     {
274       sched.cancel ();
275       active = false;
276     }
277 }
278
279 void
280 mep_timer::signal_nmi ()
281 {
282   nmi_pin.drive (1);
283 }