tsunami_io.cc revision 5392:c3a45fac35f8
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::TsunamiRTC::TsunamiRTC(const string &n, const TsunamiIOParams *p) : 61 MC146818(n, p->time, p->year_is_bcd, p->frequency), tsunami(p->tsunami) 62{ 63} 64 65TsunamiIO::PITimer::PITimer(const string &name) 66 : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), 67 counter2(name + ".counter2") 68{ 69 counter[0] = &counter0; 70 counter[1] = &counter0; 71 counter[2] = &counter0; 72} 73 74void 75TsunamiIO::PITimer::writeControl(const uint8_t data) 76{ 77 int rw; 78 int sel; 79 80 sel = GET_CTRL_SEL(data); 81 82 if (sel == PIT_READ_BACK) 83 panic("PITimer Read-Back Command is not implemented.\n"); 84 85 rw = GET_CTRL_RW(data); 86 87 if (rw == PIT_RW_LATCH_COMMAND) 88 counter[sel]->latchCount(); 89 else { 90 counter[sel]->setRW(rw); 91 counter[sel]->setMode(GET_CTRL_MODE(data)); 92 counter[sel]->setBCD(GET_CTRL_BCD(data)); 93 } 94} 95 96void 97TsunamiIO::PITimer::serialize(const string &base, ostream &os) 98{ 99 // serialize the counters 100 counter0.serialize(base + ".counter0", os); 101 counter1.serialize(base + ".counter1", os); 102 counter2.serialize(base + ".counter2", os); 103} 104 105void 106TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, 107 const string §ion) 108{ 109 // unserialze the counters 110 counter0.unserialize(base + ".counter0", cp, section); 111 counter1.unserialize(base + ".counter1", cp, section); 112 counter2.unserialize(base + ".counter2", cp, section); 113} 114 115TsunamiIO::PITimer::Counter::Counter(const string &name) 116 : _name(name), event(this), count(0), latched_count(0), period(0), 117 mode(0), output_high(false), latch_on(false), read_byte(LSB), 118 write_byte(LSB) 119{ 120 121} 122 123void 124TsunamiIO::PITimer::Counter::latchCount() 125{ 126 // behave like a real latch 127 if(!latch_on) { 128 latch_on = true; 129 read_byte = LSB; 130 latched_count = count; 131 } 132} 133 134uint8_t 135TsunamiIO::PITimer::Counter::read() 136{ 137 if (latch_on) { 138 switch (read_byte) { 139 case LSB: 140 read_byte = MSB; 141 return (uint8_t)latched_count; 142 break; 143 case MSB: 144 read_byte = LSB; 145 latch_on = false; 146 return latched_count >> 8; 147 break; 148 default: 149 panic("Shouldn't be here"); 150 } 151 } else { 152 switch (read_byte) { 153 case LSB: 154 read_byte = MSB; 155 return (uint8_t)count; 156 break; 157 case MSB: 158 read_byte = LSB; 159 return count >> 8; 160 break; 161 default: 162 panic("Shouldn't be here"); 163 } 164 } 165} 166 167void 168TsunamiIO::PITimer::Counter::write(const uint8_t data) 169{ 170 switch (write_byte) { 171 case LSB: 172 count = (count & 0xFF00) | data; 173 174 if (event.scheduled()) 175 event.deschedule(); 176 output_high = false; 177 write_byte = MSB; 178 break; 179 180 case MSB: 181 count = (count & 0x00FF) | (data << 8); 182 period = count; 183 184 if (period > 0) { 185 DPRINTF(Tsunami, "Timer set to curTick + %d\n", 186 count * event.interval); 187 event.schedule(curTick + count * event.interval); 188 } 189 write_byte = LSB; 190 break; 191 } 192} 193 194void 195TsunamiIO::PITimer::Counter::setRW(int rw_val) 196{ 197 if (rw_val != PIT_RW_16BIT) 198 panic("Only LSB/MSB read/write is implemented.\n"); 199} 200 201void 202TsunamiIO::PITimer::Counter::setMode(int mode_val) 203{ 204 if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && 205 mode_val != PIT_MODE_SQWAVE) 206 panic("PIT mode %#x is not implemented: \n", mode_val); 207 208 mode = mode_val; 209} 210 211void 212TsunamiIO::PITimer::Counter::setBCD(int bcd_val) 213{ 214 if (bcd_val != PIT_BCD_FALSE) 215 panic("PITimer does not implement BCD counts.\n"); 216} 217 218bool 219TsunamiIO::PITimer::Counter::outputHigh() 220{ 221 return output_high; 222} 223 224void 225TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) 226{ 227 paramOut(os, base + ".count", count); 228 paramOut(os, base + ".latched_count", latched_count); 229 paramOut(os, base + ".period", period); 230 paramOut(os, base + ".mode", mode); 231 paramOut(os, base + ".output_high", output_high); 232 paramOut(os, base + ".latch_on", latch_on); 233 paramOut(os, base + ".read_byte", read_byte); 234 paramOut(os, base + ".write_byte", write_byte); 235 236 Tick event_tick = 0; 237 if (event.scheduled()) 238 event_tick = event.when(); 239 paramOut(os, base + ".event_tick", event_tick); 240} 241 242void 243TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, 244 const string §ion) 245{ 246 paramIn(cp, section, base + ".count", count); 247 paramIn(cp, section, base + ".latched_count", latched_count); 248 paramIn(cp, section, base + ".period", period); 249 paramIn(cp, section, base + ".mode", mode); 250 paramIn(cp, section, base + ".output_high", output_high); 251 paramIn(cp, section, base + ".latch_on", latch_on); 252 paramIn(cp, section, base + ".read_byte", read_byte); 253 paramIn(cp, section, base + ".write_byte", write_byte); 254 255 Tick event_tick; 256 paramIn(cp, section, base + ".event_tick", event_tick); 257 if (event_tick) 258 event.schedule(event_tick); 259} 260 261TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 262 : Event(&mainEventQueue) 263{ 264 interval = (Tick)(Clock::Float::s / 1193180.0); 265 counter = c_ptr; 266} 267 268void 269TsunamiIO::PITimer::Counter::CounterEvent::process() 270{ 271 DPRINTF(Tsunami, "Timer Interrupt\n"); 272 switch (counter->mode) { 273 case PIT_MODE_INTTC: 274 counter->output_high = true; 275 case PIT_MODE_RATEGEN: 276 case PIT_MODE_SQWAVE: 277 break; 278 default: 279 panic("Unimplemented PITimer mode.\n"); 280 } 281} 282 283const char * 284TsunamiIO::PITimer::Counter::CounterEvent::description() const 285{ 286 return "tsunami 8254 Interval timer"; 287} 288 289TsunamiIO::TsunamiIO(const Params *p) 290 : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), 291 rtc(p->name + ".rtc", p) 292{ 293 pioSize = 0x100; 294 295 // set the back pointer from tsunami to myself 296 tsunami->io = this; 297 298 timerData = 0; 299 picr = 0; 300 picInterrupting = false; 301} 302 303Tick 304TsunamiIO::frequency() const 305{ 306 return Clock::Frequency / params()->frequency; 307} 308 309Tick 310TsunamiIO::read(PacketPtr pkt) 311{ 312 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 313 314 Addr daddr = pkt->getAddr() - pioAddr; 315 316 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(), 317 pkt->getSize(), daddr); 318 319 pkt->allocate(); 320 321 if (pkt->getSize() == sizeof(uint8_t)) { 322 switch(daddr) { 323 // PIC1 mask read 324 case TSDEV_PIC1_MASK: 325 pkt->set(~mask1); 326 break; 327 case TSDEV_PIC2_MASK: 328 pkt->set(~mask2); 329 break; 330 case TSDEV_PIC1_ISR: 331 // !!! If this is modified 64bit case needs to be too 332 // Pal code has to do a 64 bit physical read because there is 333 // no load physical byte instruction 334 pkt->set(picr); 335 break; 336 case TSDEV_PIC2_ISR: 337 // PIC2 not implemnted... just return 0 338 pkt->set(0x00); 339 break; 340 case TSDEV_TMR0_DATA: 341 pkt->set(pitimer.counter0.read()); 342 break; 343 case TSDEV_TMR1_DATA: 344 pkt->set(pitimer.counter1.read()); 345 break; 346 case TSDEV_TMR2_DATA: 347 pkt->set(pitimer.counter2.read()); 348 break; 349 case TSDEV_RTC_DATA: 350 pkt->set(rtc.readData(rtcAddr)); 351 break; 352 case TSDEV_CTRL_PORTB: 353 if (pitimer.counter2.outputHigh()) 354 pkt->set(PORTB_SPKR_HIGH); 355 else 356 pkt->set(0x00); 357 break; 358 default: 359 panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize()); 360 } 361 } else if (pkt->getSize() == sizeof(uint64_t)) { 362 if (daddr == TSDEV_PIC1_ISR) 363 pkt->set<uint64_t>(picr); 364 else 365 panic("I/O Read - invalid addr - va %#x size %d\n", 366 pkt->getAddr(), pkt->getSize()); 367 } else { 368 panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize()); 369 } 370 pkt->makeAtomicResponse(); 371 return pioDelay; 372} 373 374Tick 375TsunamiIO::write(PacketPtr pkt) 376{ 377 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 378 Addr daddr = pkt->getAddr() - pioAddr; 379 380 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 381 pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>()); 382 383 assert(pkt->getSize() == sizeof(uint8_t)); 384 385 switch(daddr) { 386 case TSDEV_PIC1_MASK: 387 mask1 = ~(pkt->get<uint8_t>()); 388 if ((picr & mask1) && !picInterrupting) { 389 picInterrupting = true; 390 tsunami->cchip->postDRIR(55); 391 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 392 } 393 if ((!(picr & mask1)) && picInterrupting) { 394 picInterrupting = false; 395 tsunami->cchip->clearDRIR(55); 396 DPRINTF(Tsunami, "clearing pic interrupt\n"); 397 } 398 break; 399 case TSDEV_PIC2_MASK: 400 mask2 = pkt->get<uint8_t>(); 401 //PIC2 Not implemented to interrupt 402 break; 403 case TSDEV_PIC1_ACK: 404 // clear the interrupt on the PIC 405 picr &= ~(1 << (pkt->get<uint8_t>() & 0xF)); 406 if (!(picr & mask1)) 407 tsunami->cchip->clearDRIR(55); 408 break; 409 case TSDEV_DMA1_MODE: 410 mode1 = pkt->get<uint8_t>(); 411 break; 412 case TSDEV_DMA2_MODE: 413 mode2 = pkt->get<uint8_t>(); 414 break; 415 case TSDEV_TMR0_DATA: 416 pitimer.counter0.write(pkt->get<uint8_t>()); 417 break; 418 case TSDEV_TMR1_DATA: 419 pitimer.counter1.write(pkt->get<uint8_t>()); 420 break; 421 case TSDEV_TMR2_DATA: 422 pitimer.counter2.write(pkt->get<uint8_t>()); 423 break; 424 case TSDEV_TMR_CTRL: 425 pitimer.writeControl(pkt->get<uint8_t>()); 426 break; 427 case TSDEV_RTC_ADDR: 428 rtcAddr = pkt->get<uint8_t>(); 429 break; 430 case TSDEV_RTC_DATA: 431 rtc.writeData(rtcAddr, pkt->get<uint8_t>()); 432 break; 433 case TSDEV_KBD: 434 case TSDEV_DMA1_CMND: 435 case TSDEV_DMA2_CMND: 436 case TSDEV_DMA1_MMASK: 437 case TSDEV_DMA2_MMASK: 438 case TSDEV_PIC2_ACK: 439 case TSDEV_DMA1_RESET: 440 case TSDEV_DMA2_RESET: 441 case TSDEV_DMA1_MASK: 442 case TSDEV_DMA2_MASK: 443 case TSDEV_CTRL_PORTB: 444 break; 445 default: 446 panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>()); 447 } 448 449 pkt->makeAtomicResponse(); 450 return pioDelay; 451} 452 453void 454TsunamiIO::postPIC(uint8_t bitvector) 455{ 456 //PIC2 Is not implemented, because nothing of interest there 457 picr |= bitvector; 458 if (picr & mask1) { 459 tsunami->cchip->postDRIR(55); 460 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 461 } 462} 463 464void 465TsunamiIO::clearPIC(uint8_t bitvector) 466{ 467 //PIC2 Is not implemented, because nothing of interest there 468 picr &= ~bitvector; 469 if (!(picr & mask1)) { 470 tsunami->cchip->clearDRIR(55); 471 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 472 } 473} 474 475void 476TsunamiIO::serialize(ostream &os) 477{ 478 SERIALIZE_SCALAR(rtcAddr); 479 SERIALIZE_SCALAR(timerData); 480 SERIALIZE_SCALAR(mask1); 481 SERIALIZE_SCALAR(mask2); 482 SERIALIZE_SCALAR(mode1); 483 SERIALIZE_SCALAR(mode2); 484 SERIALIZE_SCALAR(picr); 485 SERIALIZE_SCALAR(picInterrupting); 486 487 // Serialize the timers 488 pitimer.serialize("pitimer", os); 489 rtc.serialize("rtc", os); 490} 491 492void 493TsunamiIO::unserialize(Checkpoint *cp, const string §ion) 494{ 495 UNSERIALIZE_SCALAR(rtcAddr); 496 UNSERIALIZE_SCALAR(timerData); 497 UNSERIALIZE_SCALAR(mask1); 498 UNSERIALIZE_SCALAR(mask2); 499 UNSERIALIZE_SCALAR(mode1); 500 UNSERIALIZE_SCALAR(mode2); 501 UNSERIALIZE_SCALAR(picr); 502 UNSERIALIZE_SCALAR(picInterrupting); 503 504 // Unserialize the timers 505 pitimer.unserialize("pitimer", cp, section); 506 rtc.unserialize("rtc", cp, section); 507} 508 509TsunamiIO * 510TsunamiIOParams::create() 511{ 512 return new TsunamiIO(this); 513} 514