dev: prevent intel 8254 timer counter events firing before startup
authorcdirik <cdirik@micron.com>
Tue, 6 Jan 2015 22:10:22 +0000 (15:10 -0700)
committercdirik <cdirik@micron.com>
Tue, 6 Jan 2015 22:10:22 +0000 (15:10 -0700)
This change includes edits to Intel8254Timer to prevent counter events firing
before startup to comply with SimObject initialization call sequence.

Committed by: Nilay Vaish <nilay@cs.wisc.edu>

src/dev/alpha/tsunami_io.cc
src/dev/intel_8254_timer.cc
src/dev/intel_8254_timer.hh
src/dev/mips/malta_io.cc
src/dev/x86/i8254.cc
src/dev/x86/i8254.hh

index a20cd8a88145c8f38b22617a9cb8d3a3d6cae6fd..2236546fc8aa18dd876768fd3a12c97d19a13368 100644 (file)
@@ -288,6 +288,7 @@ void
 TsunamiIO::startup()
 {
     rtc.startup();
+    pitimer.startup();
 }
 
 TsunamiIO *
index 4aa3fec143dc596b9f486d70f647497369830e63..63bb6e8afeb901f99e5c11edc40250f1b59eabdd 100644 (file)
@@ -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;
+}
+
index ad751447edbdfe564fc56f0172c5dea35a6aa3de..b2fd949f2abea48841e6623df1b6ada271ea0a43 100644 (file)
@@ -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 &section);
+
+        /** Start ticking */
+        void startup();
     };
 
   protected:
@@ -246,6 +257,9 @@ class Intel8254Timer : public EventManager
      */
     void unserialize(const std::string &base, Checkpoint *cp,
                      const std::string &section);
+
+    /** Start ticking */
+    void startup();
 };
 
 #endif // __DEV_8254_HH__
index 6797a054ce7e1dbea0c72ea8dea9e1710665ae6e..d79e43260ff528008fdc9ad5362b25695f1be375 100755 (executable)
@@ -146,6 +146,7 @@ void
 MaltaIO::startup()
 {
     rtc.startup();
+    pitimer.startup();
 }
 
 MaltaIO *
index f6af34a655a5c878586146c80b4885d27c440c14..b80952237492d208114afbc666a8d8b041b98c8e 100644 (file)
@@ -89,6 +89,12 @@ X86ISA::I8254::unserialize(Checkpoint *cp, const std::string &section)
     pit.unserialize("pit", cp, section);
 }
 
+void
+X86ISA::I8254::startup()
+{
+    pit.startup();
+}
+
 X86ISA::I8254 *
 I8254Params::create()
 {
index 49ea271e94ea9f0578f0c9a5253c536f35f16277..76521e73ed6b6abd248fa41c4ab2752614e45a1a 100644 (file)
@@ -111,6 +111,7 @@ class I8254 : public BasicPioDevice
 
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
+    virtual void startup();
 
 };