Move options files from <build_dir>/build_options to build_options/<build_dir>.
[gem5.git] / dev / tsunami_io.cc
index e757c805ee2ea91419b6e60444a40cafa179b310..fd30d4fc179949172a4939c3d119b33bdfbbe3a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 The Regents of The University of Michigan
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* @file
+/** @file
  * Tsunami I/O including PIC, PIT, RTC, DMA
  */
 
 #include <vector>
 
 #include "base/trace.hh"
-#include "cpu/exec_context.hh"
-#include "dev/console.hh"
-#include "dev/tlaser_clock.hh"
 #include "dev/tsunami_io.hh"
-#include "dev/tsunamireg.h"
 #include "dev/tsunami.hh"
-#include "mem/functional_mem/memory_control.hh"
+#include "dev/pitreg.h"
+#include "mem/bus/bus.hh"
+#include "mem/bus/pio_interface.hh"
+#include "mem/bus/pio_interface_impl.hh"
 #include "sim/builder.hh"
 #include "dev/tsunami_cchip.hh"
+#include "dev/tsunamireg.h"
+#include "dev/rtcreg.h"
+#include "mem/functional/memory_control.hh"
 
 using namespace std;
 
-#define UNIX_YEAR_OFFSET 52
+TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i)
+    : _name(name), event(t, i), addr(0)
+{
+    memset(clock_data, 0, sizeof(clock_data));
+    stat_regA = RTCA_32768HZ | RTCA_1024HZ;
+    stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
+}
+
+void
+TsunamiIO::RTC::set_time(time_t t)
+{
+    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;
+
+    DPRINTFN("Real-time clock set to %s", asctime(&tm));
+}
+
+void
+TsunamiIO::RTC::writeAddr(const uint8_t *data)
+{
+    if (*data <= RTC_STAT_REGD)
+        addr = *data;
+    else
+        panic("RTC addresses over 0xD are not implemented.\n");
+}
+
+void
+TsunamiIO::RTC::writeData(const uint8_t *data)
+{
+    if (addr < RTC_STAT_REGA)
+        clock_data[addr] = *data;
+    else {
+        switch (addr) {
+          case RTC_STAT_REGA:
+            if (*data != (RTCA_32768HZ | RTCA_1024HZ))
+                panic("Unimplemented RTC register A value write!\n");
+            stat_regA = *data;
+            break;
+          case RTC_STAT_REGB:
+            if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
+                panic("Write to RTC reg B bits that are not implemented!\n");
+
+            if (*data & RTCB_PRDC_IE) {
+                if (!event.scheduled())
+                    event.scheduleIntr();
+            } else {
+                if (event.scheduled())
+                    event.deschedule();
+            }
+            stat_regB = *data;
+            break;
+          case RTC_STAT_REGC:
+          case RTC_STAT_REGD:
+            panic("RTC status registers C and D are not implemented.\n");
+            break;
+        }
+    }
+}
+
+void
+TsunamiIO::RTC::readData(uint8_t *data)
+{
+    if (addr < RTC_STAT_REGA)
+        *data = clock_data[addr];
+    else {
+        switch (addr) {
+          case RTC_STAT_REGA:
+            // toggle UIP bit for linux
+            stat_regA ^= RTCA_UIP;
+            *data = stat_regA;
+            break;
+          case RTC_STAT_REGB:
+            *data = stat_regB;
+            break;
+          case RTC_STAT_REGC:
+          case RTC_STAT_REGD:
+            *data = 0x00;
+            break;
+        }
+    }
+}
 
