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