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