tsunami_io.cc revision 776
12292SN/A/* $Id$ */ 22329SN/A 32292SN/A/* @file 42292SN/A * Tsunami I/O including PIC, PIT, RTC, DMA 52292SN/A */ 62292SN/A 72292SN/A#include <sys/time.h> 82292SN/A 92292SN/A#include <deque> 102292SN/A#include <string> 112292SN/A#include <vector> 122292SN/A 132292SN/A#include "base/trace.hh" 142292SN/A#include "cpu/exec_context.hh" 152292SN/A#include "dev/console.hh" 162292SN/A#include "dev/tlaser_clock.hh" 172292SN/A#include "dev/tsunami_io.hh" 182292SN/A#include "dev/tsunamireg.h" 192292SN/A#include "dev/tsunami.hh" 202292SN/A#include "mem/functional_mem/memory_control.hh" 212292SN/A#include "sim/builder.hh" 222292SN/A#include "dev/tsunami_cchip.hh" 232292SN/A 242292SN/Ausing namespace std; 252292SN/A 262292SN/A#define UNIX_YEAR_OFFSET 52 272689Sktlim@umich.edu 282689Sktlim@umich.edu 292689Sktlim@umich.edu// Timer Event for Periodic interrupt of RTC 302292SN/ATsunamiIO::RTCEvent::RTCEvent(Tsunami* t) 312292SN/A : Event(&mainEventQueue), tsunami(t) 322292SN/A{ 332292SN/A DPRINTF(MC146818, "RTC Event Initilizing\n"); 342292SN/A schedule(curTick + ticksPerSecond/RTC_RATE); 352329SN/A} 362292SN/A 372292SN/Avoid 382292SN/ATsunamiIO::RTCEvent::process() 392329SN/A{ 402292SN/A DPRINTF(MC146818, "RTC Timer Interrupt\n"); 412292SN/A schedule(curTick + ticksPerSecond/RTC_RATE); 422292SN/A //Actually interrupt the processor here 432808Ssaidi@eecs.umich.edu if (!tsunami->cchip->RTCInterrupting) { 442669Sktlim@umich.edu tsunami->cchip->misc |= 1 << 7; 452292SN/A tsunami->cchip->RTCInterrupting = true; 462292SN/A tsunami->intrctrl->post(0, TheISA::INTLEVEL_IRQ2, 0); 472329SN/A } 482329SN/A} 492329SN/A 502329SN/Aconst char * 512329SN/ATsunamiIO::RTCEvent::description() 522329SN/A{ 532329SN/A return "tsunami RTC 1024Hz interrupt"; 542329SN/A} 552329SN/A 562329SN/A// Timer Event for PIT Timers 572292SN/ATsunamiIO::ClockEvent::ClockEvent() 582292SN/A : Event(&mainEventQueue) 592292SN/A{ 602292SN/A DPRINTF(Tsunami, "Clock Event Initilizing\n"); 612292SN/A mode = 0; 622292SN/A} 632292SN/A 642733Sktlim@umich.eduvoid 652292SN/ATsunamiIO::ClockEvent::process() 662292SN/A{ 672907Sktlim@umich.edu DPRINTF(Tsunami, "Timer Interrupt\n"); 682292SN/A if (mode == 0) 692292SN/A status = 0x20; // set bit that linux is looking for 702292SN/A else 712292SN/A schedule(curTick + interval); 722292SN/A} 732292SN/A 742292SN/Avoid 752907Sktlim@umich.eduTsunamiIO::ClockEvent::Program(int count) 762292SN/A{ 772292SN/A DPRINTF(Tsunami, "Timer set to curTick + %d\n", count); 782292SN/A // should be count * (cpufreq/pitfreq) 792292SN/A interval = count * ticksPerSecond/1193180UL; 802292SN/A schedule(curTick + interval); 812727Sktlim@umich.edu status = 0; 822727Sktlim@umich.edu} 832727Sktlim@umich.edu 842292SN/Aconst char * 852733Sktlim@umich.eduTsunamiIO::ClockEvent::description() 862292SN/A{ 872292SN/A return "tsunami 8254 Interval timer"; 882292SN/A} 892292SN/A 902292SN/Avoid 912907Sktlim@umich.eduTsunamiIO::ClockEvent::ChangeMode(uint8_t md) 922907Sktlim@umich.edu{ 932907Sktlim@umich.edu mode = md; 942907Sktlim@umich.edu} 952348SN/A 962307SN/Auint8_t 972307SN/ATsunamiIO::ClockEvent::Status() 982348SN/A{ 992307SN/A return status; 1002307SN/A} 1012348SN/A 1022307SN/A 1032307SN/A 1042292SN/A 1052292SN/ATsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, 1062292SN/A Addr addr, Addr mask, MemoryController *mmu) 1072292SN/A : MmapDevice(name, addr, mask, mmu), tsunami(t), rtc(t) 1082292SN/A{ 1092292SN/A timerData = 0; 1102292SN/A set_time(init_time == 0 ? time(NULL) : init_time); 1112292SN/A uip = 1; 1122292SN/A} 1132292SN/A 1142292SN/Avoid 1152292SN/ATsunamiIO::set_time(time_t t) 1162292SN/A{ 1172292SN/A gmtime_r(&t, &tm); 1182292SN/A DPRINTFN("Real-time clock set to %s", asctime(&tm)); 1192292SN/A} 1202292SN/A 1212329SN/AFault 1222292SN/ATsunamiIO::read(MemReqPtr req, uint8_t *data) 1232292SN/A{ 1242292SN/A DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", 1252292SN/A req->vaddr, req->size, req->vaddr & 0xfff); 1262292SN/A 1272292SN/A Addr daddr = (req->paddr & addr_mask); 1282292SN/A// ExecContext *xc = req->xc; 1292292SN/A// int cpuid = xc->cpu_id; 1302292SN/A 1312292SN/A switch(req->size) { 1322292SN/A case sizeof(uint8_t): 1332292SN/A switch(daddr) { 1342292SN/A case TSDEV_TMR_CTL: 1352292SN/A *(uint8_t*)data = timer2.Status(); 1362790Sktlim@umich.edu return No_Fault; 1372790Sktlim@umich.edu case TSDEV_RTC_DATA: 1382669Sktlim@umich.edu switch(RTCAddress) { 1392669Sktlim@umich.edu case RTC_CONTROL_REGISTERA: 1402292SN/A *(uint8_t*)data = uip << 7 | 0x26; 1412292SN/A uip = !uip; 1422292SN/A return No_Fault; 1432292SN/A case RTC_CONTROL_REGISTERB: 1442292SN/A // DM and 24/12 and UIE 1452292SN/A *(uint8_t*)data = 0x46; 1462292SN/A return No_Fault; 1472292SN/A case RTC_CONTROL_REGISTERC: 1482292SN/A // If we want to support RTC user access in linux 1492292SN/A // This won't work, but for now it's fine 1502292SN/A *(uint8_t*)data = 0x00; 1512292SN/A return No_Fault; 1522292SN/A case RTC_CONTROL_REGISTERD: 1532292SN/A panic("RTC Control Register D not implemented"); 1542292SN/A case RTC_SECOND: 1552292SN/A *(uint8_t *)data = tm.tm_sec; 1562292SN/A return No_Fault; 1572292SN/A case RTC_MINUTE: 1582292SN/A *(uint8_t *)data = tm.tm_min; 1592292SN/A return No_Fault; 1602292SN/A case RTC_HOUR: 1612292SN/A *(uint8_t *)data = tm.tm_hour; 1622292SN/A return No_Fault; 1632329SN/A case RTC_DAY_OF_WEEK: 1642292SN/A *(uint8_t *)data = tm.tm_wday; 1652292SN/A return No_Fault; 1662292SN/A case RTC_DAY_OF_MONTH: 1672348SN/A *(uint8_t *)data = tm.tm_mday; 1682292SN/A case RTC_MONTH: 1692292SN/A *(uint8_t *)data = tm.tm_mon + 1; 1702292SN/A return No_Fault; 1712348SN/A case RTC_YEAR: 1722292SN/A *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET; 1732292SN/A return No_Fault; 1742292SN/A default: 1752348SN/A panic("Unknown RTC Address\n"); 1762292SN/A } 1772292SN/A 1782292SN/A default: 1792292SN/A panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 1802292SN/A } 1812292SN/A case sizeof(uint16_t): 1822292SN/A case sizeof(uint32_t): 1832292SN/A case sizeof(uint64_t): 1842292SN/A default: 1852292SN/A panic("I/O Read - invalid size - va %#x size %d\n", req->vaddr, req->size); 1862292SN/A } 1872292SN/A panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); 1882292SN/A 1892292SN/A return No_Fault; 1902292SN/A} 1912292SN/A 1922292SN/AFault 1932292SN/ATsunamiIO::write(MemReqPtr req, const uint8_t *data) 1942292SN/A{ 1952292SN/A DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x\n", 1962292SN/A req->vaddr, req->size, req->vaddr & 0xfff); 1972292SN/A 1982292SN/A Addr daddr = (req->paddr & addr_mask); 1992292SN/A 2002292SN/A switch(req->size) { 2012292SN/A case sizeof(uint8_t): 2022292SN/A switch(daddr) { 2032292SN/A case TSDEV_PIC1_MASK: 2042292SN/A mask1 = *(uint8_t*)data; 2052292SN/A return No_Fault; 2062292SN/A case TSDEV_PIC2_MASK: 2072292SN/A mask2 = *(uint8_t*)data; 2082292SN/A return No_Fault; 2092292SN/A case TSDEV_DMA1_RESET: 2102292SN/A return No_Fault; 2112678Sktlim@umich.edu case TSDEV_DMA2_RESET: 2122678Sktlim@umich.edu return No_Fault; 2132292SN/A case TSDEV_DMA1_MODE: 2142907Sktlim@umich.edu mode1 = *(uint8_t*)data; 2152907Sktlim@umich.edu return No_Fault; 2162907Sktlim@umich.edu case TSDEV_DMA2_MODE: 2172292SN/A mode2 = *(uint8_t*)data; 2182698Sktlim@umich.edu return No_Fault; 2192678Sktlim@umich.edu case TSDEV_DMA1_MASK: 2202678Sktlim@umich.edu case TSDEV_DMA2_MASK: 2212698Sktlim@umich.edu return No_Fault; 2222693Sktlim@umich.edu case TSDEV_TMR_CTL: 2232693Sktlim@umich.edu return No_Fault; 2242292SN/A case TSDEV_TMR2_CTL: 2252292SN/A if ((*(uint8_t*)data & 0x30) != 0x30) 2262292SN/A panic("Only L/M write supported\n"); 2272292SN/A 2282292SN/A switch(*(uint8_t*)data >> 6) { 2292292SN/A case 0: 2302292SN/A timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 2312292SN/A break; 2322292SN/A case 2: 2332292SN/A timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1); 2342292SN/A break; 2352292SN/A default: 2362329SN/A panic("Read Back Command not implemented\n"); 2372329SN/A } 2382329SN/A return No_Fault; 2392329SN/A case TSDEV_TMR2_DATA: 2402292SN/A /* two writes before we actually start the Timer 2412292SN/A so I set a flag in the timerData */ 2422733Sktlim@umich.edu if(timerData & 0x1000) { 2432292SN/A timerData &= 0x1000; 2442292SN/A timerData += *(uint8_t*)data << 8; 2452292SN/A timer2.Program(timerData); 2462292SN/A } else { 2472907Sktlim@umich.edu timerData = *(uint8_t*)data; 2482907Sktlim@umich.edu timerData |= 0x1000; 2492669Sktlim@umich.edu } 2502907Sktlim@umich.edu return No_Fault; 2512907Sktlim@umich.edu case TSDEV_TMR0_DATA: 2522292SN/A /* two writes before we actually start the Timer 2532698Sktlim@umich.edu so I set a flag in the timerData */ 2542678Sktlim@umich.edu if(timerData & 0x1000) { 2552678Sktlim@umich.edu timerData &= 0x1000; 2562678Sktlim@umich.edu timerData += *(uint8_t*)data << 8; 2572698Sktlim@umich.edu timer0.Program(timerData); 2582678Sktlim@umich.edu } else { 2592678Sktlim@umich.edu timerData = *(uint8_t*)data; 2602678Sktlim@umich.edu timerData |= 0x1000; 2612678Sktlim@umich.edu } 2622698Sktlim@umich.edu return No_Fault; 2632678Sktlim@umich.edu case TSDEV_RTC_ADDR: 2642698Sktlim@umich.edu RTCAddress = *(uint8_t*)data; 2652678Sktlim@umich.edu return No_Fault; 2662698Sktlim@umich.edu case TSDEV_RTC_DATA: 2672678Sktlim@umich.edu panic("RTC Write not implmented (rtc.o won't work)\n"); 2682698Sktlim@umich.edu default: 2692678Sktlim@umich.edu panic("I/O Write - va%#x size %d\n", req->vaddr, req->size); 2702678Sktlim@umich.edu } 2712678Sktlim@umich.edu case sizeof(uint16_t): 2722698Sktlim@umich.edu case sizeof(uint32_t): 2732678Sktlim@umich.edu case sizeof(uint64_t): 2742678Sktlim@umich.edu default: 2752678Sktlim@umich.edu panic("I/O Write - invalid size - va %#x size %d\n", req->vaddr, req->size); 2762678Sktlim@umich.edu } 2772678Sktlim@umich.edu 2782678Sktlim@umich.edu 2792678Sktlim@umich.edu return No_Fault; 2802678Sktlim@umich.edu} 2812678Sktlim@umich.edu 2822678Sktlim@umich.eduvoid 2832678Sktlim@umich.eduTsunamiIO::serialize(std::ostream &os) 2842678Sktlim@umich.edu{ 2852698Sktlim@umich.edu // code should be written 2862678Sktlim@umich.edu} 2872678Sktlim@umich.edu 2882698Sktlim@umich.eduvoid 2892678Sktlim@umich.eduTsunamiIO::unserialize(Checkpoint *cp, const std::string §ion) 2902678Sktlim@umich.edu{ 2912678Sktlim@umich.edu //code should be written 2922678Sktlim@umich.edu} 2932678Sktlim@umich.edu 2942678Sktlim@umich.eduBEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 2952292SN/A 2962292SN/A SimObjectParam<Tsunami *> tsunami; 2972292SN/A Param<time_t> time; 2982292SN/A SimObjectParam<MemoryController *> mmu; 2992292SN/A Param<Addr> addr; 3002292SN/A Param<Addr> mask; 3012292SN/A 3022292SN/AEND_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) 3032292SN/A 3042292SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 3052292SN/A 3062292SN/A INIT_PARAM(tsunami, "Tsunami"), 3072292SN/A INIT_PARAM_DFLT(time, "System time to use " 3082292SN/A "(0 for actual time, default is 1/1/06", ULL(1136073600)), 3092292SN/A INIT_PARAM(mmu, "Memory Controller"), 3102292SN/A INIT_PARAM(addr, "Device Address"), 3112669Sktlim@umich.edu INIT_PARAM(mask, "Address Mask") 3122669Sktlim@umich.edu 3132292SN/AEND_INIT_SIM_OBJECT_PARAMS(TsunamiIO) 3142292SN/A 3152292SN/ACREATE_SIM_OBJECT(TsunamiIO) 3162292SN/A{ 3172292SN/A return new TsunamiIO(getInstanceName(), tsunami, time, addr, 3182292SN/A mask, mmu); 3192292SN/A} 3202292SN/A 3212292SN/AREGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) 3222292SN/A