-// Timer Event for Periodic interrupt of RTC
-TsunamiIO::RTCEvent::RTCEvent(Tsunami* t)
-    : Event(&mainEventQueue), tsunami(t)
+void
+TsunamiIO::RTC::serialize(const string &base, ostream &os)
+{
+    paramOut(os, base + ".addr", addr);
+    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
+    paramOut(os, base + ".stat_regA", stat_regA);
+    paramOut(os, base + ".stat_regB", stat_regB);
+}
+
+void
+TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
+                            const string &section)
+{
+    paramIn(cp, section, base + ".addr", addr);
+    arrayParamIn(cp, section, base + ".clock_data", clock_data,
+                 sizeof(clock_data));
+    paramIn(cp, section, base + ".stat_regA", stat_regA);
+    paramIn(cp, section, base + ".stat_regB", stat_regB);
+
+    // We're not unserializing the event here, but we need to
+    // rescehedule the event since curTick was moved forward by the
+    // checkpoint
+    event.reschedule(curTick + event.interval);
+}
+
+TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
+    : Event(&mainEventQueue), tsunami(t), interval(i)
 {
     DPRINTF(MC146818, "RTC Event Initilizing\n");
-    schedule(curTick + ticksPerSecond/RTC_RATE);
+    schedule(curTick + interval);
+}
+
+void
+TsunamiIO::RTC::RTCEvent::scheduleIntr()
+{
+  schedule(curTick + interval);
 }
 
 void
-TsunamiIO::RTCEvent::process()
+TsunamiIO::RTC::RTCEvent::process()
 {
     DPRINTF(MC146818, "RTC Timer Interrupt\n");
-    schedule(curTick + ticksPerSecond/RTC_RATE);
+    schedule(curTick + interval);
     //Actually interrupt the processor here
     tsunami->cchip->postRTC();
-
 }
 
 const char *
-TsunamiIO::RTCEvent::description()
+TsunamiIO::RTC::RTCEvent::description()
 {
-    return "tsunami RTC 1024Hz interrupt";
+    return "tsunami RTC interrupt";
 }
 
-// Timer Event for PIT Timers
-TsunamiIO::ClockEvent::ClockEvent()
-    : Event(&mainEventQueue)
+TsunamiIO::PITimer::PITimer(const string &name)
+    : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
+      counter2(name + ".counter2")
 {
-    DPRINTF(Tsunami, "Clock Event Initilizing\n");
-    mode = 0;
+    counter[0] = &counter0;
+    counter[1] = &counter0;
+    counter[2] = &counter0;
 }
 
 void
-TsunamiIO::ClockEvent::process()
+TsunamiIO::PITimer::writeControl(const uint8_t *data)
 {
-    DPRINTF(Tsunami, "Timer Interrupt\n");
-    if (mode == 0)
-        status = 0x20; // set bit that linux is looking for
-    else
-        schedule(curTick + interval);
+    int rw;
+    int sel;
+
+    sel = GET_CTRL_SEL(*data);
+
+    if (sel == PIT_READ_BACK)
+       panic("PITimer Read-Back Command is not implemented.\n");
+
+    rw = GET_CTRL_RW(*data);
+
+    if (rw == PIT_RW_LATCH_COMMAND)
+        counter[sel]->latchCount();
+    else {
+        counter[sel]->setRW(rw);
+        counter[sel]->setMode(GET_CTRL_MODE(*data));
+        counter[sel]->setBCD(GET_CTRL_BCD(*data));
+    }
 }
 
 void
-TsunamiIO::ClockEvent::Program(int count)
+TsunamiIO::PITimer::serialize(const string &base, ostream &os)
 {
-    DPRINTF(Tsunami, "Timer set to curTick + %d\n", count);
-    // should be count * (cpufreq/pitfreq)
-    interval = count * ticksPerSecond/1193180UL;
-    schedule(curTick + interval);
-    status = 0;
+    // serialize the counters
+    counter0.serialize(base + ".counter0", os);
+    counter1.serialize(base + ".counter1", os);
+    counter2.serialize(base + ".counter2", os);
 }
 
-const char *
-TsunamiIO::ClockEvent::description()
+void
+TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
+                                const string &section)
 {
-    return "tsunami 8254 Interval timer";
+    // unserialze the counters
+    counter0.unserialize(base + ".counter0", cp, section);
+    counter1.unserialize(base + ".counter1", cp, section);
+    counter2.unserialize(base + ".counter2", cp, section);
+}
+
+TsunamiIO::PITimer::Counter::Counter(const string &name)
+    : _name(name), event(this), count(0), latched_count(0), period(0),
+      mode(0), output_high(false), latch_on(false), read_byte(LSB),
+      write_byte(LSB)
+{
+
+}
+
+void
+TsunamiIO::PITimer::Counter::latchCount()
+{
+    // behave like a real latch
+    if(!latch_on) {
+        latch_on = true;
+        read_byte = LSB;
+        latched_count = count;
+    }
 }
 
 void
-TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
+TsunamiIO::PITimer::Counter::read(uint8_t *data)
 {
-    mode = md;
+    if (latch_on) {
+        switch (read_byte) {
+          case LSB:
+            read_byte = MSB;
+            *data = (uint8_t)latched_count;
+            break;
+          case MSB:
+            read_byte = LSB;
+            latch_on = false;
+            *data = latched_count >> 8;
+            break;
+        }
+    } else {
+        switch (read_byte) {
+          case LSB:
+            read_byte = MSB;
+            *data = (uint8_t)count;
+            break;
+          case MSB:
+            read_byte = LSB;
+            *data = count >> 8;
+            break;
+        }
+    }
 }
 
-uint8_t
-TsunamiIO::ClockEvent::Status()
+void
+TsunamiIO::PITimer::Counter::write(const uint8_t *data)
 {
-    return status;
+    switch (write_byte) {
+      case LSB:
+        count = (count & 0xFF00) | *data;
+
+        if (event.scheduled())
+          event.deschedule();
+        output_high = false;
+        write_byte = MSB;
+        break;
+
+      case MSB:
+        count = (count & 0x00FF) | (*data << 8);
+        period = count;
+
+        if (period > 0) {
+            DPRINTF(Tsunami, "Timer set to curTick + %d\n",
+                    count * event.interval);
+            event.schedule(curTick + count * event.interval);
+        }
+        write_byte = LSB;
+        break;
+    }
+}
+
+void
+TsunamiIO::PITimer::Counter::setRW(int rw_val)
+{
+    if (rw_val != PIT_RW_16BIT)
+        panic("Only LSB/MSB read/write is implemented.\n");
+}
+
+void
+TsunamiIO::PITimer::Counter::setMode(int mode_val)
+{
+    if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
+       mode_val != PIT_MODE_SQWAVE)
+        panic("PIT mode %#x is not implemented: \n", mode_val);
+
+    mode = mode_val;
+}
+
+void
+TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
+{
+    if (bcd_val != PIT_BCD_FALSE)
+        panic("PITimer does not implement BCD counts.\n");
+}
+
+bool
+TsunamiIO::PITimer::Counter::outputHigh()
+{
+    return output_high;
+}
+
+void
+TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
+{
+    paramOut(os, base + ".count", count);
+    paramOut(os, base + ".latched_count", latched_count);
+    paramOut(os, base + ".period", period);
+    paramOut(os, base + ".mode", mode);
+    paramOut(os, base + ".output_high", output_high);
+    paramOut(os, base + ".latch_on", latch_on);
+    paramOut(os, base + ".read_byte", read_byte);
+    paramOut(os, base + ".write_byte", write_byte);
+
+    Tick event_tick = 0;
+    if (event.scheduled())
+        event_tick = event.when();
+    paramOut(os, base + ".event_tick", event_tick);
+}
+
+void
+TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
+                                         const string &section)
+{
+    paramIn(cp, section, base + ".count", count);
+    paramIn(cp, section, base + ".latched_count", latched_count);
+    paramIn(cp, section, base + ".period", period);
+    paramIn(cp, section, base + ".mode", mode);
+    paramIn(cp, section, base + ".output_high", output_high);
+    paramIn(cp, section, base + ".latch_on", latch_on);
+    paramIn(cp, section, base + ".read_byte", read_byte);
+    paramIn(cp, section, base + ".write_byte", write_byte);
+
+    Tick event_tick;
+    paramIn(cp, section, base + ".event_tick", event_tick);
+    if (event_tick)
+        event.schedule(event_tick);
+}
+
+TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
+    : Event(&mainEventQueue)
+{
+    interval = (Tick)(Clock::Float::s / 1193180.0);
+    counter = c_ptr;
+}
+
+void
+TsunamiIO::PITimer::Counter::CounterEvent::process()
+{
+    DPRINTF(Tsunami, "Timer Interrupt\n");
+    switch (counter->mode) {
+      case PIT_MODE_INTTC:
+        counter->output_high = true;
+      case PIT_MODE_RATEGEN:
+      case PIT_MODE_SQWAVE:
+        break;
+      default:
+        panic("Unimplemented PITimer mode.\n");
+    }
+}
+
+const char *
+TsunamiIO::PITimer::Counter::CounterEvent::description()
+{
+    return "tsunami 8254 Interval timer";
 }
 
 TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
