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