Instead of passing an int to represent time between python and C++
authorNathan Binkert <binkertn@umich.edu>
Thu, 25 Jan 2007 19:59:41 +0000 (14:59 -0500)
committerNathan Binkert <binkertn@umich.edu>
Thu, 25 Jan 2007 19:59:41 +0000 (14:59 -0500)
pass the tuple of python's struct_time and interpret that.
Fixes a problem where the local timezone leaked into the time
calculation.  Also fix things so that the unix, python, and RTC
data sheets all get the right time.  Provide both years since 1900
and BCD two digit year.
Put the date back at 1/1/2006 for now.

--HG--
extra : convert_revision : 473244572f468de2cb579a3dd7ae296a6f81f5d7

src/dev/alpha/tsunami_io.cc
src/dev/alpha/tsunami_io.hh
src/python/m5/objects/Tsunami.py
src/python/m5/params.py

index 38986b77e6146fb23849176ef2d0c7b12b8301db..d701dc98f27144110609d9b9ef200833a5d79695 100644 (file)
@@ -57,25 +57,77 @@ using namespace std;
 //Should this be AlphaISA?
 using namespace TheISA;
 
-TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami, time_t t, Tick i)
-    : _name(n), event(tsunami, i), addr(0)
+TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami, const vector<int> &t,
+                    bool bcd, Tick i)
+    : _name(n), event(tsunami, i), addr(0), year_is_bcd(bcd)
 {
     memset(clock_data, 0, sizeof(clock_data));
     stat_regA = RTCA_32768HZ | RTCA_1024HZ;
     stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
 
+    if (year_is_bcd) {
+        // The RTC uses BCD for the last two digits in the year.
+        // They python year is a full year.
+        int _year = t[0] % 100;
+        int tens = _year / 10;
+        int ones = _year % 10;
+
+        year = (tens << 4) + ones;
+    } else {
+        // Even though the datasheet says that the year field should be
+        // interpreted as BCD, we just enter the number of years since
+        // 1900 since linux seems to be happy with that (and I believe
+        // that Tru64 was as well)
+        year = t[0] - 1900;
+    }
+
+    mon = t[1];
+    mday = t[2];
+    hour = t[3];
+    min = t[4];
+    sec = t[5];
+
+    // wday is defined to be in the range from 1 - 7 with 1 being Sunday.
+    // the value coming from python is in the range from 0 - 6 with 0 being
+    // Monday.  Fix that here.
+    wday = t[6]  + 2;
+    if (wday > 7)
+        wday -= 7;
+
+    DPRINTFN("Real-time clock set to %s", getDateString());
+}
+
+std::string
+TsunamiIO::RTC::getDateString()
+{
     struct tm tm;
-    gmtime_r(&t, &tm);
 
-    sec = tm.tm_sec;
-    min = tm.tm_min;
-    hour = tm.tm_hour;
-    wday = tm.tm_wday + 1;
-    mday = tm.tm_mday;
-    mon = tm.tm_mon + 1;
-    year = tm.tm_year;
+    memset(&tm, 0, sizeof(tm));
+
+    if (year_is_bcd) {
+        // undo the BCD and conver to years since 1900 guessing that
+        // anything before 1970 is actually after 2000
+        int _year = (year >> 4) * 10 + (year & 0xf);
+        if (_year < 70)
+            _year += 100;
+
+        tm.tm_year = _year;
+    } else {
+        // number of years since 1900
+        tm.tm_year = year;
+    }
+
+    // unix is 0-11 for month
+    tm.tm_mon = mon - 1;
+    tm.tm_mday = mday;
+    tm.tm_hour = hour;
+    tm.tm_min = min;
+    tm.tm_sec = sec;
+
+    // to add more annoyance unix is 0 - 6 with 0 as sunday
+    tm.tm_wday = wday - 1;
 
-    DPRINTFN("Real-time clock set to %s", asctime(&tm));
+    return asctime(&tm);
 }
 
 void
@@ -424,7 +476,8 @@ TsunamiIO::PITimer::Counter::CounterEvent::description()
 
 TsunamiIO::TsunamiIO(Params *p)
     : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
-      rtc(p->name + ".rtc", p->tsunami, p->init_time, p->frequency)
+      rtc(p->name + ".rtc", p->tsunami, p->init_time, p->year_is_bcd,
+          p->frequency)
 {
     pioSize = 0x100;
 
@@ -649,7 +702,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
     Param<Tick> frequency;
     SimObjectParam<Platform *> platform;
     SimObjectParam<System *> system;
-    Param<time_t> time;
+    VectorParam<int> time;
+    Param<bool> year_is_bcd;
     SimObjectParam<Tsunami *> tsunami;
 
 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
@@ -662,6 +716,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
     INIT_PARAM(platform, "platform"),
     INIT_PARAM(system, "system object"),
     INIT_PARAM(time, "System time to use (0 for actual time"),
+    INIT_PARAM(year_is_bcd, ""),
     INIT_PARAM(tsunami, "Tsunami")
 
 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
@@ -676,6 +731,7 @@ CREATE_SIM_OBJECT(TsunamiIO)
     p->platform = platform;
     p->system = system;
     p->init_time = time;
+    p->year_is_bcd = year_is_bcd;
     p->tsunami = tsunami;
     return new TsunamiIO(p);
 }
