sparc: Use big endian packet accessors.
[gem5.git] / src / dev / mc146818.cc
index 276c985817e45a4ea83912655defb1f91f4cbb09..4f5793543a3117fd7c1b300005600042fb666e75 100644 (file)
@@ -30,6 +30,8 @@
  *          Miguel Serrano
  */
 
+#include "dev/mc146818.hh"
+
 #include <sys/time.h>
 
 #include <ctime>
@@ -39,7 +41,6 @@
 #include "base/time.hh"
 #include "base/trace.hh"
 #include "debug/MC146818.hh"
-#include "dev/mc146818.hh"
 #include "dev/rtcreg.h"
 
 using namespace std;
@@ -122,6 +123,18 @@ MC146818::rega_dv_disabled(const RtcRegA &reg)
         reg.dv == RTCA_DV_DISABLED1;
 }
 
+void
+MC146818::startup()
+{
+    assert(!event.scheduled());
+    assert(!tickEvent.scheduled());
+
+    if (stat_regB.pie)
+        schedule(event, curTick() + event.offset);
+    if (!rega_dv_disabled(stat_regA))
+        schedule(tickEvent, curTick() + tickEvent.offset);
+}
+
 void
 MC146818::writeData(const uint8_t addr, const uint8_t data)
 {
@@ -144,7 +157,8 @@ MC146818::writeData(const uint8_t addr, const uint8_t data)
               // The "update in progress" bit is read only.
               stat_regA.uip = old_rega;
 
-              if (stat_regA.dv != RTCA_DV_32768HZ) {
+              if (!rega_dv_disabled(stat_regA) &&
+                  stat_regA.dv != RTCA_DV_32768HZ) {
                   inform("RTC: Unimplemented divider configuration: %i\n",
                         stat_regA.dv);
                   panic_unsupported = true;
@@ -155,14 +169,23 @@ MC146818::writeData(const uint8_t addr, const uint8_t data)
                         stat_regA.rs);
                   panic_unsupported = true;
               }
+
+              if (rega_dv_disabled(stat_regA)) {
+                  // The divider is disabled, make sure that we don't
+                  // schedule any ticks.
+                  if (tickEvent.scheduled())
+                      deschedule(tickEvent);
+              } else if (rega_dv_disabled(old_rega))  {
+                  // According to the specification, the next tick
+                  // happens after 0.5s when the divider chain goes
+                  // from reset to active. So, we simply schedule the
+                  // tick after 0.5s.
+                  assert(!tickEvent.scheduled());
+                  schedule(tickEvent, curTick() + SimClock::Int::s / 2);
+              }
           } break;
           case RTC_STAT_REGB:
             stat_regB = data;
-            if (stat_regB.set) {
-                inform("RTC: Updating stopping not implemented.\n");
-                panic_unsupported = true;
-            }
-
             if (stat_regB.aie || stat_regB.uie) {
                 inform("RTC: Unimplemented interrupt configuration: %s %s\n",
                       stat_regB.aie ? "alarm" : "",
@@ -233,6 +256,8 @@ MC146818::readData(uint8_t addr)
 void
 MC146818::tickClock()
 {
+    assert(!rega_dv_disabled(stat_regA));
+
     if (stat_regB.set)
         return;
     time_t calTime = mkutctime(&curTime);
@@ -241,17 +266,17 @@ MC146818::tickClock()
 }
 
 void
-MC146818::serialize(const string &base, ostream &os)
+MC146818::serialize(const string &base, CheckpointOut &cp) const
 {
     uint8_t regA_serial(stat_regA);
     uint8_t regB_serial(stat_regB);
 
-    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
-    paramOut(os, base + ".stat_regA", (uint8_t)regA_serial);
-    paramOut(os, base + ".stat_regB", (uint8_t)regB_serial);
+    arrayParamOut(cp, base + ".clock_data", clock_data, sizeof(clock_data));
+    paramOut(cp, base + ".stat_regA", (uint8_t)regA_serial);
+    paramOut(cp, base + ".stat_regB", (uint8_t)regB_serial);
 
     //
-    // save the timer tick and rtc clock tick values to correctly reschedule 
+    // save the timer tick and rtc clock tick values to correctly reschedule
     // them during unserialize
     //
     Tick rtcTimerInterruptTickOffset = event.when() - curTick();
@@ -261,17 +286,16 @@ MC146818::serialize(const string &base, ostream &os)
 }
 
 void
-MC146818::unserialize(const string &base, Checkpoint *cp,
-                      const string &section)
+MC146818::unserialize(const string &base, CheckpointIn &cp)
 {
     uint8_t tmp8;
 
-    arrayParamIn(cp, section, base + ".clock_data", clock_data,
+    arrayParamIn(cp, base + ".clock_data", clock_data,
                  sizeof(clock_data));
 
-    paramIn(cp, section, base + ".stat_regA", tmp8);
+    paramIn(cp, base + ".stat_regA", tmp8);
     stat_regA = tmp8;
-    paramIn(cp, section, base + ".stat_regB", tmp8);
+    paramIn(cp, base + ".stat_regB", tmp8);
     stat_regB = tmp8;
 
     //
@@ -279,17 +303,16 @@ MC146818::unserialize(const string &base, Checkpoint *cp,
     //
     Tick rtcTimerInterruptTickOffset;
     UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
-    reschedule(event, curTick() + rtcTimerInterruptTickOffset);
+    event.offset = rtcTimerInterruptTickOffset;
     Tick rtcClockTickOffset;
     UNSERIALIZE_SCALAR(rtcClockTickOffset);
-    reschedule(tickEvent, curTick() + rtcClockTickOffset);
+    tickEvent.offset = rtcClockTickOffset;
 }
 
 MC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i)
-    : parent(_parent), interval(i)
+    : parent(_parent), interval(i), offset(i)
 {
     DPRINTF(MC146818, "RTC Event Initilizing\n");
-    parent->schedule(this, curTick() + interval);
 }
 
 void