OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / samples / timer.cxx
1 // timer.cxx - an example of a SID component implementation.  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 // Noteworthy remarks about the code in this source file:
8 // * For clarity, the C++ "using" keyword is used sparingly and all members
9 //   of the "sid::" namespace appear fully qualified.
10 // * Documentation for the Standard Template Library, plus any obscure
11 //   C++ syntax you may encounter can be discovered in the 3rd edition of
12 //   ``The C++ Programming Language'', by Stroustup. ISBN 0-201-88954-4.
13
14 #include <sidcomp.h>
15 #include <sidso.h>
16 #include <sidtypes.h>
17
18 #include <set>
19 #include <string>
20 #include <vector>
21
22
23 // Wrap everything in a unique namespace 
24 namespace timer_example
25 {
26
27
28 // Import standard types into this namespace.
29 using namespace std;
30
31
32 class Timer: public virtual sid::component
33 {
34 public:
35   Timer()
36     :scheduler_pin(0), clock_pin(this), bus(this), enabled(false) { }
37   
38   // Provide implementations for abstract methods in sid::component.
39   // See include/sidcomp.h.
40   
41   vector<string> pin_names() throw();
42   sid::pin* find_pin(const string& name) throw();
43   sid::component::status connect_pin(const string& name, sid::pin* pin) throw();
44   sid::component::status disconnect_pin(const string& name, sid::pin* pin) throw();
45   vector<sid::pin*> connected_pins(const string& name) throw();
46   
47   vector<string> accessor_names() throw();
48   sid::component::status connect_accessor(const string& name, sid::bus* bus) throw();
49   sid::component::status disconnect_accessor(const string& name, sid::bus* bus) throw();
50   
51   vector<string> bus_names() throw();
52   sid::bus* find_bus(const string& name) throw();
53   sid::bus* connected_bus(const string& name) throw();
54   
55   vector<string> attribute_names() throw();
56   vector<string> attribute_names(const string& category) throw();
57   string attribute_value(const string& name) throw();
58   sid::component::status set_attribute_value(const string& name, const string& value) throw();
59   
60   vector<string> relationship_names() throw();
61   sid::component::status relate(const string& rel, sid::component* c) throw();
62   sid::component::status unrelate(const string& rel, sid::component* c) throw();
63   vector<sid::component*> related_components(const string& rel) throw();
64   
65 private:
66   // A netlist, which tracks pins connected to the interrupt pin.
67   typedef set<sid::pin*> netlist_t;
68   netlist_t intpin_netlist;
69
70   // A handle to the scheduler's "control" pin.
71   // The scheduler is a preexisting SID component which can schedule
72   // and deliver events to a component via an "event" pin.
73   // See schedule() for more details.
74   sid::pin* scheduler_pin;
75
76   // Schedule an event for some time in the future.
77   void schedule(sid::host_int_4 time);
78
79   // Cancel any pending events.
80   void cancel();
81
82   // Reschedule an event.
83   void reset_schedule();
84
85   // This method is called whenever the scheduler delivers an event,
86   // because the "divided-clock-event" pin will be connected to the
87   // scheduler.  It is a specialised pin with these fixed semantics.
88   // Refer to class clock_pin_t below.
89   void tick();
90
91   // Drive a value on the interrupt pin (which propogates to all
92   // connected pins).
93   void drive_interrupt(sid::host_int_4 value);
94
95   class clock_pin_t: public sid::pin
96   {
97     // clock_pin_t is a specialised pin.
98     // It calls timer->tick() whenever a value is driven. 
99   public:
100     clock_pin_t(Timer* t): timer(t) { }
101     void driven(sid::host_int_4 value) throw() { timer->tick(); }
102   private:
103     Timer* timer;
104   };
105   friend class clock_pin_t;
106   clock_pin_t clock_pin;
107
108
109   // register_bus is a specialised bus.
110   // It handles the majority of the component's functionality, since
111   // that is mostly controlled by the timer's register set.
112
113   class register_bus: public sid::bus
114   {
115   public:
116     register_bus(Timer* t): timer(t) { }
117
118     // Prototypes for bus read/write methods of all kinds.
119     sid::bus::status read(sid::host_int_4 addr,sid::little_int_1& data) throw();
120     sid::bus::status read(sid::host_int_4 addr,sid::big_int_1& data) throw();
121     sid::bus::status read(sid::host_int_4 addr,sid::little_int_2& data) throw();
122     sid::bus::status read(sid::host_int_4 addr,sid::big_int_2& data) throw();
123     sid::bus::status read(sid::host_int_4 addr,sid::little_int_4& data) throw();
124     sid::bus::status read(sid::host_int_4 addr,sid::big_int_4& data) throw();
125     sid::bus::status read(sid::host_int_4 addr,sid::little_int_8& data) throw();
126     sid::bus::status read(sid::host_int_4 addr,sid::big_int_8& data) throw();
127
128     sid::bus::status write(sid::host_int_4 addr,sid::little_int_1 data) throw();
129     sid::bus::status write(sid::host_int_4 addr,sid::big_int_1 data) throw();
130     sid::bus::status write(sid::host_int_4 addr,sid::little_int_2 data) throw();
131     sid::bus::status write(sid::host_int_4 addr,sid::big_int_2 data) throw();
132     sid::bus::status write(sid::host_int_4 addr,sid::little_int_4 data) throw();
133     sid::bus::status write(sid::host_int_4 addr,sid::big_int_4 data) throw();
134     sid::bus::status write(sid::host_int_4 addr,sid::little_int_8 data) throw();
135     sid::bus::status write(sid::host_int_4 addr,sid::big_int_8 data) throw();
136
137   private:
138     Timer* timer;
139   };
140   friend class register_bus;
141   register_bus bus;
142
143   // Data members that represent the timer's internal state.
144
145   bool enabled;
146   sid::host_int_2 load_value, prescale, counter;
147   enum timer_mode { PERIODIC, FREERUNNING } mode;
148 };
149
150
151 // Return a list of pin names which are visible to other components.
152
153 vector<string>
154 Timer::pin_names() throw()
155 {
156   vector<string> pins;
157   pins.push_back("divided-clock-event");
158   return pins;
159 }
160
161
162 // Return a list of pins that are connected to a named pin.
163 // We recognize "interrupt" and "divided-clock-control".
164
165 vector<sid::pin*>
166 Timer::connected_pins(const string& name) throw()
167 {
168   vector<sid::pin*> pins;
169   netlist_t::const_iterator it;
170
171   if (name == "interrupt")
172     {
173       for (it = intpin_netlist.begin(); it != intpin_netlist.end();
174            it++)
175         {
176           pins.push_back(*it);
177         }
178       return pins;
179     }
180   else if (name == "divided-clock-control")
181     {
182       pins.push_back(scheduler_pin);
183       return pins;
184     }
185   return vector<sid::pin*>();
186 }
187
188
189 // Connect a pin to a named pin.
190 // We recognize "interrupt" and "divided-clock-control".
191
192 // We allow multiple pins to be connected to the interrupt pin (with
193 // infinite fan-out!), so these are kept in a netlist.  For
194 // efficiency, the STL container chosen for the netlist ensures that
195 // no duplicate pin handles are stored.
196
197 sid::component::status
198 Timer::connect_pin(const string& name, sid::pin* pin) throw()
199 {
200   if (name == "interrupt")
201     {
202       // Add this pin to the netlist.
203       intpin_netlist.insert(intpin_netlist.end(), pin);
204       return sid::component::ok;
205     }
206   else if (name == "divided-clock-control")
207     {
208       // Reassign the scheduler pin.
209       scheduler_pin = pin;
210       return sid::component::ok;
211     }
212   return sid::component::not_found;
213 }
214
215 // Disconnect a pin from a named pin.
216
217 sid::component::status
218 Timer::disconnect_pin(const string& name, sid::pin* pin) throw()
219 {
220   if (name == "interrupt")
221     {
222       // Remove this pin from the netlist.
223       if (intpin_netlist.erase(pin) > 0)
224         return sid::component::ok;
225     }
226   else if (name == "divided-clock-control" && scheduler_pin == pin)
227     {
228       // Elsewhere, we make sure to not use this pin if it's null.
229       scheduler_pin = 0;
230       return sid::component::ok;
231     }
232   return sid::component::not_found;
233 }
234
235
236 // Find a pin of a given name.
237 // We only recognize "divided-clock-event".
238
239 sid::pin*
240 Timer::find_pin(const string& name) throw()
241 {
242   if (name == "divided-clock-event")
243     return &clock_pin;
244
245   return 0;
246 }
247
248
249 vector<string>
250 Timer::accessor_names() throw()
251 {
252   // No accessors.
253   return vector<string>();
254 }
255
256
257 sid::component::status
258 Timer::connect_accessor(const string& name, sid::bus* bus) throw()
259 {
260   // No acccessors; any name is unknown.
261   return sid::component::not_found;
262 }
263
264
265 sid::component::status
266 Timer::disconnect_accessor(const string& name, sid::bus* bus) throw()
267 {
268   // No accessors; any name is unknown.
269   return sid::component::not_found;
270 }
271
272
273 // Return a list of bus names. We have just one--"registers".
274
275 vector<string>
276 Timer::bus_names() throw()
277 {
278   vector<string> buses;
279   buses.push_back("registers");
280   return buses;
281 }
282
283 sid::bus*
284 Timer::find_bus(const string& name) throw()
285 {
286   if (name == "registers")
287     return &bus;
288   return 0;
289 }
290
291
292 sid::bus*
293 Timer::connected_bus(const string& name) throw()
294 {
295   // No connected buses; return a null pointer.
296   return 0;
297 }
298
299
300 vector<string>
301 Timer::attribute_names() throw()
302 {
303   // No attributes; return an empty vector.
304   return vector<string>();
305 }
306
307 vector<string>
308 Timer::attribute_names(const string& category) throw()
309 {
310   // No attributes, regardless of category. Return an empty vector.
311   return vector<string>();
312 }
313
314 string
315 Timer::attribute_value(const string& name) throw()
316 {
317   // No attributes--return the empty string for any attribute value.
318   return string();
319 }
320
321 sid::component::status
322 Timer::set_attribute_value(const string& name, const string& value) throw()
323 {
324   // No attributes--return not_found regardless of attribute name.
325   return sid::component::not_found;
326 }
327
328
329 vector<sid::component*>
330 Timer::related_components(const string& rel) throw()
331 {
332   // No related components.
333   return vector<sid::component*>();
334 }
335
336 sid::component::status
337 Timer::unrelate(const string& rel, sid::component* c) throw()
338 {
339   // No related components; always unfound.
340   return sid::component::not_found;
341 }
342
343 sid::component::status
344 Timer::relate(const string& rel, sid::component* c) throw()
345 {
346   // No related components; always unfound.
347   return sid::component::not_found;
348 }
349
350 vector<string>
351 Timer::relationship_names() throw()
352 {
353   // No relations.
354   return vector<string>();
355 }
356
357
358
359 void
360 Timer::drive_interrupt(sid::host_int_4 value)
361 {
362   // Iterate the netlist, driving the value to all pins connected to
363   // the interrupt pin.
364
365   for (netlist_t::const_iterator it = intpin_netlist.begin();
366        it != intpin_netlist.end();
367        it++)
368     {
369       (*it)->driven(value);
370     }
371 }
372
373
374 // Schedule an event to be delivered at a later time.
375
376 void
377 Timer::schedule(sid::host_int_4 time)
378 {
379   // The scheduler component tests bit 31 of a value carried on its
380   // "control" pin.  If this bit is set, the event will be delivered
381   // routinely at the specified interval.  Otherwise, the event will
382   // only occur once.
383
384   assert ((time & 0x80000000) == 0);
385   assert ((time & 0x7FFFFFFF) != 0);
386   
387   if (scheduler_pin)
388     scheduler_pin->driven(0x80000000 | time);
389 }
390
391
392 // Cancel any pending event.
393
394 void
395 Timer::cancel()
396 {
397   // Cancel the event by driving a zero value to the scheduler.
398
399   if (scheduler_pin)
400     scheduler_pin->driven(0);
401 }
402
403
404 // Reset the schedule, in case the timer's enable or divisor registers
405 // have been altered.
406
407 void
408 Timer::reset_schedule()
409 {
410   cancel();
411   
412   if (!enabled)
413     return;
414   
415   assert (prescale <= 2);
416   unsigned divisor = 1 << (prescale * 4);
417   
418   schedule(divisor);
419 }
420
421
422 // Handle 32-bit (little endian) reads.
423 // If the address is not 32-bit aligned or does not match any register
424 // address, return an error.
425
426 sid::bus::status
427 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_4& data) throw()
428 {
429   if (addr % 4 != 0)
430     return sid::bus::misaligned;
431   
432   switch (addr)
433     { 
434     case 0x0:
435       data = timer->load_value;
436       break;
437       
438     case 0x4:
439       data = timer->counter;
440       break;
441       
442     case 0x8:
443       data =
444         (timer->enabled << 7) | 
445         (timer->mode << 6) | 
446         (timer->prescale << 2);
447       break;
448       
449     case 0xC:
450       break;
451       
452     default:
453       return sid::bus::unmapped;
454     }
455
456   return sid::bus::ok;
457 }
458
459
460 // Handle 32-bit (big endian) reads.
461 // Just do a little endian read and rearrange the result.
462
463 sid::bus::status
464 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_4& data) throw()
465 {
466   sid::little_int_4 le_data;
467   sid::bus::status st = read(addr, le_data);
468   data.set_target_memory_value (le_data.target_memory_value ());
469   return st;
470 }
471
472
473 // Handle 32-bit (little endian) writes.
474 // If the address is not 32-bit aligned or does not match any register
475 // address, return an error.
476
477 sid::bus::status
478 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_4 data) throw()
479 {
480   if (addr % 4 != 0)
481     return sid::bus::misaligned;
482   
483   switch (addr)
484     {
485     case 0x0:
486       // A write to LOAD_REG.
487       // Clear top 16 bits when loading a new value.
488       timer->load_value = data & 0xFFFF;
489       // Reset the counter value.
490       timer->counter = timer->load_value;
491       break;
492
493     case 0x4:
494       break;
495
496     case 0x8:
497       // A write to CTL_REG.
498       timer->prescale = (data & 0x0C) >> 2;
499       timer->enabled = ((data & 0x80) == 0x80);
500       timer->mode = (data & 0x40) ? PERIODIC : FREERUNNING;
501       timer->reset_schedule();
502       break;
503
504     case 0xC:
505       timer->drive_interrupt(0);
506       break;
507
508     default:
509       return sid::bus::unmapped;
510     }
511
512   return sid::bus::ok;
513 }
514
515
516 // Handle 32-bit (big endian) writes.
517 // Just rearrange the data and do a little endian write.
518
519 sid::bus::status
520 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_4 data) throw()
521 {
522   sid::little_int_4 le_data;
523   le_data.set_target_memory_value (data.target_memory_value ());
524   return write(addr, le_data);
525 }
526
527 // For simplicity, bus accesses that are not 32-bits wide are not
528 // handled.  Ideally, different widths should be handled sensibly.
529 // For example, a one-byte write to location n+1, where n is 32-bit
530 // aligned, should behave as you might expect.
531
532 sid::bus::status
533 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_1& data) throw()
534 {
535   return sid::bus::unpermitted;
536 }
537
538 sid::bus::status
539 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_1& data) throw()
540 {
541   return sid::bus::unpermitted;
542 }
543
544 sid::bus::status
545 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_2& data) throw()
546 {
547   return sid::bus::unpermitted;
548 }
549
550 sid::bus::status
551 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_2& data) throw()
552 {
553   return sid::bus::unpermitted;
554 }
555
556 sid::bus::status
557 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_8& data) throw()
558 {
559   return sid::bus::unpermitted;
560 }
561
562 sid::bus::status
563 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_8& data) throw()
564 {
565   return sid::bus::unpermitted;
566 }
567
568 sid::bus::status
569 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_1 data) throw()
570 {
571   return sid::bus::unpermitted;
572 }
573
574 sid::bus::status
575 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_1 data) throw()
576 {
577   return sid::bus::unpermitted;
578 }
579
580 sid::bus::status
581 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_2 data) throw()
582 {
583   return sid::bus::unpermitted;
584 }
585
586 sid::bus::status
587 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_2 data) throw()
588 {
589   return sid::bus::unpermitted;
590 }
591
592 sid::bus::status
593 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_8 data) throw()
594 {
595   return sid::bus::unpermitted;
596 }
597
598 sid::bus::status
599 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_8 data) throw()
600 {
601   return sid::bus::unpermitted;
602 }
603
604 // Called when the scheduled event arrives.
605 // Decrement the counter register and check for an interrupt
606 // condition--and if so, drive the interrupt pin.
607
608 void
609 Timer::tick()
610 {
611   if (!enabled) return;
612   
613   counter--;
614   if (counter == 0)
615     {
616       if (mode == PERIODIC)
617         {
618           counter = load_value;
619           drive_interrupt(1);
620         }
621       else
622         {
623           // Rolls over from maximum value; no interrupts.
624           counter = 0xFFFF;
625         }
626     }
627 }
628
629
630 // Return a list of component types supported by this library.
631
632 static vector<string>
633 TimerListTypes()
634 {
635   vector<string> types;
636   types.push_back("hw-timer-example");
637   return types;
638 }
639
640 // Instantiate a component, given a specified component type.
641
642 static sid::component*
643 TimerCreate(const string& typeName)
644 {
645   if (typeName == "hw-timer-example")
646     return new Timer();
647
648   return 0;
649 }
650
651 // Destruct a component instance.
652
653 static void
654 TimerDelete(sid::component* c)
655 {
656   delete dynamic_cast<Timer*>(c);
657 }
658
659
660 } // end namespace
661
662
663 // This symbol is used by the library loader to validate the library
664 // and instantiate components of the types supported by this library.
665
666 extern const sid::component_library example_component_library;
667
668 const sid::component_library example_component_library DLLEXPORT =
669 {
670   sid::COMPONENT_LIBRARY_MAGIC,
671   &timer_example::TimerListTypes,
672   &timer_example::TimerCreate,
673   &timer_example::TimerDelete
674 };