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