From 1693e526d090f47323e378f0bd8546f28c2a97f7 Mon Sep 17 00:00:00 2001 From: cdirik Date: Tue, 6 Jan 2015 15:10:22 -0700 Subject: [PATCH] dev: prevent intel 8254 timer counter events firing before startup This change includes edits to Intel8254Timer to prevent counter events firing before startup to comply with SimObject initialization call sequence. Committed by: Nilay Vaish --- src/dev/alpha/tsunami_io.cc | 1 + src/dev/intel_8254_timer.cc | 54 +++++++++++++++++++++++++++---------- src/dev/intel_8254_timer.hh | 14 ++++++++++ src/dev/mips/malta_io.cc | 1 + src/dev/x86/i8254.cc | 6 +++++ src/dev/x86/i8254.hh | 1 + 6 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/dev/alpha/tsunami_io.cc b/src/dev/alpha/tsunami_io.cc index a20cd8a88..2236546fc 100644 --- a/src/dev/alpha/tsunami_io.cc +++ b/src/dev/alpha/tsunami_io.cc @@ -288,6 +288,7 @@ void TsunamiIO::startup() { rtc.startup(); + pitimer.startup(); } TsunamiIO * diff --git a/src/dev/intel_8254_timer.cc b/src/dev/intel_8254_timer.cc index 4aa3fec14..63bb6e8af 100644 --- a/src/dev/intel_8254_timer.cc +++ b/src/dev/intel_8254_timer.cc @@ -89,13 +89,22 @@ Intel8254Timer::unserialize(const string &base, Checkpoint *cp, counter[2]->unserialize(base + ".counter2", cp, section); } +void +Intel8254Timer::startup() +{ + counter[0]->startup(); + counter[1]->startup(); + counter[2]->startup(); +} + Intel8254Timer::Counter::Counter(Intel8254Timer *p, const string &name, unsigned int _num) - : _name(name), num(_num), event(this), initial_count(0), - latched_count(0), period(0), mode(0), output_high(false), - latch_on(false), read_byte(LSB), write_byte(LSB), parent(p) + : _name(name), num(_num), event(this), running(false), + initial_count(0), latched_count(0), period(0), mode(0), + output_high(false), latch_on(false), read_byte(LSB), + write_byte(LSB), parent(p) { - + offset = period * event.getInterval(); } void @@ -179,7 +188,9 @@ Intel8254Timer::Counter::write(const uint8_t data) else period = initial_count; - if (period > 0) + offset = period * event.getInterval(); + + if (running && (period > 0)) event.setTo(period); write_byte = LSB; @@ -229,10 +240,10 @@ Intel8254Timer::Counter::serialize(const string &base, ostream &os) paramOut(os, base + ".read_byte", read_byte); paramOut(os, base + ".write_byte", write_byte); - Tick event_tick = 0; + Tick event_tick_offset = 0; if (event.scheduled()) - event_tick = event.when(); - paramOut(os, base + ".event_tick", event_tick); + event_tick_offset = event.when() - curTick(); + paramOut(os, base + ".event_tick_offset", event_tick_offset); } void @@ -248,12 +259,20 @@ Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp, paramIn(cp, section, base + ".read_byte", read_byte); paramIn(cp, section, base + ".write_byte", write_byte); - Tick event_tick = 0; - if (event.scheduled()) - parent->deschedule(event); - paramIn(cp, section, base + ".event_tick", event_tick); - if (event_tick) - parent->schedule(event, event_tick); + Tick event_tick_offset = 0; + assert(!event.scheduled()); + paramIn(cp, section, base + ".event_tick_offset", event_tick_offset); + offset = event_tick_offset; +} + +void +Intel8254Timer::Counter::startup() +{ + running = true; + if ((period > 0) && (offset > 0)) + { + parent->schedule(event, curTick() + offset); + } } Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) @@ -302,3 +321,10 @@ Intel8254Timer::Counter::CounterEvent::description() const { return "Intel 8254 Interval timer"; } + +Tick +Intel8254Timer::Counter::CounterEvent::getInterval() +{ + return interval; +} + diff --git a/src/dev/intel_8254_timer.hh b/src/dev/intel_8254_timer.hh index ad751447e..b2fd949f2 100644 --- a/src/dev/intel_8254_timer.hh +++ b/src/dev/intel_8254_timer.hh @@ -102,6 +102,8 @@ class Intel8254Timer : public EventManager void setTo(int clocks); int clocksLeft(); + + Tick getInterval(); }; private: @@ -112,6 +114,9 @@ class Intel8254Timer : public EventManager CounterEvent event; + /** True after startup is called. */ + bool running; + /** Initial count value */ uint16_t initial_count; @@ -121,6 +126,9 @@ class Intel8254Timer : public EventManager /** Interrupt period */ uint16_t period; + /** When to start ticking */ + Tick offset; + /** Current mode of operation */ uint8_t mode; @@ -181,6 +189,9 @@ class Intel8254Timer : public EventManager */ void unserialize(const std::string &base, Checkpoint *cp, const std::string §ion); + + /** Start ticking */ + void startup(); }; protected: @@ -246,6 +257,9 @@ class Intel8254Timer : public EventManager */ void unserialize(const std::string &base, Checkpoint *cp, const std::string §ion); + + /** Start ticking */ + void startup(); }; #endif // __DEV_8254_HH__ diff --git a/src/dev/mips/malta_io.cc b/src/dev/mips/malta_io.cc index 6797a054c..d79e43260 100755 --- a/src/dev/mips/malta_io.cc +++ b/src/dev/mips/malta_io.cc @@ -146,6 +146,7 @@ void MaltaIO::startup() { rtc.startup(); + pitimer.startup(); } MaltaIO * diff --git a/src/dev/x86/i8254.cc b/src/dev/x86/i8254.cc index f6af34a65..b80952237 100644 --- a/src/dev/x86/i8254.cc +++ b/src/dev/x86/i8254.cc @@ -89,6 +89,12 @@ X86ISA::I8254::unserialize(Checkpoint *cp, const std::string §ion) pit.unserialize("pit", cp, section); } +void +X86ISA::I8254::startup() +{ + pit.startup(); +} + X86ISA::I8254 * I8254Params::create() { diff --git a/src/dev/x86/i8254.hh b/src/dev/x86/i8254.hh index 49ea271e9..76521e73e 100644 --- a/src/dev/x86/i8254.hh +++ b/src/dev/x86/i8254.hh @@ -111,6 +111,7 @@ class I8254 : public BasicPioDevice virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); + virtual void startup(); }; -- 2.30.2