tsunami_io.cc revision 831
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// ExecContext *xc = req->xc; 155// int cpuid = xc->cpu_id; 156 157 switch(req->size) { 158 case sizeof(uint8_t): 159 switch(daddr) { 160 case TSDEV_TMR_CTL: 161 *(uint8_t*)data = timer2.Status(); 162 return No_Fault; 163 case TSDEV_RTC_DATA: 164 switch(RTCAddress) { 165 case RTC_CONTROL_REGISTERA: 166 *(uint8_t*)data = uip << 7 | 0x26; 167 uip = !uip; 168 return No_Fault; 169 case RTC_CONTROL_REGISTERB: 170 // DM and 24/12 and UIE 171 *(uint8_t*)data = 0x46; 172 return No_Fault; 173 case RTC_CONTROL_REGISTERC: 174 // If we want to support RTC user access in linux 175 // This won't work, but for now it's fine 176 *(uint8_t*)data = 0x00; 177 return No_Fault; 178 case RTC_CONTROL_REGISTERD: 179 panic("RTC Control Register D not implemented"); 180 case RTC_SECOND: 181 *(uint8_t *)data = tm.tm_sec; 182 return No_Fault; 183 case RTC_MINUTE: 184 *(uint8_t *)data = tm.tm_min; 185 return No_Fault; 186 case RTC_HOUR: 187 *(uint8_t *)data = tm.tm_hour; 188 return No_Fault; 189 case RTC_DAY_OF_WEEK: 190 *(uint8_t *)data = tm.tm_wday; 191 return No_Fault; 192 case RTC_DAY_OF_MONTH: 193 *(uint8_t *)data = tm.tm_mday; 194 case RTC_MONTH: 195 *(uint8_t *)data = tm.tm_mon + 1; 196 return No_Fault; 197 case RTC_YEAR: 198 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET; 199 return No_Fault; 200 default: 201 panic("Unknown RTC Address\n"); 202 } 203 204 default: 205 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 206 } 207 case sizeof(uint16_t): 208 case sizeof(uint32_t): 209 case sizeof(uint64_t): 210 default: 211 panic("I/O Read - invalid size - va %#x size %d\n", 212 req->vaddr, req->size); 213 } 214 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 215 216 return No_Fault; 217} 218 219Fault 220TsunamiIO::write(MemReqPtr &req, const uint8_t *data) 221{ 222 uint8_t dt = *(uint8_t*)data; 223 uint64_t dt64 = dt; 224 225 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 226 req->vaddr, req->size, req->vaddr & 0xfff, dt64); 227 228 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)); 229 230 switch(req->size) { 231 case sizeof(uint8_t): 232 switch(daddr) { 233 case TSDEV_PIC1_MASK: 234 mask1 = *(uint8_t*)data; 235 if ((picr & mask1) && !picInterrupting) { 236 picInterrupting = true; 237 tsunami->cchip->postDRIR(55); 238 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 239 } 240 return No_Fault; 241 case TSDEV_PIC2_MASK: 242 mask2 = *(uint8_t*)data; 243 //PIC2 Not implemented to interrupt 244 return No_Fault; 245 case TSDEV_DMA1_RESET: 246 return No_Fault; 247 case TSDEV_DMA2_RESET: 248 return No_Fault; 249 case TSDEV_DMA1_MODE: 250 mode1 = *(uint8_t*)data; 251 return No_Fault; 252 case TSDEV_DMA2_MODE: 253 mode2 = *(uint8_t*)data; 254 return No_Fault; 255 case TSDEV_DMA1_MASK: 256 case TSDEV_DMA2_MASK: 257 return No_Fault; 258 case TSDEV_TMR_CTL: 259 return No_Fault; 260 case TSDEV_TMR2_CTL: 261 if ((*(uint8_t*)data & 0x30) != 0x30) 262 panic("Only L/M write supported\n"); 263 264 switch(*(uint8_t*)data >> 6) { 265 case 0: 266 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 267 break; 268 case 2: 269 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 270 break; 271 default: 272 panic("Read Back Command not implemented\n"); 273 } 274 return No_Fault; 275 case TSDEV_TMR2_DATA: 276 /* two writes before we actually start the Timer 277 so I set a flag in the timerData */ 278 if(timerData & 0x1000) { 279 timerData &= 0x1000; 280 timerData += *(uint8_t*)data << 8; 281 timer2.Program(timerData); 282 } else { 283 timerData = *(uint8_t*)data; 284 timerData |= 0x1000; 285 } 286 return No_Fault; 287 case TSDEV_TMR0_DATA: 288 /* two writes before we actually start the Timer 289 so I set a flag in the timerData */ 290 if(timerData & 0x1000) { 291 timerData &= 0x1000; 292 timerData += *(uint8_t*)data << 8; 293 timer0.Program(timerData); 294 } else { 295 timerData = *(uint8_t*)data; 296 timerData |= 0x1000; 297 } 298 return No_Fault; 299 case TSDEV_RTC_ADDR: 300 RTCAddress = *(uint8_t*)data; 301 return No_Fault; 302 case TSDEV_RTC_DATA: 303 panic("RTC Write not implmented (rtc.o won't work)\n"); 304 default: 305 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size); 306 } 307 case sizeof(uint16_t): 308 case sizeof(uint32_t): 309 case sizeof(uint64_t): 310 default: 311 panic("I/O Write - invalid size - va %#x size %d\n", 312 req->vaddr, req->size); 313 } 314 315 316 return No_Fault; 317} 318 319void 320TsunamiIO::postPIC(uint8_t bitvector) 321{ 322 //PIC2 Is not implemented, because nothing of interest there 323 picr |= bitvector; 324 if ((picr & mask1) && !picInterrupting) { 325 picInterrupting = true; 326 tsunami->cchip->postDRIR(55); 327 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 328 } 329} 330 331void 332TsunamiIO::clearPIC(uint8_t bitvector) 333{ 334 //PIC2 Is not implemented, because nothing of interest there 335 picr &= ~bitvector; 336 if (!(picr & mask1)) { 337 picInterrupting = false; 338 tsunami->cchip->clearDRIR(55); 339 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 340 } 341} 342 343void 344TsunamiIO::serialize(std::ostream &os) 345{ 346 SERIALIZE_SCALAR(timerData); 347 SERIALIZE_SCALAR(uip); 348 SERIALIZE_SCALAR(picr); 349 SERIALIZE_SCALAR(picInterrupting); 350 Tick time0when = timer0.when(); 351 Tick time2when = timer2.when(); 352 Tick rtcwhen = rtc.when(); 353 SERIALIZE_SCALAR(time0when); 354 SERIALIZE_SCALAR(time2when); 355 SERIALIZE_SCALAR(rtcwhen); 356 357} 358 359void 360TsunamiIO::unserialize(Checkpoint *cp, const std::string §ion) 361{ 362 UNSERIALIZE_SCALAR(timerData); 363 UNSERIALIZE_SCALAR(uip); 364 UNSERIALIZE_SCALAR(picr); 365 UNSERIALIZE_SCALAR(picInterrupting); 366 Tick time0when; 367 Tick time2when; 368 Tick rtcwhen; 369 UNSERIALIZE_SCALAR(time0when); 370 UNSERIALIZE_SCALAR(time2when); 371 UNSERIALIZE_SCALAR(rtcwhen); 372 timer0.reschedule(time0when); 373 timer2.reschedule(time2when); 374 rtc.reschedule(rtcwhen); 375} 376 377BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 378 379 SimObjectParam<Tsunami *> tsunami; 380 Param<time_t> time; 381 SimObjectParam<MemoryController *> mmu; 382 Param<Addr> addr; 383 384END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 385 386BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 387 388 INIT_PARAM(tsunami, "Tsunami"), 389 INIT_PARAM_DFLT(time, "System time to use " 390 "(0 for actual time, default is 1/1/06", ULL(1136073600)), 391 INIT_PARAM(mmu, "Memory Controller"), 392 INIT_PARAM(addr, "Device Address") 393 394END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 395 396CREATE_SIM_OBJECT(TsunamiIO) 397{ 398 return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu); 399} 400 401REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 402