-                     Addr a, MemoryController *mmu)
-    : FunctionalMemory(name), addr(a), tsunami(t), rtc(t)
+                     Addr a, MemoryController *mmu, HierParams *hier, Bus *bus,
+                     Tick pio_latency, Tick ci)
+    : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t),
+      pitimer(name + "pitimer"), rtc(name + ".rtc", t, ci)
 {
-    mmu->add_child(this, Range<Addr>(addr, addr + size));
+    mmu->add_child(this, RangeSize(addr, size));
+
+    if (bus) {
+        pioInterface = newPioInterface(name + ".pio", hier, bus, this,
+                                       &TsunamiIO::cacheAccess);
+        pioInterface->addAddrRange(RangeSize(addr, size));
+        pioLatency = pio_latency * bus->clockRate;
+    }
 
     // set the back pointer from tsunami to myself
     tsunami->io = this;
 
     timerData = 0;
-    set_time(init_time == 0 ? time(NULL) : init_time);
-    uip = 1;
+    rtc.set_time(init_time == 0 ? time(NULL) : init_time);
     picr = 0;
     picInterrupting = false;
 }
 
-void
-TsunamiIO::set_time(time_t t)
+Tick
+TsunamiIO::frequency() const
 {
-    gmtime_r(&t, &tm);
-    DPRINTFN("Real-time clock set to %s", asctime(&tm));
+    return Clock::Frequency / clockInterval;
 }
 
 Fault
@@ -150,12 +450,19 @@ TsunamiIO::read(MemReqPtr &req, uint8_t *data)
     DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n",
             req->vaddr, req->size, req->vaddr & 0xfff);
 
