1 // timer.cxx - an example of a SID component implementation. -*- C++ -*-
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.
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.
23 // Wrap everything in a unique namespace
24 namespace timer_example
28 // Import standard types into this namespace.
32 class Timer: public virtual sid::component
36 :scheduler_pin(0), clock_pin(this), bus(this), enabled(false) { }
38 // Provide implementations for abstract methods in sid::component.
39 // See include/sidcomp.h.
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();
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();
51 vector<string> bus_names() throw();
52 sid::bus* find_bus(const string& name) throw();
53 sid::bus* connected_bus(const string& name) throw();
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();
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();
66 // A netlist, which tracks pins connected to the interrupt pin.
67 typedef set<sid::pin*> netlist_t;
68 netlist_t intpin_netlist;
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;
76 // Schedule an event for some time in the future.
77 void schedule(sid::host_int_4 time);
79 // Cancel any pending events.
82 // Reschedule an event.
83 void reset_schedule();
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.
91 // Drive a value on the interrupt pin (which propogates to all
93 void drive_interrupt(sid::host_int_4 value);
95 class clock_pin_t: public sid::pin
97 // clock_pin_t is a specialised pin.
98 // It calls timer->tick() whenever a value is driven.
100 clock_pin_t(Timer* t): timer(t) { }
101 void driven(sid::host_int_4 value) throw() { timer->tick(); }
105 friend class clock_pin_t;
106 clock_pin_t clock_pin;
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.
113 class register_bus: public sid::bus
116 register_bus(Timer* t): timer(t) { }
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();
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();
140 friend class register_bus;
143 // Data members that represent the timer's internal state.
146 sid::host_int_2 load_value, prescale, counter;
147 enum timer_mode { PERIODIC, FREERUNNING } mode;
151 // Return a list of pin names which are visible to other components.
154 Timer::pin_names() throw()
157 pins.push_back("divided-clock-event");
162 // Return a list of pins that are connected to a named pin.
163 // We recognize "interrupt" and "divided-clock-control".
166 Timer::connected_pins(const string& name) throw()
168 vector<sid::pin*> pins;
169 netlist_t::const_iterator it;
171 if (name == "interrupt")
173 for (it = intpin_netlist.begin(); it != intpin_netlist.end();
180 else if (name == "divided-clock-control")
182 pins.push_back(scheduler_pin);
185 return vector<sid::pin*>();
189 // Connect a pin to a named pin.
190 // We recognize "interrupt" and "divided-clock-control".
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.
197 sid::component::status
198 Timer::connect_pin(const string& name, sid::pin* pin) throw()
200 if (name == "interrupt")
202 // Add this pin to the netlist.
203 intpin_netlist.insert(intpin_netlist.end(), pin);
204 return sid::component::ok;
206 else if (name == "divided-clock-control")
208 // Reassign the scheduler pin.
210 return sid::component::ok;
212 return sid::component::not_found;
215 // Disconnect a pin from a named pin.
217 sid::component::status
218 Timer::disconnect_pin(const string& name, sid::pin* pin) throw()
220 if (name == "interrupt")
222 // Remove this pin from the netlist.
223 if (intpin_netlist.erase(pin) > 0)
224 return sid::component::ok;
226 else if (name == "divided-clock-control" && scheduler_pin == pin)
228 // Elsewhere, we make sure to not use this pin if it's null.
230 return sid::component::ok;
232 return sid::component::not_found;
236 // Find a pin of a given name.
237 // We only recognize "divided-clock-event".
240 Timer::find_pin(const string& name) throw()
242 if (name == "divided-clock-event")
250 Timer::accessor_names() throw()
253 return vector<string>();
257 sid::component::status
258 Timer::connect_accessor(const string& name, sid::bus* bus) throw()
260 // No acccessors; any name is unknown.
261 return sid::component::not_found;
265 sid::component::status
266 Timer::disconnect_accessor(const string& name, sid::bus* bus) throw()
268 // No accessors; any name is unknown.
269 return sid::component::not_found;
273 // Return a list of bus names. We have just one--"registers".
276 Timer::bus_names() throw()
278 vector<string> buses;
279 buses.push_back("registers");
284 Timer::find_bus(const string& name) throw()
286 if (name == "registers")
293 Timer::connected_bus(const string& name) throw()
295 // No connected buses; return a null pointer.
301 Timer::attribute_names() throw()
303 // No attributes; return an empty vector.
304 return vector<string>();
308 Timer::attribute_names(const string& category) throw()
310 // No attributes, regardless of category. Return an empty vector.
311 return vector<string>();
315 Timer::attribute_value(const string& name) throw()
317 // No attributes--return the empty string for any attribute value.
321 sid::component::status
322 Timer::set_attribute_value(const string& name, const string& value) throw()
324 // No attributes--return not_found regardless of attribute name.
325 return sid::component::not_found;
329 vector<sid::component*>
330 Timer::related_components(const string& rel) throw()
332 // No related components.
333 return vector<sid::component*>();
336 sid::component::status
337 Timer::unrelate(const string& rel, sid::component* c) throw()
339 // No related components; always unfound.
340 return sid::component::not_found;
343 sid::component::status
344 Timer::relate(const string& rel, sid::component* c) throw()
346 // No related components; always unfound.
347 return sid::component::not_found;
351 Timer::relationship_names() throw()
354 return vector<string>();
360 Timer::drive_interrupt(sid::host_int_4 value)
362 // Iterate the netlist, driving the value to all pins connected to
363 // the interrupt pin.
365 for (netlist_t::const_iterator it = intpin_netlist.begin();
366 it != intpin_netlist.end();
369 (*it)->driven(value);
374 // Schedule an event to be delivered at a later time.
377 Timer::schedule(sid::host_int_4 time)
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
384 assert ((time & 0x80000000) == 0);
385 assert ((time & 0x7FFFFFFF) != 0);
388 scheduler_pin->driven(0x80000000 | time);
392 // Cancel any pending event.
397 // Cancel the event by driving a zero value to the scheduler.
400 scheduler_pin->driven(0);
404 // Reset the schedule, in case the timer's enable or divisor registers
405 // have been altered.
408 Timer::reset_schedule()
415 assert (prescale <= 2);
416 unsigned divisor = 1 << (prescale * 4);
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.
427 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_4& data) throw()
430 return sid::bus::misaligned;
435 data = timer->load_value;
439 data = timer->counter;
444 (timer->enabled << 7) |
446 (timer->prescale << 2);
453 return sid::bus::unmapped;
460 // Handle 32-bit (big endian) reads.
461 // Just do a little endian read and rearrange the result.
464 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_4& data) throw()
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 ());
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.
478 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_4 data) throw()
481 return sid::bus::misaligned;
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;
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();
505 timer->drive_interrupt(0);
509 return sid::bus::unmapped;
516 // Handle 32-bit (big endian) writes.
517 // Just rearrange the data and do a little endian write.
520 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_4 data) throw()
522 sid::little_int_4 le_data;
523 le_data.set_target_memory_value (data.target_memory_value ());
524 return write(addr, le_data);
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.
533 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_1& data) throw()
535 return sid::bus::unpermitted;
539 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_1& data) throw()
541 return sid::bus::unpermitted;
545 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_2& data) throw()
547 return sid::bus::unpermitted;
551 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_2& data) throw()
553 return sid::bus::unpermitted;
557 Timer::register_bus::read(sid::host_int_4 addr, sid::little_int_8& data) throw()
559 return sid::bus::unpermitted;
563 Timer::register_bus::read(sid::host_int_4 addr, sid::big_int_8& data) throw()
565 return sid::bus::unpermitted;
569 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_1 data) throw()
571 return sid::bus::unpermitted;
575 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_1 data) throw()
577 return sid::bus::unpermitted;
581 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_2 data) throw()
583 return sid::bus::unpermitted;
587 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_2 data) throw()
589 return sid::bus::unpermitted;
593 Timer::register_bus::write(sid::host_int_4 addr, sid::little_int_8 data) throw()
595 return sid::bus::unpermitted;
599 Timer::register_bus::write(sid::host_int_4 addr, sid::big_int_8 data) throw()
601 return sid::bus::unpermitted;
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.
611 if (!enabled) return;
616 if (mode == PERIODIC)
618 counter = load_value;
623 // Rolls over from maximum value; no interrupts.
630 // Return a list of component types supported by this library.
632 static vector<string>
635 vector<string> types;
636 types.push_back("hw-timer-example");
640 // Instantiate a component, given a specified component type.
642 static sid::component*
643 TimerCreate(const string& typeName)
645 if (typeName == "hw-timer-example")
651 // Destruct a component instance.
654 TimerDelete(sid::component* c)
656 delete dynamic_cast<Timer*>(c);
663 // This symbol is used by the library loader to validate the library
664 // and instantiate components of the types supported by this library.
666 extern const sid::component_library example_component_library;
668 const sid::component_library example_component_library DLLEXPORT =
670 sid::COMPONENT_LIBRARY_MAGIC,
671 &timer_example::TimerListTypes,
672 &timer_example::TimerCreate,
673 &timer_example::TimerDelete