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 §ion) 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 §ion) 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 §ion) 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 §ion) 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