Merge zizzer.eecs.umich.edu:/bk/m5
[gem5.git] / dev / tsunami_io.cc
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
24 using namespace std;
25
26 #define UNIX_YEAR_OFFSET 52
27
28
29 // Timer Event for Periodic interrupt of RTC
30 TsunamiIO::RTCEvent::RTCEvent(Tsunami* t)
31 : Event(&mainEventQueue), tsunami(t)
32 {
33 DPRINTF(MC146818, "RTC Event Initilizing\n");
34 schedule(curTick + ticksPerSecond/RTC_RATE);
35 }
36
37 void
38 TsunamiIO::RTCEvent::process()
39 {
40 DPRINTF(MC146818, "RTC Timer Interrupt\n");
41 schedule(curTick + ticksPerSecond/RTC_RATE);
42 //Actually interrupt the processor here
43 if (!tsunami->cchip->RTCInterrupting) {
44 tsunami->cchip->misc |= 1 << 7;
45 tsunami->cchip->RTCInterrupting = true;
46 tsunami->intrctrl->post(0, TheISA::INTLEVEL_IRQ2, 0);
47 }
48 }
49
50 const char *
51 TsunamiIO::RTCEvent::description()
52 {
53 return "tsunami RTC 1024Hz interrupt";
54 }
55
56 // Timer Event for PIT Timers
57 TsunamiIO::ClockEvent::ClockEvent()
58 : Event(&mainEventQueue)
59 {
60 DPRINTF(Tsunami, "Clock Event Initilizing\n");
61 mode = 0;
62 }
63
64 void
65 TsunamiIO::ClockEvent::process()
66 {
67 DPRINTF(Tsunami, "Timer Interrupt\n");
68 if (mode == 0)
69 status = 0x20; // set bit that linux is looking for
70 else
71 schedule(curTick + interval);
72 }
73
74 void
75 TsunamiIO::ClockEvent::Program(int count)
76 {
77 DPRINTF(Tsunami, "Timer set to curTick + %d\n", count);
78 // should be count * (cpufreq/pitfreq)
79 interval = count * ticksPerSecond/1193180UL;
80 schedule(curTick + interval);
81 status = 0;
82 }
83
84 const char *
85 TsunamiIO::ClockEvent::description()
86 {
87 return "tsunami 8254 Interval timer";
88 }
89
90 void
91 TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
92 {
93 mode = md;
94 }
95
96 uint8_t
97 TsunamiIO::ClockEvent::Status()
98 {
99 return status;
100 }
101
102
103
104
105 TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
106 Addr addr, Addr mask, MemoryController *mmu)
107 : MmapDevice(name, addr, mask, mmu), tsunami(t), rtc(t)
108 {
109 timerData = 0;
110 set_time(init_time == 0 ? time(NULL) : init_time);
111 uip = 1;
112 picr = 0;
113 picInterrupting = false;
114 }
115
116 void
117 TsunamiIO::set_time(time_t t)
118 {
119 gmtime_r(&t, &tm);
120 DPRINTFN("Real-time clock set to %s", asctime(&tm));
121 }
122
123 Fault
124 TsunamiIO::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
194 Fault
195 TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
196 {
197 uint8_t dt = *(uint8_t*)data;
198 uint64_t dt64 = dt;
199
200 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
201 req->vaddr, req->size, req->vaddr & 0xfff, dt64);
202
203 Addr daddr = (req->paddr & addr_mask);
204
205 switch(req->size) {
206 case sizeof(uint8_t):
207 switch(daddr) {
208 case TSDEV_PIC1_MASK:
209 mask1 = *(uint8_t*)data;
210 if ((picr & mask1) && !picInterrupting) {
211 picInterrupting = true;
212 tsunami->cchip->postDRIR(uint64_t(1) << 55);
213 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
214 }
215 return No_Fault;
216 case TSDEV_PIC2_MASK:
217 mask2 = *(uint8_t*)data;
218 //PIC2 Not implemented to interrupt
219 return No_Fault;
220 case TSDEV_DMA1_RESET:
221 return No_Fault;
222 case TSDEV_DMA2_RESET:
223 return No_Fault;
224 case TSDEV_DMA1_MODE:
225 mode1 = *(uint8_t*)data;
226 return No_Fault;
227 case TSDEV_DMA2_MODE:
228 mode2 = *(uint8_t*)data;
229 return No_Fault;
230 case TSDEV_DMA1_MASK:
231 case TSDEV_DMA2_MASK:
232 return No_Fault;
233 case TSDEV_TMR_CTL:
234 return No_Fault;
235 case TSDEV_TMR2_CTL:
236 if ((*(uint8_t*)data & 0x30) != 0x30)
237 panic("Only L/M write supported\n");
238
239 switch(*(uint8_t*)data >> 6) {
240 case 0:
241 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
242 break;
243 case 2:
244 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
245 break;
246 default:
247 panic("Read Back Command not implemented\n");
248 }
249 return No_Fault;
250 case TSDEV_TMR2_DATA:
251 /* two writes before we actually start the Timer
252 so I set a flag in the timerData */
253 if(timerData & 0x1000) {
254 timerData &= 0x1000;
255 timerData += *(uint8_t*)data << 8;
256 timer2.Program(timerData);
257 } else {
258 timerData = *(uint8_t*)data;
259 timerData |= 0x1000;
260 }
261 return No_Fault;
262 case TSDEV_TMR0_DATA:
263 /* two writes before we actually start the Timer
264 so I set a flag in the timerData */
265 if(timerData & 0x1000) {
266 timerData &= 0x1000;
267 timerData += *(uint8_t*)data << 8;
268 timer0.Program(timerData);
269 } else {
270 timerData = *(uint8_t*)data;
271 timerData |= 0x1000;
272 }
273 return No_Fault;
274 case TSDEV_RTC_ADDR:
275 RTCAddress = *(uint8_t*)data;
276 return No_Fault;
277 case TSDEV_RTC_DATA:
278 panic("RTC Write not implmented (rtc.o won't work)\n");
279 default:
280 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
281 }
282 case sizeof(uint16_t):
283 case sizeof(uint32_t):
284 case sizeof(uint64_t):
285 default:
286 panic("I/O Write - invalid size - va %#x size %d\n", req->vaddr, req->size);
287 }
288
289
290 return No_Fault;
291 }
292
293 void
294 TsunamiIO::postPIC(uint8_t bitvector)
295 {
296 //PIC2 Is not implemented, because nothing of interest there
297 picr |= bitvector;
298 if ((picr & mask1) && !picInterrupting) {
299 picInterrupting = true;
300 tsunami->cchip->postDRIR(uint64_t(1) << 55);
301 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
302 }
303 }
304
305 void
306 TsunamiIO::clearPIC(uint8_t bitvector)
307 {
308 //PIC2 Is not implemented, because nothing of interest there
309 picr &= ~bitvector;
310 if (!(picr & mask1)) {
311 picInterrupting = false;
312 tsunami->cchip->clearDRIR(uint64_t(1) << 55);
313 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
314 }
315 }
316
317 void
318 TsunamiIO::serialize(std::ostream &os)
319 {
320 // code should be written
321 }
322
323 void
324 TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
325 {
326 //code should be written
327 }
328
329 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
330
331 SimObjectParam<Tsunami *> tsunami;
332 Param<time_t> time;
333 SimObjectParam<MemoryController *> mmu;
334 Param<Addr> addr;
335 Param<Addr> mask;
336
337 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
338
339 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
340
341 INIT_PARAM(tsunami, "Tsunami"),
342 INIT_PARAM_DFLT(time, "System time to use "
343 "(0 for actual time, default is 1/1/06", ULL(1136073600)),
344 INIT_PARAM(mmu, "Memory Controller"),
345 INIT_PARAM(addr, "Device Address"),
346 INIT_PARAM(mask, "Address Mask")
347
348 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
349
350 CREATE_SIM_OBJECT(TsunamiIO)
351 {
352 return new TsunamiIO(getInstanceName(), tsunami, time, addr,
353 mask, mmu);
354 }
355
356 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)