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