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