summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2009-08-20 00:42:43 -0700
committerGabe Black <gblack@eecs.umich.edu>2009-08-20 00:42:43 -0700
commitda3c3bfa98e7cf81010a476b0b6ceba4c936f417 (patch)
tree033a31bb94eee23f76d1825510d6f54eb49ec810 /src
parente8c0ca5cd15be99ea8b56ac64824fce50e76d577 (diff)
downloadgem5-da3c3bfa98e7cf81010a476b0b6ceba4c936f417.tar.xz
X86: Make the real time clock actually keep track of time.
Diffstat (limited to 'src')
-rw-r--r--src/dev/mc146818.cc96
-rw-r--r--src/dev/mc146818.hh26
2 files changed, 103 insertions, 19 deletions
diff --git a/src/dev/mc146818.cc b/src/dev/mc146818.cc
index 2ee5dbaaa..8d289a416 100644
--- a/src/dev/mc146818.cc
+++ b/src/dev/mc146818.cc
@@ -43,28 +43,20 @@
using namespace std;
-MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
- bool bcd, Tick frequency)
- : EventManager(em), _name(n), event(this, frequency)
+static uint8_t
+bcdize(uint8_t val)
{
- memset(clock_data, 0, sizeof(clock_data));
- stat_regA = RTCA_32768HZ | RTCA_1024HZ;
- stat_regB = RTCB_PRDC_IE | RTCB_24HR;
- if (!bcd)
- stat_regB |= RTCB_BIN;
+ uint8_t result;
+ result = val % 10;
+ result += (val / 10) << 4;
+ return result;
+}
+void
+MC146818::setTime(const struct tm time)
+{
+ curTime = time;
year = time.tm_year;
-
- if (bcd) {
- // 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 = year % 100;
- int tens = year / 10;
- int ones = year % 10;
- year = (tens << 4) + ones;
- }
-
// Unix is 0-11 for month, data seet says start at 1
mon = time.tm_mon + 1;
mday = time.tm_mday;
@@ -75,6 +67,30 @@ MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
// Datasheet says 1 is sunday
wday = time.tm_wday + 1;
+ 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);
+ }
+}
+
+MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
+ bool bcd, Tick frequency)
+ : EventManager(em), _name(n), event(this, frequency), tickEvent(this)
+{
+ memset(clock_data, 0, sizeof(clock_data));
+ stat_regA = RTCA_32768HZ | RTCA_1024HZ;
+ stat_regB = RTCB_PRDC_IE | RTCB_24HR;
+ if (!bcd)
+ stat_regB |= RTCB_BIN;
+
+ setTime(time);
DPRINTFN("Real-time clock set to %s", asctime(&time));
}
@@ -141,6 +157,34 @@ MC146818::readData(uint8_t addr)
}
}
+static time_t
+mkutctime(struct tm *time)
+{
+ time_t ret;
+ char *tz;
+
+ tz = getenv("TZ");
+ setenv("TZ", "", 1);
+ tzset();
+ ret = mktime(time);
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ return ret;
+}
+
+void
+MC146818::tickClock()
+{
+ if (stat_regB & RTCB_NO_UPDT)
+ return;
+ time_t calTime = mkutctime(&curTime);
+ calTime++;
+ setTime(*gmtime(&calTime));
+}
+
void
MC146818::serialize(const string &base, ostream &os)
{
@@ -190,3 +234,17 @@ MC146818::RTCEvent::description() const
{
return "RTC interrupt";
}
+
+void
+MC146818::RTCTickEvent::process()
+{
+ DPRINTF(MC146818, "RTC clock tick\n");
+ parent->schedule(this, curTick + Clock::Int::s);
+ parent->tickClock();
+}
+
+const char *
+MC146818::RTCTickEvent::description() const
+{
+ return "RTC clock tick";
+}
diff --git a/src/dev/mc146818.hh b/src/dev/mc146818.hh
index e145ad3fd..e33658903 100644
--- a/src/dev/mc146818.hh
+++ b/src/dev/mc146818.hh
@@ -64,6 +64,23 @@ class MC146818 : public EventManager
virtual const char *description() const;
};
+ /** Event for RTC periodic interrupt */
+ struct RTCTickEvent : public Event
+ {
+ MC146818 * parent;
+
+ RTCTickEvent(MC146818 * _parent) : parent(_parent)
+ {
+ parent->schedule(this, curTick + Clock::Int::s);
+ }
+
+ /** Event process to occur at interrupt*/
+ void process();
+
+ /** Event description */
+ const char *description() const;
+ };
+
private:
std::string _name;
const std::string &name() const { return _name; }
@@ -71,6 +88,9 @@ class MC146818 : public EventManager
/** RTC periodic interrupt event */
RTCEvent event;
+ /** RTC tick event */
+ RTCTickEvent tickEvent;
+
/** Data for real-time clock function */
union {
uint8_t clock_data[10];
@@ -89,6 +109,10 @@ class MC146818 : public EventManager
};
};
+ struct tm curTime;
+
+ void setTime(const struct tm time);
+
/** RTC status register A */
uint8_t stat_regA;
@@ -106,6 +130,8 @@ class MC146818 : public EventManager
/** RTC read data */
uint8_t readData(const uint8_t addr);
+ void tickClock();
+
/**
* Serialize this object to the given output stream.
* @param base The base name of the counter object.