tsunami_io.cc revision 803
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 if (!tsunami->cchip->RTCInterrupting) { 69 tsunami->cchip->misc |= 1 << 7; 70 tsunami->cchip->RTCInterrupting = true; 71 tsunami->intrctrl->post(0, TheISA::INTLEVEL_IRQ2, 0); 72 } 73} 74 75const char * 76TsunamiIO::RTCEvent::description() 77{ 78 return "tsunami RTC 1024Hz interrupt"; 79} 80 81// Timer Event for PIT Timers 82TsunamiIO::ClockEvent::ClockEvent() 83 : Event(&mainEventQueue) 84{ 85 DPRINTF(Tsunami, "Clock Event Initilizing\n"); 86 mode = 0; 87} 88 89void 90TsunamiIO::ClockEvent::process() 91{ 92 DPRINTF(Tsunami, "Timer Interrupt\n"); 93 if (mode == 0) 94 status = 0x20; // set bit that linux is looking for 95 else 96 schedule(curTick + interval); 97} 98 99void 100TsunamiIO::ClockEvent::Program(int count) 101{ 102 DPRINTF(Tsunami, "Timer set to curTick + %d\n", count); 103 // should be count * (cpufreq/pitfreq) 104 interval = count * ticksPerSecond/1193180UL; 105 schedule(curTick + interval); 106 status = 0; 107} 108 109const char * 110TsunamiIO::ClockEvent::description() 111{ 112 return "tsunami 8254 Interval timer"; 113} 114 115void 116TsunamiIO::ClockEvent::ChangeMode(uint8_t md) 117{ 118 mode = md; 119} 120 121uint8_t 122TsunamiIO::ClockEvent::Status() 123{ 124 return status; 125} 126 127TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, 128 Addr addr, Addr mask, MemoryController *mmu) 129 : MmapDevice(name, addr, mask, mmu), tsunami(t), rtc(t) 130{ 131 // set the back pointer from tsunami to myself 132 tsunami->io = this; 133 134 timerData = 0; 135 set_time(init_time == 0 ? time(NULL) : init_time); 136 uip = 1; 137 picr = 0; 138 picInterrupting = false; 139} 140 141void 142TsunamiIO::set_time(time_t t) 143{ 144 gmtime_r(&t, &tm); 145 DPRINTFN("Real-time clock set to %s", asctime(&tm)); 146} 147 148Fault 149TsunamiIO::read(MemReqPtr &req, uint8_t *data) 150{ 151 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", 152 req->vaddr, req->size, req->vaddr & 0xfff); 153 154 Addr daddr = (req->paddr & addr_mask); 155// ExecContext *xc = req->xc; 156// int cpuid = xc->cpu_id; 157 158 switch(req->size) { 159 case sizeof(uint8_t): 160 switch(daddr) { 161 case TSDEV_TMR_CTL: 162 *(uint8_t*)data = timer2.Status(); 163 return No_Fault; 164 case TSDEV_RTC_DATA: 165 switch(RTCAddress) { 166 case RTC_CONTROL_REGISTERA: 167 *(uint8_t*)data = uip << 7 | 0x26; 168 uip = !uip; 169 return No_Fault; 170 case RTC_CONTROL_REGISTERB: 171 // DM and 24/12 and UIE 172 *(uint8_t*)data = 0x46; 173 return No_Fault; 174 case RTC_CONTROL_REGISTERC: 175 // If we want to support RTC user access in linux 176 // This won't work, but for now it's fine 177 *(uint8_t*)data = 0x00; 178 return No_Fault; 179 case RTC_CONTROL_REGISTERD: 180 panic("RTC Control Register D not implemented"); 181 case RTC_SECOND: 182 *(uint8_t *)data = tm.tm_sec; 183 return No_Fault; 184 case RTC_MINUTE: 185 *(uint8_t *)data = tm.tm_min; 186 return No_Fault; 187 case RTC_HOUR: 188 *(uint8_t *)data = tm.tm_hour; 189 return No_Fault; 190 case RTC_DAY_OF_WEEK: 191 *(uint8_t *)data = tm.tm_wday; 192 return No_Fault; 193 case RTC_DAY_OF_MONTH: 194 *(uint8_t *)data = tm.tm_mday; 195 case RTC_MONTH: 196 *(uint8_t *)data = tm.tm_mon + 1; 197 return No_Fault; 198 case RTC_YEAR: 199 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET; 200 return No_Fault; 201 default: 202 panic("Unknown RTC Address\n"); 203 } 204 205 default: 206 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 207 } 208 case sizeof(uint16_t): 209 case sizeof(uint32_t): 210 case sizeof(uint64_t): 211 default: 212 panic("I/O Read - invalid size - va %#x size %d\n", 213 req->vaddr, req->size); 214 } 215 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 216 217 return No_Fault; 218} 219 220Fault 221TsunamiIO::write(MemReqPtr &req, const uint8_t *data) 222{ 223 uint8_t dt = *(uint8_t*)data; 224 uint64_t dt64 = dt; 225 226 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", 227 req->vaddr, req->size, req->vaddr & 0xfff, dt64); 228 229 Addr daddr = (req->paddr & addr_mask); 230 231 switch(req->size) { 232 case sizeof(uint8_t): 233 switch(daddr) { 234 case TSDEV_PIC1_MASK: 235 mask1 = *(uint8_t*)data; 236 if ((picr & mask1) && !picInterrupting) { 237 picInterrupting = true; 238 tsunami->cchip->postDRIR(uint64_t(1) << 55); 239 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 240 } 241 return No_Fault; 242 case TSDEV_PIC2_MASK: 243 mask2 = *(uint8_t*)data; 244 //PIC2 Not implemented to interrupt 245 return No_Fault; 246 case TSDEV_DMA1_RESET: 247 return No_Fault; 248 case TSDEV_DMA2_RESET: 249 return No_Fault; 250 case TSDEV_DMA1_MODE: 251 mode1 = *(uint8_t*)data; 252 return No_Fault; 253 case TSDEV_DMA2_MODE: 254 mode2 = *(uint8_t*)data; 255 return No_Fault; 256 case TSDEV_DMA1_MASK: 257 case TSDEV_DMA2_MASK: 258 return No_Fault; 259 case TSDEV_TMR_CTL: 260 return No_Fault; 261 case TSDEV_TMR2_CTL: 262 if ((*(uint8_t*)data & 0x30) != 0x30) 263 panic("Only L/M write supported\n"); 264 265 switch(*(uint8_t*)data >> 6) { 266 case 0: 267 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 268 break; 269 case 2: 270 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 271 break; 272 default: 273 panic("Read Back Command not implemented\n"); 274 } 275 return No_Fault; 276 case TSDEV_TMR2_DATA: 277 /* two writes before we actually start the Timer 278 so I set a flag in the timerData */ 279 if(timerData & 0x1000) { 280 timerData &= 0x1000; 281 timerData += *(uint8_t*)data << 8; 282 timer2.Program(timerData); 283 } else { 284 timerData = *(uint8_t*)data; 285 timerData |= 0x1000; 286 } 287 return No_Fault; 288 case TSDEV_TMR0_DATA: 289 /* two writes before we actually start the Timer 290 so I set a flag in the timerData */ 291 if(timerData & 0x1000) { 292 timerData &= 0x1000; 293 timerData += *(uint8_t*)data << 8; 294 timer0.Program(timerData); 295 } else { 296 timerData = *(uint8_t*)data; 297 timerData |= 0x1000; 298 } 299 return No_Fault; 300 case TSDEV_RTC_ADDR: 301 RTCAddress = *(uint8_t*)data; 302 return No_Fault; 303 case TSDEV_RTC_DATA: 304 panic("RTC Write not implmented (rtc.o won't work)\n"); 305 default: 306 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size); 307 } 308 case sizeof(uint16_t): 309 case sizeof(uint32_t): 310 case sizeof(uint64_t): 311 default: 312 panic("I/O Write - invalid size - va %#x size %d\n", 313 req->vaddr, req->size); 314 } 315 316 317 return No_Fault; 318} 319 320void 321TsunamiIO::postPIC(uint8_t bitvector) 322{ 323 //PIC2 Is not implemented, because nothing of interest there 324 picr |= bitvector; 325 if ((picr & mask1) && !picInterrupting) { 326 picInterrupting = true; 327 tsunami->cchip->postDRIR(uint64_t(1) << 55); 328 DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); 329 } 330} 331 332void 333TsunamiIO::clearPIC(uint8_t bitvector) 334{ 335 //PIC2 Is not implemented, because nothing of interest there 336 picr &= ~bitvector; 337 if (!(picr & mask1)) { 338 picInterrupting = false; 339 tsunami->cchip->clearDRIR(uint64_t(1) << 55); 340 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); 341 } 342} 343 344void 345TsunamiIO::serialize(std::ostream &os) 346{ 347 // code should be written 348} 349 350void 351TsunamiIO::unserialize(Checkpoint *cp, const std::string §ion) 352{ 353 //code should be written 354} 355 356BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 357 358 SimObjectParam<Tsunami *> tsunami; 359 Param<time_t> time; 360 SimObjectParam<MemoryController *> mmu; 361 Param<Addr> addr; 362 Param<Addr> mask; 363 364END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 365 366BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 367 368 INIT_PARAM(tsunami, "Tsunami"), 369 INIT_PARAM_DFLT(time, "System time to use " 370 "(0 for actual time, default is 1/1/06", ULL(1136073600)), 371 INIT_PARAM(mmu, "Memory Controller"), 372 INIT_PARAM(addr, "Device Address"), 373 INIT_PARAM(mask, "Address Mask") 374 375END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 376 377CREATE_SIM_OBJECT(TsunamiIO) 378{ 379 return new TsunamiIO(getInstanceName(), tsunami, time, addr, 380 mask, mmu); 381} 382 383REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 384