OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / timers / arm7t / arm.cxx
1 // arm.cxx - An implementation of the timer from the ARM PID7T
2 // development board.  -*- C++ -*-
3
4 // Copyright (C) 1999, 2000 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 // arm.cxx
8
9 // A more thorough description of this component may be found at
10 // <http://www.arm.com/Documentation/UserMans/rps/#timer>
11
12 #include "arm7t-timer.h"
13
14 ostream& operator << (ostream& o, const armTimer::timer_mode& m)
15 {
16   switch (m)
17     {
18     case armTimer::free_running: 
19       o << "free-running";
20       break;
21     case armTimer::periodic:
22       o << "periodic";
23       break;
24     default:
25       o << "?";
26     }
27   return o;
28 }
29
30 istream& operator >> (istream& i, armTimer::timer_mode& m)
31 {
32   string mode;
33   i >> mode;
34   if (mode == "free-running")
35     m = armTimer::free_running;
36   else if (mode == "periodic")
37     m = armTimer::periodic;
38   else 
39     i.setstate (ios::badbit);
40   return i;
41 }
42
43
44
45 armTimer::armTimer()
46   :counter(0), enabled(false), loadValue(0),
47    mode(free_running), prescale(0), bus(this),
48    reset_pin(this, & armTimer::reset_pin_handler), 
49    triggerpoint_manager(this)
50 {
51   add_bus("registers", &this->bus);
52
53   add_pin("interrupt", &this->interrupt_pin);
54   add_attribute("interrupt", & this->interrupt_pin, "pin");
55   triggerpoint_manager.add_watchable_attribute("interrupt");
56   categorize("interrupt", "watchable");
57   
58   add_attribute("counter", &this->counter, "register"); 
59   triggerpoint_manager.add_watchable_attribute("counter");
60   categorize("counter", "watchable");
61
62   add_attribute("load-value", &this->loadValue, "register");
63   triggerpoint_manager.add_watchable_attribute("load-value");
64   categorize("load-value", "watchable");
65
66   add_attribute("enabled", &this->enabled, "register");
67   triggerpoint_manager.add_watchable_attribute("enabled");
68   categorize("enabled", "watchable");
69
70   add_attribute("mode", &this->mode, "register");
71   triggerpoint_manager.add_watchable_attribute("mode");
72   categorize("mode", "watchable");
73
74   add_attribute("prescale", &this->prescale, "register");
75   triggerpoint_manager.add_watchable_attribute("prescale");
76   categorize("prescale", "watchable");
77
78   add_pin ("reset", & this->reset_pin);
79   add_attribute ("reset", & this->reset_pin, "pin");
80   triggerpoint_manager.add_watchable_attribute("reset");
81   categorize("reset", "watchable");
82
83   add_attribute_virtual ("state-snapshot", this, 
84                          & armTimer:: save_state,
85                          & armTimer:: restore_state);
86 }
87
88
89
90 void
91 armTimer::reset ()
92 {
93   this->counter = 0;
94   this->enabled = false;
95   this->loadValue = 0;
96   this->mode = free_running;
97   this->prescale = 0;
98   if (this->interrupt_pin.recall() != 0)
99     this->interrupt_pin.drive (0);
100   this->reset_schedule ();
101 }
102
103
104 armTimerNoSched::armTimerNoSched()
105   :armTimer(), clockpin(this, & armTimerNoSched::tick), ticks(0)
106 {
107   add_pin("clock", &clockpin);
108
109   add_attribute_ro("ticks", &ticks, "register");
110   triggerpoint_manager.add_watchable_attribute("ticks");
111   categorize("ticks", "watchable");
112 }
113
114
115 void
116 armTimerNoSched::reset ()
117 {
118   armTimer::reset ();
119   this->ticks = 0;
120 }
121
122
123 armTimerSched::armTimerSched()
124   :armTimer(), ticker("divided-clock", this, & armTimer::tick)
125 {
126 }
127
128
129
130 void
131 armTimer::tick()
132 {
133   // check for triggerpoints
134   triggerpoint_manager.check_and_dispatch();
135
136   if (!enabled)
137     return;
138
139   counter--;
140   // cerr << "divisor=" << divisor << " counter=" << counter << endl;
141   if (counter == 0)
142     {
143       if (mode == periodic) {
144         counter = loadValue;
145         if (interrupt_pin.recall() != 1)
146           interrupt_pin.drive(1);
147       } else {
148         counter = 65535; // rolls over from maximum value; no interrupts
149       }
150     }
151 }
152
153
154 void
155 armTimerNoSched::tick()
156 {
157   // check for triggerpoints
158   triggerpoint_manager.check_and_dispatch();
159
160   if (!enabled)
161     return;
162
163   if (prescale > 3) 
164     {
165       cerr << "hw-timer-arm/ref error: invalid prescale value" << prescale << endl;
166       prescale = 3;
167     }
168   assert (prescale <= 3);
169   unsigned divisor = 1 << (prescale * 4);
170
171   ticks ++;
172   assert (divisor != 0);
173   if ((ticks % divisor) == 0) {
174     ticks = 0;
175
176     armTimer::tick();
177   }
178 }
179
180
181 void
182 armTimerSched::reset_schedule()
183 {
184   // cerr << "reset_schedule" << endl;
185   this->ticker.cancel();
186
187   if (!enabled)
188     return;
189
190   // XXX: prescale == 3 has undefined behavior.
191   assert (prescale <= 3);
192   unsigned divisor = 1 << (prescale * 4);
193
194   // cerr << "divisor = " << divisor << endl;
195   this->ticker.schedule_regular (divisor);
196 }
197
198
199
200
201 bus::status
202 armTimer::bus_interface::word_write(host_int_4 addr,
203                                     little_int_4 mask,
204                                     little_int_4 le_data)
205 {
206   host_int_4 data = le_data;
207   switch (addr)
208     {
209     case 0:
210       // Clear top 16 bits when loading a new value.
211       host->loadValue = data & 0xFFFF;
212       // Reset the counter value.
213       host->counter = host->loadValue;
214       break;
215     case 1:
216       // Reserved.
217       break;
218     case 2:
219       host->prescale = (data & 0x0C) >> 2;
220       host->enabled = ((data & 0x80) == 0x80);
221       host->mode = ((data & 0x40) >> 6) ? periodic : free_running;
222       host->reset_schedule();
223       break;
224     case 3:
225       if (host->interrupt_pin.recall() != 0)
226         host->interrupt_pin.drive(0);
227       break;
228     case 4:
229       // Reserved.
230       break;
231     default:
232       return bus::unmapped;
233     }
234
235   // check for triggerpoints
236   host->triggerpoint_manager.check_and_dispatch();
237   return bus::ok;
238 }
239
240 bus::status
241 armTimer::bus_interface::word_read(host_int_4 addr,
242                                    little_int_4 mask,
243                                    little_int_4& data)
244 {
245   switch (addr)
246     { 
247     case 0:
248       // Timer load
249       data = host->loadValue;
250       return bus::ok;
251
252     case 1:
253       // Timer value
254       data = host->counter;
255       return bus::ok;
256
257     case 2:
258       // Timer control
259       data = (host->enabled << 7) | (host->mode << 6) | (host->prescale << 2);
260       return bus::ok;
261
262     case 3:
263       // Reserved.
264       return bus::ok;
265
266     case 4:
267       // Reserved.
268       return bus::ok;
269
270     default:
271       return bus::unmapped;
272     }
273
274   // NOTREACHED
275 }
276
277 std::string
278 armTimer::save_state()
279 {
280   return make_attribute(*this);
281 }
282
283
284 sid::component::status
285 armTimer::restore_state(const string& state)
286 {
287   return parse_attribute(state, *this);
288 }
289
290 ostream&
291 operator << (ostream& op, const armTimer& obj)
292 {
293   obj.stream(op);
294   return op;
295 }
296
297 istream& operator >> (istream& ip, armTimer& obj)
298 {
299   obj.destream(ip);
300   return ip;
301 }
302
303 void
304 armTimer::stream(ostream& op) const
305 {
306   op << "Interrupt " << interrupt_pin << ' ';
307   op << "Counter " << counter << ' ';
308   op << "Enable " << enabled << ' ';
309   op << "LoadValue " << loadValue << ' ';
310   op << mode << ' ' ;
311   op << "Prescale " << prescale << ' ';
312   op << "Reset " << reset_pin;
313 }
314
315 void
316 armTimerNoSched::stream(ostream& op) const
317 {
318   armTimer::stream(op);
319   if (!op.good())
320     return;
321
322   op << ' ' << "Ticks " << ticks;
323 }
324
325 void
326 armTimerNoSched::destream(istream& ip)
327 {
328   armTimer::destream(ip);
329   if (!ip.good())
330     return;
331
332   string key;
333
334   ip >> key;
335   if (key != "Ticks")
336     {
337       ip.setstate(ios::badbit);
338       return;
339     }
340
341   ip >> ticks;
342 }
343
344 void
345 armTimer::destream(istream& ip)
346 {
347   string key;
348   
349   ip >> key;
350   if (key == "Interrupt")
351     {
352       ip >> interrupt_pin;
353     }
354   else
355     {
356       ip.setstate(ios::badbit);
357       return;
358     }
359
360   ip >> key;
361   if (key == "Counter")
362     ip >> counter;
363   else
364     {
365       ip.setstate(ios::badbit);
366       return;
367     }       
368   
369   ip >> key;
370   if (key != "Enable")
371     {
372       ip.setstate(ios::badbit);
373       return;
374     }
375   else 
376     ip >> enabled;
377   
378   ip >> key;
379   if (key != "LoadValue")
380     {
381       ip.setstate(ios::badbit);
382       return;
383     }
384   else 
385     ip >> loadValue;
386   
387   // following >> is taken care by timer_mode operator
388   ip >> mode;
389   
390   ip >> key;
391   if (key != "Prescale")
392     {
393       ip.setstate(ios::badbit);
394       return;
395     }
396   else 
397     ip >> prescale;
398
399   ip >> key;
400   if (key != "Reset")
401     {
402       ip.setstate(ios::badbit);
403       return;
404     }
405   else 
406     ip >> reset_pin;
407 }
408