tsunami_io.cc revision 773
1/* $Id$ */ 2 3/* @file 4 * Tsunami I/O including PIC, PIT, RTC, DMA 5 */ 6 7#include <sys/time.h> 8 9#include <deque> 10#include <string> 11#include <vector> 12 13#include "base/trace.hh" 14#include "cpu/exec_context.hh" 15#include "dev/console.hh" 16#include "dev/tlaser_clock.hh" 17#include "dev/tsunami_io.hh" 18#include "dev/tsunamireg.h" 19#include "dev/tsunami.hh" 20#include "mem/functional_mem/memory_control.hh" 21#include "sim/builder.hh" 22 23using namespace std; 24 25#define UNIX_YEAR_OFFSET 52 26 27//This will have to be dynamic if we want support usermode access of the RTC 28#define RTC_RATE 1024 29 30// Timer Event for Periodic interrupt of RTC 31TsunamiIO::RTCEvent::RTCEvent() 32 : Event(&mainEventQueue) 33{ 34 DPRINTF(MC146818, "RTC Event Initilizing\n"); 35 schedule(curTick + ticksPerSecond/RTC_RATE); 36} 37 38void 39TsunamiIO::RTCEvent::process() 40{ 41 DPRINTF(MC146818, "Timer Interrupt\n"); 42 schedule(curTick + ticksPerSecond/RTC_RATE); 43 //Actually interrupt the processor here 44} 45 46const char * 47TsunamiIO::RTCEvent::description() 48{ 49 return "tsunami RTC 1024Hz interrupt"; 50} 51 52// Timer Event for PIT Timers 53TsunamiIO::ClockEvent::ClockEvent() 54 : Event(&mainEventQueue) 55{ 56 DPRINTF(Tsunami, "Clock Event Initilizing\n"); 57 mode = 0; 58} 59 60void 61TsunamiIO::ClockEvent::process() 62{ 63 DPRINTF(Tsunami, "Timer Interrupt\n"); 64 if (mode == 0) 65 status = 0x20; // set bit that linux is looking for 66 else 67 schedule(curTick + interval); 68} 69 70void 71TsunamiIO::ClockEvent::Program(int count) 72{ 73 DPRINTF(Tsunami, "Timer set to curTick + %d\n", count); 74 // should be count * (cpufreq/pitfreq) 75 interval = count * ticksPerSecond/1193180UL; 76 schedule(curTick + interval); 77 status = 0; 78} 79 80const char * 81TsunamiIO::ClockEvent::description() 82{ 83 return "tsunami 8254 Interval timer"; 84} 85 86void 87TsunamiIO::ClockEvent::ChangeMode(uint8_t md) 88{ 89 mode = md; 90} 91 92uint8_t 93TsunamiIO::ClockEvent::Status() 94{ 95 return status; 96} 97 98 99 100 101TsunamiIO::TsunamiIO(const string &name, /*Tsunami *t,*/ time_t init_time, 102 Addr addr, Addr mask, MemoryController *mmu) 103 : MmapDevice(name, addr, mask, mmu)/*, tsunami(t) */ 104{ 105 timerData = 0; 106 set_time(init_time == 0 ? time(NULL) : init_time); 107 uip = 1; 108} 109 110void 111TsunamiIO::set_time(time_t t) 112{ 113 gmtime_r(&t, &tm); 114 DPRINTFN("Real-time clock set to %s", asctime(&tm)); 115} 116 117Fault 118TsunamiIO::read(MemReqPtr req, uint8_t *data) 119{ 120 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", 121 req->vaddr, req->size, req->vaddr & 0xfff); 122 123 Addr daddr = (req->paddr & addr_mask); 124// ExecContext *xc = req->xc; 125// int cpuid = xc->cpu_id; 126 127 switch(req->size) { 128 case sizeof(uint8_t): 129 switch(daddr) { 130 case TSDEV_TMR_CTL: 131 *(uint8_t*)data = timer2.Status(); 132 return No_Fault; 133 case TSDEV_RTC_DATA: 134 switch(RTCAddress) { 135 case RTC_CONTROL_REGISTERA: 136 *(uint8_t*)data = uip << 7 | 0x26; 137 uip = !uip; 138 return No_Fault; 139 case RTC_CONTROL_REGISTERB: 140 // DM and 24/12 and UIE 141 *(uint8_t*)data = 0x46; 142 return No_Fault; 143 case RTC_CONTROL_REGISTERC: 144 // If we want to support RTC user access in linux 145 // This won't work, but for now it's fine 146 *(uint8_t*)data = 0x00; 147 return No_Fault; 148 case RTC_CONTROL_REGISTERD: 149 panic("RTC Control Register D not implemented"); 150 case RTC_SECOND: 151 *(uint8_t *)data = tm.tm_sec; 152 return No_Fault; 153 case RTC_MINUTE: 154 *(uint8_t *)data = tm.tm_min; 155 return No_Fault; 156 case RTC_HOUR: 157 *(uint8_t *)data = tm.tm_hour; 158 return No_Fault; 159 case RTC_DAY_OF_WEEK: 160 *(uint8_t *)data = tm.tm_wday; 161 return No_Fault; 162 case RTC_DAY_OF_MONTH: 163 *(uint8_t *)data = tm.tm_mday; 164 case RTC_MONTH: 165 *(uint8_t *)data = tm.tm_mon + 1; 166 return No_Fault; 167 case RTC_YEAR: 168 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET; 169 return No_Fault; 170 default: 171 panic("Unknown RTC Address\n"); 172 } 173 174 default: 175 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 176 } 177 case sizeof(uint16_t): 178 case sizeof(uint32_t): 179 case sizeof(uint64_t): 180 default: 181 panic("I/O Read - invalid size - va %#x size %d\n", req->vaddr, req->size); 182 } 183 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 184 185 return No_Fault; 186} 187 188Fault 189TsunamiIO::write(MemReqPtr req, const uint8_t *data) 190{ 191 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x\n", 192 req->vaddr, req->size, req->vaddr & 0xfff); 193 194 Addr daddr = (req->paddr & addr_mask); 195 196 switch(req->size) { 197 case sizeof(uint8_t): 198 switch(daddr) { 199 case TSDEV_PIC1_MASK: 200 mask1 = *(uint8_t*)data; 201 return No_Fault; 202 case TSDEV_PIC2_MASK: 203 mask2 = *(uint8_t*)data; 204 return No_Fault; 205 case TSDEV_DMA1_RESET: 206 return No_Fault; 207 case TSDEV_DMA2_RESET: 208 return No_Fault; 209 case TSDEV_DMA1_MODE: 210 mode1 = *(uint8_t*)data; 211 return No_Fault; 212 case TSDEV_DMA2_MODE: 213 mode2 = *(uint8_t*)data; 214 return No_Fault; 215 case TSDEV_DMA1_MASK: 216 case TSDEV_DMA2_MASK: 217 return No_Fault; 218 case TSDEV_TMR_CTL: 219 return No_Fault; 220 case TSDEV_TMR2_CTL: 221 if ((*(uint8_t*)data & 0x30) != 0x30) 222 panic("Only L/M write supported\n"); 223 224 switch(*(uint8_t*)data >> 6) { 225 case 0: 226 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 227 break; 228 case 2: 229 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 230 break; 231 default: 232 panic("Read Back Command not implemented\n"); 233 } 234 return No_Fault; 235 case TSDEV_TMR2_DATA: 236 /* two writes before we actually start the Timer 237 so I set a flag in the timerData */ 238 if(timerData & 0x1000) { 239 timerData &= 0x1000; 240 timerData += *(uint8_t*)data << 8; 241 timer2.Program(timerData); 242 } else { 243 timerData = *(uint8_t*)data; 244 timerData |= 0x1000; 245 } 246 return No_Fault; 247 case TSDEV_TMR0_DATA: 248 /* two writes before we actually start the Timer 249 so I set a flag in the timerData */ 250 if(timerData & 0x1000) { 251 timerData &= 0x1000; 252 timerData += *(uint8_t*)data << 8; 253 timer0.Program(timerData); 254 } else { 255 timerData = *(uint8_t*)data; 256 timerData |= 0x1000; 257 } 258 return No_Fault; 259 case TSDEV_RTC_ADDR: 260 RTCAddress = *(uint8_t*)data; 261 return No_Fault; 262 case TSDEV_RTC_DATA: 263 panic("RTC Write not implmented (rtc.o won't work)\n"); 264 default: 265 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size); 266 } 267 case sizeof(uint16_t): 268 case sizeof(uint32_t): 269 case sizeof(uint64_t): 270 default: 271 panic("I/O Write - invalid size - va %#x size %d\n", req->vaddr, req->size); 272 } 273 274 275 return No_Fault; 276} 277 278void 279TsunamiIO::serialize(std::ostream &os) 280{ 281 // code should be written 282} 283 284void 285TsunamiIO::unserialize(Checkpoint *cp, const std::string §ion) 286{ 287 //code should be written 288} 289 290BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 291 292 // SimObjectParam<Tsunami *> tsunami; 293 Param<time_t> time; 294 SimObjectParam<MemoryController *> mmu; 295 Param<Addr> addr; 296 Param<Addr> mask; 297 298END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 299 300BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 301 302// INIT_PARAM(tsunami, "Tsunami"), 303 INIT_PARAM_DFLT(time, "System time to use " 304 "(0 for actual time, default is 1/1/06", ULL(1136073600)), 305 INIT_PARAM(mmu, "Memory Controller"), 306 INIT_PARAM(addr, "Device Address"), 307 INIT_PARAM(mask, "Address Mask") 308 309END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 310 311CREATE_SIM_OBJECT(TsunamiIO) 312{ 313 return new TsunamiIO(getInstanceName(), /*tsunami,*/ time, addr, mask, mmu); 314} 315 316REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 317