tsunami_io.cc revision 2648
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/** @file 30 * Tsunami I/O including PIC, PIT, RTC, DMA 31 */ 32 33#include <sys/time.h> 34 35#include <deque> 36#include <string> 37#include <vector> 38 39#include "base/trace.hh" 40#include "dev/pitreg.h" 41#include "dev/rtcreg.h" 42#include "dev/tsunami_cchip.hh" 43#include "dev/tsunami.hh" 44#include "dev/tsunami_io.hh" 45#include "dev/tsunamireg.h" 46#include "mem/port.hh" 47#include "sim/builder.hh" 48#include "sim/system.hh" 49 50using namespace std; 51//Should this be AlphaISA? 52using namespace TheISA; 53 54TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i) 55 : _name(name), event(t, i), addr(0) 56{ 57 memset(clock_data, 0, sizeof(clock_data)); 58 stat_regA = RTCA_32768HZ | RTCA_1024HZ; 59 stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; 60} 61 62void 63TsunamiIO::RTC::set_time(time_t t) 64{ 65 struct tm tm; 66 gmtime_r(&t, &tm); 67 68 sec = tm.tm_sec; 69 min = tm.tm_min; 70 hour = tm.tm_hour; 71 wday = tm.tm_wday + 1; 72 mday = tm.tm_mday; 73 mon = tm.tm_mon + 1; 74 year = tm.tm_year; 75 76 DPRINTFN("Real-time clock set to %s", asctime(&tm)); 77} 78 79void 80TsunamiIO::RTC::writeAddr(const uint8_t data) 81{ 82 if (data <= RTC_STAT_REGD) 83 addr = data; 84 else 85 panic("RTC addresses over 0xD are not implemented.\n"); 86} 87 88void 89TsunamiIO::RTC::writeData(const uint8_t data) 90{ 91 if (addr < RTC_STAT_REGA) 92 clock_data[addr] = data; 93 else { 94 switch (addr) { 95 case RTC_STAT_REGA: 96 if (data != (RTCA_32768HZ | RTCA_1024HZ)) 97 panic("Unimplemented RTC register A value write!\n"); 98 stat_regA = data; 99 break; 100 case RTC_STAT_REGB: 101 if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) 102 panic("Write to RTC reg B bits that are not implemented!\n"); 103 104 if (data & RTCB_PRDC_IE) { 105 if (!event.scheduled()) 106 event.scheduleIntr(); 107 } else { 108 if (event.scheduled()) 109 event.deschedule(); 110 } 111 stat_regB = data; 112 break; 113 case RTC_STAT_REGC: 114 case RTC_STAT_REGD: 115 panic("RTC status registers C and D are not implemented.\n"); 116 break; 117 } 118 } 119} 120 121uint8_t 122TsunamiIO::RTC::readData() 123{ 124 if (addr < RTC_STAT_REGA) 125 return clock_data[addr]; 126 else { 127 switch (addr) { 128 case RTC_STAT_REGA: 129 // toggle UIP bit for linux 130 stat_regA ^= RTCA_UIP; 131 return stat_regA; 132 break; 133 case RTC_STAT_REGB: 134 return stat_regB; 135 break; 136 case RTC_STAT_REGC: 137 case RTC_STAT_REGD: 138 return 0x00; 139 break; 140 default: 141 panic("Shouldn't be here"); 142 } 143 } 144} 145 146void 147TsunamiIO::RTC::serialize(const string &base, ostream &os) 148{ 149 paramOut(os, base + ".addr", addr); 150 arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); 151 paramOut(os, base + ".stat_regA", stat_regA); 152 paramOut(os, base + ".stat_regB", stat_regB); 153} 154 155void 156TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, 157 const string §ion) 158{ 159 paramIn(cp, section, base + ".addr", addr); 160 arrayParamIn(cp, section, base + ".clock_data", clock_data, 161 sizeof(clock_data)); 162 paramIn(cp, section, base + ".stat_regA", stat_regA); 163 paramIn(cp, section, base + ".stat_regB", stat_regB); 164 165 // We're not unserializing the event here, but we need to 166 // rescehedule the event since curTick was moved forward by the 167 // checkpoint 168 event.reschedule(curTick + event.interval); 169} 170 171TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) 172 : Event(&mainEventQueue), tsunami(t), interval(i) 173{ 174 DPRINTF(MC146818, "RTC Event Initilizing\n"); 175 schedule(curTick + interval); 176} 177 178void 179TsunamiIO::RTC::RTCEvent::scheduleIntr() 180{ 181 schedule(curTick + interval); 182} 183 184void 185TsunamiIO::RTC::RTCEvent::process() 186{ 187 DPRINTF(MC146818, "RTC Timer Interrupt\n"); 188 schedule(curTick + interval); 189 //Actually interrupt the processor here 190 tsunami->cchip->postRTC(); 191} 192 193const char * 194TsunamiIO::RTC::RTCEvent::description() 195{ 196 return "tsunami RTC interrupt"; 197} 198 199TsunamiIO::PITimer::PITimer(const string &name) 200 : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), 201 counter2(name + ".counter2") 202{ 203 counter[0] = &counter0; 204 counter[1] = &counter0; 205 counter[2] = &counter0; 206} 207 208void 209TsunamiIO::PITimer::writeControl(const uint8_t data) 210{ 211 int rw; 212 int sel; 213 214 sel = GET_CTRL_SEL(data); 215 216 if (sel == PIT_READ_BACK) 217 panic("PITimer Read-Back Command is not implemented.\n"); 218 219 rw = GET_CTRL_RW(data); 220 221 if (rw == PIT_RW_LATCH_COMMAND) 222 counter[sel]->latchCount(); 223 else { 224 counter[sel]->setRW(rw); 225 counter[sel]->setMode(GET_CTRL_MODE(data)); 226 counter[sel]->setBCD(GET_CTRL_BCD(data)); 227 } 228} 229 230void 231TsunamiIO::PITimer::serialize(const string &base, ostream &os) 232{ 233 // serialize the counters 234 counter0.serialize(base + ".counter0", os); 235 counter1.serialize(base + ".counter1", os); 236 counter2.serialize(base + ".counter2", os); 237} 238 239void 240TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, 241 const string §ion) 242{ 243 // unserialze the counters 244 counter0.unserialize(base + ".counter0", cp, section); 245 counter1.unserialize(base + ".counter1", cp, section); 246 counter2.unserialize(base + ".counter2", cp, section); 247} 248 249TsunamiIO::PITimer::Counter::Counter(const string &name) 250 : _name(name), event(this), count(0), latched_count(0), period(0), 251 mode(0), output_high(false), latch_on(false), read_byte(LSB), 252 write_byte(LSB) 253{ 254 255} 256 257void 258TsunamiIO::PITimer::Counter::latchCount() 259{ 260 // behave like a real latch 261 if(!latch_on) { 262 latch_on = true; 263 read_byte = LSB; 264 latched_count = count; 265 } 266} 267 268uint8_t 269TsunamiIO::PITimer::Counter::read() 270{ 271 if (latch_on) { 272 switch (read_byte) { 273 case LSB: 274 read_byte = MSB; 275 return (uint8_t)latched_count; 276 break; 277 case MSB: 278 read_byte = LSB; 279 latch_on = false; 280 return latched_count >> 8; 281 break; 282 default: 283 panic("Shouldn't be here"); 284 } 285 } else { 286 switch (read_byte) { 287 case LSB: 288 read_byte = MSB; 289 return (uint8_t)count; 290 break; 291 case MSB: 292 read_byte = LSB; 293 return count >> 8; 294 break; 295 default: 296 panic("Shouldn't be here"); 297 } 298 } 299} 300 301void 302TsunamiIO::PITimer::Counter::write(const uint8_t data) 303{ 304 switch (write_byte) { 305 case LSB: 306 count = (count & 0xFF00) | data; 307 308 if (event.scheduled()) 309 event.deschedule(); 310 output_high = false; 311 write_byte = MSB; 312 break; 313 314 case MSB: 315 count = (count & 0x00FF) | (data << 8); 316 period = count; 317 318 if (period > 0) { 319 DPRINTF(Tsunami, "Timer set to curTick + %d\n", 320 count * event.interval); 321 event.schedule(curTick + count * event.interval); 322 } 323 write_byte = LSB; 324 break; 325 } 326} 327 328void 329TsunamiIO::PITimer::Counter::setRW(int rw_val) 330{ 331 if (rw_val != PIT_RW_16BIT) 332 panic("Only LSB/MSB read/write is implemented.\n"); 333} 334 335void 336TsunamiIO::PITimer::Counter::setMode(int mode_val) 337{ 338 if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && 339 mode_val != PIT_MODE_SQWAVE) 340 panic("PIT mode %#x is not implemented: \n", mode_val); 341 342 mode = mode_val; 343} 344 345void 346TsunamiIO::PITimer::Counter::setBCD(int bcd_val) 347{ 348 if (bcd_val != PIT_BCD_FALSE) 349 panic("PITimer does not implement BCD counts.\n"); 350} 351 352bool 353TsunamiIO::PITimer::Counter::outputHigh() 354{ 355 return output_high; 356} 357 358void 359TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) 360{ 361 paramOut(os, base + ".count", count); 362 paramOut(os, base + ".latched_count", latched_count); 363 paramOut(os, base + ".period", period); 364 paramOut(os, base + ".mode", mode); 365 paramOut(os, base + ".output_high", output_high); 366 paramOut(os, base + ".latch_on", latch_on); 367 paramOut(os, base + ".read_byte", read_byte); 368 paramOut(os, base + ".write_byte", write_byte); 369 370 Tick event_tick = 0; 371 if (event.scheduled()) 372 event_tick = event.when(); 373 paramOut(os, base + ".event_tick", event_tick); 374} 375 376void 377TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, 378 const string §ion) 379{ 380 paramIn(cp, section, base + ".count", count); 381 paramIn(cp, section, base + ".latched_count", latched_count); 382 paramIn(cp, section, base + ".period", period); 383 paramIn(cp, section, base + ".mode", mode); 384 paramIn(cp, section, base + ".output_high", output_high); 385 paramIn(cp, section, base + ".latch_on", latch_on); 386 paramIn(cp, section, base + ".read_byte", read_byte); 387 paramIn(cp, section, base + ".write_byte", write_byte); 388 389 Tick event_tick; 390 paramIn(cp, section, base + ".event_tick", event_tick); 391 if (event_tick) 392 event.schedule(event_tick); 393} 394 395TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 396 : Event(&mainEventQueue) 397{ 398 interval = (Tick)(Clock::Float::s / 1193180.0); 399 counter = c_ptr; 400} 401 402void 403TsunamiIO::PITimer::Counter::CounterEvent::process() 404{ 405 DPRINTF(Tsunami, "Timer Interrupt\n"); 406 switch (counter->mode) { 407 case PIT_MODE_INTTC: 408 counter->output_high = true; 409 case PIT_MODE_RATEGEN: 410 case PIT_MODE_SQWAVE: 411 break; 412 default: 413 panic("Unimplemented PITimer mode.\n"); 414 } 415} 416 417const char * 418TsunamiIO::PITimer::Counter::CounterEvent::description() 419{ 420 return "tsunami 8254 Interval timer"; 421} 422 423TsunamiIO::TsunamiIO(Params *p) 424 : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), 425 rtc(p->name + ".rtc", p->tsunami, p->frequency) 426{ 427 pioSize = 0xff; 428 429 // set the back pointer from tsunami to myself 430 tsunami->io = this; 431 432 timerData = 0; 433 rtc.set_time(p->init_time == 0 ? time(NULL) : p->init_time); 434 picr = 0; 435 picInterrupting = false; 436} 437 438Tick 439TsunamiIO::frequency() const 440{ 441 return Clock::Frequency / params()->frequency; 442} 443 444Tick 445TsunamiIO::read(Packet *pkt) 446{ 447 assert(pkt->result == Packet::Unknown); 448 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 449 450 pkt->time += pioDelay; 451 Addr daddr = pkt->getAddr() - pioAddr; 452 453 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(), 454 pkt->getSize(), daddr); 455 456 pkt->allocate(); 457 458 if (pkt->getSize() == sizeof(uint8_t)) { 459 switch(daddr) { 460 // PIC1 mask read 461 case TSDEV_PIC1_MASK: 462 pkt->set(~mask1); 463 break; 464 case TSDEV_PIC2_MASK: 465 pkt->set(~mask2); 466 break; 467 case TSDEV_PIC1_ISR: 468 // !!! If this is modified 64bit case needs to be too 469 // Pal code has to do a 64 bit physical read because there is 470 // no load physical byte instruction 471 pkt->set(picr); 472 break; 473 case TSDEV_PIC2_ISR: 474 // PIC2 not implemnted... just return 0 475 pkt->set(0x00); 476 break; 477 case TSDEV_TMR0_DATA: 478 pkt->set(pitimer.counter0.read()); 479 break; 480 case TSDEV_TMR1_DATA: 481 pkt->set(pitimer.counter1.read()); 482 break; 483 case TSDEV_TMR2_DATA: 484 pkt->set(pitimer.counter2.read()); 485 break; 486 case TSDEV_RTC_DATA: 487 pkt->set(rtc.readData()); 488 break; 489 case TSDEV_CTRL_PORTB: 490 if (pitimer.counter2.outputHigh()) 491 pkt->set(PORTB_SPKR_HIGH); 492 else 493 pkt->set(0x00); 494 break; 495 default: 496 panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize()); 497 } 498 } else if (pkt->getSize() == sizeof(uint64_t)) { 499 if (daddr == TSDEV_PIC1_ISR) 500 pkt->set<uint64_t>(picr); 501 else 502 panic("I/O Read - invalid addr - va %#x size %d\n", 503 pkt->getAddr(), pkt->getSize()); 504 } else { 505 panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize()); 506 } 507 pkt->result = Packet::Success; 508 return pioDelay; 509} 510 511Tick 512TsunamiIO::write(Packet *pkt) 513{ 514 pkt->time += pioDelay; 515 516 assert(pkt->result == Packet::Unknown); 517 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 518 Addr daddr = pkt->getAddr() - pioAddr; 519 520 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 521 pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>()); 522 523 assert(pkt->getSize() == sizeof(uint8_t)); 524 525 switch(daddr) { 526 case TSDEV_PIC1_MASK: 527 mask1 = ~(pkt->get<uint8_t>()); 528 if ((picr & mask1) && !picInterrupting) { 529 picInterrupting = true; 530 tsunami->cchip->postDRIR(55); 531 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 532 } 533 if ((!(picr & mask1)) && picInterrupting) { 534 picInterrupting = false; 535 tsunami->cchip->clearDRIR(55); 536 DPRINTF(Tsunami, "clearing pic interrupt\n"); 537 } 538 break; 539 case TSDEV_PIC2_MASK: 540 mask2 = pkt->get<uint8_t>(); 541 //PIC2 Not implemented to interrupt 542 break; 543 case TSDEV_PIC1_ACK: 544 // clear the interrupt on the PIC 545 picr &= ~(1 << (pkt->get<uint8_t>() & 0xF)); 546 if (!(picr & mask1)) 547 tsunami->cchip->clearDRIR(55); 548 break; 549 case TSDEV_DMA1_MODE: 550 mode1 = pkt->get<uint8_t>(); 551 break; 552 case TSDEV_DMA2_MODE: 553 mode2 = pkt->get<uint8_t>(); 554 break; 555 case TSDEV_TMR0_DATA: 556 pitimer.counter0.write(pkt->get<uint8_t>()); 557 break; 558 case TSDEV_TMR1_DATA: 559 pitimer.counter1.write(pkt->get<uint8_t>()); 560 break; 561 case TSDEV_TMR2_DATA: 562 pitimer.counter2.write(pkt->get<uint8_t>()); 563 break; 564 case TSDEV_TMR_CTRL: 565 pitimer.writeControl(pkt->get<uint8_t>()); 566 break; 567 case TSDEV_RTC_ADDR: 568 rtc.writeAddr(pkt->get<uint8_t>()); 569 break; 570 case TSDEV_RTC_DATA: 571 rtc.writeData(pkt->get<uint8_t>()); 572 break; 573 case TSDEV_KBD: 574 case TSDEV_DMA1_CMND: 575 case TSDEV_DMA2_CMND: 576 case TSDEV_DMA1_MMASK: 577 case TSDEV_DMA2_MMASK: 578 case TSDEV_PIC2_ACK: 579 case TSDEV_DMA1_RESET: 580 case TSDEV_DMA2_RESET: 581 case TSDEV_DMA1_MASK: 582 case TSDEV_DMA2_MASK: 583 case TSDEV_CTRL_PORTB: 584 break; 585 default: 586 panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>()); 587 } 588 589 pkt->result = Packet::Success; 590 return pioDelay; 591} 592 593void 594TsunamiIO::postPIC(uint8_t bitvector) 595{ 596 //PIC2 Is not implemented, because nothing of interest there 597 picr |= bitvector; 598 if (picr & mask1) { 599 tsunami->cchip->postDRIR(55); 600 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 601 } 602} 603 604void 605TsunamiIO::clearPIC(uint8_t bitvector) 606{ 607 //PIC2 Is not implemented, because nothing of interest there 608 picr &= ~bitvector; 609 if (!(picr & mask1)) { 610 tsunami->cchip->clearDRIR(55); 611 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 612 } 613} 614 615void 616TsunamiIO::serialize(ostream &os) 617{ 618 SERIALIZE_SCALAR(timerData); 619 SERIALIZE_SCALAR(mask1); 620 SERIALIZE_SCALAR(mask2); 621 SERIALIZE_SCALAR(mode1); 622 SERIALIZE_SCALAR(mode2); 623 SERIALIZE_SCALAR(picr); 624 SERIALIZE_SCALAR(picInterrupting); 625 626 // Serialize the timers 627 pitimer.serialize("pitimer", os); 628 rtc.serialize("rtc", os); 629} 630 631void 632TsunamiIO::unserialize(Checkpoint *cp, const string §ion) 633{ 634 UNSERIALIZE_SCALAR(timerData); 635 UNSERIALIZE_SCALAR(mask1); 636 UNSERIALIZE_SCALAR(mask2); 637 UNSERIALIZE_SCALAR(mode1); 638 UNSERIALIZE_SCALAR(mode2); 639 UNSERIALIZE_SCALAR(picr); 640 UNSERIALIZE_SCALAR(picInterrupting); 641 642 // Unserialize the timers 643 pitimer.unserialize("pitimer", cp, section); 644 rtc.unserialize("rtc", cp, section); 645} 646 647BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 648 649 Param<Addr> pio_addr; 650 Param<Tick> pio_latency; 651 Param<Tick> frequency; 652 SimObjectParam<Platform *> platform; 653 SimObjectParam<System *> system; 654 Param<time_t> time; 655 SimObjectParam<Tsunami *> tsunami; 656 657END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 658 659BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 660 661 INIT_PARAM(pio_addr, "Device Address"), 662 INIT_PARAM(pio_latency, "Programmed IO latency"), 663 INIT_PARAM(frequency, "clock interrupt frequency"), 664 INIT_PARAM(platform, "platform"), 665 INIT_PARAM(system, "system object"), 666 INIT_PARAM(time, "System time to use (0 for actual time"), 667 INIT_PARAM(tsunami, "Tsunami") 668 669END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 670 671CREATE_SIM_OBJECT(TsunamiIO) 672{ 673 TsunamiIO::Params *p = new TsunamiIO::Params; 674 p->frequency = frequency; 675 p->name = getInstanceName(); 676 p->pio_addr = pio_addr; 677 p->pio_delay = pio_latency; 678 p->platform = platform; 679 p->system = system; 680 p->init_time = time; 681 p->tsunami = tsunami; 682 return new TsunamiIO(p); 683} 684 685REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 686