index b0c368eb8f806cf8aaf0a74d296e31db300085d3..f42af4197637d3c3b6b95e2718e8025d96873d22 100644 (file)
@@ -85,6 +85,9 @@ class TsunamiIO : public BasicPioDevice
         /** Current RTC register address/index */
         int addr;
 
+        /** should the year be interpreted as BCD? */
+        bool year_is_bcd;
+
         /** Data for real-time clock function */
         union {
             uint8_t clock_data[10];
@@ -110,7 +113,8 @@ class TsunamiIO : public BasicPioDevice
         uint8_t stat_regB;
 
       public:
-        RTC(const std::string &name, Tsunami* tsunami, time_t t, Tick i);
+        RTC(const std::string &name, Tsunami* tsunami,
+            const std::vector<int> &t, bool bcd, Tick i);
 
         /** RTC address port: write address of RTC RAM data to access */
         void writeAddr(const uint8_t data);
@@ -121,6 +125,9 @@ class TsunamiIO : public BasicPioDevice
         /** RTC read data */
         uint8_t readData();
 
+        /** RTC get the date */
+        std::string getDateString();
+
         /**
           * Serialize this object to the given output stream.
           * @param base The base name of the counter object.
@@ -313,8 +320,10 @@ class TsunamiIO : public BasicPioDevice
     {
         Tick frequency;
         Tsunami *tsunami;
-        time_t init_time;
+        std::vector<int> init_time;
+        bool year_is_bcd;
     };
+
   protected:
     const Params *params() const { return (const Params*)_params; }
 
index 18a776a7ff1a47570842d4727be7286045ece426..3d8e6dd0478065578a00da7fce50c6e22854bd6d 100644 (file)
@@ -13,8 +13,10 @@ class TsunamiCChip(BasicPioDevice):
 
 class TsunamiIO(BasicPioDevice):
     type = 'TsunamiIO'
-    time = Param.Time('01/01/2009',
+    time = Param.Time('01/01/2006',
         "System time to use ('Now' for actual time)")
+    year_is_bcd = Param.Bool(False,
+        "The RTC should interpret the year as a BCD value")
     tsunami = Param.Tsunami(Parent.any, "Tsunami")
     frequency = Param.Frequency('1024Hz', "frequency of interrupts")
 
index d570804d8d916798ac2b7e8fc44770be49b1acbf..f8a9f9ddd1371201adca0019ffb07138d684883c 100644 (file)
@@ -518,49 +518,55 @@ class EthernetAddr(ParamValue):
         else:
             return self.value
 
+time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
+                 "%a %b %d %H:%M:%S %Z %Y",
+                 "%Y/%m/%d %H:%M:%S",
+                 "%Y/%m/%d %H:%M",
+                 "%Y/%m/%d",
+                 "%m/%d/%Y %H:%M:%S",
+                 "%m/%d/%Y %H:%M",
+                 "%m/%d/%Y",
+                 "%m/%d/%y %H:%M:%S",
+                 "%m/%d/%y %H:%M",
+                 "%m/%d/%y"]
+
+
 def parse_time(value):
-    strings = [ "%a %b %d %H:%M:%S %Z %Y",
-                "%a %b %d %H:%M:%S %Z %Y",
-                "%Y/%m/%d %H:%M:%S",
-                "%Y/%m/%d %H:%M",
-                "%Y/%m/%d",
-                "%m/%d/%Y %H:%M:%S",
-                "%m/%d/%Y %H:%M",
-                "%m/%d/%Y",
-                "%m/%d/%y %H:%M:%S",
-                "%m/%d/%y %H:%M",
-                "%m/%d/%y"]
-
-    for string in strings:
-        try:
-            return time.strptime(value, string)
-        except ValueError:
-            pass
+    from time import gmtime, strptime, struct_time, time
+    from datetime import datetime, date
+
+    if isinstance(value, struct_time):
+        return value
+
+    if isinstance(value, (int, long)):
+        return gmtime(value)
+
+    if isinstance(value, (datetime, date)):
+        return value.timetuple()
+
+    if isinstance(value, str):
+        if value in ('Now', 'Today'):
+            return time.gmtime(time.time())
+
+        for format in time_formats:
+            try:
+                return strptime(value, format)
+            except ValueError:
+                pass
 
     raise ValueError, "Could not parse '%s' as a time" % value
 
 class Time(ParamValue):
     cxx_type = 'time_t'
     def __init__(self, value):
-        if isinstance(value, time.struct_time):
-            self.value = time.mktime(value)
-        elif isinstance(value, int):
-            self.value = value
-        elif isinstance(value, str):
-            if value in ('Now', 'Today'):
-                self.value = time.time()
-            else:
-                self.value = time.mktime(parse_time(value))
-        elif isinstance(value, (datetime.datetime, datetime.date)):
-            self.value = time.mktime(value.timetuple())
-        else:
-            raise ValueError, "Could not parse '%s' as a time" % value
+        self.value = parse_time(value)
 
     def __str__(self):
-        return str(int(self.value))
+        tm = self.value
+        return ' '.join([ str(tm[i]) for i in xrange(8)])
 
     def ini_str(self):
-        return str(int(self.value))
+        return str(self)
 
 # Enumerated types are a little more complex.  The user specifies the
 # type as Enum(foo) where foo is either a list or dictionary of