tsunami_io.cc revision 1634
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 29/* @file 30 * Tsunami I/O including PIC, PIT, RTC, DMA 31 */ 32 33#include <sys/time.h> 34 35#include <deque> 36#include <string> 37#include <vector> 38 39#include "base/trace.hh" 40#include "dev/tsunami_io.hh" 41#include "dev/tsunami.hh" 42#include "mem/bus/bus.hh" 43#include "mem/bus/pio_interface.hh" 44#include "mem/bus/pio_interface_impl.hh" 45#include "sim/builder.hh" 46#include "dev/tsunami_cchip.hh" 47#include "dev/tsunamireg.h" 48#include "dev/rtcreg.h" 49#include "mem/functional_mem/memory_control.hh" 50 51using namespace std; 52 53#define UNIX_YEAR_OFFSET 52 54 55// Timer Event for Periodic interrupt of RTC 56TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i) 57 : Event(&mainEventQueue), tsunami(t), interval(i) 58{ 59 DPRINTF(MC146818, "RTC Event Initilizing\n"); 60 schedule(curTick + interval); 61} 62 63void 64TsunamiIO::RTCEvent::process() 65{ 66 DPRINTF(MC146818, "RTC Timer Interrupt\n"); 67 schedule(curTick + interval); 68 //Actually interrupt the processor here 69 tsunami->cchip->postRTC(); 70} 71 72const char * 73TsunamiIO::RTCEvent::description() 74{ 75 return "tsunami RTC interrupt"; 76} 77 78void 79TsunamiIO::RTCEvent::serialize(std::ostream &os) 80{ 81 Tick time = when(); 82 SERIALIZE_SCALAR(time); 83} 84 85void 86TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string §ion) 87{ 88 Tick time; 89 UNSERIALIZE_SCALAR(time); 90 reschedule(time); 91} 92 93 94// Timer Event for PIT Timers 95TsunamiIO::ClockEvent::ClockEvent() 96 : Event(&mainEventQueue) 97{ 98 /* This is the PIT Tick Rate. A constant for the 8254 timer. The 99 * Tsunami platform has one of these cycle counters on the Cypress 100 * South Bridge and it is used by linux for estimating the cycle 101 * frequency of the machine it is running on. --Ali 102 */ 103 interval = (Tick)(Clock::Float::s / 1193180.0); 104 105 DPRINTF(Tsunami, "Clock Event Initilizing\n"); 106 mode = 0; 107} 108 109void 110TsunamiIO::ClockEvent::process() 111{ 112 DPRINTF(Tsunami, "Timer Interrupt\n"); 113 if (mode == 0) 114 status = 0x20; // set bit that linux is looking for 115 else 116 schedule(curTick + interval); 117} 118 119void 120TsunamiIO::ClockEvent::Program(int count) 121{ 122 DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * interval); 123 schedule(curTick + count * interval); 124 status = 0; 125} 126 127const char * 128TsunamiIO::ClockEvent::description() 129{ 130 return "tsunami 8254 Interval timer"; 131} 132 133void 134TsunamiIO::ClockEvent::ChangeMode(uint8_t md) 135{ 136 mode = md; 137} 138 139uint8_t 140TsunamiIO::ClockEvent::Status() 141{ 142 return status; 143} 144 145void 146TsunamiIO::ClockEvent::serialize(std::ostream &os) 147{ 148 Tick time = scheduled() ? when() : 0; 149 SERIALIZE_SCALAR(time); 150 SERIALIZE_SCALAR(status); 151 SERIALIZE_SCALAR(mode); 152 SERIALIZE_SCALAR(interval); 153} 154 155void 156TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string §ion) 157{ 158 Tick time; 159 UNSERIALIZE_SCALAR(time); 160 UNSERIALIZE_SCALAR(status); 161 UNSERIALIZE_SCALAR(mode); 162 UNSERIALIZE_SCALAR(interval); 163 if (time) 164 schedule(time); 165} 166 167TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, 168 Addr a, MemoryController *mmu, HierParams *hier, Bus *bus, 169 Tick pio_latency, Tick ci) 170 : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t), rtc(t, ci) 171{ 172 mmu->add_child(this, RangeSize(addr, size)); 173 174 if (bus) { 175 pioInterface = newPioInterface(name, hier, bus, this, 176 &TsunamiIO::cacheAccess); 177 pioInterface->addAddrRange(RangeSize(addr, size)); 178 pioLatency = pio_latency * bus->clockRatio; 179 } 180 181 // set the back pointer from tsunami to myself 182 tsunami->io = this; 183 184 timerData = 0; 185 set_time(init_time == 0 ? time(NULL) : init_time); 186 uip = 1; 187 picr = 0; 188 picInterrupting = false; 189} 190 191Tick 192TsunamiIO::frequency() const 193{ 194 return Clock::Frequency / clockInterval; 195} 196 197void 198TsunamiIO::set_time(time_t t) 199{ 200 gmtime_r(&t, &tm); 201 DPRINTFN("Real-time clock set to %s", asctime(&tm)); 202} 203 204Fault 205TsunamiIO::read(MemReqPtr &req, uint8_t *data) 206{ 207 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", 208 req->vaddr, req->size, req->vaddr & 0xfff); 209 210 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); 211 212 213 switch(req->size) { 214 case sizeof(uint8_t): 215 switch(daddr) { 216 case TSDEV_PIC1_ISR: 217 // !!! If this is modified 64bit case needs to be too 218 // Pal code has to do a 64 bit physical read because there is 219 // no load physical byte instruction 220 *(uint8_t*)data = picr; 221 return No_Fault; 222 case TSDEV_PIC2_ISR: 223 // PIC2 not implemnted... just return 0 224 *(uint8_t*)data = 0x00; 225 return No_Fault; 226 case TSDEV_TMR_CTL: 227 *(uint8_t*)data = timer2.Status(); 228 return No_Fault; 229 case TSDEV_RTC_DATA: 230 switch(RTCAddress) { 231 case RTC_CNTRL_REGA: 232 *(uint8_t*)data = uip << 7 | 0x26; 233 uip = !uip; 234 return No_Fault; 235 case RTC_CNTRL_REGB: 236 // DM and 24/12 and UIE 237 *(uint8_t*)data = 0x46; 238 return No_Fault; 239 case RTC_CNTRL_REGC: 240 // If we want to support RTC user access in linux 241 // This won't work, but for now it's fine 242 *(uint8_t*)data = 0x00; 243 return No_Fault; 244 case RTC_CNTRL_REGD: 245 panic("RTC Control Register D not implemented"); 246 case RTC_SEC: 247 *(uint8_t *)data = tm.tm_sec; 248 return No_Fault; 249 case RTC_MIN: 250 *(uint8_t *)data = tm.tm_min; 251 return No_Fault; 252 case RTC_HR: 253 *(uint8_t *)data = tm.tm_hour; 254 return No_Fault; 255 case RTC_DOW: 256 *(uint8_t *)data = tm.tm_wday; 257 return No_Fault; 258 case RTC_DOM: 259 *(uint8_t *)data = tm.tm_mday; 260 case RTC_MON: 261 *(uint8_t *)data = tm.tm_mon + 1; 262 return No_Fault; 263 case RTC_YEAR: 264 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET; 265 return No_Fault; 266 default: 267 panic("Unknown RTC Address\n"); 268 } 269 270 default: 271 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 272 } 273 case sizeof(uint16_t): 274 case sizeof(uint32_t): 275 panic("I/O Read - invalid size - va %#x size %d\n", 276 req->vaddr, req->size); 277 278 case sizeof(uint64_t): 279 switch(daddr) { 280 case TSDEV_PIC1_ISR: 281 // !!! If this is modified 8bit case needs to be too 282 // Pal code has to do a 64 bit physical read because there is 283 // no load physical byte instruction 284 *(uint64_t*)data = (uint64_t)picr; 285 return No_Fault; 286 default: 287 panic("I/O Read - invalid size - va %#x size %d\n", 288 req->vaddr, req->size); 289 } 290 291 default: 292 panic("I/O Read - invalid size - va %#x size %d\n", 293 req->vaddr, req->size); 294 } 295 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 296 297 return No_Fault; 298} 299 300Fault 301TsunamiIO::write(MemReqPtr &req, const uint8_t *data) 302{ 303 304#if TRACING_ON 305 uint8_t dt = *(uint8_t*)data; 306 uint64_t dt64 = dt; 307#endif 308 309 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 310 req->vaddr, req->size, req->vaddr & 0xfff, dt64); 311 312 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); 313 314 switch(req->size) { 315 case sizeof(uint8_t): 316 switch(daddr) { 317 case TSDEV_PIC1_MASK: 318 mask1 = ~(*(uint8_t*)data); 319 if ((picr & mask1) && !picInterrupting) { 320 picInterrupting = true; 321 tsunami->cchip->postDRIR(55); 322 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 323 } 324 if ((!(picr & mask1)) && picInterrupting) { 325 picInterrupting = false; 326 tsunami->cchip->clearDRIR(55); 327 DPRINTF(Tsunami, "clearing pic interrupt\n"); 328 } 329 return No_Fault; 330 case TSDEV_PIC2_MASK: 331 mask2 = *(uint8_t*)data; 332 //PIC2 Not implemented to interrupt 333 return No_Fault; 334 case TSDEV_PIC1_ACK: 335 // clear the interrupt on the PIC 336 picr &= ~(1 << (*(uint8_t*)data & 0xF)); 337 if (!(picr & mask1)) 338 tsunami->cchip->clearDRIR(55); 339 return No_Fault; 340 case TSDEV_PIC2_ACK: 341 return No_Fault; 342 case TSDEV_DMA1_RESET: 343 return No_Fault; 344 case TSDEV_DMA2_RESET: 345 return No_Fault; 346 case TSDEV_DMA1_MODE: 347 mode1 = *(uint8_t*)data; 348 return No_Fault; 349 case TSDEV_DMA2_MODE: 350 mode2 = *(uint8_t*)data; 351 return No_Fault; 352 case TSDEV_DMA1_MASK: 353 case TSDEV_DMA2_MASK: 354 return No_Fault; 355 case TSDEV_TMR_CTL: 356 return No_Fault; 357 case TSDEV_TMR2_CTL: 358 if ((*(uint8_t*)data & 0x30) != 0x30) 359 panic("Only L/M write supported\n"); 360 361 switch(*(uint8_t*)data >> 6) { 362 case 0: 363 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 364 break; 365 case 2: 366 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 367 break; 368 default: 369 panic("Read Back Command not implemented\n"); 370 } 371 return No_Fault; 372 case TSDEV_TMR2_DATA: 373 /* two writes before we actually start the Timer 374 so I set a flag in the timerData */ 375 if(timerData & 0x1000) { 376 timerData &= 0x1000; 377 timerData += *(uint8_t*)data << 8; 378 timer2.Program(timerData); 379 } else { 380 timerData = *(uint8_t*)data; 381 timerData |= 0x1000; 382 } 383 return No_Fault; 384 case TSDEV_TMR0_DATA: 385 /* two writes before we actually start the Timer 386 so I set a flag in the timerData */ 387 if(timerData & 0x1000) { 388 timerData &= 0x1000; 389 timerData += *(uint8_t*)data << 8; 390 timer0.Program(timerData); 391 } else { 392 timerData = *(uint8_t*)data; 393 timerData |= 0x1000; 394 } 395 return No_Fault; 396 case TSDEV_RTC_ADDR: 397 RTCAddress = *(uint8_t*)data; 398 return No_Fault; 399 case TSDEV_RTC_DATA: 400 panic("RTC Write not implmented (rtc.o won't work)\n"); 401 default: 402 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size); 403 } 404 case sizeof(uint16_t): 405 case sizeof(uint32_t): 406 case sizeof(uint64_t): 407 default: 408 panic("I/O Write - invalid size - va %#x size %d\n", 409 req->vaddr, req->size); 410 } 411 412 413 return No_Fault; 414} 415 416void 417TsunamiIO::postPIC(uint8_t bitvector) 418{ 419 //PIC2 Is not implemented, because nothing of interest there 420 picr |= bitvector; 421 if (picr & mask1) { 422 tsunami->cchip->postDRIR(55); 423 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 424 } 425} 426 427void 428TsunamiIO::clearPIC(uint8_t bitvector) 429{ 430 //PIC2 Is not implemented, because nothing of interest there 431 picr &= ~bitvector; 432 if (!(picr & mask1)) { 433 tsunami->cchip->clearDRIR(55); 434 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 435 } 436} 437 438Tick 439TsunamiIO::cacheAccess(MemReqPtr &req) 440{ 441 return curTick + pioLatency; 442} 443 444void 445TsunamiIO::serialize(std::ostream &os) 446{ 447 SERIALIZE_SCALAR(timerData); 448 SERIALIZE_SCALAR(uip); 449 SERIALIZE_SCALAR(mask1); 450 SERIALIZE_SCALAR(mask2); 451 SERIALIZE_SCALAR(mode1); 452 SERIALIZE_SCALAR(mode2); 453 SERIALIZE_SCALAR(picr); 454 SERIALIZE_SCALAR(picInterrupting); 455 SERIALIZE_SCALAR(RTCAddress); 456 457 // Serialize the timers 458 nameOut(os, csprintf("%s.timer0", name())); 459 timer0.serialize(os); 460 nameOut(os, csprintf("%s.timer2", name())); 461 timer2.serialize(os); 462 nameOut(os, csprintf("%s.rtc", name())); 463 rtc.serialize(os); 464} 465 466void 467TsunamiIO::unserialize(Checkpoint *cp, const std::string §ion) 468{ 469 UNSERIALIZE_SCALAR(timerData); 470 UNSERIALIZE_SCALAR(uip); 471 UNSERIALIZE_SCALAR(mask1); 472 UNSERIALIZE_SCALAR(mask2); 473 UNSERIALIZE_SCALAR(mode1); 474 UNSERIALIZE_SCALAR(mode2); 475 UNSERIALIZE_SCALAR(picr); 476 UNSERIALIZE_SCALAR(picInterrupting); 477 UNSERIALIZE_SCALAR(RTCAddress); 478 479 // Unserialize the timers 480 timer0.unserialize(cp, csprintf("%s.timer0", section)); 481 timer2.unserialize(cp, csprintf("%s.timer2", section)); 482 rtc.unserialize(cp, csprintf("%s.rtc", section)); 483} 484 485BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 486 487 SimObjectParam<Tsunami *> tsunami; 488 Param<time_t> time; 489 SimObjectParam<MemoryController *> mmu; 490 Param<Addr> addr; 491 SimObjectParam<Bus*> io_bus; 492 Param<Tick> pio_latency; 493 SimObjectParam<HierParams *> hier; 494 Param<Tick> frequency; 495 496END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 497 498BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 499 500 INIT_PARAM(tsunami, "Tsunami"), 501 INIT_PARAM(time, "System time to use (0 for actual time"), 502 INIT_PARAM(mmu, "Memory Controller"), 503 INIT_PARAM(addr, "Device Address"), 504 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), 505 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 506 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 507 INIT_PARAM(frequency, "clock interrupt frequency") 508 509END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 510 511CREATE_SIM_OBJECT(TsunamiIO) 512{ 513 return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier, 514 io_bus, pio_latency, frequency); 515} 516 517REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 518