tsunami_io.cc revision 5336:c7e21f4e5a2e
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() const 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() const 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->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 461 462 Addr daddr = pkt->getAddr() - pioAddr; 463 464 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(), 465 pkt->getSize(), daddr); 466 467 pkt->allocate(); 468 469 if (pkt->getSize() == sizeof(uint8_t)) { 470 switch(daddr) { 471 // PIC1 mask read 472 case TSDEV_PIC1_MASK: 473 pkt->set(~mask1); 474 break; 475 case TSDEV_PIC2_MASK: 476 pkt->set(~mask2); 477 break; 478 case TSDEV_PIC1_ISR: 479 // !!! If this is modified 64bit case needs to be too 480 // Pal code has to do a 64 bit physical read because there is 481 // no load physical byte instruction 482 pkt->set(picr); 483 break; 484 case TSDEV_PIC2_ISR: 485 // PIC2 not implemnted... just return 0 486 pkt->set(0x00); 487 break; 488 case TSDEV_TMR0_DATA: 489 pkt->set(pitimer.counter0.read()); 490 break; 491 case TSDEV_TMR1_DATA: 492 pkt->set(pitimer.counter1.read()); 493 break; 494 case TSDEV_TMR2_DATA: 495 pkt->set(pitimer.counter2.read()); 496 break; 497 case TSDEV_RTC_DATA: 498 pkt->set(rtc.readData()); 499 break; 500 case TSDEV_CTRL_PORTB: 501 if (pitimer.counter2.outputHigh()) 502 pkt->set(PORTB_SPKR_HIGH); 503 else 504 pkt->set(0x00); 505 break; 506 default: 507 panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize()); 508 } 509 } else if (pkt->getSize() == sizeof(uint64_t)) { 510 if (daddr == TSDEV_PIC1_ISR) 511 pkt->set<uint64_t>(picr); 512 else 513 panic("I/O Read - invalid addr - va %#x size %d\n", 514 pkt->getAddr(), pkt->getSize()); 515 } else { 516 panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize()); 517 } 518 pkt->makeAtomicResponse(); 519 return pioDelay; 520} 521 522Tick 523TsunamiIO::write(PacketPtr pkt) 524{ 525 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 526 Addr daddr = pkt->getAddr() - pioAddr; 527 528 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 529 pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>()); 530 531 assert(pkt->getSize() == sizeof(uint8_t)); 532 533 switch(daddr) { 534 case TSDEV_PIC1_MASK: 535 mask1 = ~(pkt->get<uint8_t>()); 536 if ((picr & mask1) && !picInterrupting) { 537 picInterrupting = true; 538 tsunami->cchip->postDRIR(55); 539 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 540 } 541 if ((!(picr & mask1)) && picInterrupting) { 542 picInterrupting = false; 543 tsunami->cchip->clearDRIR(55); 544 DPRINTF(Tsunami, "clearing pic interrupt\n"); 545 } 546 break; 547 case TSDEV_PIC2_MASK: 548 mask2 = pkt->get<uint8_t>(); 549 //PIC2 Not implemented to interrupt 550 break; 551 case TSDEV_PIC1_ACK: 552 // clear the interrupt on the PIC 553 picr &= ~(1 << (pkt->get<uint8_t>() & 0xF)); 554 if (!(picr & mask1)) 555 tsunami->cchip->clearDRIR(55); 556 break; 557 case TSDEV_DMA1_MODE: 558 mode1 = pkt->get<uint8_t>(); 559 break; 560 case TSDEV_DMA2_MODE: 561 mode2 = pkt->get<uint8_t>(); 562 break; 563 case TSDEV_TMR0_DATA: 564 pitimer.counter0.write(pkt->get<uint8_t>()); 565 break; 566 case TSDEV_TMR1_DATA: 567 pitimer.counter1.write(pkt->get<uint8_t>()); 568 break; 569 case TSDEV_TMR2_DATA: 570 pitimer.counter2.write(pkt->get<uint8_t>()); 571 break; 572 case TSDEV_TMR_CTRL: 573 pitimer.writeControl(pkt->get<uint8_t>()); 574 break; 575 case TSDEV_RTC_ADDR: 576 rtc.writeAddr(pkt->get<uint8_t>()); 577 break; 578 case TSDEV_RTC_DATA: 579 rtc.writeData(pkt->get<uint8_t>()); 580 break; 581 case TSDEV_KBD: 582 case TSDEV_DMA1_CMND: 583 case TSDEV_DMA2_CMND: 584 case TSDEV_DMA1_MMASK: 585 case TSDEV_DMA2_MMASK: 586 case TSDEV_PIC2_ACK: 587 case TSDEV_DMA1_RESET: 588 case TSDEV_DMA2_RESET: 589 case TSDEV_DMA1_MASK: 590 case TSDEV_DMA2_MASK: 591 case TSDEV_CTRL_PORTB: 592 break; 593 default: 594 panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>()); 595 } 596 597 pkt->makeAtomicResponse(); 598 return pioDelay; 599} 600 601void 602TsunamiIO::postPIC(uint8_t bitvector) 603{ 604 //PIC2 Is not implemented, because nothing of interest there 605 picr |= bitvector; 606 if (picr & mask1) { 607 tsunami->cchip->postDRIR(55); 608 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 609 } 610} 611 612void 613TsunamiIO::clearPIC(uint8_t bitvector) 614{ 615 //PIC2 Is not implemented, because nothing of interest there 616 picr &= ~bitvector; 617 if (!(picr & mask1)) { 618 tsunami->cchip->clearDRIR(55); 619 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 620 } 621} 622 623void 624TsunamiIO::serialize(ostream &os) 625{ 626 SERIALIZE_SCALAR(timerData); 627 SERIALIZE_SCALAR(mask1); 628 SERIALIZE_SCALAR(mask2); 629 SERIALIZE_SCALAR(mode1); 630 SERIALIZE_SCALAR(mode2); 631 SERIALIZE_SCALAR(picr); 632 SERIALIZE_SCALAR(picInterrupting); 633 634 // Serialize the timers 635 pitimer.serialize("pitimer", os); 636 rtc.serialize("rtc", os); 637} 638 639void 640TsunamiIO::unserialize(Checkpoint *cp, const string §ion) 641{ 642 UNSERIALIZE_SCALAR(timerData); 643 UNSERIALIZE_SCALAR(mask1); 644 UNSERIALIZE_SCALAR(mask2); 645 UNSERIALIZE_SCALAR(mode1); 646 UNSERIALIZE_SCALAR(mode2); 647 UNSERIALIZE_SCALAR(picr); 648 UNSERIALIZE_SCALAR(picInterrupting); 649 650 // Unserialize the timers 651 pitimer.unserialize("pitimer", cp, section); 652 rtc.unserialize("rtc", cp, section); 653} 654 655TsunamiIO * 656TsunamiIOParams::create() 657{ 658 return new TsunamiIO(this); 659} 660