tsunami_io.cc revision 803
12SN/A/* 21762SN/A * Copyright (c) 2003 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292665Ssaidi@eecs.umich.edu/* @file 302SN/A * Tsunami I/O including PIC, PIT, RTC, DMA 312SN/A */ 322SN/A 332SN/A#include <sys/time.h> 342SN/A 353918Ssaidi@eecs.umich.edu#include <deque> 362SN/A#include <string> 372SN/A#include <vector> 382SN/A 394046Sbinkertn@umich.edu#include "base/trace.hh" 404046Sbinkertn@umich.edu#include "cpu/exec_context.hh" 414046Sbinkertn@umich.edu#include "dev/console.hh" 424046Sbinkertn@umich.edu#include "dev/tlaser_clock.hh" 4356SN/A#include "dev/tsunami_io.hh" 442SN/A#include "dev/tsunamireg.h" 453064Sgblack@eecs.umich.edu#include "dev/tsunami.hh" 462SN/A#include "mem/functional_mem/memory_control.hh" 472SN/A#include "sim/builder.hh" 482SN/A#include "dev/tsunami_cchip.hh" 492SN/A 504046Sbinkertn@umich.eduusing namespace std; 512SN/A 522SN/A#define UNIX_YEAR_OFFSET 52 532107SN/A 542SN/A// Timer Event for Periodic interrupt of RTC 554046Sbinkertn@umich.eduTsunamiIO::RTCEvent::RTCEvent(Tsunami* t) 564046Sbinkertn@umich.edu : Event(&mainEventQueue), tsunami(t) 572SN/A{ 582SN/A DPRINTF(MC146818, "RTC Event Initilizing\n"); 593064Sgblack@eecs.umich.edu schedule(curTick + ticksPerSecond/RTC_RATE); 602SN/A} 612SN/A 622107SN/Avoid 632SN/ATsunamiIO::RTCEvent::process() 642SN/A{ 652SN/A DPRINTF(MC146818, "RTC Timer Interrupt\n"); 662SN/A schedule(curTick + ticksPerSecond/RTC_RATE); 672SN/A //Actually interrupt the processor here 682SN/A if (!tsunami->cchip->RTCInterrupting) { 692SN/A tsunami->cchip->misc |= 1 << 7; 702SN/A tsunami->cchip->RTCInterrupting = true; 712SN/A tsunami->intrctrl->post(0, TheISA::INTLEVEL_IRQ2, 0); 722SN/A } 732SN/A} 742SN/A 752SN/Aconst char * 762SN/ATsunamiIO::RTCEvent::description() 772SN/A{ 782SN/A return "tsunami RTC 1024Hz interrupt"; 792SN/A} 802SN/A 812SN/A// Timer Event for PIT Timers 822SN/ATsunamiIO::ClockEvent::ClockEvent() 832SN/A : Event(&mainEventQueue) 842SN/A{ 852SN/A DPRINTF(Tsunami, "Clock Event Initilizing\n"); 862SN/A mode = 0; 872SN/A} 882SN/A 892SN/Avoid 902SN/ATsunamiIO::ClockEvent::process() 912SN/A{ 922SN/A DPRINTF(Tsunami, "Timer Interrupt\n"); 932SN/A if (mode == 0) 942SN/A status = 0x20; // set bit that linux is looking for 952SN/A else 962SN/A schedule(curTick + interval); 972SN/A} 982SN/A 992SN/Avoid 1004046Sbinkertn@umich.eduTsunamiIO::ClockEvent::Program(int count) 1012107SN/A{ 1023064Sgblack@eecs.umich.edu DPRINTF(Tsunami, "Timer set to curTick + %d\n", count); 1034046Sbinkertn@umich.edu // should be count * (cpufreq/pitfreq) 1043064Sgblack@eecs.umich.edu interval = count * ticksPerSecond/1193180UL; 1053064Sgblack@eecs.umich.edu schedule(curTick + interval); 1062SN/A status = 0; 1072SN/A} 1082SN/A 1092SN/Aconst char * 1102SN/ATsunamiIO::ClockEvent::description() 1112SN/A{ 1122SN/A return "tsunami 8254 Interval timer"; 1132SN/A} 1142SN/A 1154046Sbinkertn@umich.eduvoid 1162SN/ATsunamiIO::ClockEvent::ChangeMode(uint8_t md) 1172SN/A{ 1182SN/A mode = md; 1192SN/A} 1202SN/A 1212SN/Auint8_t 1222SN/ATsunamiIO::ClockEvent::Status() 1232SN/A{ 1242SN/A return status; 1252SN/A} 1262SN/A 1272SN/ATsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, 1282SN/A Addr addr, Addr mask, MemoryController *mmu) 1292SN/A : MmapDevice(name, addr, mask, mmu), tsunami(t), rtc(t) 1302SN/A{ 1312SN/A // set the back pointer from tsunami to myself 1322SN/A tsunami->io = this; 1332SN/A 1342SN/A timerData = 0; 1352SN/A set_time(init_time == 0 ? time(NULL) : init_time); 1362SN/A uip = 1; 1372SN/A picr = 0; 1382SN/A picInterrupting = false; 1394046Sbinkertn@umich.edu} 1402SN/A 1412SN/Avoid 1422SN/ATsunamiIO::set_time(time_t t) 1432SN/A{ 1442SN/A gmtime_r(&t, &tm); 1452SN/A DPRINTFN("Real-time clock set to %s", asctime(&tm)); 1462SN/A} 1472SN/A 1482SN/AFault 1493918Ssaidi@eecs.umich.eduTsunamiIO::read(MemReqPtr &req, uint8_t *data) 1502SN/A{ 1512SN/A DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", 1522SN/A req->vaddr, req->size, req->vaddr & 0xfff); 1534054Sbinkertn@umich.edu 1544054Sbinkertn@umich.edu Addr daddr = (req->paddr & addr_mask); 1553064Sgblack@eecs.umich.edu// ExecContext *xc = req->xc; 1562SN/A// int cpuid = xc->cpu_id; 1574054Sbinkertn@umich.edu 1584054Sbinkertn@umich.edu switch(req->size) { 1592SN/A case sizeof(uint8_t): 1604074Sbinkertn@umich.edu switch(daddr) { 1614074Sbinkertn@umich.edu case TSDEV_TMR_CTL: 1624074Sbinkertn@umich.edu *(uint8_t*)data = timer2.Status(); 1634054Sbinkertn@umich.edu return No_Fault; 1644054Sbinkertn@umich.edu case TSDEV_RTC_DATA: 1654054Sbinkertn@umich.edu switch(RTCAddress) { 1664054Sbinkertn@umich.edu case RTC_CONTROL_REGISTERA: 1672SN/A *(uint8_t*)data = uip << 7 | 0x26; 1682SN/A uip = !uip; 1694054Sbinkertn@umich.edu return No_Fault; 1702SN/A case RTC_CONTROL_REGISTERB: 1712SN/A // 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