tsunami_io.cc revision 2641
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 121void 122TsunamiIO::RTC::readData(uint8_t *data) 123{ 124 if (addr < RTC_STAT_REGA) 125 *data = 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 *data = stat_regA; 132 break; 133 case RTC_STAT_REGB: 134 *data = stat_regB; 135 break; 136 case RTC_STAT_REGC: 137 case RTC_STAT_REGD: 138 *data = 0x00; 139 break; 140 } 141 } 142} 143 144void 145TsunamiIO::RTC::serialize(const string &base, ostream &os) 146{ 147 paramOut(os, base + ".addr", addr); 148 arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); 149 paramOut(os, base + ".stat_regA", stat_regA); 150 paramOut(os, base + ".stat_regB", stat_regB); 151} 152 153void 154TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, 155 const string §ion) 156{ 157 paramIn(cp, section, base + ".addr", addr); 158 arrayParamIn(cp, section, base + ".clock_data", clock_data, 159 sizeof(clock_data)); 160 paramIn(cp, section, base + ".stat_regA", stat_regA); 161 paramIn(cp, section, base + ".stat_regB", stat_regB); 162 163 // We're not unserializing the event here, but we need to 164 // rescehedule the event since curTick was moved forward by the 165 // checkpoint 166 event.reschedule(curTick + event.interval); 167} 168 169TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) 170 : Event(&mainEventQueue), tsunami(t), interval(i) 171{ 172 DPRINTF(MC146818, "RTC Event Initilizing\n"); 173 schedule(curTick + interval); 174} 175 176void 177TsunamiIO::RTC::RTCEvent::scheduleIntr() 178{ 179 schedule(curTick + interval); 180} 181 182void 183TsunamiIO::RTC::RTCEvent::process() 184{ 185 DPRINTF(MC146818, "RTC Timer Interrupt\n"); 186 schedule(curTick + interval); 187 //Actually interrupt the processor here 188 tsunami->cchip->postRTC(); 189} 190 191const char * 192TsunamiIO::RTC::RTCEvent::description() 193{ 194 return "tsunami RTC interrupt"; 195} 196 197TsunamiIO::PITimer::PITimer(const string &name) 198 : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), 199 counter2(name + ".counter2") 200{ 201 counter[0] = &counter0; 202 counter[1] = &counter0; 203 counter[2] = &counter0; 204} 205 206void 207TsunamiIO::PITimer::writeControl(const uint8_t data) 208{ 209 int rw; 210 int sel; 211 212 sel = GET_CTRL_SEL(data); 213 214 if (sel == PIT_READ_BACK) 215 panic("PITimer Read-Back Command is not implemented.\n"); 216 217 rw = GET_CTRL_RW(data); 218 219 if (rw == PIT_RW_LATCH_COMMAND) 220 counter[sel]->latchCount(); 221 else { 222 counter[sel]->setRW(rw); 223 counter[sel]->setMode(GET_CTRL_MODE(data)); 224 counter[sel]->setBCD(GET_CTRL_BCD(data)); 225 } 226} 227 228void 229TsunamiIO::PITimer::serialize(const string &base, ostream &os) 230{ 231 // serialize the counters 232 counter0.serialize(base + ".counter0", os); 233 counter1.serialize(base + ".counter1", os); 234 counter2.serialize(base + ".counter2", os); 235} 236 237void 238TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, 239 const string §ion) 240{ 241 // unserialze the counters 242 counter0.unserialize(base + ".counter0", cp, section); 243 counter1.unserialize(base + ".counter1", cp, section); 244 counter2.unserialize(base + ".counter2", cp, section); 245} 246 247TsunamiIO::PITimer::Counter::Counter(const string &name) 248 : _name(name), event(this), count(0), latched_count(0), period(0), 249 mode(0), output_high(false), latch_on(false), read_byte(LSB), 250 write_byte(LSB) 251{ 252 253} 254 255void 256TsunamiIO::PITimer::Counter::latchCount() 257{ 258 // behave like a real latch 259 if(!latch_on) { 260 latch_on = true; 261 read_byte = LSB; 262 latched_count = count; 263 } 264} 265 266void 267TsunamiIO::PITimer::Counter::read(uint8_t *data) 268{ 269 if (latch_on) { 270 switch (read_byte) { 271 case LSB: 272 read_byte = MSB; 273 *data = (uint8_t)latched_count; 274 break; 275 case MSB: 276 read_byte = LSB; 277 latch_on = false; 278 *data = latched_count >> 8; 279 break; 280 } 281 } else { 282 switch (read_byte) { 283 case LSB: 284 read_byte = MSB; 285 *data = (uint8_t)count; 286 break; 287 case MSB: 288 read_byte = LSB; 289 *data = count >> 8; 290 break; 291 } 292 } 293} 294 295void 296TsunamiIO::PITimer::Counter::write(const uint8_t data) 297{ 298 switch (write_byte) { 299 case LSB: 300 count = (count & 0xFF00) | data; 301 302 if (event.scheduled()) 303 event.deschedule(); 304 output_high = false; 305 write_byte = MSB; 306 break; 307 308 case MSB: 309 count = (count & 0x00FF) | (data << 8); 310 period = count; 311 312 if (period > 0) { 313 DPRINTF(Tsunami, "Timer set to curTick + %d\n", 314 count * event.interval); 315 event.schedule(curTick + count * event.interval); 316 } 317 write_byte = LSB; 318 break; 319 } 320} 321 322void 323TsunamiIO::PITimer::Counter::setRW(int rw_val) 324{ 325 if (rw_val != PIT_RW_16BIT) 326 panic("Only LSB/MSB read/write is implemented.\n"); 327} 328 329void 330TsunamiIO::PITimer::Counter::setMode(int mode_val) 331{ 332 if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && 333 mode_val != PIT_MODE_SQWAVE) 334 panic("PIT mode %#x is not implemented: \n", mode_val); 335 336 mode = mode_val; 337} 338 339void 340TsunamiIO::PITimer::Counter::setBCD(int bcd_val) 341{ 342 if (bcd_val != PIT_BCD_FALSE) 343 panic("PITimer does not implement BCD counts.\n"); 344} 345 346bool 347TsunamiIO::PITimer::Counter::outputHigh() 348{ 349 return output_high; 350} 351 352void 353TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) 354{ 355 paramOut(os, base + ".count", count); 356 paramOut(os, base + ".latched_count", latched_count); 357 paramOut(os, base + ".period", period); 358 paramOut(os, base + ".mode", mode); 359 paramOut(os, base + ".output_high", output_high); 360 paramOut(os, base + ".latch_on", latch_on); 361 paramOut(os, base + ".read_byte", read_byte); 362 paramOut(os, base + ".write_byte", write_byte); 363 364 Tick event_tick = 0; 365 if (event.scheduled()) 366 event_tick = event.when(); 367 paramOut(os, base + ".event_tick", event_tick); 368} 369 370void 371TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, 372 const string §ion) 373{ 374 paramIn(cp, section, base + ".count", count); 375 paramIn(cp, section, base + ".latched_count", latched_count); 376 paramIn(cp, section, base + ".period", period); 377 paramIn(cp, section, base + ".mode", mode); 378 paramIn(cp, section, base + ".output_high", output_high); 379 paramIn(cp, section, base + ".latch_on", latch_on); 380 paramIn(cp, section, base + ".read_byte", read_byte); 381 paramIn(cp, section, base + ".write_byte", write_byte); 382 383 Tick event_tick; 384 paramIn(cp, section, base + ".event_tick", event_tick); 385 if (event_tick) 386 event.schedule(event_tick); 387} 388 389TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 390 : Event(&mainEventQueue) 391{ 392 interval = (Tick)(Clock::Float::s / 1193180.0); 393 counter = c_ptr; 394} 395 396void 397TsunamiIO::PITimer::Counter::CounterEvent::process() 398{ 399 DPRINTF(Tsunami, "Timer Interrupt\n"); 400 switch (counter->mode) { 401 case PIT_MODE_INTTC: 402 counter->output_high = true; 403 case PIT_MODE_RATEGEN: 404 case PIT_MODE_SQWAVE: 405 break; 406 default: 407 panic("Unimplemented PITimer mode.\n"); 408 } 409} 410 411const char * 412TsunamiIO::PITimer::Counter::CounterEvent::description() 413{ 414 return "tsunami 8254 Interval timer"; 415} 416 417TsunamiIO::TsunamiIO(Params *p) 418 : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), 419 rtc(p->name + ".rtc", p->tsunami, p->frequency) 420{ 421 pioSize = 0xff; 422 423 // set the back pointer from tsunami to myself 424 tsunami->io = this; 425 426 timerData = 0; 427 rtc.set_time(p->init_time == 0 ? time(NULL) : p->init_time); 428 picr = 0; 429 picInterrupting = false; 430} 431 432Tick 433TsunamiIO::frequency() const 434{ 435 return Clock::Frequency / params()->frequency; 436} 437 438Tick 439TsunamiIO::read(Packet *pkt) 440{ 441 assert(pkt->result == Packet::Unknown); 442 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 443 444 pkt->time += pioDelay; 445 Addr daddr = pkt->getAddr() - pioAddr; 446 447 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(), 448 pkt->getSize(), daddr); 449 450 pkt->allocate(); 451 452 if (pkt->getSize() == sizeof(uint8_t)) { 453 switch(daddr) { 454 // PIC1 mask read 455 case TSDEV_PIC1_MASK: 456 pkt->set(~mask1); 457 break; 458 case TSDEV_PIC2_MASK: 459 pkt->set(~mask2); 460 break; 461 case TSDEV_PIC1_ISR: 462 // !!! If this is modified 64bit case needs to be too 463 // Pal code has to do a 64 bit physical read because there is 464 // no load physical byte instruction 465 pkt->set(picr); 466 break; 467 case TSDEV_PIC2_ISR: 468 // PIC2 not implemnted... just return 0 469 pkt->set(0x00); 470 break; 471 case TSDEV_TMR0_DATA: 472 pitimer.counter0.read(pkt->getPtr<uint8_t>()); 473 break; 474 case TSDEV_TMR1_DATA: 475 pitimer.counter1.read(pkt->getPtr<uint8_t>()); 476 break; 477 case TSDEV_TMR2_DATA: 478 pitimer.counter2.read(pkt->getPtr<uint8_t>()); 479 break; 480 case TSDEV_RTC_DATA: 481 rtc.readData(pkt->getPtr<uint8_t>()); 482 break; 483 case TSDEV_CTRL_PORTB: 484 if (pitimer.counter2.outputHigh()) 485 pkt->set(PORTB_SPKR_HIGH); 486 else 487 pkt->set(0x00); 488 break; 489 default: 490 panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize()); 491 } 492 } else if (pkt->getSize() == sizeof(uint64_t)) { 493 if (daddr == TSDEV_PIC1_ISR) 494 pkt->set<uint64_t>(picr); 495 else 496 panic("I/O Read - invalid addr - va %#x size %d\n", 497 pkt->getAddr(), pkt->getSize()); 498 } else { 499 panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize()); 500 } 501 pkt->result = Packet::Success; 502 return pioDelay; 503} 504 505Tick 506TsunamiIO::write(Packet *pkt) 507{ 508 pkt->time += pioDelay; 509 510 assert(pkt->result == Packet::Unknown); 511 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 512 Addr daddr = pkt->getAddr() - pioAddr; 513 514 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 515 pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>()); 516 517 assert(pkt->getSize() == sizeof(uint8_t)); 518 519 switch(daddr) { 520 case TSDEV_PIC1_MASK: 521 mask1 = ~(pkt->get<uint8_t>()); 522 if ((picr & mask1) && !picInterrupting) { 523 picInterrupting = true; 524 tsunami->cchip->postDRIR(55); 525 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 526 } 527 if ((!(picr & mask1)) && picInterrupting) { 528 picInterrupting = false; 529 tsunami->cchip->clearDRIR(55); 530 DPRINTF(Tsunami, "clearing pic interrupt\n"); 531 } 532 break; 533 case TSDEV_PIC2_MASK: 534 mask2 = pkt->get<uint8_t>(); 535 //PIC2 Not implemented to interrupt 536 break; 537 case TSDEV_PIC1_ACK: 538 // clear the interrupt on the PIC 539 picr &= ~(1 << (pkt->get<uint8_t>() & 0xF)); 540 if (!(picr & mask1)) 541 tsunami->cchip->clearDRIR(55); 542 break; 543 case TSDEV_DMA1_MODE: 544 mode1 = pkt->get<uint8_t>(); 545 break; 546 case TSDEV_DMA2_MODE: 547 mode2 = pkt->get<uint8_t>(); 548 break; 549 case TSDEV_TMR0_DATA: 550 pitimer.counter0.write(pkt->get<uint8_t>()); 551 break; 552 case TSDEV_TMR1_DATA: 553 pitimer.counter1.write(pkt->get<uint8_t>()); 554 break; 555 case TSDEV_TMR2_DATA: 556 pitimer.counter2.write(pkt->get<uint8_t>()); 557 break; 558 case TSDEV_TMR_CTRL: 559 pitimer.writeControl(pkt->get<uint8_t>()); 560 break; 561 case TSDEV_RTC_ADDR: 562 rtc.writeAddr(pkt->get<uint8_t>()); 563 break; 564 case TSDEV_RTC_DATA: 565 rtc.writeData(pkt->get<uint8_t>()); 566 break; 567 case TSDEV_KBD: 568 case TSDEV_DMA1_CMND: 569 case TSDEV_DMA2_CMND: 570 case TSDEV_DMA1_MMASK: 571 case TSDEV_DMA2_MMASK: 572 case TSDEV_PIC2_ACK: 573 case TSDEV_DMA1_RESET: 574 case TSDEV_DMA2_RESET: 575 case TSDEV_DMA1_MASK: 576 case TSDEV_DMA2_MASK: 577 case TSDEV_CTRL_PORTB: 578 break; 579 default: 580 panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>()); 581 } 582 583 pkt->result = Packet::Success; 584 return pioDelay; 585} 586 587void 588TsunamiIO::postPIC(uint8_t bitvector) 589{ 590 //PIC2 Is not implemented, because nothing of interest there 591 picr |= bitvector; 592 if (picr & mask1) { 593 tsunami->cchip->postDRIR(55); 594 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 595 } 596} 597 598void 599TsunamiIO::clearPIC(uint8_t bitvector) 600{ 601 //PIC2 Is not implemented, because nothing of interest there 602 picr &= ~bitvector; 603 if (!(picr & mask1)) { 604 tsunami->cchip->clearDRIR(55); 605 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 606 } 607} 608 609void 610TsunamiIO::serialize(ostream &os) 611{ 612 SERIALIZE_SCALAR(timerData); 613 SERIALIZE_SCALAR(mask1); 614 SERIALIZE_SCALAR(mask2); 615 SERIALIZE_SCALAR(mode1); 616 SERIALIZE_SCALAR(mode2); 617 SERIALIZE_SCALAR(picr); 618 SERIALIZE_SCALAR(picInterrupting); 619 620 // Serialize the timers 621 pitimer.serialize("pitimer", os); 622 rtc.serialize("rtc", os); 623} 624 625void 626TsunamiIO::unserialize(Checkpoint *cp, const string §ion) 627{ 628 UNSERIALIZE_SCALAR(timerData); 629 UNSERIALIZE_SCALAR(mask1); 630 UNSERIALIZE_SCALAR(mask2); 631 UNSERIALIZE_SCALAR(mode1); 632 UNSERIALIZE_SCALAR(mode2); 633 UNSERIALIZE_SCALAR(picr); 634 UNSERIALIZE_SCALAR(picInterrupting); 635 636 // Unserialize the timers 637 pitimer.unserialize("pitimer", cp, section); 638 rtc.unserialize("rtc", cp, section); 639} 640 641BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 642 643 Param<Addr> pio_addr; 644 Param<Tick> pio_latency; 645 Param<Tick> frequency; 646 SimObjectParam<Platform *> platform; 647 SimObjectParam<System *> system; 648 Param<time_t> time; 649 SimObjectParam<Tsunami *> tsunami; 650 651END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 652 653BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 654 655 INIT_PARAM(pio_addr, "Device Address"), 656 INIT_PARAM(pio_latency, "Programmed IO latency"), 657 INIT_PARAM(frequency, "clock interrupt frequency"), 658 INIT_PARAM(platform, "platform"), 659 INIT_PARAM(system, "system object"), 660 INIT_PARAM(time, "System time to use (0 for actual time"), 661 INIT_PARAM(tsunami, "Tsunami") 662 663END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 664 665CREATE_SIM_OBJECT(TsunamiIO) 666{ 667 TsunamiIO::Params *p = new TsunamiIO::Params; 668 p->frequency = frequency; 669 p->name = getInstanceName(); 670 p->pio_addr = pio_addr; 671 p->pio_delay = pio_latency; 672 p->platform = platform; 673 p->system = system; 674 p->init_time = time; 675 p->tsunami = tsunami; 676 return new TsunamiIO(p); 677} 678 679REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 680