tsunami_io.cc revision 4870
12847Sksewell@umich.edu/* 25596Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 32847Sksewell@umich.edu * All rights reserved. 42847Sksewell@umich.edu * 52847Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 62847Sksewell@umich.edu * modification, are permitted provided that the following conditions are 72847Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 82847Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 92847Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 102847Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 112847Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 122847Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 132847Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 142847Sksewell@umich.edu * this software without specific prior written permission. 152847Sksewell@umich.edu * 162847Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172847Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182847Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192847Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202847Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212847Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222847Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232847Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242847Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252847Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262847Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272847Sksewell@umich.edu * 285596Sgblack@eecs.umich.edu * Authors: Ali Saidi 292847Sksewell@umich.edu * Andrew Schultz 302847Sksewell@umich.edu * Miguel Serrano 312847Sksewell@umich.edu */ 322847Sksewell@umich.edu 332847Sksewell@umich.edu/** @file 345596Sgblack@eecs.umich.edu * Tsunami I/O including PIC, PIT, RTC, DMA 356658Snate@binkert.org */ 365596Sgblack@eecs.umich.edu 375596Sgblack@eecs.umich.edu#include <sys/time.h> 385596Sgblack@eecs.umich.edu 395596Sgblack@eecs.umich.edu#include <deque> 402847Sksewell@umich.edu#include <string> 415596Sgblack@eecs.umich.edu#include <vector> 425596Sgblack@eecs.umich.edu 435596Sgblack@eecs.umich.edu#include "base/trace.hh" 445596Sgblack@eecs.umich.edu#include "dev/pitreg.h" 455596Sgblack@eecs.umich.edu#include "dev/rtcreg.h" 465596Sgblack@eecs.umich.edu#include "dev/alpha/tsunami_cchip.hh" 475596Sgblack@eecs.umich.edu#include "dev/alpha/tsunami.hh" 485596Sgblack@eecs.umich.edu#include "dev/alpha/tsunami_io.hh" 495596Sgblack@eecs.umich.edu#include "dev/alpha/tsunamireg.h" 505596Sgblack@eecs.umich.edu#include "mem/packet.hh" 515596Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 525596Sgblack@eecs.umich.edu#include "mem/port.hh" 535596Sgblack@eecs.umich.edu#include "sim/builder.hh" 545596Sgblack@eecs.umich.edu#include "sim/system.hh" 555596Sgblack@eecs.umich.edu 565596Sgblack@eecs.umich.eduusing namespace std; 575596Sgblack@eecs.umich.edu//Should this be AlphaISA? 585596Sgblack@eecs.umich.eduusing namespace TheISA; 595596Sgblack@eecs.umich.edu 605596Sgblack@eecs.umich.eduTsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami, const vector<int> &t, 615596Sgblack@eecs.umich.edu bool bcd, Tick i) 625596Sgblack@eecs.umich.edu : _name(n), event(tsunami, i), addr(0), year_is_bcd(bcd) 635596Sgblack@eecs.umich.edu{ 645596Sgblack@eecs.umich.edu memset(clock_data, 0, sizeof(clock_data)); 655596Sgblack@eecs.umich.edu stat_regA = RTCA_32768HZ | RTCA_1024HZ; 665596Sgblack@eecs.umich.edu stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; 675596Sgblack@eecs.umich.edu 685596Sgblack@eecs.umich.edu struct tm tm; 695596Sgblack@eecs.umich.edu parseTime(t, &tm); 705596Sgblack@eecs.umich.edu 715596Sgblack@eecs.umich.edu year = tm.tm_year; 725596Sgblack@eecs.umich.edu 735596Sgblack@eecs.umich.edu if (year_is_bcd) { 745596Sgblack@eecs.umich.edu // The datasheet says that the year field can be either BCD or 755596Sgblack@eecs.umich.edu // years since 1900. Linux seems to be happy with years since 765596Sgblack@eecs.umich.edu // 1900. 777720Sgblack@eecs.umich.edu year = year % 100; 787720Sgblack@eecs.umich.edu int tens = year / 10; 797720Sgblack@eecs.umich.edu int ones = year % 10; 805596Sgblack@eecs.umich.edu year = (tens << 4) + ones; 815596Sgblack@eecs.umich.edu } 827720Sgblack@eecs.umich.edu 837720Sgblack@eecs.umich.edu // Unix is 0-11 for month, data seet says start at 1 847720Sgblack@eecs.umich.edu mon = tm.tm_mon + 1; 855596Sgblack@eecs.umich.edu mday = tm.tm_mday; 865596Sgblack@eecs.umich.edu hour = tm.tm_hour; 875596Sgblack@eecs.umich.edu min = tm.tm_min; 885596Sgblack@eecs.umich.edu sec = tm.tm_sec; 895596Sgblack@eecs.umich.edu 905596Sgblack@eecs.umich.edu // Datasheet says 1 is sunday 915596Sgblack@eecs.umich.edu wday = tm.tm_wday + 1; 925596Sgblack@eecs.umich.edu 935596Sgblack@eecs.umich.edu DPRINTFN("Real-time clock set to %s", asctime(&tm)); 945596Sgblack@eecs.umich.edu} 955596Sgblack@eecs.umich.edu 965596Sgblack@eecs.umich.eduvoid 975596Sgblack@eecs.umich.eduTsunamiIO::RTC::writeAddr(const uint8_t data) 985596Sgblack@eecs.umich.edu{ 995596Sgblack@eecs.umich.edu if (data <= RTC_STAT_REGD) 1005596Sgblack@eecs.umich.edu addr = data; 1015596Sgblack@eecs.umich.edu else 1025596Sgblack@eecs.umich.edu panic("RTC addresses over 0xD are not implemented.\n"); 1035596Sgblack@eecs.umich.edu} 1045596Sgblack@eecs.umich.edu 1055596Sgblack@eecs.umich.eduvoid 1065596Sgblack@eecs.umich.eduTsunamiIO::RTC::writeData(const uint8_t data) 1075596Sgblack@eecs.umich.edu{ 1085596Sgblack@eecs.umich.edu if (addr < RTC_STAT_REGA) 1095596Sgblack@eecs.umich.edu clock_data[addr] = data; 1105596Sgblack@eecs.umich.edu else { 1115596Sgblack@eecs.umich.edu switch (addr) { 1125596Sgblack@eecs.umich.edu case RTC_STAT_REGA: 1135596Sgblack@eecs.umich.edu if (data != (RTCA_32768HZ | RTCA_1024HZ)) 1145596Sgblack@eecs.umich.edu panic("Unimplemented RTC register A value write!\n"); 1155596Sgblack@eecs.umich.edu stat_regA = data; 1165596Sgblack@eecs.umich.edu break; 1175596Sgblack@eecs.umich.edu case RTC_STAT_REGB: 1185596Sgblack@eecs.umich.edu if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) 1195596Sgblack@eecs.umich.edu panic("Write to RTC reg B bits that are not implemented!\n"); 1205596Sgblack@eecs.umich.edu 1215596Sgblack@eecs.umich.edu if (data & RTCB_PRDC_IE) { 1225596Sgblack@eecs.umich.edu if (!event.scheduled()) 1235596Sgblack@eecs.umich.edu event.scheduleIntr(); 1245596Sgblack@eecs.umich.edu } else { 1255596Sgblack@eecs.umich.edu if (event.scheduled()) 1265596Sgblack@eecs.umich.edu event.deschedule(); 1275596Sgblack@eecs.umich.edu } 1285596Sgblack@eecs.umich.edu stat_regB = data; 1295596Sgblack@eecs.umich.edu break; 1305596Sgblack@eecs.umich.edu case RTC_STAT_REGC: 1315596Sgblack@eecs.umich.edu case RTC_STAT_REGD: 1325596Sgblack@eecs.umich.edu panic("RTC status registers C and D are not implemented.\n"); 1335596Sgblack@eecs.umich.edu break; 1345596Sgblack@eecs.umich.edu } 1355596Sgblack@eecs.umich.edu } 1365596Sgblack@eecs.umich.edu} 1375596Sgblack@eecs.umich.edu 1385596Sgblack@eecs.umich.eduuint8_t 1395596Sgblack@eecs.umich.eduTsunamiIO::RTC::readData() 1405596Sgblack@eecs.umich.edu{ 1415596Sgblack@eecs.umich.edu if (addr < RTC_STAT_REGA) 1425596Sgblack@eecs.umich.edu return clock_data[addr]; 1435596Sgblack@eecs.umich.edu else { 1445596Sgblack@eecs.umich.edu switch (addr) { 1455596Sgblack@eecs.umich.edu case RTC_STAT_REGA: 1465596Sgblack@eecs.umich.edu // toggle UIP bit for linux 1475596Sgblack@eecs.umich.edu stat_regA ^= RTCA_UIP; 1485596Sgblack@eecs.umich.edu return stat_regA; 1495596Sgblack@eecs.umich.edu break; 1505596Sgblack@eecs.umich.edu case RTC_STAT_REGB: 1515596Sgblack@eecs.umich.edu return stat_regB; 1525596Sgblack@eecs.umich.edu break; 1535596Sgblack@eecs.umich.edu case RTC_STAT_REGC: 1545596Sgblack@eecs.umich.edu case RTC_STAT_REGD: 1555596Sgblack@eecs.umich.edu return 0x00; 1565596Sgblack@eecs.umich.edu break; 1575596Sgblack@eecs.umich.edu default: 1585596Sgblack@eecs.umich.edu panic("Shouldn't be here"); 1595596Sgblack@eecs.umich.edu } 1605596Sgblack@eecs.umich.edu } 1615596Sgblack@eecs.umich.edu} 1625596Sgblack@eecs.umich.edu 1635596Sgblack@eecs.umich.eduvoid 1645596Sgblack@eecs.umich.eduTsunamiIO::RTC::serialize(const string &base, ostream &os) 1655596Sgblack@eecs.umich.edu{ 1665596Sgblack@eecs.umich.edu paramOut(os, base + ".addr", addr); 1675596Sgblack@eecs.umich.edu arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); 1685596Sgblack@eecs.umich.edu paramOut(os, base + ".stat_regA", stat_regA); 1695596Sgblack@eecs.umich.edu paramOut(os, base + ".stat_regB", stat_regB); 1705596Sgblack@eecs.umich.edu} 1715596Sgblack@eecs.umich.edu 1725702Ssaidi@eecs.umich.eduvoid 1735702Ssaidi@eecs.umich.eduTsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, 1745596Sgblack@eecs.umich.edu const string §ion) 1755596Sgblack@eecs.umich.edu{ 1765702Ssaidi@eecs.umich.edu paramIn(cp, section, base + ".addr", addr); 1772935Sksewell@umich.edu arrayParamIn(cp, section, base + ".clock_data", clock_data, 1785596Sgblack@eecs.umich.edu sizeof(clock_data)); 1795596Sgblack@eecs.umich.edu paramIn(cp, section, base + ".stat_regA", stat_regA); 1802848Sksewell@umich.edu paramIn(cp, section, base + ".stat_regB", stat_regB); 1812847Sksewell@umich.edu 1825596Sgblack@eecs.umich.edu // We're not unserializing the event here, but we need to 1835596Sgblack@eecs.umich.edu // rescehedule the event since curTick was moved forward by the 1845596Sgblack@eecs.umich.edu // checkpoint 1855596Sgblack@eecs.umich.edu event.reschedule(curTick + event.interval); 1865596Sgblack@eecs.umich.edu} 1875596Sgblack@eecs.umich.edu 1885596Sgblack@eecs.umich.eduTsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) 1895596Sgblack@eecs.umich.edu : Event(&mainEventQueue), tsunami(t), interval(i) 1905596Sgblack@eecs.umich.edu{ 1915596Sgblack@eecs.umich.edu DPRINTF(MC146818, "RTC Event Initilizing\n"); 1925596Sgblack@eecs.umich.edu schedule(curTick + interval); 1935596Sgblack@eecs.umich.edu} 1945596Sgblack@eecs.umich.edu 1955596Sgblack@eecs.umich.eduvoid 1965596Sgblack@eecs.umich.eduTsunamiIO::RTC::RTCEvent::scheduleIntr() 1975596Sgblack@eecs.umich.edu{ 1985596Sgblack@eecs.umich.edu schedule(curTick + interval); 1995596Sgblack@eecs.umich.edu} 2005596Sgblack@eecs.umich.edu 2015596Sgblack@eecs.umich.eduvoid 2025596Sgblack@eecs.umich.eduTsunamiIO::RTC::RTCEvent::process() 2035596Sgblack@eecs.umich.edu{ 2045596Sgblack@eecs.umich.edu DPRINTF(MC146818, "RTC Timer Interrupt\n"); 2055596Sgblack@eecs.umich.edu schedule(curTick + interval); 2065596Sgblack@eecs.umich.edu //Actually interrupt the processor here 2075596Sgblack@eecs.umich.edu tsunami->cchip->postRTC(); 2085596Sgblack@eecs.umich.edu} 2095596Sgblack@eecs.umich.edu 2105596Sgblack@eecs.umich.educonst char * 2115596Sgblack@eecs.umich.eduTsunamiIO::RTC::RTCEvent::description() 2125596Sgblack@eecs.umich.edu{ 2135596Sgblack@eecs.umich.edu return "tsunami RTC interrupt"; 2145596Sgblack@eecs.umich.edu} 2155596Sgblack@eecs.umich.edu 2165596Sgblack@eecs.umich.eduTsunamiIO::PITimer::PITimer(const string &name) 2175596Sgblack@eecs.umich.edu : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), 2185596Sgblack@eecs.umich.edu counter2(name + ".counter2") 2195596Sgblack@eecs.umich.edu{ 2205596Sgblack@eecs.umich.edu counter[0] = &counter0; 2215596Sgblack@eecs.umich.edu counter[1] = &counter0; 2225596Sgblack@eecs.umich.edu counter[2] = &counter0; 2235596Sgblack@eecs.umich.edu} 2245596Sgblack@eecs.umich.edu 2255596Sgblack@eecs.umich.eduvoid 2265596Sgblack@eecs.umich.eduTsunamiIO::PITimer::writeControl(const uint8_t data) 2275596Sgblack@eecs.umich.edu{ 2285596Sgblack@eecs.umich.edu int rw; 2295596Sgblack@eecs.umich.edu int sel; 2305596Sgblack@eecs.umich.edu 2315596Sgblack@eecs.umich.edu sel = GET_CTRL_SEL(data); 2325596Sgblack@eecs.umich.edu 2335596Sgblack@eecs.umich.edu if (sel == PIT_READ_BACK) 2345596Sgblack@eecs.umich.edu panic("PITimer Read-Back Command is not implemented.\n"); 2355596Sgblack@eecs.umich.edu 2365596Sgblack@eecs.umich.edu rw = GET_CTRL_RW(data); 2375596Sgblack@eecs.umich.edu 2385596Sgblack@eecs.umich.edu if (rw == PIT_RW_LATCH_COMMAND) 2395596Sgblack@eecs.umich.edu counter[sel]->latchCount(); 2405596Sgblack@eecs.umich.edu else { 2415596Sgblack@eecs.umich.edu counter[sel]->setRW(rw); 2425596Sgblack@eecs.umich.edu counter[sel]->setMode(GET_CTRL_MODE(data)); 2435596Sgblack@eecs.umich.edu counter[sel]->setBCD(GET_CTRL_BCD(data)); 2445596Sgblack@eecs.umich.edu } 2455596Sgblack@eecs.umich.edu} 2465596Sgblack@eecs.umich.edu 2475596Sgblack@eecs.umich.eduvoid 2485596Sgblack@eecs.umich.eduTsunamiIO::PITimer::serialize(const string &base, ostream &os) 2495596Sgblack@eecs.umich.edu{ 2505596Sgblack@eecs.umich.edu // serialize the counters 2515596Sgblack@eecs.umich.edu counter0.serialize(base + ".counter0", os); 2525596Sgblack@eecs.umich.edu counter1.serialize(base + ".counter1", os); 2535596Sgblack@eecs.umich.edu counter2.serialize(base + ".counter2", os); 2545596Sgblack@eecs.umich.edu} 2555596Sgblack@eecs.umich.edu 2565596Sgblack@eecs.umich.eduvoid 2575596Sgblack@eecs.umich.eduTsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, 2585596Sgblack@eecs.umich.edu const string §ion) 2595596Sgblack@eecs.umich.edu{ 2605596Sgblack@eecs.umich.edu // unserialze the counters 2615596Sgblack@eecs.umich.edu counter0.unserialize(base + ".counter0", cp, section); 2625596Sgblack@eecs.umich.edu counter1.unserialize(base + ".counter1", cp, section); 2635596Sgblack@eecs.umich.edu counter2.unserialize(base + ".counter2", cp, section); 2645596Sgblack@eecs.umich.edu} 2655596Sgblack@eecs.umich.edu 2665596Sgblack@eecs.umich.eduTsunamiIO::PITimer::Counter::Counter(const string &name) 267 : _name(name), event(this), count(0), latched_count(0), period(0), 268 mode(0), output_high(false), latch_on(false), read_byte(LSB), 269 write_byte(LSB) 270{ 271 272} 273 274void 275TsunamiIO::PITimer::Counter::latchCount() 276{ 277 // behave like a real latch 278 if(!latch_on) { 279 latch_on = true; 280 read_byte = LSB; 281 latched_count = count; 282 } 283} 284 285uint8_t 286TsunamiIO::PITimer::Counter::read() 287{ 288 if (latch_on) { 289 switch (read_byte) { 290 case LSB: 291 read_byte = MSB; 292 return (uint8_t)latched_count; 293 break; 294 case MSB: 295 read_byte = LSB; 296 latch_on = false; 297 return latched_count >> 8; 298 break; 299 default: 300 panic("Shouldn't be here"); 301 } 302 } else { 303 switch (read_byte) { 304 case LSB: 305 read_byte = MSB; 306 return (uint8_t)count; 307 break; 308 case MSB: 309 read_byte = LSB; 310 return count >> 8; 311 break; 312 default: 313 panic("Shouldn't be here"); 314 } 315 } 316} 317 318void 319TsunamiIO::PITimer::Counter::write(const uint8_t data) 320{ 321 switch (write_byte) { 322 case LSB: 323 count = (count & 0xFF00) | data; 324 325 if (event.scheduled()) 326 event.deschedule(); 327 output_high = false; 328 write_byte = MSB; 329 break; 330 331 case MSB: 332 count = (count & 0x00FF) | (data << 8); 333 period = count; 334 335 if (period > 0) { 336 DPRINTF(Tsunami, "Timer set to curTick + %d\n", 337 count * event.interval); 338 event.schedule(curTick + count * event.interval); 339 } 340 write_byte = LSB; 341 break; 342 } 343} 344 345void 346TsunamiIO::PITimer::Counter::setRW(int rw_val) 347{ 348 if (rw_val != PIT_RW_16BIT) 349 panic("Only LSB/MSB read/write is implemented.\n"); 350} 351 352void 353TsunamiIO::PITimer::Counter::setMode(int mode_val) 354{ 355 if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && 356 mode_val != PIT_MODE_SQWAVE) 357 panic("PIT mode %#x is not implemented: \n", mode_val); 358 359 mode = mode_val; 360} 361 362void 363TsunamiIO::PITimer::Counter::setBCD(int bcd_val) 364{ 365 if (bcd_val != PIT_BCD_FALSE) 366 panic("PITimer does not implement BCD counts.\n"); 367} 368 369bool 370TsunamiIO::PITimer::Counter::outputHigh() 371{ 372 return output_high; 373} 374 375void 376TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) 377{ 378 paramOut(os, base + ".count", count); 379 paramOut(os, base + ".latched_count", latched_count); 380 paramOut(os, base + ".period", period); 381 paramOut(os, base + ".mode", mode); 382 paramOut(os, base + ".output_high", output_high); 383 paramOut(os, base + ".latch_on", latch_on); 384 paramOut(os, base + ".read_byte", read_byte); 385 paramOut(os, base + ".write_byte", write_byte); 386 387 Tick event_tick = 0; 388 if (event.scheduled()) 389 event_tick = event.when(); 390 paramOut(os, base + ".event_tick", event_tick); 391} 392 393void 394TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, 395 const string §ion) 396{ 397 paramIn(cp, section, base + ".count", count); 398 paramIn(cp, section, base + ".latched_count", latched_count); 399 paramIn(cp, section, base + ".period", period); 400 paramIn(cp, section, base + ".mode", mode); 401 paramIn(cp, section, base + ".output_high", output_high); 402 paramIn(cp, section, base + ".latch_on", latch_on); 403 paramIn(cp, section, base + ".read_byte", read_byte); 404 paramIn(cp, section, base + ".write_byte", write_byte); 405 406 Tick event_tick; 407 paramIn(cp, section, base + ".event_tick", event_tick); 408 if (event_tick) 409 event.schedule(event_tick); 410} 411 412TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 413 : Event(&mainEventQueue) 414{ 415 interval = (Tick)(Clock::Float::s / 1193180.0); 416 counter = c_ptr; 417} 418 419void 420TsunamiIO::PITimer::Counter::CounterEvent::process() 421{ 422 DPRINTF(Tsunami, "Timer Interrupt\n"); 423 switch (counter->mode) { 424 case PIT_MODE_INTTC: 425 counter->output_high = true; 426 case PIT_MODE_RATEGEN: 427 case PIT_MODE_SQWAVE: 428 break; 429 default: 430 panic("Unimplemented PITimer mode.\n"); 431 } 432} 433 434const char * 435TsunamiIO::PITimer::Counter::CounterEvent::description() 436{ 437 return "tsunami 8254 Interval timer"; 438} 439 440TsunamiIO::TsunamiIO(Params *p) 441 : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), 442 rtc(p->name + ".rtc", p->tsunami, p->init_time, p->year_is_bcd, 443 p->frequency) 444{ 445 pioSize = 0x100; 446 447 // set the back pointer from tsunami to myself 448 tsunami->io = this; 449 450 timerData = 0; 451 picr = 0; 452 picInterrupting = false; 453} 454 455Tick 456TsunamiIO::frequency() const 457{ 458 return Clock::Frequency / params()->frequency; 459} 460 461Tick 462TsunamiIO::read(PacketPtr pkt) 463{ 464 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 465 466 Addr daddr = pkt->getAddr() - pioAddr; 467 468 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(), 469 pkt->getSize(), daddr); 470 471 pkt->allocate(); 472 473 if (pkt->getSize() == sizeof(uint8_t)) { 474 switch(daddr) { 475 // PIC1 mask read 476 case TSDEV_PIC1_MASK: 477 pkt->set(~mask1); 478 break; 479 case TSDEV_PIC2_MASK: 480 pkt->set(~mask2); 481 break; 482 case TSDEV_PIC1_ISR: 483 // !!! If this is modified 64bit case needs to be too 484 // Pal code has to do a 64 bit physical read because there is 485 // no load physical byte instruction 486 pkt->set(picr); 487 break; 488 case TSDEV_PIC2_ISR: 489 // PIC2 not implemnted... just return 0 490 pkt->set(0x00); 491 break; 492 case TSDEV_TMR0_DATA: 493 pkt->set(pitimer.counter0.read()); 494 break; 495 case TSDEV_TMR1_DATA: 496 pkt->set(pitimer.counter1.read()); 497 break; 498 case TSDEV_TMR2_DATA: 499 pkt->set(pitimer.counter2.read()); 500 break; 501 case TSDEV_RTC_DATA: 502 pkt->set(rtc.readData()); 503 break; 504 case TSDEV_CTRL_PORTB: 505 if (pitimer.counter2.outputHigh()) 506 pkt->set(PORTB_SPKR_HIGH); 507 else 508 pkt->set(0x00); 509 break; 510 default: 511 panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize()); 512 } 513 } else if (pkt->getSize() == sizeof(uint64_t)) { 514 if (daddr == TSDEV_PIC1_ISR) 515 pkt->set<uint64_t>(picr); 516 else 517 panic("I/O Read - invalid addr - va %#x size %d\n", 518 pkt->getAddr(), pkt->getSize()); 519 } else { 520 panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize()); 521 } 522 pkt->makeAtomicResponse(); 523 return pioDelay; 524} 525 526Tick 527TsunamiIO::write(PacketPtr pkt) 528{ 529 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 530 Addr daddr = pkt->getAddr() - pioAddr; 531 532 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 533 pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>()); 534 535 assert(pkt->getSize() == sizeof(uint8_t)); 536 537 switch(daddr) { 538 case TSDEV_PIC1_MASK: 539 mask1 = ~(pkt->get<uint8_t>()); 540 if ((picr & mask1) && !picInterrupting) { 541 picInterrupting = true; 542 tsunami->cchip->postDRIR(55); 543 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 544 } 545 if ((!(picr & mask1)) && picInterrupting) { 546 picInterrupting = false; 547 tsunami->cchip->clearDRIR(55); 548 DPRINTF(Tsunami, "clearing pic interrupt\n"); 549 } 550 break; 551 case TSDEV_PIC2_MASK: 552 mask2 = pkt->get<uint8_t>(); 553 //PIC2 Not implemented to interrupt 554 break; 555 case TSDEV_PIC1_ACK: 556 // clear the interrupt on the PIC 557 picr &= ~(1 << (pkt->get<uint8_t>() & 0xF)); 558 if (!(picr & mask1)) 559 tsunami->cchip->clearDRIR(55); 560 break; 561 case TSDEV_DMA1_MODE: 562 mode1 = pkt->get<uint8_t>(); 563 break; 564 case TSDEV_DMA2_MODE: 565 mode2 = pkt->get<uint8_t>(); 566 break; 567 case TSDEV_TMR0_DATA: 568 pitimer.counter0.write(pkt->get<uint8_t>()); 569 break; 570 case TSDEV_TMR1_DATA: 571 pitimer.counter1.write(pkt->get<uint8_t>()); 572 break; 573 case TSDEV_TMR2_DATA: 574 pitimer.counter2.write(pkt->get<uint8_t>()); 575 break; 576 case TSDEV_TMR_CTRL: 577 pitimer.writeControl(pkt->get<uint8_t>()); 578 break; 579 case TSDEV_RTC_ADDR: 580 rtc.writeAddr(pkt->get<uint8_t>()); 581 break; 582 case TSDEV_RTC_DATA: 583 rtc.writeData(pkt->get<uint8_t>()); 584 break; 585 case TSDEV_KBD: 586 case TSDEV_DMA1_CMND: 587 case TSDEV_DMA2_CMND: 588 case TSDEV_DMA1_MMASK: 589 case TSDEV_DMA2_MMASK: 590 case TSDEV_PIC2_ACK: 591 case TSDEV_DMA1_RESET: 592 case TSDEV_DMA2_RESET: 593 case TSDEV_DMA1_MASK: 594 case TSDEV_DMA2_MASK: 595 case TSDEV_CTRL_PORTB: 596 break; 597 default: 598 panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>()); 599 } 600 601 pkt->makeAtomicResponse(); 602 return pioDelay; 603} 604 605void 606TsunamiIO::postPIC(uint8_t bitvector) 607{ 608 //PIC2 Is not implemented, because nothing of interest there 609 picr |= bitvector; 610 if (picr & mask1) { 611 tsunami->cchip->postDRIR(55); 612 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 613 } 614} 615 616void 617TsunamiIO::clearPIC(uint8_t bitvector) 618{ 619 //PIC2 Is not implemented, because nothing of interest there 620 picr &= ~bitvector; 621 if (!(picr & mask1)) { 622 tsunami->cchip->clearDRIR(55); 623 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 624 } 625} 626 627void 628TsunamiIO::serialize(ostream &os) 629{ 630 SERIALIZE_SCALAR(timerData); 631 SERIALIZE_SCALAR(mask1); 632 SERIALIZE_SCALAR(mask2); 633 SERIALIZE_SCALAR(mode1); 634 SERIALIZE_SCALAR(mode2); 635 SERIALIZE_SCALAR(picr); 636 SERIALIZE_SCALAR(picInterrupting); 637 638 // Serialize the timers 639 pitimer.serialize("pitimer", os); 640 rtc.serialize("rtc", os); 641} 642 643void 644TsunamiIO::unserialize(Checkpoint *cp, const string §ion) 645{ 646 UNSERIALIZE_SCALAR(timerData); 647 UNSERIALIZE_SCALAR(mask1); 648 UNSERIALIZE_SCALAR(mask2); 649 UNSERIALIZE_SCALAR(mode1); 650 UNSERIALIZE_SCALAR(mode2); 651 UNSERIALIZE_SCALAR(picr); 652 UNSERIALIZE_SCALAR(picInterrupting); 653 654 // Unserialize the timers 655 pitimer.unserialize("pitimer", cp, section); 656 rtc.unserialize("rtc", cp, section); 657} 658 659BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 660 661 Param<Addr> pio_addr; 662 Param<Tick> pio_latency; 663 Param<Tick> frequency; 664 SimObjectParam<Platform *> platform; 665 SimObjectParam<System *> system; 666 VectorParam<int> time; 667 Param<bool> year_is_bcd; 668 SimObjectParam<Tsunami *> tsunami; 669 670END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 671 672BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 673 674 INIT_PARAM(pio_addr, "Device Address"), 675 INIT_PARAM(pio_latency, "Programmed IO latency"), 676 INIT_PARAM(frequency, "clock interrupt frequency"), 677 INIT_PARAM(platform, "platform"), 678 INIT_PARAM(system, "system object"), 679 INIT_PARAM(time, "System time to use (0 for actual time"), 680 INIT_PARAM(year_is_bcd, ""), 681 INIT_PARAM(tsunami, "Tsunami") 682 683END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 684 685CREATE_SIM_OBJECT(TsunamiIO) 686{ 687 TsunamiIO::Params *p = new TsunamiIO::Params; 688 p->frequency = frequency; 689 p->name = getInstanceName(); 690 p->pio_addr = pio_addr; 691 p->pio_delay = pio_latency; 692 p->platform = platform; 693 p->system = system; 694 p->init_time = time; 695 p->year_is_bcd = year_is_bcd; 696 p->tsunami = tsunami; 697 return new TsunamiIO(p); 698} 699 700REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 701