tsunami_io.cc revision 4762
1803SN/A/*
21363SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
3803SN/A * All rights reserved.
4803SN/A *
5803SN/A * Redistribution and use in source and binary forms, with or without
6803SN/A * modification, are permitted provided that the following conditions are
7803SN/A * met: redistributions of source code must retain the above copyright
8803SN/A * notice, this list of conditions and the following disclaimer;
9803SN/A * redistributions in binary form must reproduce the above copyright
10803SN/A * notice, this list of conditions and the following disclaimer in the
11803SN/A * documentation and/or other materials provided with the distribution;
12803SN/A * neither the name of the copyright holders nor the names of its
13803SN/A * contributors may be used to endorse or promote products derived from
14803SN/A * this software without specific prior written permission.
15803SN/A *
16803SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17803SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18803SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19803SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20803SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21803SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22803SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23803SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24803SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25803SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26803SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665SN/A *
282665SN/A * Authors: Ali Saidi
292665SN/A *          Andrew Schultz
302665SN/A *          Miguel Serrano
31803SN/A */
32768SN/A
331730SN/A/** @file
34773SN/A * Tsunami I/O including PIC, PIT, RTC, DMA
35768SN/A */
36768SN/A
37773SN/A#include <sys/time.h>
38773SN/A
39768SN/A#include <deque>
40768SN/A#include <string>
41768SN/A#include <vector>
42768SN/A
434762Snate@binkert.org#include "base/time.hh"
44768SN/A#include "base/trace.hh"
452542SN/A#include "dev/pitreg.h"
462542SN/A#include "dev/rtcreg.h"
473540Sgblack@eecs.umich.edu#include "dev/alpha/tsunami_cchip.hh"
483540Sgblack@eecs.umich.edu#include "dev/alpha/tsunami.hh"
493540Sgblack@eecs.umich.edu#include "dev/alpha/tsunami_io.hh"
503540Sgblack@eecs.umich.edu#include "dev/alpha/tsunamireg.h"
513348SN/A#include "mem/packet.hh"
523348SN/A#include "mem/packet_access.hh"
532542SN/A#include "mem/port.hh"
542542SN/A#include "sim/system.hh"
55768SN/A
56768SN/Ausing namespace std;
572107SN/A//Should this be AlphaISA?
582107SN/Ausing namespace TheISA;
59773SN/A
604762Snate@binkert.orgTsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami,
614762Snate@binkert.org                    const TsunamiIO::Params *p)
624762Snate@binkert.org    : _name(n), event(tsunami, p->frequency), addr(0)
631817SN/A{
641817SN/A    memset(clock_data, 0, sizeof(clock_data));
651817SN/A    stat_regA = RTCA_32768HZ | RTCA_1024HZ;
661817SN/A    stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
67773SN/A
684762Snate@binkert.org    year = p->time.tm_year;
693943Sbinkertn@umich.edu
704762Snate@binkert.org    if (p->year_is_bcd) {
713943Sbinkertn@umich.edu        // The datasheet says that the year field can be either BCD or
723943Sbinkertn@umich.edu        // years since 1900.  Linux seems to be happy with years since
733943Sbinkertn@umich.edu        // 1900.
743943Sbinkertn@umich.edu        year = year % 100;
753943Sbinkertn@umich.edu        int tens = year / 10;
763943Sbinkertn@umich.edu        int ones = year % 10;
773932Sbinkertn@umich.edu        year = (tens << 4) + ones;
783932Sbinkertn@umich.edu    }
793932Sbinkertn@umich.edu
803943Sbinkertn@umich.edu    // Unix is 0-11 for month, data seet says start at 1
814762Snate@binkert.org    mon = p->time.tm_mon + 1;
824762Snate@binkert.org    mday = p->time.tm_mday;
834762Snate@binkert.org    hour = p->time.tm_hour;
844762Snate@binkert.org    min = p->time.tm_min;
854762Snate@binkert.org    sec = p->time.tm_sec;
863932Sbinkertn@umich.edu
873943Sbinkertn@umich.edu    // Datasheet says 1 is sunday
884762Snate@binkert.org    wday = p->time.tm_wday + 1;
893932Sbinkertn@umich.edu
904762Snate@binkert.org    DPRINTFN("Real-time clock set to %s", asctime(&p->time));
911817SN/A}
921817SN/A
931817SN/Avoid
942539SN/ATsunamiIO::RTC::writeAddr(const uint8_t data)
951817SN/A{
962542SN/A    if (data <= RTC_STAT_REGD)
972539SN/A        addr = data;
981817SN/A    else
991817SN/A        panic("RTC addresses over 0xD are not implemented.\n");
1001817SN/A}
1011817SN/A
1021817SN/Avoid
1032539SN/ATsunamiIO::RTC::writeData(const uint8_t data)
1041817SN/A{
1051817SN/A    if (addr < RTC_STAT_REGA)
1062539SN/A        clock_data[addr] = data;
1071817SN/A    else {
1081817SN/A        switch (addr) {
1091817SN/A          case RTC_STAT_REGA:
1102539SN/A            if (data != (RTCA_32768HZ | RTCA_1024HZ))
1111817SN/A                panic("Unimplemented RTC register A value write!\n");
1122542SN/A            stat_regA = data;
1131817SN/A            break;
1141817SN/A          case RTC_STAT_REGB:
1152539SN/A            if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
1161817SN/A                panic("Write to RTC reg B bits that are not implemented!\n");
1171817SN/A
1182542SN/A            if (data & RTCB_PRDC_IE) {
1191817SN/A                if (!event.scheduled())
1201817SN/A                    event.scheduleIntr();
1211817SN/A            } else {
1221817SN/A                if (event.scheduled())
1231817SN/A                    event.deschedule();
1241817SN/A            }
1252539SN/A            stat_regB = data;
1261817SN/A            break;
1271817SN/A          case RTC_STAT_REGC:
1281817SN/A          case RTC_STAT_REGD:
1291817SN/A            panic("RTC status registers C and D are not implemented.\n");
1301817SN/A            break;
1311817SN/A        }
1321817SN/A    }
1331817SN/A}
1341817SN/A
1352648SN/Auint8_t
1362648SN/ATsunamiIO::RTC::readData()
1371817SN/A{
1381817SN/A    if (addr < RTC_STAT_REGA)
1392648SN/A        return clock_data[addr];
1401817SN/A    else {
1411817SN/A        switch (addr) {
1421817SN/A          case RTC_STAT_REGA:
1431817SN/A            // toggle UIP bit for linux
1441817SN/A            stat_regA ^= RTCA_UIP;
1452648SN/A            return stat_regA;
1461817SN/A            break;
1471817SN/A          case RTC_STAT_REGB:
1482648SN/A            return stat_regB;
1491817SN/A            break;
1501817SN/A          case RTC_STAT_REGC:
1511817SN/A          case RTC_STAT_REGD:
1522648SN/A            return 0x00;
1531817SN/A            break;
1542648SN/A          default:
1552648SN/A            panic("Shouldn't be here");
1561817SN/A        }
1571817SN/A    }
1581817SN/A}
1591817SN/A
1601817SN/Avoid
1611854SN/ATsunamiIO::RTC::serialize(const string &base, ostream &os)
1621817SN/A{
1631854SN/A    paramOut(os, base + ".addr", addr);
1641854SN/A    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
1651854SN/A    paramOut(os, base + ".stat_regA", stat_regA);
1661854SN/A    paramOut(os, base + ".stat_regB", stat_regB);
1671817SN/A}
1681817SN/A
1691817SN/Avoid
1701854SN/ATsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
1711854SN/A                            const string &section)
1721817SN/A{
1731854SN/A    paramIn(cp, section, base + ".addr", addr);
1741854SN/A    arrayParamIn(cp, section, base + ".clock_data", clock_data,
1751854SN/A                 sizeof(clock_data));
1761854SN/A    paramIn(cp, section, base + ".stat_regA", stat_regA);
1771854SN/A    paramIn(cp, section, base + ".stat_regB", stat_regB);
1781817SN/A
1791854SN/A    // We're not unserializing the event here, but we need to
1801854SN/A    // rescehedule the event since curTick was moved forward by the
1811854SN/A    // checkpoint
1821854SN/A    event.reschedule(curTick + event.interval);
1831817SN/A}
1841817SN/A
1851817SN/ATsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
1861634SN/A    : Event(&mainEventQueue), tsunami(t), interval(i)
187772SN/A{
188773SN/A    DPRINTF(MC146818, "RTC Event Initilizing\n");
1891634SN/A    schedule(curTick + interval);
190772SN/A}
191772SN/A
192772SN/Avoid
1931817SN/ATsunamiIO::RTC::RTCEvent::scheduleIntr()
1941817SN/A{
1951817SN/A  schedule(curTick + interval);
1961817SN/A}
1971817SN/A
1981817SN/Avoid
1991817SN/ATsunamiIO::RTC::RTCEvent::process()
200772SN/A{
201776SN/A    DPRINTF(MC146818, "RTC Timer Interrupt\n");
2021634SN/A    schedule(curTick + interval);
203773SN/A    //Actually interrupt the processor here
204831SN/A    tsunami->cchip->postRTC();
205772SN/A}
206772SN/A
207772SN/Aconst char *
2081817SN/ATsunamiIO::RTC::RTCEvent::description()
209772SN/A{
2101634SN/A    return "tsunami RTC interrupt";
211772SN/A}
212772SN/A
2131854SN/ATsunamiIO::PITimer::PITimer(const string &name)
2141854SN/A    : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
2151854SN/A      counter2(name + ".counter2")
216918SN/A{
2171854SN/A    counter[0] = &counter0;
2181854SN/A    counter[1] = &counter0;
2191854SN/A    counter[2] = &counter0;
220771SN/A}
221771SN/A
222771SN/Avoid
2232539SN/ATsunamiIO::PITimer::writeControl(const uint8_t data)
224771SN/A{
2251817SN/A    int rw;
2261817SN/A    int sel;
2271817SN/A
2282539SN/A    sel = GET_CTRL_SEL(data);
2291817SN/A
2301817SN/A    if (sel == PIT_READ_BACK)
2311817SN/A       panic("PITimer Read-Back Command is not implemented.\n");
2321817SN/A
2332542SN/A    rw = GET_CTRL_RW(data);
2341817SN/A
2351817SN/A    if (rw == PIT_RW_LATCH_COMMAND)
2361854SN/A        counter[sel]->latchCount();
2371817SN/A    else {
2381854SN/A        counter[sel]->setRW(rw);
2392539SN/A        counter[sel]->setMode(GET_CTRL_MODE(data));
2402539SN/A        counter[sel]->setBCD(GET_CTRL_BCD(data));
2411817SN/A    }
242771SN/A}
243771SN/A
244771SN/Avoid
2451854SN/ATsunamiIO::PITimer::serialize(const string &base, ostream &os)
246771SN/A{
2471817SN/A    // serialize the counters
2481854SN/A    counter0.serialize(base + ".counter0", os);
2491854SN/A    counter1.serialize(base + ".counter1", os);
2501854SN/A    counter2.serialize(base + ".counter2", os);
2511817SN/A}
2521817SN/A
2531817SN/Avoid
2541854SN/ATsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
2551854SN/A                                const string &section)
2561817SN/A{
2571817SN/A    // unserialze the counters
2581854SN/A    counter0.unserialize(base + ".counter0", cp, section);
2591854SN/A    counter1.unserialize(base + ".counter1", cp, section);
2601854SN/A    counter2.unserialize(base + ".counter2", cp, section);
2611817SN/A}
2621817SN/A
2631854SN/ATsunamiIO::PITimer::Counter::Counter(const string &name)
2641854SN/A    : _name(name), event(this), count(0), latched_count(0), period(0),
2651817SN/A      mode(0), output_high(false), latch_on(false), read_byte(LSB),
2661817SN/A      write_byte(LSB)
2671817SN/A{
2681817SN/A
2691817SN/A}
2701817SN/A
2711817SN/Avoid
2721817SN/ATsunamiIO::PITimer::Counter::latchCount()
2731817SN/A{
2741817SN/A    // behave like a real latch
2751817SN/A    if(!latch_on) {
2761817SN/A        latch_on = true;
2771817SN/A        read_byte = LSB;
2781817SN/A        latched_count = count;
2791817SN/A    }
2801817SN/A}
2811817SN/A
2822648SN/Auint8_t
2832648SN/ATsunamiIO::PITimer::Counter::read()
2841817SN/A{
2851817SN/A    if (latch_on) {
2861817SN/A        switch (read_byte) {
2871817SN/A          case LSB:
2881817SN/A            read_byte = MSB;
2892648SN/A            return (uint8_t)latched_count;
2901817SN/A            break;
2911817SN/A          case MSB:
2921817SN/A            read_byte = LSB;
2931817SN/A            latch_on = false;
2942648SN/A            return latched_count >> 8;
2951817SN/A            break;
2962648SN/A          default:
2972648SN/A            panic("Shouldn't be here");
2981817SN/A        }
2991817SN/A    } else {
3001817SN/A        switch (read_byte) {
3011817SN/A          case LSB:
3021817SN/A            read_byte = MSB;
3032648SN/A            return (uint8_t)count;
3041817SN/A            break;
3051817SN/A          case MSB:
3061817SN/A            read_byte = LSB;
3072648SN/A            return count >> 8;
3081817SN/A            break;
3092648SN/A          default:
3102648SN/A            panic("Shouldn't be here");
3111817SN/A        }
3121817SN/A    }
3131817SN/A}
3141817SN/A
3151817SN/Avoid
3162539SN/ATsunamiIO::PITimer::Counter::write(const uint8_t data)
3171817SN/A{
3181817SN/A    switch (write_byte) {
3191817SN/A      case LSB:
3202539SN/A        count = (count & 0xFF00) | data;
3211817SN/A
3221817SN/A        if (event.scheduled())
3231817SN/A          event.deschedule();
3241817SN/A        output_high = false;
3251817SN/A        write_byte = MSB;
3261817SN/A        break;
3271817SN/A
3281817SN/A      case MSB:
3292539SN/A        count = (count & 0x00FF) | (data << 8);
3301817SN/A        period = count;
3311817SN/A
3321817SN/A        if (period > 0) {
3331854SN/A            DPRINTF(Tsunami, "Timer set to curTick + %d\n",
3341854SN/A                    count * event.interval);
3351817SN/A            event.schedule(curTick + count * event.interval);
3361817SN/A        }
3371817SN/A        write_byte = LSB;
3381817SN/A        break;
3391817SN/A    }
3401817SN/A}
3411817SN/A
3421817SN/Avoid
3431817SN/ATsunamiIO::PITimer::Counter::setRW(int rw_val)
3441817SN/A{
3451817SN/A    if (rw_val != PIT_RW_16BIT)
3461817SN/A        panic("Only LSB/MSB read/write is implemented.\n");
3471817SN/A}
3481817SN/A
3491817SN/Avoid
3501817SN/ATsunamiIO::PITimer::Counter::setMode(int mode_val)
3511817SN/A{
3521817SN/A    if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
3531817SN/A       mode_val != PIT_MODE_SQWAVE)
3541817SN/A        panic("PIT mode %#x is not implemented: \n", mode_val);
3551817SN/A
3561817SN/A    mode = mode_val;
3571817SN/A}
3581817SN/A
3591817SN/Avoid
3601817SN/ATsunamiIO::PITimer::Counter::setBCD(int bcd_val)
3611817SN/A{
3621817SN/A    if (bcd_val != PIT_BCD_FALSE)
3631817SN/A        panic("PITimer does not implement BCD counts.\n");
3641817SN/A}
3651817SN/A
3661817SN/Abool
3671817SN/ATsunamiIO::PITimer::Counter::outputHigh()
3681817SN/A{
3691817SN/A    return output_high;
3701817SN/A}
3711817SN/A
3721817SN/Avoid
3731854SN/ATsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
3741817SN/A{
3751854SN/A    paramOut(os, base + ".count", count);
3761854SN/A    paramOut(os, base + ".latched_count", latched_count);
3771854SN/A    paramOut(os, base + ".period", period);
3781854SN/A    paramOut(os, base + ".mode", mode);
3791854SN/A    paramOut(os, base + ".output_high", output_high);
3801854SN/A    paramOut(os, base + ".latch_on", latch_on);
3811854SN/A    paramOut(os, base + ".read_byte", read_byte);
3821854SN/A    paramOut(os, base + ".write_byte", write_byte);
3831817SN/A
3841854SN/A    Tick event_tick = 0;
3851854SN/A    if (event.scheduled())
3861854SN/A        event_tick = event.when();
3871854SN/A    paramOut(os, base + ".event_tick", event_tick);
3881817SN/A}
3891817SN/A
3901817SN/Avoid
3911854SN/ATsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
3921854SN/A                                         const string &section)
3931817SN/A{
3941854SN/A    paramIn(cp, section, base + ".count", count);
3951854SN/A    paramIn(cp, section, base + ".latched_count", latched_count);
3961854SN/A    paramIn(cp, section, base + ".period", period);
3971854SN/A    paramIn(cp, section, base + ".mode", mode);
3981854SN/A    paramIn(cp, section, base + ".output_high", output_high);
3991854SN/A    paramIn(cp, section, base + ".latch_on", latch_on);
4001854SN/A    paramIn(cp, section, base + ".read_byte", read_byte);
4011854SN/A    paramIn(cp, section, base + ".write_byte", write_byte);
4021817SN/A
4031854SN/A    Tick event_tick;
4041854SN/A    paramIn(cp, section, base + ".event_tick", event_tick);
4051854SN/A    if (event_tick)
4061854SN/A        event.schedule(event_tick);
4071817SN/A}
4081817SN/A
4091817SN/ATsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
4101817SN/A    : Event(&mainEventQueue)
4111817SN/A{
4121817SN/A    interval = (Tick)(Clock::Float::s / 1193180.0);
4131817SN/A    counter = c_ptr;
4141817SN/A}
4151817SN/A
4161817SN/Avoid
4171817SN/ATsunamiIO::PITimer::Counter::CounterEvent::process()
4181817SN/A{
4191817SN/A    DPRINTF(Tsunami, "Timer Interrupt\n");
4201817SN/A    switch (counter->mode) {
4211817SN/A      case PIT_MODE_INTTC:
4221817SN/A        counter->output_high = true;
4231817SN/A      case PIT_MODE_RATEGEN:
4241817SN/A      case PIT_MODE_SQWAVE:
4251817SN/A        break;
4261817SN/A      default:
4271817SN/A        panic("Unimplemented PITimer mode.\n");
4281817SN/A    }
429771SN/A}
430771SN/A
431771SN/Aconst char *
4321817SN/ATsunamiIO::PITimer::Counter::CounterEvent::description()
433771SN/A{
434771SN/A    return "tsunami 8254 Interval timer";
435771SN/A}
436771SN/A
4374762Snate@binkert.orgTsunamiIO::TsunamiIO(const Params *p)
4382539SN/A    : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
4394762Snate@binkert.org      rtc(p->name + ".rtc", p->tsunami, p)
440768SN/A{
4413846Shsul@eecs.umich.edu    pioSize = 0x100;
442909SN/A
443803SN/A    // set the back pointer from tsunami to myself
444803SN/A    tsunami->io = this;
445803SN/A
446771SN/A    timerData = 0;
447777SN/A    picr = 0;
448777SN/A    picInterrupting = false;
449773SN/A}
450773SN/A
4511634SN/ATick
4521634SN/ATsunamiIO::frequency() const
4531634SN/A{
4542539SN/A    return Clock::Frequency / params()->frequency;
4551634SN/A}
4561634SN/A
4572542SN/ATick
4583349SN/ATsunamiIO::read(PacketPtr pkt)
459768SN/A{
4602641SN/A    assert(pkt->result == Packet::Unknown);
4612641SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
462768SN/A
4632641SN/A    Addr daddr = pkt->getAddr() - pioAddr;
464865SN/A
4652641SN/A    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(),
4662641SN/A            pkt->getSize(), daddr);
467771SN/A
4682630SN/A    pkt->allocate();
4692539SN/A
4702641SN/A    if (pkt->getSize() == sizeof(uint8_t)) {
471803SN/A        switch(daddr) {
4721817SN/A          // PIC1 mask read
4731817SN/A          case TSDEV_PIC1_MASK:
4742630SN/A            pkt->set(~mask1);
4752539SN/A            break;
4761817SN/A          case TSDEV_PIC2_MASK:
4772630SN/A            pkt->set(~mask2);
4782539SN/A            break;
479865SN/A          case TSDEV_PIC1_ISR:
480865SN/A              // !!! If this is modified 64bit case needs to be too
481865SN/A              // Pal code has to do a 64 bit physical read because there is
482865SN/A              // no load physical byte instruction
4832630SN/A              pkt->set(picr);
4842539SN/A              break;
485865SN/A          case TSDEV_PIC2_ISR:
486865SN/A              // PIC2 not implemnted... just return 0
4872630SN/A              pkt->set(0x00);
4882539SN/A              break;
4891817SN/A          case TSDEV_TMR0_DATA:
4902648SN/A            pkt->set(pitimer.counter0.read());
4912542SN/A            break;
4921817SN/A          case TSDEV_TMR1_DATA:
4932648SN/A            pkt->set(pitimer.counter1.read());
4942542SN/A            break;
4951817SN/A          case TSDEV_TMR2_DATA:
4962648SN/A            pkt->set(pitimer.counter2.read());
4972539SN/A            break;
498803SN/A          case TSDEV_RTC_DATA:
4992648SN/A            pkt->set(rtc.readData());
5002539SN/A            break;
5011817SN/A          case TSDEV_CTRL_PORTB:
5021817SN/A            if (pitimer.counter2.outputHigh())
5032630SN/A                pkt->set(PORTB_SPKR_HIGH);
5041817SN/A            else
5052630SN/A                pkt->set(0x00);
5062539SN/A            break;
507803SN/A          default:
5082641SN/A            panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize());
509803SN/A        }
5102641SN/A    } else if (pkt->getSize() == sizeof(uint64_t)) {
5112539SN/A        if (daddr == TSDEV_PIC1_ISR)
5122630SN/A            pkt->set<uint64_t>(picr);
5132539SN/A        else
5142539SN/A           panic("I/O Read - invalid addr - va %#x size %d\n",
5152641SN/A                   pkt->getAddr(), pkt->getSize());
5162539SN/A    } else {
5172641SN/A       panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize());
518771SN/A    }
5192641SN/A    pkt->result = Packet::Success;
5202539SN/A    return pioDelay;
521768SN/A}
522768SN/A
5232539SN/ATick
5243349SN/ATsunamiIO::write(PacketPtr pkt)
525768SN/A{
5262641SN/A    assert(pkt->result == Packet::Unknown);
5272641SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
5282641SN/A    Addr daddr = pkt->getAddr() - pioAddr;
529779SN/A
530779SN/A    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
5312641SN/A            pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>());
532768SN/A
5332641SN/A    assert(pkt->getSize() == sizeof(uint8_t));
534769SN/A
5352539SN/A    switch(daddr) {
5362539SN/A      case TSDEV_PIC1_MASK:
5372630SN/A        mask1 = ~(pkt->get<uint8_t>());
5382539SN/A        if ((picr & mask1) && !picInterrupting) {
5392539SN/A            picInterrupting = true;
5402539SN/A            tsunami->cchip->postDRIR(55);
5412539SN/A            DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
542803SN/A        }
5432539SN/A        if ((!(picr & mask1)) && picInterrupting) {
5442539SN/A            picInterrupting = false;
5452539SN/A            tsunami->cchip->clearDRIR(55);
5462539SN/A            DPRINTF(Tsunami, "clearing pic interrupt\n");
5472539SN/A        }
5482539SN/A        break;
5492539SN/A      case TSDEV_PIC2_MASK:
5502630SN/A        mask2 = pkt->get<uint8_t>();
5512539SN/A        //PIC2 Not implemented to interrupt
5522539SN/A        break;
5532539SN/A      case TSDEV_PIC1_ACK:
5542539SN/A        // clear the interrupt on the PIC
5552630SN/A        picr &= ~(1 << (pkt->get<uint8_t>() & 0xF));
5562539SN/A        if (!(picr & mask1))
5572539SN/A            tsunami->cchip->clearDRIR(55);
5582539SN/A        break;
5592539SN/A      case TSDEV_DMA1_MODE:
5602630SN/A        mode1 = pkt->get<uint8_t>();
5612539SN/A        break;
5622539SN/A      case TSDEV_DMA2_MODE:
5632630SN/A        mode2 = pkt->get<uint8_t>();
5642539SN/A        break;
5652539SN/A      case TSDEV_TMR0_DATA:
5662630SN/A        pitimer.counter0.write(pkt->get<uint8_t>());
5672539SN/A        break;
5682539SN/A      case TSDEV_TMR1_DATA:
5692630SN/A        pitimer.counter1.write(pkt->get<uint8_t>());
5702539SN/A        break;
5712539SN/A      case TSDEV_TMR2_DATA:
5722630SN/A        pitimer.counter2.write(pkt->get<uint8_t>());
5732539SN/A        break;
5742539SN/A      case TSDEV_TMR_CTRL:
5752630SN/A        pitimer.writeControl(pkt->get<uint8_t>());
5762539SN/A        break;
5772539SN/A      case TSDEV_RTC_ADDR:
5782630SN/A        rtc.writeAddr(pkt->get<uint8_t>());
5792539SN/A        break;
5802539SN/A      case TSDEV_RTC_DATA:
5812630SN/A        rtc.writeData(pkt->get<uint8_t>());
5822539SN/A        break;
5832539SN/A      case TSDEV_KBD:
5842539SN/A      case TSDEV_DMA1_CMND:
5852539SN/A      case TSDEV_DMA2_CMND:
5862539SN/A      case TSDEV_DMA1_MMASK:
5872539SN/A      case TSDEV_DMA2_MMASK:
5882539SN/A      case TSDEV_PIC2_ACK:
5892539SN/A      case TSDEV_DMA1_RESET:
5902539SN/A      case TSDEV_DMA2_RESET:
5912539SN/A      case TSDEV_DMA1_MASK:
5922539SN/A      case TSDEV_DMA2_MASK:
5932539SN/A      case TSDEV_CTRL_PORTB:
5942539SN/A        break;
595803SN/A      default:
5962641SN/A        panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>());
597769SN/A    }
598769SN/A
5992641SN/A    pkt->result = Packet::Success;
6002539SN/A    return pioDelay;
601768SN/A}
602768SN/A
603768SN/Avoid
604777SN/ATsunamiIO::postPIC(uint8_t bitvector)
605777SN/A{
606777SN/A    //PIC2 Is not implemented, because nothing of interest there
607777SN/A    picr |= bitvector;
608865SN/A    if (picr & mask1) {
609817SN/A        tsunami->cchip->postDRIR(55);
610777SN/A        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
611777SN/A    }
612777SN/A}
613777SN/A
614777SN/Avoid
615777SN/ATsunamiIO::clearPIC(uint8_t bitvector)
616777SN/A{
617777SN/A    //PIC2 Is not implemented, because nothing of interest there
618777SN/A    picr &= ~bitvector;
619777SN/A    if (!(picr & mask1)) {
620817SN/A        tsunami->cchip->clearDRIR(55);
621777SN/A        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
622777SN/A    }
623777SN/A}
624777SN/A
625777SN/Avoid
6261854SN/ATsunamiIO::serialize(ostream &os)
627768SN/A{
628811SN/A    SERIALIZE_SCALAR(timerData);
629899SN/A    SERIALIZE_SCALAR(mask1);
630899SN/A    SERIALIZE_SCALAR(mask2);
631899SN/A    SERIALIZE_SCALAR(mode1);
632899SN/A    SERIALIZE_SCALAR(mode2);
633811SN/A    SERIALIZE_SCALAR(picr);
634811SN/A    SERIALIZE_SCALAR(picInterrupting);
635811SN/A
636919SN/A    // Serialize the timers
6371854SN/A    pitimer.serialize("pitimer", os);
6381854SN/A    rtc.serialize("rtc", os);
639768SN/A}
640768SN/A
641768SN/Avoid
6421854SN/ATsunamiIO::unserialize(Checkpoint *cp, const string &section)
643768SN/A{
644811SN/A    UNSERIALIZE_SCALAR(timerData);
645899SN/A    UNSERIALIZE_SCALAR(mask1);
646899SN/A    UNSERIALIZE_SCALAR(mask2);
647899SN/A    UNSERIALIZE_SCALAR(mode1);
648899SN/A    UNSERIALIZE_SCALAR(mode2);
649811SN/A    UNSERIALIZE_SCALAR(picr);
650811SN/A    UNSERIALIZE_SCALAR(picInterrupting);
651919SN/A
652919SN/A    // Unserialize the timers
6531854SN/A    pitimer.unserialize("pitimer", cp, section);
6541854SN/A    rtc.unserialize("rtc", cp, section);
655768SN/A}
656768SN/A
6574762Snate@binkert.orgTsunamiIO *
6584762Snate@binkert.orgTsunamiIOParams::create()
659768SN/A{
6604762Snate@binkert.org    return new TsunamiIO(this);
661768SN/A}
662