Brad's issues with the timer device and checkpointing reminded me that I
wasn't really happy with that code; in particular, the redundant storage in
both clock_data[] and curTime seemed bound to cause problems when they got
out of sync, and in fact Brad's checkpointing fix was incomplete in that it
didn't save and restore curTime.

I tweaked the code to get rid of curTime; now clock_data is the only state,
and we convert to/from a struct tm only temporarily as needed.  This code
passes the regressions, but since there's no X86_FS regression and that
might be the only config that cares, I didn't want to just check it in
without getting some feedback.

On a separate but related note, I also think that we can get rid of the
mkutctime() call.  We really just need a reversible conversion from 'struct
tm' to 'time_t' and back, and although mkutctime/gmtime provides that, I
don't see why mktime/localtime wouldn't do just as well (while being
simpler).  Thoughts?

Steve

-------------------

diff -r 9c33426d404a src/dev/mc146818.hh
--- a/src/dev/mc146818.hh       Mon Oct 19 17:29:34 2009 -0400
+++ b/src/dev/mc146818.hh       Tue Oct 20 22:18:27 2009 -0700
@@ -91,27 +91,33 @@
     /** RTC tick event */
     RTCTickEvent tickEvent;

+    struct ClockFields {
+        uint8_t sec;
+        uint8_t sec_alrm;
+        uint8_t min;
+        uint8_t min_alrm;
+        uint8_t hour;
+        uint8_t hour_alrm;
+        uint8_t wday;
+        uint8_t mday;
+        uint8_t mon;
+        uint8_t year;
+
+        void setBCDFromBinary(const ClockFields *);
+        void setBinaryFromBCD(const ClockFields *);
+
+        void setTime(const struct tm time);
+        void getTime(struct tm *time);
+    };
+
     /** Data for real-time clock function */
     union {
         uint8_t clock_data[10];
-
-        struct {
-            uint8_t sec;
-            uint8_t sec_alrm;
-            uint8_t min;
-            uint8_t min_alrm;
-            uint8_t hour;
-            uint8_t hour_alrm;
-            uint8_t wday;
-            uint8_t mday;
-            uint8_t mon;
-            uint8_t year;
-        };
+        struct ClockFields clock_fields;
     };

-    struct tm curTime;
-
     void setTime(const struct tm time);
+    void getTime(struct tm *time);

     /** RTC status register A */
     uint8_t stat_regA;
diff -r 9c33426d404a src/dev/mc146818.cc
--- a/src/dev/mc146818.cc       Mon Oct 19 17:29:34 2009 -0400
+++ b/src/dev/mc146818.cc       Tue Oct 20 22:18:27 2009 -0700
@@ -62,33 +62,90 @@
 }

 void
+MC146818::ClockFields::setBCDFromBinary(const ClockFields *src)
+{
+    // note that possibly src == this for in-place conversion
+    sec = bcdize(src->sec);
+    min = bcdize(src->min);
+    hour = bcdize(src->hour);
+    wday = src->wday; // wday < 8, so no need to convert
+    mday = bcdize(src->mday);
+    mon = bcdize(src->mon);
+    // The datasheet says that the year field can be either BCD or
+    // years since 1900.  Linux seems to be happy with years since
+    // 1900.
+    year = bcdize(src->year % 100);
+}
+
+void
+MC146818::ClockFields::setBinaryFromBCD(const ClockFields *src)
+{
+    // note that possibly src == this for in-place conversion
+    sec = unbcdize(src->sec);
+    min = unbcdize(src->min);
+    hour = unbcdize(src->hour);
+    wday = src->wday; // wday < 8, so no need to convert
+    mday = unbcdize(src->mday);
+    mon = unbcdize(src->mon);
+    // binary year is years since 1900, not just year % 100
+    // assume range of 1970-2069
+    year = unbcdize(src->year);
+    if (year < 70)
+        year += 100;
+}
+
+void
+MC146818::ClockFields::setTime(const struct tm time)
+{
+    sec = time.tm_sec;
+    min = time.tm_min;
+    hour = time.tm_hour;
+    // Datasheet says 1 is sunday
+    wday = time.tm_wday + 1;
+    mday = time.tm_mday;
+    // Unix is 0-11 for month, data sheet says start at 1
+    mon = time.tm_mon + 1;
+    year = time.tm_year % 1900;
+}
+
+void
+MC146818::ClockFields::getTime(struct tm *time)
+{
+    // inverse of setTime
+    time->tm_sec = sec;
+    time->tm_min = min;
+    time->tm_hour = hour;
+    time->tm_wday = wday - 1;
+    time->tm_mday = mday;
+    time->tm_mon = mon - 1;
+    time->tm_year = year + 1900;
+}
+
+void
 MC146818::setTime(const struct tm time)
 {
-    curTime = time;
-    year = time.tm_year;
-    // Unix is 0-11 for month, data seet says start at 1
-    mon = time.tm_mon + 1;
-    mday = time.tm_mday;
-    hour = time.tm_hour;
-    min = time.tm_min;
-    sec = time.tm_sec;
-
-    // Datasheet says 1 is sunday
-    wday = time.tm_wday + 1;
+    clock_fields.setTime(time);

     if (!(stat_regB & RTCB_BIN)) {
-        // The datasheet says that the year field can be either BCD or
-        // years since 1900.  Linux seems to be happy with years since
-        // 1900.
-        year = bcdize(year % 100);
-        mon = bcdize(mon);
-        mday = bcdize(mday);
-        hour = bcdize(hour);
-        min = bcdize(min);
-        sec = bcdize(sec);
+        clock_fields.setBCDFromBinary(&clock_fields);
     }
 }

+void
+MC146818::getTime(struct tm *time)
+{
+    // inverse of setTime
+    if (!(stat_regB & RTCB_BIN)) {
+        // convert temporarily to binary
+        ClockFields tmp_clock_fields;
+        tmp_clock_fields.setBinaryFromBCD(&clock_fields);
+        tmp_clock_fields.getTime(time);
+    } else {
+        clock_fields.getTime(time);
+    }
+}
+
+
 MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
                    bool bcd, Tick frequency)
     : EventManager(em), _name(n), event(this, frequency), tickEvent(this)
@@ -112,13 +169,6 @@
 {
     if (addr < RTC_STAT_REGA) {
         clock_data[addr] = data;
-        curTime.tm_sec = unbcdize(sec);
-        curTime.tm_min = unbcdize(min);
-        curTime.tm_hour = unbcdize(hour);
-        curTime.tm_mday = unbcdize(mday);
-        curTime.tm_mon = unbcdize(mon) - 1;
-        curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950;
-        curTime.tm_wday = unbcdize(wday) - 1;
     } else {
         switch (addr) {
           case RTC_STAT_REGA:
@@ -196,6 +246,8 @@
 {
     if (stat_regB & RTCB_NO_UPDT)
         return;
+    struct tm curTime;
+    getTime(&curTime);
     time_t calTime = mkutctime(&curTime);
     calTime++;
     setTime(*gmtime(&calTime));
_______________________________________________
m5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to