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