-    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
+    Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
 
 
     switch(req->size) {
       case sizeof(uint8_t):
         switch(daddr) {
+          // PIC1 mask read
+          case TSDEV_PIC1_MASK:
+            *(uint8_t*)data = ~mask1;
+            return No_Fault;
+          case TSDEV_PIC2_MASK:
+            *(uint8_t*)data = ~mask2;
+            return No_Fault;
           case TSDEV_PIC1_ISR:
               // !!! If this is modified 64bit case needs to be too
               // Pal code has to do a 64 bit physical read because there is
@@ -166,50 +473,24 @@ TsunamiIO::read(MemReqPtr &req, uint8_t *data)
               // PIC2 not implemnted... just return 0
               *(uint8_t*)data = 0x00;
               return No_Fault;
-          case TSDEV_TMR_CTL:
-            *(uint8_t*)data = timer2.Status();
+          case TSDEV_TMR0_DATA:
+            pitimer.counter0.read(data);
+            return No_Fault;
+          case TSDEV_TMR1_DATA:
+            pitimer.counter1.read(data);
+            return No_Fault;
+          case TSDEV_TMR2_DATA:
+            pitimer.counter2.read(data);
             return No_Fault;
           case TSDEV_RTC_DATA:
-            switch(RTCAddress) {
-              case RTC_CONTROL_REGISTERA:
-                *(uint8_t*)data = uip << 7 | 0x26;
-                uip = !uip;
-                return No_Fault;
-              case RTC_CONTROL_REGISTERB:
-                // DM and 24/12 and UIE
-                *(uint8_t*)data = 0x46;
-                return No_Fault;
-              case RTC_CONTROL_REGISTERC:
-                // If we want to support RTC user access in linux
-                // This won't work, but for now it's fine
-                *(uint8_t*)data = 0x00;
-                return No_Fault;
-              case RTC_CONTROL_REGISTERD:
-                panic("RTC Control Register D not implemented");
-              case RTC_SECOND:
-                *(uint8_t *)data = tm.tm_sec;
-                return No_Fault;
-              case RTC_MINUTE:
-                *(uint8_t *)data = tm.tm_min;
-                return No_Fault;
-              case RTC_HOUR:
-                *(uint8_t *)data = tm.tm_hour;
-                return No_Fault;
-              case RTC_DAY_OF_WEEK:
-                *(uint8_t *)data = tm.tm_wday;
-                return No_Fault;
-              case RTC_DAY_OF_MONTH:
-                *(uint8_t *)data = tm.tm_mday;
-              case RTC_MONTH:
-                *(uint8_t *)data = tm.tm_mon + 1;
-                return No_Fault;
-              case RTC_YEAR:
-                *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
-                return No_Fault;
-              default:
-                panic("Unknown RTC Address\n");
-            }
-
+            rtc.readData(data);
+            return No_Fault;
+          case TSDEV_CTRL_PORTB:
+            if (pitimer.counter2.outputHigh())
+                *data = PORTB_SPKR_HIGH;
+            else
+                *data = 0x00;
+            return No_Fault;
           default:
             panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
         }
@@ -243,13 +524,16 @@ TsunamiIO::read(MemReqPtr &req, uint8_t *data)
 Fault
 TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
 {
+
+#if TRACING_ON
     uint8_t dt = *(uint8_t*)data;
     uint64_t dt64 = dt;
+#endif
 
     DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
             req->vaddr, req->size, req->vaddr & 0xfff, dt64);
 
-    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
+    Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
 
     switch(req->size) {
       case sizeof(uint8_t):
@@ -277,6 +561,14 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
             if (!(picr & mask1))
                 tsunami->cchip->clearDRIR(55);
             return No_Fault;
+          case TSDEV_DMA1_CMND:
+            return No_Fault;
+          case TSDEV_DMA2_CMND:
+            return No_Fault;
+          case TSDEV_DMA1_MMASK:
+            return No_Fault;
+          case TSDEV_DMA2_MMASK:
+            return No_Fault;
           case TSDEV_PIC2_ACK:
             return No_Fault;
           case TSDEV_DMA1_RESET:
@@ -292,54 +584,31 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
           case TSDEV_DMA1_MASK:
           case TSDEV_DMA2_MASK:
             return No_Fault;
-          case TSDEV_TMR_CTL:
+          case TSDEV_TMR0_DATA:
+            pitimer.counter0.write(data);
             return No_Fault;
-          case TSDEV_TMR2_CTL:
-            if ((*(uint8_t*)data & 0x30) != 0x30)
-                panic("Only L/M write supported\n");
-
-            switch(*(uint8_t*)data >> 6) {
-              case 0:
-                timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
-                break;
-              case 2:
-                timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
-                break;
-              default:
-                panic("Read Back Command not implemented\n");
-            }
+          case TSDEV_TMR1_DATA:
+            pitimer.counter1.write(data);
             return No_Fault;
           case TSDEV_TMR2_DATA:
-            /* two writes before we actually start the Timer
-               so I set a flag in the timerData */
-            if(timerData & 0x1000) {
-                timerData &= 0x1000;
-                timerData += *(uint8_t*)data << 8;
-                timer2.Program(timerData);
-            } else {
-                timerData = *(uint8_t*)data;
-                timerData |= 0x1000;
-            }
+            pitimer.counter2.write(data);
             return No_Fault;
-          case TSDEV_TMR0_DATA:
-            /* two writes before we actually start the Timer
-               so I set a flag in the timerData */
-            if(timerData & 0x1000) {
-                timerData &= 0x1000;
-                timerData += *(uint8_t*)data << 8;
-                timer0.Program(timerData);
-            } else {
-                timerData = *(uint8_t*)data;
-                timerData |= 0x1000;
-            }
+          case TSDEV_TMR_CTRL:
+            pitimer.writeControl(data);
             return No_Fault;
           case TSDEV_RTC_ADDR:
-            RTCAddress = *(uint8_t*)data;
+            rtc.writeAddr(data);
+            return No_Fault;
+          case TSDEV_KBD:
             return No_Fault;
           case TSDEV_RTC_DATA:
-            panic("RTC Write not implmented (rtc.o won't work)\n");
+            rtc.writeData(data);
+            return No_Fault;
+          case TSDEV_CTRL_PORTB:
+            // System Control Port B not implemented
+            return No_Fault;
           default:
-            panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
+            panic("I/O Write - va%#x size %d data %#x\n", req->vaddr, req->size, (int)*data);
         }
       case sizeof(uint16_t):
       case sizeof(uint32_t):
@@ -375,48 +644,42 @@ TsunamiIO::clearPIC(uint8_t bitvector)
     }
 }
 
