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