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