1 // arm.cxx - An implementation of the timer from the ARM PID7T
2 // development board. -*- C++ -*-
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.
9 // A more thorough description of this component may be found at
10 // <http://www.arm.com/Documentation/UserMans/rps/#timer>
12 #include "arm7t-timer.h"
14 ostream& operator << (ostream& o, const armTimer::timer_mode& m)
18 case armTimer::free_running:
21 case armTimer::periodic:
30 istream& operator >> (istream& i, armTimer::timer_mode& m)
34 if (mode == "free-running")
35 m = armTimer::free_running;
36 else if (mode == "periodic")
37 m = armTimer::periodic;
39 i.setstate (ios::badbit);
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)
51 add_bus("registers", &this->bus);
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");
58 add_attribute("counter", &this->counter, "register");
59 triggerpoint_manager.add_watchable_attribute("counter");
60 categorize("counter", "watchable");
62 add_attribute("load-value", &this->loadValue, "register");
63 triggerpoint_manager.add_watchable_attribute("load-value");
64 categorize("load-value", "watchable");
66 add_attribute("enabled", &this->enabled, "register");
67 triggerpoint_manager.add_watchable_attribute("enabled");
68 categorize("enabled", "watchable");
70 add_attribute("mode", &this->mode, "register");
71 triggerpoint_manager.add_watchable_attribute("mode");
72 categorize("mode", "watchable");
74 add_attribute("prescale", &this->prescale, "register");
75 triggerpoint_manager.add_watchable_attribute("prescale");
76 categorize("prescale", "watchable");
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");
83 add_attribute_virtual ("state-snapshot", this,
84 & armTimer:: save_state,
85 & armTimer:: restore_state);
94 this->enabled = false;
96 this->mode = free_running;
98 if (this->interrupt_pin.recall() != 0)
99 this->interrupt_pin.drive (0);
100 this->reset_schedule ();
104 armTimerNoSched::armTimerNoSched()
105 :armTimer(), clockpin(this, & armTimerNoSched::tick), ticks(0)
107 add_pin("clock", &clockpin);
109 add_attribute_ro("ticks", &ticks, "register");
110 triggerpoint_manager.add_watchable_attribute("ticks");
111 categorize("ticks", "watchable");
116 armTimerNoSched::reset ()
123 armTimerSched::armTimerSched()
124 :armTimer(), ticker("divided-clock", this, & armTimer::tick)
133 // check for triggerpoints
134 triggerpoint_manager.check_and_dispatch();
140 // cerr << "divisor=" << divisor << " counter=" << counter << endl;
143 if (mode == periodic) {
145 if (interrupt_pin.recall() != 1)
146 interrupt_pin.drive(1);
148 counter = 65535; // rolls over from maximum value; no interrupts
155 armTimerNoSched::tick()
157 // check for triggerpoints
158 triggerpoint_manager.check_and_dispatch();
165 cerr << "hw-timer-arm/ref error: invalid prescale value" << prescale << endl;
168 assert (prescale <= 3);
169 unsigned divisor = 1 << (prescale * 4);
172 assert (divisor != 0);
173 if ((ticks % divisor) == 0) {
182 armTimerSched::reset_schedule()
184 // cerr << "reset_schedule" << endl;
185 this->ticker.cancel();
190 // XXX: prescale == 3 has undefined behavior.
191 assert (prescale <= 3);
192 unsigned divisor = 1 << (prescale * 4);
194 // cerr << "divisor = " << divisor << endl;
195 this->ticker.schedule_regular (divisor);
202 armTimer::bus_interface::word_write(host_int_4 addr,
204 little_int_4 le_data)
206 host_int_4 data = le_data;
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;
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();
225 if (host->interrupt_pin.recall() != 0)
226 host->interrupt_pin.drive(0);
232 return bus::unmapped;
235 // check for triggerpoints
236 host->triggerpoint_manager.check_and_dispatch();
241 armTimer::bus_interface::word_read(host_int_4 addr,
249 data = host->loadValue;
254 data = host->counter;
259 data = (host->enabled << 7) | (host->mode << 6) | (host->prescale << 2);
271 return bus::unmapped;
278 armTimer::save_state()
280 return make_attribute(*this);
284 sid::component::status
285 armTimer::restore_state(const string& state)
287 return parse_attribute(state, *this);
291 operator << (ostream& op, const armTimer& obj)
297 istream& operator >> (istream& ip, armTimer& obj)
304 armTimer::stream(ostream& op) const
306 op << "Interrupt " << interrupt_pin << ' ';
307 op << "Counter " << counter << ' ';
308 op << "Enable " << enabled << ' ';
309 op << "LoadValue " << loadValue << ' ';
311 op << "Prescale " << prescale << ' ';
312 op << "Reset " << reset_pin;
316 armTimerNoSched::stream(ostream& op) const
318 armTimer::stream(op);
322 op << ' ' << "Ticks " << ticks;
326 armTimerNoSched::destream(istream& ip)
328 armTimer::destream(ip);
337 ip.setstate(ios::badbit);
345 armTimer::destream(istream& ip)
350 if (key == "Interrupt")
356 ip.setstate(ios::badbit);
361 if (key == "Counter")
365 ip.setstate(ios::badbit);
372 ip.setstate(ios::badbit);
379 if (key != "LoadValue")
381 ip.setstate(ios::badbit);
387 // following >> is taken care by timer_mode operator
391 if (key != "Prescale")
393 ip.setstate(ios::badbit);
402 ip.setstate(ios::badbit);