Fix serialize/unserialize of the timers and RTC events
[gem5.git] / dev / tsunami_io.cc
1 /*
2 * Copyright (c) 2004 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* @file
30 * Tsunami I/O including PIC, PIT, RTC, DMA
31 */
32
33 #include <sys/time.h>
34
35 #include <deque>
36 #include <string>
37 #include <vector>
38
39 #include "base/trace.hh"
40 #include "dev/console.hh"
41 #include "dev/tsunami_io.hh"
42 #include "dev/tsunami.hh"
43 #include "mem/bus/bus.hh"
44 #include "mem/bus/pio_interface.hh"
45 #include "mem/bus/pio_interface_impl.hh"
46 #include "sim/builder.hh"
47 #include "dev/tsunami_cchip.hh"
48 #include "dev/tsunamireg.h"
49 #include "mem/functional_mem/memory_control.hh"
50
51 using namespace std;
52
53 #define UNIX_YEAR_OFFSET 52
54
55 // Timer Event for Periodic interrupt of RTC
56 TsunamiIO::RTCEvent::RTCEvent(Tsunami* t)
57 : Event(&mainEventQueue), tsunami(t)
58 {
59 DPRINTF(MC146818, "RTC Event Initilizing\n");
60 schedule(curTick + ticksPerSecond/RTC_RATE);
61 }
62
63 void
64 TsunamiIO::RTCEvent::process()
65 {
66 DPRINTF(MC146818, "RTC Timer Interrupt\n");
67 schedule(curTick + ticksPerSecond/RTC_RATE);
68 //Actually interrupt the processor here
69 tsunami->cchip->postRTC();
70
71 }
72
73 const char *
74 TsunamiIO::RTCEvent::description()
75 {
76 return "tsunami RTC 1024Hz interrupt";
77 }
78
79 void
80 TsunamiIO::RTCEvent::serialize(std::ostream &os)
81 {
82 Tick time = when();
83 SERIALIZE_SCALAR(time);
84 }
85
86 void
87 TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string &section)
88 {
89 Tick time;
90 UNSERIALIZE_SCALAR(time);
91 reschedule(time);
92 }
93
94
95 // Timer Event for PIT Timers
96 TsunamiIO::ClockEvent::ClockEvent()
97 : Event(&mainEventQueue)
98 {
99 DPRINTF(Tsunami, "Clock Event Initilizing\n");
100 mode = 0;
101 }
102
103 void
104 TsunamiIO::ClockEvent::process()
105 {
106 DPRINTF(Tsunami, "Timer Interrupt\n");
107 if (mode == 0)
108 status = 0x20; // set bit that linux is looking for
109 else
110 schedule(curTick + interval);
111 }
112
113 void
114 TsunamiIO::ClockEvent::Program(int count)
115 {
116 DPRINTF(Tsunami, "Timer set to curTick + %d\n", count);
117 // should be count * (cpufreq/pitfreq)
118 interval = count * ticksPerSecond/1193180UL;
119 schedule(curTick + interval);
120 status = 0;
121 }
122
123 const char *
124 TsunamiIO::ClockEvent::description()
125 {
126 return "tsunami 8254 Interval timer";
127 }
128
129 void
130 TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
131 {
132 mode = md;
133 }
134
135 uint8_t
136 TsunamiIO::ClockEvent::Status()
137 {
138 return status;
139 }
140
141 void
142 TsunamiIO::ClockEvent::serialize(std::ostream &os)
143 {
144 Tick time = scheduled() ? when() : 0;
145 SERIALIZE_SCALAR(time);
146 SERIALIZE_SCALAR(status);
147 SERIALIZE_SCALAR(mode);
148 SERIALIZE_SCALAR(interval);
149 }
150
151 void
152 TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string &section)
153 {
154 Tick time;
155 UNSERIALIZE_SCALAR(time);
156 UNSERIALIZE_SCALAR(status);
157 UNSERIALIZE_SCALAR(mode);
158 UNSERIALIZE_SCALAR(interval);
159 if (time)
160 schedule(time);
161 }
162
163 TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
164 Addr a, MemoryController *mmu, HierParams *hier, Bus *bus)
165 : PioDevice(name), addr(a), tsunami(t), rtc(t)
166 {
167 mmu->add_child(this, Range<Addr>(addr, addr + size));
168
169 if (bus) {
170 pioInterface = newPioInterface(name, hier, bus, this,
171 &TsunamiIO::cacheAccess);
172 pioInterface->addAddrRange(addr, addr + size - 1);
173 }
174
175 // set the back pointer from tsunami to myself
176 tsunami->io = this;
177
178 timerData = 0;
179 set_time(init_time == 0 ? time(NULL) : init_time);
180 uip = 1;
181 picr = 0;
182 picInterrupting = false;
183 }
184
185 void
186 TsunamiIO::set_time(time_t t)
187 {
188 gmtime_r(&t, &tm);
189 DPRINTFN("Real-time clock set to %s", asctime(&tm));
190 }
191
192 Fault
193 TsunamiIO::read(MemReqPtr &req, uint8_t *data)
194 {
195 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n",
196 req->vaddr, req->size, req->vaddr & 0xfff);
197
198 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
199
200
201 switch(req->size) {
202 case sizeof(uint8_t):
203 switch(daddr) {
204 case TSDEV_PIC1_ISR:
205 // !!! If this is modified 64bit case needs to be too
206 // Pal code has to do a 64 bit physical read because there is
207 // no load physical byte instruction
208 *(uint8_t*)data = picr;
209 return No_Fault;
210 case TSDEV_PIC2_ISR:
211 // PIC2 not implemnted... just return 0
212 *(uint8_t*)data = 0x00;
213 return No_Fault;
214 case TSDEV_TMR_CTL:
215 *(uint8_t*)data = timer2.Status();
216 return No_Fault;
217 case TSDEV_RTC_DATA:
218 switch(RTCAddress) {
219 case RTC_CONTROL_REGISTERA:
220 *(uint8_t*)data = uip << 7 | 0x26;
221 uip = !uip;
222 return No_Fault;
223 case RTC_CONTROL_REGISTERB:
224 // DM and 24/12 and UIE
225 *(uint8_t*)data = 0x46;
226 return No_Fault;
227 case RTC_CONTROL_REGISTERC:
228 // If we want to support RTC user access in linux
229 // This won't work, but for now it's fine
230 *(uint8_t*)data = 0x00;
231 return No_Fault;
232 case RTC_CONTROL_REGISTERD:
233 panic("RTC Control Register D not implemented");
234 case RTC_SECOND:
235 *(uint8_t *)data = tm.tm_sec;
236 return No_Fault;
237 case RTC_MINUTE:
238 *(uint8_t *)data = tm.tm_min;
239 return No_Fault;
240 case RTC_HOUR:
241 *(uint8_t *)data = tm.tm_hour;
242 return No_Fault;
243 case RTC_DAY_OF_WEEK:
244 *(uint8_t *)data = tm.tm_wday;
245 return No_Fault;
246 case RTC_DAY_OF_MONTH:
247 *(uint8_t *)data = tm.tm_mday;
248 case RTC_MONTH:
249 *(uint8_t *)data = tm.tm_mon + 1;
250 return No_Fault;
251 case RTC_YEAR:
252 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
253 return No_Fault;
254 default:
255 panic("Unknown RTC Address\n");
256 }
257
258 default:
259 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
260 }
261 case sizeof(uint16_t):
262 case sizeof(uint32_t):
263 panic("I/O Read - invalid size - va %#x size %d\n",
264 req->vaddr, req->size);
265
266 case sizeof(uint64_t):
267 switch(daddr) {
268 case TSDEV_PIC1_ISR:
269 // !!! If this is modified 8bit case needs to be too
270 // Pal code has to do a 64 bit physical read because there is
271 // no load physical byte instruction
272 *(uint64_t*)data = (uint64_t)picr;
273 return No_Fault;
274 default:
275 panic("I/O Read - invalid size - va %#x size %d\n",
276 req->vaddr, req->size);
277 }
278
279 default:
280 panic("I/O Read - invalid size - va %#x size %d\n",
281 req->vaddr, req->size);
282 }
283 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
284
285 return No_Fault;
286 }
287
288 Fault
289 TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
290 {
291
292 #if TRACING_ON
293 uint8_t dt = *(uint8_t*)data;
294 uint64_t dt64 = dt;
295 #endif
296
297 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
298 req->vaddr, req->size, req->vaddr & 0xfff, dt64);
299
300 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
301
302 switch(req->size) {
303 case sizeof(uint8_t):
304 switch(daddr) {
305 case TSDEV_PIC1_MASK:
306 mask1 = ~(*(uint8_t*)data);
307 if ((picr & mask1) && !picInterrupting) {
308 picInterrupting = true;
309 tsunami->cchip->postDRIR(55);
310 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
311 }
312 if ((!(picr & mask1)) && picInterrupting) {
313 picInterrupting = false;
314 tsunami->cchip->clearDRIR(55);
315 DPRINTF(Tsunami, "clearing pic interrupt\n");
316 }
317 return No_Fault;
318 case TSDEV_PIC2_MASK:
319 mask2 = *(uint8_t*)data;
320 //PIC2 Not implemented to interrupt
321 return No_Fault;
322 case TSDEV_PIC1_ACK:
323 // clear the interrupt on the PIC
324 picr &= ~(1 << (*(uint8_t*)data & 0xF));
325 if (!(picr & mask1))
326 tsunami->cchip->clearDRIR(55);
327 return No_Fault;
328 case TSDEV_PIC2_ACK:
329 return No_Fault;
330 case TSDEV_DMA1_RESET:
331 return No_Fault;
332 case TSDEV_DMA2_RESET:
333 return No_Fault;
334 case TSDEV_DMA1_MODE:
335 mode1 = *(uint8_t*)data;
336 return No_Fault;
337 case TSDEV_DMA2_MODE:
338 mode2 = *(uint8_t*)data;
339 return No_Fault;
340 case TSDEV_DMA1_MASK:
341 case TSDEV_DMA2_MASK:
342 return No_Fault;
343 case TSDEV_TMR_CTL:
344 return No_Fault;
345 case TSDEV_TMR2_CTL:
346 if ((*(uint8_t*)data & 0x30) != 0x30)
347 panic("Only L/M write supported\n");
348
349 switch(*(uint8_t*)data >> 6) {
350 case 0:
351 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
352 break;
353 case 2:
354 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
355 break;
356 default:
357 panic("Read Back Command not implemented\n");
358 }
359 return No_Fault;
360 case TSDEV_TMR2_DATA:
361 /* two writes before we actually start the Timer
362 so I set a flag in the timerData */
363 if(timerData & 0x1000) {
364 timerData &= 0x1000;
365 timerData += *(uint8_t*)data << 8;
366 timer2.Program(timerData);
367 } else {
368 timerData = *(uint8_t*)data;
369 timerData |= 0x1000;
370 }
371 return No_Fault;
372 case TSDEV_TMR0_DATA:
373 /* two writes before we actually start the Timer
374 so I set a flag in the timerData */
375 if(timerData & 0x1000) {
376 timerData &= 0x1000;
377 timerData += *(uint8_t*)data << 8;
378 timer0.Program(timerData);
379 } else {
380 timerData = *(uint8_t*)data;
381 timerData |= 0x1000;
382 }
383 return No_Fault;
384 case TSDEV_RTC_ADDR:
385 RTCAddress = *(uint8_t*)data;
386 return No_Fault;
387 case TSDEV_RTC_DATA:
388 panic("RTC Write not implmented (rtc.o won't work)\n");
389 default:
390 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
391 }
392 case sizeof(uint16_t):
393 case sizeof(uint32_t):
394 case sizeof(uint64_t):
395 default:
396 panic("I/O Write - invalid size - va %#x size %d\n",
397 req->vaddr, req->size);
398 }
399
400
401 return No_Fault;
402 }
403
404 void
405 TsunamiIO::postPIC(uint8_t bitvector)
406 {
407 //PIC2 Is not implemented, because nothing of interest there
408 picr |= bitvector;
409 if (picr & mask1) {
410 tsunami->cchip->postDRIR(55);
411 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
412 }
413 }
414
415 void
416 TsunamiIO::clearPIC(uint8_t bitvector)
417 {
418 //PIC2 Is not implemented, because nothing of interest there
419 picr &= ~bitvector;
420 if (!(picr & mask1)) {
421 tsunami->cchip->clearDRIR(55);
422 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
423 }
424 }
425
426 Tick
427 TsunamiIO::cacheAccess(MemReqPtr &req)
428 {
429 return curTick + 1000;
430 }
431
432 void
433 TsunamiIO::serialize(std::ostream &os)
434 {
435 SERIALIZE_SCALAR(timerData);
436 SERIALIZE_SCALAR(uip);
437 SERIALIZE_SCALAR(mask1);
438 SERIALIZE_SCALAR(mask2);
439 SERIALIZE_SCALAR(mode1);
440 SERIALIZE_SCALAR(mode2);
441 SERIALIZE_SCALAR(picr);
442 SERIALIZE_SCALAR(picInterrupting);
443 SERIALIZE_SCALAR(RTCAddress);
444
445 // Serialize the timers
446 nameOut(os, csprintf("%s.timer0", name()));
447 timer0.serialize(os);
448 nameOut(os, csprintf("%s.timer2", name()));
449 timer2.serialize(os);
450 nameOut(os, csprintf("%s.rtc", name()));
451 rtc.serialize(os);
452 }
453
454 void
455 TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
456 {
457 UNSERIALIZE_SCALAR(timerData);
458 UNSERIALIZE_SCALAR(uip);
459 UNSERIALIZE_SCALAR(mask1);
460 UNSERIALIZE_SCALAR(mask2);
461 UNSERIALIZE_SCALAR(mode1);
462 UNSERIALIZE_SCALAR(mode2);
463 UNSERIALIZE_SCALAR(picr);
464 UNSERIALIZE_SCALAR(picInterrupting);
465 UNSERIALIZE_SCALAR(RTCAddress);
466
467 // Unserialize the timers
468 timer0.unserialize(cp, csprintf("%s.timer0", section));
469 timer2.unserialize(cp, csprintf("%s.timer2", section));
470 rtc.unserialize(cp, csprintf("%s.rtc", section));
471 }
472
473 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
474
475 SimObjectParam<Tsunami *> tsunami;
476 Param<time_t> time;
477 SimObjectParam<MemoryController *> mmu;
478 Param<Addr> addr;
479 SimObjectParam<Bus*> io_bus;
480 SimObjectParam<HierParams *> hier;
481
482 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
483
484 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
485
486 INIT_PARAM(tsunami, "Tsunami"),
487 INIT_PARAM_DFLT(time, "System time to use "
488 "(0 for actual time, default is 1/1/06", ULL(1136073600)),
489 INIT_PARAM(mmu, "Memory Controller"),
490 INIT_PARAM(addr, "Device Address"),
491 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
492 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
493
494 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
495
496 CREATE_SIM_OBJECT(TsunamiIO)
497 {
498 return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier,
499 io_bus);
500 }
501
502 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)