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