+Tick
+TsunamiIO::cacheAccess(MemReqPtr &req)
+{
+    return curTick + pioLatency;
+}
+
 void
-TsunamiIO::serialize(std::ostream &os)
+TsunamiIO::serialize(ostream &os)
 {
     SERIALIZE_SCALAR(timerData);
-    SERIALIZE_SCALAR(uip);
     SERIALIZE_SCALAR(mask1);
     SERIALIZE_SCALAR(mask2);
     SERIALIZE_SCALAR(mode1);
     SERIALIZE_SCALAR(mode2);
     SERIALIZE_SCALAR(picr);
     SERIALIZE_SCALAR(picInterrupting);
-    Tick time0when = timer0.when();
-    Tick time2when = timer2.when();
-    Tick rtcwhen = rtc.when();
-    SERIALIZE_SCALAR(time0when);
-    SERIALIZE_SCALAR(time2when);
-    SERIALIZE_SCALAR(rtcwhen);
-    SERIALIZE_SCALAR(RTCAddress);
 
+    // Serialize the timers
+    pitimer.serialize("pitimer", os);
+    rtc.serialize("rtc", os);
 }
 
 void
-TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
+TsunamiIO::unserialize(Checkpoint *cp, const string &section)
 {
     UNSERIALIZE_SCALAR(timerData);
-    UNSERIALIZE_SCALAR(uip);
     UNSERIALIZE_SCALAR(mask1);
     UNSERIALIZE_SCALAR(mask2);
     UNSERIALIZE_SCALAR(mode1);
     UNSERIALIZE_SCALAR(mode2);
     UNSERIALIZE_SCALAR(picr);
     UNSERIALIZE_SCALAR(picInterrupting);
-    Tick time0when;
-    Tick time2when;
-    Tick rtcwhen;
-    UNSERIALIZE_SCALAR(time0when);
-    UNSERIALIZE_SCALAR(time2when);
-    UNSERIALIZE_SCALAR(rtcwhen);
-    timer0.schedule(time0when);
-    timer2.schedule(time2when);
-    rtc.reschedule(rtcwhen);
-    UNSERIALIZE_SCALAR(RTCAddress);
+
+    // Unserialize the timers
+    pitimer.unserialize("pitimer", cp, section);
+    rtc.unserialize("rtc", cp, section);
 }
 
 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
@@ -425,22 +688,30 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
     Param<time_t> time;
     SimObjectParam<MemoryController *> mmu;
     Param<Addr> addr;
+    SimObjectParam<Bus*> io_bus;
+    Param<Tick> pio_latency;
+    SimObjectParam<HierParams *> hier;
+    Param<Tick> frequency;
 
 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
 
 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
 
     INIT_PARAM(tsunami, "Tsunami"),
-    INIT_PARAM_DFLT(time, "System time to use "
-            "(0 for actual time, default is 1/1/06", ULL(1136073600)),
+    INIT_PARAM(time, "System time to use (0 for actual time"),
     INIT_PARAM(mmu, "Memory Controller"),
-    INIT_PARAM(addr, "Device Address")
+    INIT_PARAM(addr, "Device Address"),
+    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
+    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
+    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
+    INIT_PARAM(frequency, "clock interrupt frequency")
 
 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
 
 CREATE_SIM_OBJECT(TsunamiIO)
 {
-    return new TsunamiIO(getInstanceName(), tsunami, time,  addr, mmu);
+    return new TsunamiIO(getInstanceName(), tsunami, time,  addr, mmu, hier,
+                         io_bus, pio_latency, frequency);
 }
 
 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)