tsunami_io.cc revision 3932
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
43768SN/A#include "base/trace.hh"
442542SN/A#include "dev/pitreg.h"
452542SN/A#include "dev/rtcreg.h"
463540Sgblack@eecs.umich.edu#include "dev/alpha/tsunami_cchip.hh"
473540Sgblack@eecs.umich.edu#include "dev/alpha/tsunami.hh"
483540Sgblack@eecs.umich.edu#include "dev/alpha/tsunami_io.hh"
493540Sgblack@eecs.umich.edu#include "dev/alpha/tsunamireg.h"
503348SN/A#include "mem/packet.hh"
513348SN/A#include "mem/packet_access.hh"
522542SN/A#include "mem/port.hh"
53768SN/A#include "sim/builder.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
603932Sbinkertn@umich.eduTsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami, const vector<int> &t,
613932Sbinkertn@umich.edu                    bool bcd, Tick i)
623932Sbinkertn@umich.edu    : _name(n), event(tsunami, i), addr(0), year_is_bcd(bcd)
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
683932Sbinkertn@umich.edu    if (year_is_bcd) {
693932Sbinkertn@umich.edu        // The RTC uses BCD for the last two digits in the year.
703932Sbinkertn@umich.edu        // They python year is a full year.
713932Sbinkertn@umich.edu        int _year = t[0] % 100;
723932Sbinkertn@umich.edu        int tens = _year / 10;
733932Sbinkertn@umich.edu        int ones = _year % 10;
743932Sbinkertn@umich.edu
753932Sbinkertn@umich.edu        year = (tens << 4) + ones;
763932Sbinkertn@umich.edu    } else {
773932Sbinkertn@umich.edu        // Even though the datasheet says that the year field should be
783932Sbinkertn@umich.edu        // interpreted as BCD, we just enter the number of years since
793932Sbinkertn@umich.edu        // 1900 since linux seems to be happy with that (and I believe
803932Sbinkertn@umich.edu        // that Tru64 was as well)
813932Sbinkertn@umich.edu        year = t[0] - 1900;
823932Sbinkertn@umich.edu    }
833932Sbinkertn@umich.edu
843932Sbinkertn@umich.edu    mon = t[1];
853932Sbinkertn@umich.edu    mday = t[2];
863932Sbinkertn@umich.edu    hour = t[3];
873932Sbinkertn@umich.edu    min = t[4];
883932Sbinkertn@umich.edu    sec = t[5];
893932Sbinkertn@umich.edu
903932Sbinkertn@umich.edu    // wday is defined to be in the range from 1 - 7 with 1 being Sunday.
913932Sbinkertn@umich.edu    // the value coming from python is in the range from 0 - 6 with 0 being
923932Sbinkertn@umich.edu    // Monday.  Fix that here.
933932Sbinkertn@umich.edu    wday = t[6]  + 2;
943932Sbinkertn@umich.edu    if (wday > 7)
953932Sbinkertn@umich.edu        wday -= 7;
963932Sbinkertn@umich.edu
973932Sbinkertn@umich.edu    DPRINTFN("Real-time clock set to %s", getDateString());
983932Sbinkertn@umich.edu}
993932Sbinkertn@umich.edu
1003932Sbinkertn@umich.edustd::string
1013932Sbinkertn@umich.eduTsunamiIO::RTC::getDateString()
1023932Sbinkertn@umich.edu{
1031817SN/A    struct tm tm;
1041817SN/A
1053932Sbinkertn@umich.edu    memset(&tm, 0, sizeof(tm));
1061817SN/A
1073932Sbinkertn@umich.edu    if (year_is_bcd) {
1083932Sbinkertn@umich.edu        // undo the BCD and conver to years since 1900 guessing that
1093932Sbinkertn@umich.edu        // anything before 1970 is actually after 2000
1103932Sbinkertn@umich.edu        int _year = (year >> 4) * 10 + (year & 0xf);
1113932Sbinkertn@umich.edu        if (_year < 70)
1123932Sbinkertn@umich.edu            _year += 100;
1133932Sbinkertn@umich.edu
1143932Sbinkertn@umich.edu        tm.tm_year = _year;
1153932Sbinkertn@umich.edu    } else {
1163932Sbinkertn@umich.edu        // number of years since 1900
1173932Sbinkertn@umich.edu        tm.tm_year = year;
1183932Sbinkertn@umich.edu    }
1193932Sbinkertn@umich.edu
1203932Sbinkertn@umich.edu    // unix is 0-11 for month
1213932Sbinkertn@umich.edu    tm.tm_mon = mon - 1;
1223932Sbinkertn@umich.edu    tm.tm_mday = mday;
1233932Sbinkertn@umich.edu    tm.tm_hour = hour;
1243932Sbinkertn@umich.edu    tm.tm_min = min;
1253932Sbinkertn@umich.edu    tm.tm_sec = sec;
1263932Sbinkertn@umich.edu
1273932Sbinkertn@umich.edu    // to add more annoyance unix is 0 - 6 with 0 as sunday
1283932Sbinkertn@umich.edu    tm.tm_wday = wday - 1;
1293932Sbinkertn@umich.edu
1303932Sbinkertn@umich.edu    return asctime(&tm);
1311817SN/A}
1321817SN/A
1331817SN/Avoid
1342539SN/ATsunamiIO::RTC::writeAddr(const uint8_t data)
1351817SN/A{
1362542SN/A    if (data <= RTC_STAT_REGD)
1372539SN/A        addr = data;
1381817SN/A    else
1391817SN/A        panic("RTC addresses over 0xD are not implemented.\n");
1401817SN/A}
1411817SN/A
1421817SN/Avoid
1432539SN/ATsunamiIO::RTC::writeData(const uint8_t data)
1441817SN/A{
1451817SN/A    if (addr < RTC_STAT_REGA)
1462539SN/A        clock_data[addr] = data;
1471817SN/A    else {
1481817SN/A        switch (addr) {
1491817SN/A          case RTC_STAT_REGA:
1502539SN/A            if (data != (RTCA_32768HZ | RTCA_1024HZ))
1511817SN/A                panic("Unimplemented RTC register A value write!\n");
1522542SN/A            stat_regA = data;
1531817SN/A            break;
1541817SN/A          case RTC_STAT_REGB:
1552539SN/A            if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
1561817SN/A                panic("Write to RTC reg B bits that are not implemented!\n");
1571817SN/A
1582542SN/A            if (data & RTCB_PRDC_IE) {
1591817SN/A                if (!event.scheduled())
1601817SN/A                    event.scheduleIntr();
1611817SN/A            } else {
1621817SN/A                if (event.scheduled())
1631817SN/A                    event.deschedule();
1641817SN/A            }
1652539SN/A            stat_regB = data;
1661817SN/A            break;
1671817SN/A          case RTC_STAT_REGC:
1681817SN/A          case RTC_STAT_REGD:
1691817SN/A            panic("RTC status registers C and D are not implemented.\n");
1701817SN/A            break;
1711817SN/A        }
1721817SN/A    }
1731817SN/A}
1741817SN/A
1752648SN/Auint8_t
1762648SN/ATsunamiIO::RTC::readData()
1771817SN/A{
1781817SN/A    if (addr < RTC_STAT_REGA)
1792648SN/A        return clock_data[addr];
1801817SN/A    else {
1811817SN/A        switch (addr) {
1821817SN/A          case RTC_STAT_REGA:
1831817SN/A            // toggle UIP bit for linux
1841817SN/A            stat_regA ^= RTCA_UIP;
1852648SN/A            return stat_regA;
1861817SN/A            break;
1871817SN/A          case RTC_STAT_REGB:
1882648SN/A            return stat_regB;
1891817SN/A            break;
1901817SN/A          case RTC_STAT_REGC:
1911817SN/A          case RTC_STAT_REGD:
1922648SN/A            return 0x00;
1931817SN/A            break;
1942648SN/A          default:
1952648SN/A            panic("Shouldn't be here");
1961817SN/A        }
1971817SN/A    }
1981817SN/A}
1991817SN/A
2001817SN/Avoid
2011854SN/ATsunamiIO::RTC::serialize(const string &base, ostream &os)
2021817SN/A{
2031854SN/A    paramOut(os, base + ".addr", addr);
2041854SN/A    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
2051854SN/A    paramOut(os, base + ".stat_regA", stat_regA);
2061854SN/A    paramOut(os, base + ".stat_regB", stat_regB);
2071817SN/A}
2081817SN/A
2091817SN/Avoid
2101854SN/ATsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
2111854SN/A                            const string &section)
2121817SN/A{
2131854SN/A    paramIn(cp, section, base + ".addr", addr);
2141854SN/A    arrayParamIn(cp, section, base + ".clock_data", clock_data,
2151854SN/A                 sizeof(clock_data));
2161854SN/A    paramIn(cp, section, base + ".stat_regA", stat_regA);
2171854SN/A    paramIn(cp, section, base + ".stat_regB", stat_regB);
2181817SN/A
2191854SN/A    // We're not unserializing the event here, but we need to
2201854SN/A    // rescehedule the event since curTick was moved forward by the
2211854SN/A    // checkpoint
2221854SN/A    event.reschedule(curTick + event.interval);
2231817SN/A}
2241817SN/A
2251817SN/ATsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
2261634SN/A    : Event(&mainEventQueue), tsunami(t), interval(i)
227772SN/A{
228773SN/A    DPRINTF(MC146818, "RTC Event Initilizing\n");
2291634SN/A    schedule(curTick + interval);
230772SN/A}
231772SN/A
232772SN/Avoid
2331817SN/ATsunamiIO::RTC::RTCEvent::scheduleIntr()
2341817SN/A{
2351817SN/A  schedule(curTick + interval);
2361817SN/A}
2371817SN/A
2381817SN/Avoid
2391817SN/ATsunamiIO::RTC::RTCEvent::process()
240772SN/A{
241776SN/A    DPRINTF(MC146818, "RTC Timer Interrupt\n");
2421634SN/A    schedule(curTick + interval);
243773SN/A    //Actually interrupt the processor here
244831SN/A    tsunami->cchip->postRTC();
245772SN/A}
246772SN/A
247772SN/Aconst char *
2481817SN/ATsunamiIO::RTC::RTCEvent::description()
249772SN/A{
2501634SN/A    return "tsunami RTC interrupt";
251772SN/A}
252772SN/A
2531854SN/ATsunamiIO::PITimer::PITimer(const string &name)
2541854SN/A    : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
2551854SN/A      counter2(name + ".counter2")
256918SN/A{
2571854SN/A    counter[0] = &counter0;
2581854SN/A    counter[1] = &counter0;
2591854SN/A    counter[2] = &counter0;
260771SN/A}
261771SN/A
262771SN/Avoid
2632539SN/ATsunamiIO::PITimer::writeControl(const uint8_t data)
264771SN/A{
2651817SN/A    int rw;
2661817SN/A    int sel;
2671817SN/A
2682539SN/A    sel = GET_CTRL_SEL(data);
2691817SN/A
2701817SN/A    if (sel == PIT_READ_BACK)
2711817SN/A       panic("PITimer Read-Back Command is not implemented.\n");
2721817SN/A
2732542SN/A    rw = GET_CTRL_RW(data);
2741817SN/A
2751817SN/A    if (rw == PIT_RW_LATCH_COMMAND)
2761854SN/A        counter[sel]->latchCount();
2771817SN/A    else {
2781854SN/A        counter[sel]->setRW(rw);
2792539SN/A        counter[sel]->setMode(GET_CTRL_MODE(data));
2802539SN/A        counter[sel]->setBCD(GET_CTRL_BCD(data));
2811817SN/A    }
282771SN/A}
283771SN/A
284771SN/Avoid
2851854SN/ATsunamiIO::PITimer::serialize(const string &base, ostream &os)
286771SN/A{
2871817SN/A    // serialize the counters
2881854SN/A    counter0.serialize(base + ".counter0", os);
2891854SN/A    counter1.serialize(base + ".counter1", os);
2901854SN/A    counter2.serialize(base + ".counter2", os);
2911817SN/A}
2921817SN/A
2931817SN/Avoid
2941854SN/ATsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
2951854SN/A                                const string &section)
2961817SN/A{
2971817SN/A    // unserialze the counters
2981854SN/A    counter0.unserialize(base + ".counter0", cp, section);
2991854SN/A    counter1.unserialize(base + ".counter1", cp, section);
3001854SN/A    counter2.unserialize(base + ".counter2", cp, section);
3011817SN/A}
3021817SN/A
3031854SN/ATsunamiIO::PITimer::Counter::Counter(const string &name)
3041854SN/A    : _name(name), event(this), count(0), latched_count(0), period(0),
3051817SN/A      mode(0), output_high(false), latch_on(false), read_byte(LSB),
3061817SN/A      write_byte(LSB)
3071817SN/A{
3081817SN/A
3091817SN/A}
3101817SN/A
3111817SN/Avoid
3121817SN/ATsunamiIO::PITimer::Counter::latchCount()
3131817SN/A{
3141817SN/A    // behave like a real latch
3151817SN/A    if(!latch_on) {
3161817SN/A        latch_on = true;
3171817SN/A        read_byte = LSB;
3181817SN/A        latched_count = count;
3191817SN/A    }
3201817SN/A}
3211817SN/A
3222648SN/Auint8_t
3232648SN/ATsunamiIO::PITimer::Counter::read()
3241817SN/A{
3251817SN/A    if (latch_on) {
3261817SN/A        switch (read_byte) {
3271817SN/A          case LSB:
3281817SN/A            read_byte = MSB;
3292648SN/A            return (uint8_t)latched_count;
3301817SN/A            break;
3311817SN/A          case MSB:
3321817SN/A            read_byte = LSB;
3331817SN/A            latch_on = false;
3342648SN/A            return latched_count >> 8;
3351817SN/A            break;
3362648SN/A          default:
3372648SN/A            panic("Shouldn't be here");
3381817SN/A        }
3391817SN/A    } else {
3401817SN/A        switch (read_byte) {
3411817SN/A          case LSB:
3421817SN/A            read_byte = MSB;
3432648SN/A            return (uint8_t)count;
3441817SN/A            break;
3451817SN/A          case MSB:
3461817SN/A            read_byte = LSB;
3472648SN/A            return count >> 8;
3481817SN/A            break;
3492648SN/A          default:
3502648SN/A            panic("Shouldn't be here");
3511817SN/A        }
3521817SN/A    }
3531817SN/A}
3541817SN/A
3551817SN/Avoid
3562539SN/ATsunamiIO::PITimer::Counter::write(const uint8_t data)
3571817SN/A{
3581817SN/A    switch (write_byte) {
3591817SN/A      case LSB:
3602539SN/A        count = (count & 0xFF00) | data;
3611817SN/A
3621817SN/A        if (event.scheduled())
3631817SN/A          event.deschedule();
3641817SN/A        output_high = false;
3651817SN/A        write_byte = MSB;
3661817SN/A        break;
3671817SN/A
3681817SN/A      case MSB:
3692539SN/A        count = (count & 0x00FF) | (data << 8);
3701817SN/A        period = count;
3711817SN/A
3721817SN/A        if (period > 0) {
3731854SN/A            DPRINTF(Tsunami, "Timer set to curTick + %d\n",
3741854SN/A                    count * event.interval);
3751817SN/A            event.schedule(curTick + count * event.interval);
3761817SN/A        }
3771817SN/A        write_byte = LSB;
3781817SN/A        break;
3791817SN/A    }
3801817SN/A}
3811817SN/A
3821817SN/Avoid
3831817SN/ATsunamiIO::PITimer::Counter::setRW(int rw_val)
3841817SN/A{
3851817SN/A    if (rw_val != PIT_RW_16BIT)
3861817SN/A        panic("Only LSB/MSB read/write is implemented.\n");
3871817SN/A}
3881817SN/A
3891817SN/Avoid
3901817SN/ATsunamiIO::PITimer::Counter::setMode(int mode_val)
3911817SN/A{
3921817SN/A    if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
3931817SN/A       mode_val != PIT_MODE_SQWAVE)
3941817SN/A        panic("PIT mode %#x is not implemented: \n", mode_val);
3951817SN/A
3961817SN/A    mode = mode_val;
3971817SN/A}
3981817SN/A
3991817SN/Avoid
4001817SN/ATsunamiIO::PITimer::Counter::setBCD(int bcd_val)
4011817SN/A{
4021817SN/A    if (bcd_val != PIT_BCD_FALSE)
4031817SN/A        panic("PITimer does not implement BCD counts.\n");
4041817SN/A}
4051817SN/A
4061817SN/Abool
4071817SN/ATsunamiIO::PITimer::Counter::outputHigh()
4081817SN/A{
4091817SN/A    return output_high;
4101817SN/A}
4111817SN/A
4121817SN/Avoid
4131854SN/ATsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
4141817SN/A{
4151854SN/A    paramOut(os, base + ".count", count);
4161854SN/A    paramOut(os, base + ".latched_count", latched_count);
4171854SN/A    paramOut(os, base + ".period", period);
4181854SN/A    paramOut(os, base + ".mode", mode);
4191854SN/A    paramOut(os, base + ".output_high", output_high);
4201854SN/A    paramOut(os, base + ".latch_on", latch_on);
4211854SN/A    paramOut(os, base + ".read_byte", read_byte);
4221854SN/A    paramOut(os, base + ".write_byte", write_byte);
4231817SN/A
4241854SN/A    Tick event_tick = 0;
4251854SN/A    if (event.scheduled())
4261854SN/A        event_tick = event.when();
4271854SN/A    paramOut(os, base + ".event_tick", event_tick);
4281817SN/A}
4291817SN/A
4301817SN/Avoid
4311854SN/ATsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
4321854SN/A                                         const string &section)
4331817SN/A{
4341854SN/A    paramIn(cp, section, base + ".count", count);
4351854SN/A    paramIn(cp, section, base + ".latched_count", latched_count);
4361854SN/A    paramIn(cp, section, base + ".period", period);
4371854SN/A    paramIn(cp, section, base + ".mode", mode);
4381854SN/A    paramIn(cp, section, base + ".output_high", output_high);
4391854SN/A    paramIn(cp, section, base + ".latch_on", latch_on);
4401854SN/A    paramIn(cp, section, base + ".read_byte", read_byte);
4411854SN/A    paramIn(cp, section, base + ".write_byte", write_byte);
4421817SN/A
4431854SN/A    Tick event_tick;
4441854SN/A    paramIn(cp, section, base + ".event_tick", event_tick);
4451854SN/A    if (event_tick)
4461854SN/A        event.schedule(event_tick);
4471817SN/A}
4481817SN/A
4491817SN/ATsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
4501817SN/A    : Event(&mainEventQueue)
4511817SN/A{
4521817SN/A    interval = (Tick)(Clock::Float::s / 1193180.0);
4531817SN/A    counter = c_ptr;
4541817SN/A}
4551817SN/A
4561817SN/Avoid
4571817SN/ATsunamiIO::PITimer::Counter::CounterEvent::process()
4581817SN/A{
4591817SN/A    DPRINTF(Tsunami, "Timer Interrupt\n");
4601817SN/A    switch (counter->mode) {
4611817SN/A      case PIT_MODE_INTTC:
4621817SN/A        counter->output_high = true;
4631817SN/A      case PIT_MODE_RATEGEN:
4641817SN/A      case PIT_MODE_SQWAVE:
4651817SN/A        break;
4661817SN/A      default:
4671817SN/A        panic("Unimplemented PITimer mode.\n");
4681817SN/A    }
469771SN/A}
470771SN/A
471771SN/Aconst char *
4721817SN/ATsunamiIO::PITimer::Counter::CounterEvent::description()
473771SN/A{
474771SN/A    return "tsunami 8254 Interval timer";
475771SN/A}
476771SN/A
4772539SN/ATsunamiIO::TsunamiIO(Params *p)
4782539SN/A    : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
4793932Sbinkertn@umich.edu      rtc(p->name + ".rtc", p->tsunami, p->init_time, p->year_is_bcd,
4803932Sbinkertn@umich.edu          p->frequency)
481768SN/A{
4823846Shsul@eecs.umich.edu    pioSize = 0x100;
483909SN/A
484803SN/A    // set the back pointer from tsunami to myself
485803SN/A    tsunami->io = this;
486803SN/A
487771SN/A    timerData = 0;
488777SN/A    picr = 0;
489777SN/A    picInterrupting = false;
490773SN/A}
491773SN/A
4921634SN/ATick
4931634SN/ATsunamiIO::frequency() const
4941634SN/A{
4952539SN/A    return Clock::Frequency / params()->frequency;
4961634SN/A}
4971634SN/A
4982542SN/ATick
4993349SN/ATsunamiIO::read(PacketPtr pkt)
500768SN/A{
5012641SN/A    assert(pkt->result == Packet::Unknown);
5022641SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
503768SN/A
5042641SN/A    Addr daddr = pkt->getAddr() - pioAddr;
505865SN/A
5062641SN/A    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(),
5072641SN/A            pkt->getSize(), daddr);
508771SN/A
5092630SN/A    pkt->allocate();
5102539SN/A
5112641SN/A    if (pkt->getSize() == sizeof(uint8_t)) {
512803SN/A        switch(daddr) {
5131817SN/A          // PIC1 mask read
5141817SN/A          case TSDEV_PIC1_MASK:
5152630SN/A            pkt->set(~mask1);
5162539SN/A            break;
5171817SN/A          case TSDEV_PIC2_MASK:
5182630SN/A            pkt->set(~mask2);
5192539SN/A            break;
520865SN/A          case TSDEV_PIC1_ISR:
521865SN/A              // !!! If this is modified 64bit case needs to be too
522865SN/A              // Pal code has to do a 64 bit physical read because there is
523865SN/A              // no load physical byte instruction
5242630SN/A              pkt->set(picr);
5252539SN/A              break;
526865SN/A          case TSDEV_PIC2_ISR:
527865SN/A              // PIC2 not implemnted... just return 0
5282630SN/A              pkt->set(0x00);
5292539SN/A              break;
5301817SN/A          case TSDEV_TMR0_DATA:
5312648SN/A            pkt->set(pitimer.counter0.read());
5322542SN/A            break;
5331817SN/A          case TSDEV_TMR1_DATA:
5342648SN/A            pkt->set(pitimer.counter1.read());
5352542SN/A            break;
5361817SN/A          case TSDEV_TMR2_DATA:
5372648SN/A            pkt->set(pitimer.counter2.read());
5382539SN/A            break;
539803SN/A          case TSDEV_RTC_DATA:
5402648SN/A            pkt->set(rtc.readData());
5412539SN/A            break;
5421817SN/A          case TSDEV_CTRL_PORTB:
5431817SN/A            if (pitimer.counter2.outputHigh())
5442630SN/A                pkt->set(PORTB_SPKR_HIGH);
5451817SN/A            else
5462630SN/A                pkt->set(0x00);
5472539SN/A            break;
548803SN/A          default:
5492641SN/A            panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize());
550803SN/A        }
5512641SN/A    } else if (pkt->getSize() == sizeof(uint64_t)) {
5522539SN/A        if (daddr == TSDEV_PIC1_ISR)
5532630SN/A            pkt->set<uint64_t>(picr);
5542539SN/A        else
5552539SN/A           panic("I/O Read - invalid addr - va %#x size %d\n",
5562641SN/A                   pkt->getAddr(), pkt->getSize());
5572539SN/A    } else {
5582641SN/A       panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize());
559771SN/A    }
5602641SN/A    pkt->result = Packet::Success;
5612539SN/A    return pioDelay;
562768SN/A}
563768SN/A
5642539SN/ATick
5653349SN/ATsunamiIO::write(PacketPtr pkt)
566768SN/A{
5672641SN/A    assert(pkt->result == Packet::Unknown);
5682641SN/A    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
5692641SN/A    Addr daddr = pkt->getAddr() - pioAddr;
570779SN/A
571779SN/A    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
5722641SN/A            pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>());
573768SN/A
5742641SN/A    assert(pkt->getSize() == sizeof(uint8_t));
575769SN/A
5762539SN/A    switch(daddr) {
5772539SN/A      case TSDEV_PIC1_MASK:
5782630SN/A        mask1 = ~(pkt->get<uint8_t>());
5792539SN/A        if ((picr & mask1) && !picInterrupting) {
5802539SN/A            picInterrupting = true;
5812539SN/A            tsunami->cchip->postDRIR(55);
5822539SN/A            DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
583803SN/A        }
5842539SN/A        if ((!(picr & mask1)) && picInterrupting) {
5852539SN/A            picInterrupting = false;
5862539SN/A            tsunami->cchip->clearDRIR(55);
5872539SN/A            DPRINTF(Tsunami, "clearing pic interrupt\n");
5882539SN/A        }
5892539SN/A        break;
5902539SN/A      case TSDEV_PIC2_MASK:
5912630SN/A        mask2 = pkt->get<uint8_t>();
5922539SN/A        //PIC2 Not implemented to interrupt
5932539SN/A        break;
5942539SN/A      case TSDEV_PIC1_ACK:
5952539SN/A        // clear the interrupt on the PIC
5962630SN/A        picr &= ~(1 << (pkt->get<uint8_t>() & 0xF));
5972539SN/A        if (!(picr & mask1))
5982539SN/A            tsunami->cchip->clearDRIR(55);
5992539SN/A        break;
6002539SN/A      case TSDEV_DMA1_MODE:
6012630SN/A        mode1 = pkt->get<uint8_t>();
6022539SN/A        break;
6032539SN/A      case TSDEV_DMA2_MODE:
6042630SN/A        mode2 = pkt->get<uint8_t>();
6052539SN/A        break;
6062539SN/A      case TSDEV_TMR0_DATA:
6072630SN/A        pitimer.counter0.write(pkt->get<uint8_t>());
6082539SN/A        break;
6092539SN/A      case TSDEV_TMR1_DATA:
6102630SN/A        pitimer.counter1.write(pkt->get<uint8_t>());
6112539SN/A        break;
6122539SN/A      case TSDEV_TMR2_DATA:
6132630SN/A        pitimer.counter2.write(pkt->get<uint8_t>());
6142539SN/A        break;
6152539SN/A      case TSDEV_TMR_CTRL:
6162630SN/A        pitimer.writeControl(pkt->get<uint8_t>());
6172539SN/A        break;
6182539SN/A      case TSDEV_RTC_ADDR:
6192630SN/A        rtc.writeAddr(pkt->get<uint8_t>());
6202539SN/A        break;
6212539SN/A      case TSDEV_RTC_DATA:
6222630SN/A        rtc.writeData(pkt->get<uint8_t>());
6232539SN/A        break;
6242539SN/A      case TSDEV_KBD:
6252539SN/A      case TSDEV_DMA1_CMND:
6262539SN/A      case TSDEV_DMA2_CMND:
6272539SN/A      case TSDEV_DMA1_MMASK:
6282539SN/A      case TSDEV_DMA2_MMASK:
6292539SN/A      case TSDEV_PIC2_ACK:
6302539SN/A      case TSDEV_DMA1_RESET:
6312539SN/A      case TSDEV_DMA2_RESET:
6322539SN/A      case TSDEV_DMA1_MASK:
6332539SN/A      case TSDEV_DMA2_MASK:
6342539SN/A      case TSDEV_CTRL_PORTB:
6352539SN/A        break;
636803SN/A      default:
6372641SN/A        panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>());
638769SN/A    }
639769SN/A
6402641SN/A    pkt->result = Packet::Success;
6412539SN/A    return pioDelay;
642768SN/A}
643768SN/A
644768SN/Avoid
645777SN/ATsunamiIO::postPIC(uint8_t bitvector)
646777SN/A{
647777SN/A    //PIC2 Is not implemented, because nothing of interest there
648777SN/A    picr |= bitvector;
649865SN/A    if (picr & mask1) {
650817SN/A        tsunami->cchip->postDRIR(55);
651777SN/A        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
652777SN/A    }
653777SN/A}
654777SN/A
655777SN/Avoid
656777SN/ATsunamiIO::clearPIC(uint8_t bitvector)
657777SN/A{
658777SN/A    //PIC2 Is not implemented, because nothing of interest there
659777SN/A    picr &= ~bitvector;
660777SN/A    if (!(picr & mask1)) {
661817SN/A        tsunami->cchip->clearDRIR(55);
662777SN/A        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
663777SN/A    }
664777SN/A}
665777SN/A
666777SN/Avoid
6671854SN/ATsunamiIO::serialize(ostream &os)
668768SN/A{
669811SN/A    SERIALIZE_SCALAR(timerData);
670899SN/A    SERIALIZE_SCALAR(mask1);
671899SN/A    SERIALIZE_SCALAR(mask2);
672899SN/A    SERIALIZE_SCALAR(mode1);
673899SN/A    SERIALIZE_SCALAR(mode2);
674811SN/A    SERIALIZE_SCALAR(picr);
675811SN/A    SERIALIZE_SCALAR(picInterrupting);
676811SN/A
677919SN/A    // Serialize the timers
6781854SN/A    pitimer.serialize("pitimer", os);
6791854SN/A    rtc.serialize("rtc", os);
680768SN/A}
681768SN/A
682768SN/Avoid
6831854SN/ATsunamiIO::unserialize(Checkpoint *cp, const string &section)
684768SN/A{
685811SN/A    UNSERIALIZE_SCALAR(timerData);
686899SN/A    UNSERIALIZE_SCALAR(mask1);
687899SN/A    UNSERIALIZE_SCALAR(mask2);
688899SN/A    UNSERIALIZE_SCALAR(mode1);
689899SN/A    UNSERIALIZE_SCALAR(mode2);
690811SN/A    UNSERIALIZE_SCALAR(picr);
691811SN/A    UNSERIALIZE_SCALAR(picInterrupting);
692919SN/A
693919SN/A    // Unserialize the timers
6941854SN/A    pitimer.unserialize("pitimer", cp, section);
6951854SN/A    rtc.unserialize("rtc", cp, section);
696768SN/A}
697768SN/A
698770SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
699768SN/A
7002539SN/A    Param<Addr> pio_addr;
7012539SN/A    Param<Tick> pio_latency;
7022539SN/A    Param<Tick> frequency;
7032539SN/A    SimObjectParam<Platform *> platform;
7042539SN/A    SimObjectParam<System *> system;
7053932Sbinkertn@umich.edu    VectorParam<int> time;
7063932Sbinkertn@umich.edu    Param<bool> year_is_bcd;
707775SN/A    SimObjectParam<Tsunami *> tsunami;
708768SN/A
709770SN/AEND_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
710768SN/A
711770SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
712768SN/A
7132539SN/A    INIT_PARAM(pio_addr, "Device Address"),
7142539SN/A    INIT_PARAM(pio_latency, "Programmed IO latency"),
7152542SN/A    INIT_PARAM(frequency, "clock interrupt frequency"),
7162539SN/A    INIT_PARAM(platform, "platform"),
7172539SN/A    INIT_PARAM(system, "system object"),
7181634SN/A    INIT_PARAM(time, "System time to use (0 for actual time"),
7193932Sbinkertn@umich.edu    INIT_PARAM(year_is_bcd, ""),
7202539SN/A    INIT_PARAM(tsunami, "Tsunami")
721768SN/A
722770SN/AEND_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
723768SN/A
724770SN/ACREATE_SIM_OBJECT(TsunamiIO)
725768SN/A{
7262539SN/A    TsunamiIO::Params *p = new TsunamiIO::Params;
7272539SN/A    p->frequency = frequency;
7282539SN/A    p->name = getInstanceName();
7292539SN/A    p->pio_addr = pio_addr;
7302539SN/A    p->pio_delay = pio_latency;
7312539SN/A    p->platform = platform;
7322539SN/A    p->system = system;
7332539SN/A    p->init_time = time;
7343932Sbinkertn@umich.edu    p->year_is_bcd = year_is_bcd;
7352539SN/A    p->tsunami = tsunami;
7362539SN/A    return new TsunamiIO(p);
737768SN/A}
738768SN/A
739770SN/AREGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
740