tsunami_io.cc revision 2107
110923SN/A/*
210923SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
310923SN/A * All rights reserved.
410923SN/A *
510923SN/A * Redistribution and use in source and binary forms, with or without
610923SN/A * modification, are permitted provided that the following conditions are
710923SN/A * met: redistributions of source code must retain the above copyright
810923SN/A * notice, this list of conditions and the following disclaimer;
910923SN/A * redistributions in binary form must reproduce the above copyright
1010923SN/A * notice, this list of conditions and the following disclaimer in the
1110923SN/A * documentation and/or other materials provided with the distribution;
1210923SN/A * neither the name of the copyright holders nor the names of its
1310923SN/A * contributors may be used to endorse or promote products derived from
1410923SN/A * this software without specific prior written permission.
1510923SN/A *
1610923SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710923SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1810923SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1910923SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2010923SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2110923SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210923SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2310923SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2410923SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2510923SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2610923SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710923SN/A */
2810923SN/A
2910923SN/A/** @file
3010923SN/A * Tsunami I/O including PIC, PIT, RTC, DMA
3110923SN/A */
3210923SN/A
3310923SN/A#include <sys/time.h>
3410923SN/A
3510923SN/A#include <deque>
3610923SN/A#include <string>
3710923SN/A#include <vector>
3810923SN/A
3910923SN/A#include "base/trace.hh"
4010923SN/A#include "dev/tsunami_io.hh"
4111290Sgabor.dozsa@arm.com#include "dev/tsunami.hh"
4210923SN/A#include "dev/pitreg.h"
4311290Sgabor.dozsa@arm.com#include "mem/bus/bus.hh"
4411290Sgabor.dozsa@arm.com#include "mem/bus/pio_interface.hh"
4510923SN/A#include "mem/bus/pio_interface_impl.hh"
4611290Sgabor.dozsa@arm.com#include "sim/builder.hh"
4711290Sgabor.dozsa@arm.com#include "dev/tsunami_cchip.hh"
4810923SN/A#include "dev/tsunamireg.h"
4910923SN/A#include "dev/rtcreg.h"
5010923SN/A#include "mem/functional/memory_control.hh"
5110923SN/A
5210923SN/Ausing namespace std;
5311290Sgabor.dozsa@arm.com//Should this be AlphaISA?
5411290Sgabor.dozsa@arm.comusing namespace TheISA;
5510923SN/A
5610923SN/ATsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i)
5710923SN/A    : _name(name), event(t, i), addr(0)
5810923SN/A{
5910923SN/A    memset(clock_data, 0, sizeof(clock_data));
6011290Sgabor.dozsa@arm.com    stat_regA = RTCA_32768HZ | RTCA_1024HZ;
6110923SN/A    stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
6210923SN/A}
6311290Sgabor.dozsa@arm.com
6411290Sgabor.dozsa@arm.comvoid
6510923SN/ATsunamiIO::RTC::set_time(time_t t)
6610923SN/A{
6711290Sgabor.dozsa@arm.com    struct tm tm;
6810923SN/A    gmtime_r(&t, &tm);
6911290Sgabor.dozsa@arm.com
7010923SN/A    sec = tm.tm_sec;
7110923SN/A    min = tm.tm_min;
7210923SN/A    hour = tm.tm_hour;
7310923SN/A    wday = tm.tm_wday + 1;
7411290Sgabor.dozsa@arm.com    mday = tm.tm_mday;
7511290Sgabor.dozsa@arm.com    mon = tm.tm_mon + 1;
7610923SN/A    year = tm.tm_year;
7710923SN/A
7810923SN/A    DPRINTFN("Real-time clock set to %s", asctime(&tm));
7910923SN/A}
8010923SN/A
8110923SN/Avoid
8211290Sgabor.dozsa@arm.comTsunamiIO::RTC::writeAddr(const uint8_t *data)
8311290Sgabor.dozsa@arm.com{
8411290Sgabor.dozsa@arm.com    if (*data <= RTC_STAT_REGD)
8511290Sgabor.dozsa@arm.com        addr = *data;
8610923SN/A    else
8710923SN/A        panic("RTC addresses over 0xD are not implemented.\n");
8810923SN/A}
8911701Smichael.lebeane@amd.com
9011701Smichael.lebeane@amd.comvoid
9111701Smichael.lebeane@amd.comTsunamiIO::RTC::writeData(const uint8_t *data)
9211701Smichael.lebeane@amd.com{
9311701Smichael.lebeane@amd.com    if (addr < RTC_STAT_REGA)
9411290Sgabor.dozsa@arm.com        clock_data[addr] = *data;
9511290Sgabor.dozsa@arm.com    else {
9611290Sgabor.dozsa@arm.com        switch (addr) {
9711290Sgabor.dozsa@arm.com          case RTC_STAT_REGA:
9811290Sgabor.dozsa@arm.com            if (*data != (RTCA_32768HZ | RTCA_1024HZ))
9911290Sgabor.dozsa@arm.com                panic("Unimplemented RTC register A value write!\n");
10011290Sgabor.dozsa@arm.com            stat_regA = *data;
10111701Smichael.lebeane@amd.com            break;
10211290Sgabor.dozsa@arm.com          case RTC_STAT_REGB:
10311290Sgabor.dozsa@arm.com            if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
10411290Sgabor.dozsa@arm.com                panic("Write to RTC reg B bits that are not implemented!\n");
10511290Sgabor.dozsa@arm.com
10611703Smichael.lebeane@amd.com            if (*data & RTCB_PRDC_IE) {
10711290Sgabor.dozsa@arm.com                if (!event.scheduled())
10811290Sgabor.dozsa@arm.com                    event.scheduleIntr();
10911290Sgabor.dozsa@arm.com            } else {
11010923SN/A                if (event.scheduled())
11110923SN/A                    event.deschedule();
11210923SN/A            }
11311290Sgabor.dozsa@arm.com            stat_regB = *data;
114            break;
115          case RTC_STAT_REGC:
116          case RTC_STAT_REGD:
117            panic("RTC status registers C and D are not implemented.\n");
118            break;
119        }
120    }
121}
122
123void
124TsunamiIO::RTC::readData(uint8_t *data)
125{
126    if (addr < RTC_STAT_REGA)
127        *data = clock_data[addr];
128    else {
129        switch (addr) {
130          case RTC_STAT_REGA:
131            // toggle UIP bit for linux
132            stat_regA ^= RTCA_UIP;
133            *data = stat_regA;
134            break;
135          case RTC_STAT_REGB:
136            *data = stat_regB;
137            break;
138          case RTC_STAT_REGC:
139          case RTC_STAT_REGD:
140            *data = 0x00;
141            break;
142        }
143    }
144}
145
146void
147TsunamiIO::RTC::serialize(const string &base, ostream &os)
148{
149    paramOut(os, base + ".addr", addr);
150    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
151    paramOut(os, base + ".stat_regA", stat_regA);
152    paramOut(os, base + ".stat_regB", stat_regB);
153}
154
155void
156TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
157                            const string &section)
158{
159    paramIn(cp, section, base + ".addr", addr);
160    arrayParamIn(cp, section, base + ".clock_data", clock_data,
161                 sizeof(clock_data));
162    paramIn(cp, section, base + ".stat_regA", stat_regA);
163    paramIn(cp, section, base + ".stat_regB", stat_regB);
164
165    // We're not unserializing the event here, but we need to
166    // rescehedule the event since curTick was moved forward by the
167    // checkpoint
168    event.reschedule(curTick + event.interval);
169}
170
171TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
172    : Event(&mainEventQueue), tsunami(t), interval(i)
173{
174    DPRINTF(MC146818, "RTC Event Initilizing\n");
175    schedule(curTick + interval);
176}
177
178void
179TsunamiIO::RTC::RTCEvent::scheduleIntr()
180{
181  schedule(curTick + interval);
182}
183
184void
185TsunamiIO::RTC::RTCEvent::process()
186{
187    DPRINTF(MC146818, "RTC Timer Interrupt\n");
188    schedule(curTick + interval);
189    //Actually interrupt the processor here
190    tsunami->cchip->postRTC();
191}
192
193const char *
194TsunamiIO::RTC::RTCEvent::description()
195{
196    return "tsunami RTC interrupt";
197}
198
199TsunamiIO::PITimer::PITimer(const string &name)
200    : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
201      counter2(name + ".counter2")
202{
203    counter[0] = &counter0;
204    counter[1] = &counter0;
205    counter[2] = &counter0;
206}
207
208void
209TsunamiIO::PITimer::writeControl(const uint8_t *data)
210{
211    int rw;
212    int sel;
213
214    sel = GET_CTRL_SEL(*data);
215
216    if (sel == PIT_READ_BACK)
217       panic("PITimer Read-Back Command is not implemented.\n");
218
219    rw = GET_CTRL_RW(*data);
220
221    if (rw == PIT_RW_LATCH_COMMAND)
222        counter[sel]->latchCount();
223    else {
224        counter[sel]->setRW(rw);
225        counter[sel]->setMode(GET_CTRL_MODE(*data));
226        counter[sel]->setBCD(GET_CTRL_BCD(*data));
227    }
228}
229
230void
231TsunamiIO::PITimer::serialize(const string &base, ostream &os)
232{
233    // serialize the counters
234    counter0.serialize(base + ".counter0", os);
235    counter1.serialize(base + ".counter1", os);
236    counter2.serialize(base + ".counter2", os);
237}
238
239void
240TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
241                                const string &section)
242{
243    // unserialze the counters
244    counter0.unserialize(base + ".counter0", cp, section);
245    counter1.unserialize(base + ".counter1", cp, section);
246    counter2.unserialize(base + ".counter2", cp, section);
247}
248
249TsunamiIO::PITimer::Counter::Counter(const string &name)
250    : _name(name), event(this), count(0), latched_count(0), period(0),
251      mode(0), output_high(false), latch_on(false), read_byte(LSB),
252      write_byte(LSB)
253{
254
255}
256
257void
258TsunamiIO::PITimer::Counter::latchCount()
259{
260    // behave like a real latch
261    if(!latch_on) {
262        latch_on = true;
263        read_byte = LSB;
264        latched_count = count;
265    }
266}
267
268void
269TsunamiIO::PITimer::Counter::read(uint8_t *data)
270{
271    if (latch_on) {
272        switch (read_byte) {
273          case LSB:
274            read_byte = MSB;
275            *data = (uint8_t)latched_count;
276            break;
277          case MSB:
278            read_byte = LSB;
279            latch_on = false;
280            *data = latched_count >> 8;
281            break;
282        }
283    } else {
284        switch (read_byte) {
285          case LSB:
286            read_byte = MSB;
287            *data = (uint8_t)count;
288            break;
289          case MSB:
290            read_byte = LSB;
291            *data = count >> 8;
292            break;
293        }
294    }
295}
296
297void
298TsunamiIO::PITimer::Counter::write(const uint8_t *data)
299{
300    switch (write_byte) {
301      case LSB:
302        count = (count & 0xFF00) | *data;
303
304        if (event.scheduled())
305          event.deschedule();
306        output_high = false;
307        write_byte = MSB;
308        break;
309
310      case MSB:
311        count = (count & 0x00FF) | (*data << 8);
312        period = count;
313
314        if (period > 0) {
315            DPRINTF(Tsunami, "Timer set to curTick + %d\n",
316                    count * event.interval);
317            event.schedule(curTick + count * event.interval);
318        }
319        write_byte = LSB;
320        break;
321    }
322}
323
324void
325TsunamiIO::PITimer::Counter::setRW(int rw_val)
326{
327    if (rw_val != PIT_RW_16BIT)
328        panic("Only LSB/MSB read/write is implemented.\n");
329}
330
331void
332TsunamiIO::PITimer::Counter::setMode(int mode_val)
333{
334    if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
335       mode_val != PIT_MODE_SQWAVE)
336        panic("PIT mode %#x is not implemented: \n", mode_val);
337
338    mode = mode_val;
339}
340
341void
342TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
343{
344    if (bcd_val != PIT_BCD_FALSE)
345        panic("PITimer does not implement BCD counts.\n");
346}
347
348bool
349TsunamiIO::PITimer::Counter::outputHigh()
350{
351    return output_high;
352}
353
354void
355TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
356{
357    paramOut(os, base + ".count", count);
358    paramOut(os, base + ".latched_count", latched_count);
359    paramOut(os, base + ".period", period);
360    paramOut(os, base + ".mode", mode);
361    paramOut(os, base + ".output_high", output_high);
362    paramOut(os, base + ".latch_on", latch_on);
363    paramOut(os, base + ".read_byte", read_byte);
364    paramOut(os, base + ".write_byte", write_byte);
365
366    Tick event_tick = 0;
367    if (event.scheduled())
368        event_tick = event.when();
369    paramOut(os, base + ".event_tick", event_tick);
370}
371
372void
373TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
374                                         const string &section)
375{
376    paramIn(cp, section, base + ".count", count);
377    paramIn(cp, section, base + ".latched_count", latched_count);
378    paramIn(cp, section, base + ".period", period);
379    paramIn(cp, section, base + ".mode", mode);
380    paramIn(cp, section, base + ".output_high", output_high);
381    paramIn(cp, section, base + ".latch_on", latch_on);
382    paramIn(cp, section, base + ".read_byte", read_byte);
383    paramIn(cp, section, base + ".write_byte", write_byte);
384
385    Tick event_tick;
386    paramIn(cp, section, base + ".event_tick", event_tick);
387    if (event_tick)
388        event.schedule(event_tick);
389}
390
391TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
392    : Event(&mainEventQueue)
393{
394    interval = (Tick)(Clock::Float::s / 1193180.0);
395    counter = c_ptr;
396}
397
398void
399TsunamiIO::PITimer::Counter::CounterEvent::process()
400{
401    DPRINTF(Tsunami, "Timer Interrupt\n");
402    switch (counter->mode) {
403      case PIT_MODE_INTTC:
404        counter->output_high = true;
405      case PIT_MODE_RATEGEN:
406      case PIT_MODE_SQWAVE:
407        break;
408      default:
409        panic("Unimplemented PITimer mode.\n");
410    }
411}
412
413const char *
414TsunamiIO::PITimer::Counter::CounterEvent::description()
415{
416    return "tsunami 8254 Interval timer";
417}
418
419TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
420                     Addr a, MemoryController *mmu, HierParams *hier,
421                     Bus *pio_bus, Tick pio_latency, Tick ci)
422    : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t),
423      pitimer(name + "pitimer"), rtc(name + ".rtc", t, ci)
424{
425    mmu->add_child(this, RangeSize(addr, size));
426
427    if (pio_bus) {
428        pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this,
429                                       &TsunamiIO::cacheAccess);
430        pioInterface->addAddrRange(RangeSize(addr, size));
431        pioLatency = pio_latency * pio_bus->clockRate;
432    }
433
434    // set the back pointer from tsunami to myself
435    tsunami->io = this;
436
437    timerData = 0;
438    rtc.set_time(init_time == 0 ? time(NULL) : init_time);
439    picr = 0;
440    picInterrupting = false;
441}
442
443Tick
444TsunamiIO::frequency() const
445{
446    return Clock::Frequency / clockInterval;
447}
448
449Fault *
450TsunamiIO::read(MemReqPtr &req, uint8_t *data)
451{
452    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n",
453            req->vaddr, req->size, req->vaddr & 0xfff);
454
455    Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
456
457
458    switch(req->size) {
459      case sizeof(uint8_t):
460        switch(daddr) {
461          // PIC1 mask read
462          case TSDEV_PIC1_MASK:
463            *(uint8_t*)data = ~mask1;
464            return NoFault;
465          case TSDEV_PIC2_MASK:
466            *(uint8_t*)data = ~mask2;
467            return NoFault;
468          case TSDEV_PIC1_ISR:
469              // !!! If this is modified 64bit case needs to be too
470              // Pal code has to do a 64 bit physical read because there is
471              // no load physical byte instruction
472              *(uint8_t*)data = picr;
473              return NoFault;
474          case TSDEV_PIC2_ISR:
475              // PIC2 not implemnted... just return 0
476              *(uint8_t*)data = 0x00;
477              return NoFault;
478          case TSDEV_TMR0_DATA:
479            pitimer.counter0.read(data);
480            return NoFault;
481          case TSDEV_TMR1_DATA:
482            pitimer.counter1.read(data);
483            return NoFault;
484          case TSDEV_TMR2_DATA:
485            pitimer.counter2.read(data);
486            return NoFault;
487          case TSDEV_RTC_DATA:
488            rtc.readData(data);
489            return NoFault;
490          case TSDEV_CTRL_PORTB:
491            if (pitimer.counter2.outputHigh())
492                *data = PORTB_SPKR_HIGH;
493            else
494                *data = 0x00;
495            return NoFault;
496          default:
497            panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
498        }
499      case sizeof(uint16_t):
500      case sizeof(uint32_t):
501        panic("I/O Read - invalid size - va %#x size %d\n",
502              req->vaddr, req->size);
503
504      case sizeof(uint64_t):
505       switch(daddr) {
506          case TSDEV_PIC1_ISR:
507              // !!! If this is modified 8bit case needs to be too
508              // Pal code has to do a 64 bit physical read because there is
509              // no load physical byte instruction
510              *(uint64_t*)data = (uint64_t)picr;
511              return NoFault;
512          default:
513              panic("I/O Read - invalid size - va %#x size %d\n",
514                    req->vaddr, req->size);
515       }
516
517      default:
518        panic("I/O Read - invalid size - va %#x size %d\n",
519              req->vaddr, req->size);
520    }
521    panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
522
523    return NoFault;
524}
525
526Fault *
527TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
528{
529
530#if TRACING_ON
531    uint8_t dt = *(uint8_t*)data;
532    uint64_t dt64 = dt;
533#endif
534
535    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
536            req->vaddr, req->size, req->vaddr & 0xfff, dt64);
537
538    Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
539
540    switch(req->size) {
541      case sizeof(uint8_t):
542        switch(daddr) {
543          case TSDEV_PIC1_MASK:
544            mask1 = ~(*(uint8_t*)data);
545            if ((picr & mask1) && !picInterrupting) {
546                picInterrupting = true;
547                tsunami->cchip->postDRIR(55);
548                DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
549            }
550            if ((!(picr & mask1)) && picInterrupting) {
551                picInterrupting = false;
552                tsunami->cchip->clearDRIR(55);
553                DPRINTF(Tsunami, "clearing pic interrupt\n");
554            }
555            return NoFault;
556          case TSDEV_PIC2_MASK:
557            mask2 = *(uint8_t*)data;
558            //PIC2 Not implemented to interrupt
559            return NoFault;
560          case TSDEV_PIC1_ACK:
561            // clear the interrupt on the PIC
562            picr &= ~(1 << (*(uint8_t*)data & 0xF));
563            if (!(picr & mask1))
564                tsunami->cchip->clearDRIR(55);
565            return NoFault;
566          case TSDEV_DMA1_CMND:
567            return NoFault;
568          case TSDEV_DMA2_CMND:
569            return NoFault;
570          case TSDEV_DMA1_MMASK:
571            return NoFault;
572          case TSDEV_DMA2_MMASK:
573            return NoFault;
574          case TSDEV_PIC2_ACK:
575            return NoFault;
576          case TSDEV_DMA1_RESET:
577            return NoFault;
578          case TSDEV_DMA2_RESET:
579            return NoFault;
580          case TSDEV_DMA1_MODE:
581            mode1 = *(uint8_t*)data;
582            return NoFault;
583          case TSDEV_DMA2_MODE:
584            mode2 = *(uint8_t*)data;
585            return NoFault;
586          case TSDEV_DMA1_MASK:
587          case TSDEV_DMA2_MASK:
588            return NoFault;
589          case TSDEV_TMR0_DATA:
590            pitimer.counter0.write(data);
591            return NoFault;
592          case TSDEV_TMR1_DATA:
593            pitimer.counter1.write(data);
594            return NoFault;
595          case TSDEV_TMR2_DATA:
596            pitimer.counter2.write(data);
597            return NoFault;
598          case TSDEV_TMR_CTRL:
599            pitimer.writeControl(data);
600            return NoFault;
601          case TSDEV_RTC_ADDR:
602            rtc.writeAddr(data);
603            return NoFault;
604          case TSDEV_KBD:
605            return NoFault;
606          case TSDEV_RTC_DATA:
607            rtc.writeData(data);
608            return NoFault;
609          case TSDEV_CTRL_PORTB:
610            // System Control Port B not implemented
611            return NoFault;
612          default:
613            panic("I/O Write - va%#x size %d data %#x\n", req->vaddr, req->size, (int)*data);
614        }
615      case sizeof(uint16_t):
616      case sizeof(uint32_t):
617      case sizeof(uint64_t):
618      default:
619        panic("I/O Write - invalid size - va %#x size %d\n",
620              req->vaddr, req->size);
621    }
622
623
624    return NoFault;
625}
626
627void
628TsunamiIO::postPIC(uint8_t bitvector)
629{
630    //PIC2 Is not implemented, because nothing of interest there
631    picr |= bitvector;
632    if (picr & mask1) {
633        tsunami->cchip->postDRIR(55);
634        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
635    }
636}
637
638void
639TsunamiIO::clearPIC(uint8_t bitvector)
640{
641    //PIC2 Is not implemented, because nothing of interest there
642    picr &= ~bitvector;
643    if (!(picr & mask1)) {
644        tsunami->cchip->clearDRIR(55);
645        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
646    }
647}
648
649Tick
650TsunamiIO::cacheAccess(MemReqPtr &req)
651{
652    return curTick + pioLatency;
653}
654
655void
656TsunamiIO::serialize(ostream &os)
657{
658    SERIALIZE_SCALAR(timerData);
659    SERIALIZE_SCALAR(mask1);
660    SERIALIZE_SCALAR(mask2);
661    SERIALIZE_SCALAR(mode1);
662    SERIALIZE_SCALAR(mode2);
663    SERIALIZE_SCALAR(picr);
664    SERIALIZE_SCALAR(picInterrupting);
665
666    // Serialize the timers
667    pitimer.serialize("pitimer", os);
668    rtc.serialize("rtc", os);
669}
670
671void
672TsunamiIO::unserialize(Checkpoint *cp, const string &section)
673{
674    UNSERIALIZE_SCALAR(timerData);
675    UNSERIALIZE_SCALAR(mask1);
676    UNSERIALIZE_SCALAR(mask2);
677    UNSERIALIZE_SCALAR(mode1);
678    UNSERIALIZE_SCALAR(mode2);
679    UNSERIALIZE_SCALAR(picr);
680    UNSERIALIZE_SCALAR(picInterrupting);
681
682    // Unserialize the timers
683    pitimer.unserialize("pitimer", cp, section);
684    rtc.unserialize("rtc", cp, section);
685}
686
687BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
688
689    SimObjectParam<Tsunami *> tsunami;
690    Param<time_t> time;
691    SimObjectParam<MemoryController *> mmu;
692    Param<Addr> addr;
693    SimObjectParam<Bus*> pio_bus;
694    Param<Tick> pio_latency;
695    SimObjectParam<HierParams *> hier;
696    Param<Tick> frequency;
697
698END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
699
700BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
701
702    INIT_PARAM(tsunami, "Tsunami"),
703    INIT_PARAM(time, "System time to use (0 for actual time"),
704    INIT_PARAM(mmu, "Memory Controller"),
705    INIT_PARAM(addr, "Device Address"),
706    INIT_PARAM(pio_bus, "The IO Bus to attach to"),
707    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
708    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
709    INIT_PARAM(frequency, "clock interrupt frequency")
710
711END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
712
713CREATE_SIM_OBJECT(TsunamiIO)
714{
715    return new TsunamiIO(getInstanceName(), tsunami, time,  addr, mmu, hier,
716                         pio_bus, pio_latency, frequency);
717}
718
719REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
720