store the checkpoint to the proper directory
[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 : PioDevice(name), addr(a), tsunami(t), rtc(t)
165 {
166 mmu->add_child(this, Range<Addr>(addr, addr + size));
167
168 if (bus) {
169 pioInterface = newPioInterface(name, hier, bus, this,
170 &TsunamiIO::cacheAccess);
171 pioInterface->addAddrRange(addr, addr + size - 1);
172 }
173
174 // set the back pointer from tsunami to myself
175 tsunami->io = this;
176
177 timerData = 0;
178 set_time(init_time == 0 ? time(NULL) : init_time);
179 uip = 1;
180 picr = 0;
181 picInterrupting = false;
182 }
183
184 void
185 TsunamiIO::set_time(time_t t)
186 {
187 gmtime_r(&t, &tm);
188 DPRINTFN("Real-time clock set to %s", asctime(&tm));
189 }
190
191 Fault
192 TsunamiIO::read(MemReqPtr &req, uint8_t *data)
193 {
194 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n",
195 req->vaddr, req->size, req->vaddr & 0xfff);
196
197 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
198
199
200 switch(req->size) {
201 case sizeof(uint8_t):
202 switch(daddr) {
203 case TSDEV_PIC1_ISR:
204 // !!! If this is modified 64bit case needs to be too
205 // Pal code has to do a 64 bit physical read because there is
206 // no load physical byte instruction
207 *(uint8_t*)data = picr;
208 return No_Fault;
209 case TSDEV_PIC2_ISR:
210 // PIC2 not implemnted... just return 0
211 *(uint8_t*)data = 0x00;
212 return No_Fault;
213 case TSDEV_TMR_CTL:
214 *(uint8_t*)data = timer2.Status();
215 return No_Fault;
216 case TSDEV_RTC_DATA:
217 switch(RTCAddress) {
218 case RTC_CONTROL_REGISTERA:
219 *(uint8_t*)data = uip << 7 | 0x26;
220 uip = !uip;
221 return No_Fault;
222 case RTC_CONTROL_REGISTERB:
223 // DM and 24/12 and UIE
224 *(uint8_t*)data = 0x46;
225 return No_Fault;
226 case RTC_CONTROL_REGISTERC:
227 // If we want to support RTC user access in linux
228 // This won't work, but for now it's fine
229 *(uint8_t*)data = 0x00;
230 return No_Fault;
231 case RTC_CONTROL_REGISTERD:
232 panic("RTC Control Register D not implemented");
233 case RTC_SECOND:
234 *(uint8_t *)data = tm.tm_sec;
235 return No_Fault;
236 case RTC_MINUTE:
237 *(uint8_t *)data = tm.tm_min;
238 return No_Fault;
239 case RTC_HOUR:
240 *(uint8_t *)data = tm.tm_hour;
241 return No_Fault;
242 case RTC_DAY_OF_WEEK:
243 *(uint8_t *)data = tm.tm_wday;
244 return No_Fault;
245 case RTC_DAY_OF_MONTH:
246 *(uint8_t *)data = tm.tm_mday;
247 case RTC_MONTH:
248 *(uint8_t *)data = tm.tm_mon + 1;
249 return No_Fault;
250 case RTC_YEAR:
251 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
252 return No_Fault;
253 default:
254 panic("Unknown RTC Address\n");
255 }
256
257 default:
258 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
259 }
260 case sizeof(uint16_t):
261 case sizeof(uint32_t):
262 panic("I/O Read - invalid size - va %#x size %d\n",
263 req->vaddr, req->size);
264
265 case sizeof(uint64_t):
266 switch(daddr) {
267 case TSDEV_PIC1_ISR:
268 // !!! If this is modified 8bit case needs to be too
269 // Pal code has to do a 64 bit physical read because there is
270 // no load physical byte instruction
271 *(uint64_t*)data = (uint64_t)picr;
272 return No_Fault;
273 default:
274 panic("I/O Read - invalid size - va %#x size %d\n",
275 req->vaddr, req->size);
276 }
277
278 default:
279 panic("I/O Read - invalid size - va %#x size %d\n",
280 req->vaddr, req->size);
281 }
282 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
283
284 return No_Fault;
285 }
286
287 Fault
288 TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
289 {
290
291 #if TRACING_ON
292 uint8_t dt = *(uint8_t*)data;
293 uint64_t dt64 = dt;
294 #endif
295
296 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
297 req->vaddr, req->size, req->vaddr & 0xfff, dt64);
298
299 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
300
301 switch(req->size) {
302 case sizeof(uint8_t):
303 switch(daddr) {
304 case TSDEV_PIC1_MASK:
305 mask1 = ~(*(uint8_t*)data);
306 if ((picr & mask1) && !picInterrupting) {
307 picInterrupting = true;
308 tsunami->cchip->postDRIR(55);
309 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
310 }
311 if ((!(picr & mask1)) && picInterrupting) {
312 picInterrupting = false;
313 tsunami->cchip->clearDRIR(55);
314 DPRINTF(Tsunami, "clearing pic interrupt\n");
315 }
316 return No_Fault;
317 case TSDEV_PIC2_MASK:
318 mask2 = *(uint8_t*)data;
319 //PIC2 Not implemented to interrupt
320 return No_Fault;
321 case TSDEV_PIC1_ACK:
322 // clear the interrupt on the PIC
323 picr &= ~(1 << (*(uint8_t*)data & 0xF));
324 if (!(picr & mask1))
325 tsunami->cchip->clearDRIR(55);
326 return No_Fault;
327 case TSDEV_PIC2_ACK:
328 return No_Fault;
329 case TSDEV_DMA1_RESET:
330 return No_Fault;
331 case TSDEV_DMA2_RESET:
332 return No_Fault;
333 case TSDEV_DMA1_MODE:
334 mode1 = *(uint8_t*)data;
335 return No_Fault;
336 case TSDEV_DMA2_MODE:
337 mode2 = *(uint8_t*)data;
338 return No_Fault;
339 case TSDEV_DMA1_MASK:
340 case TSDEV_DMA2_MASK:
341 return No_Fault;
342 case TSDEV_TMR_CTL:
343 return No_Fault;
344 case TSDEV_TMR2_CTL:
345 if ((*(uint8_t*)data & 0x30) != 0x30)
346 panic("Only L/M write supported\n");
347
348 switch(*(uint8_t*)data >> 6) {
349 case 0:
350 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
351 break;
352 case 2:
353 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
354 break;
355 default:
356 panic("Read Back Command not implemented\n");
357 }
358 return No_Fault;
359 case TSDEV_TMR2_DATA:
360 /* two writes before we actually start the Timer
361 so I set a flag in the timerData */
362 if(timerData & 0x1000) {
363 timerData &= 0x1000;
364 timerData += *(uint8_t*)data << 8;
365 timer2.Program(timerData);
366 } else {
367 timerData = *(uint8_t*)data;
368 timerData |= 0x1000;
369 }
370 return No_Fault;
371 case TSDEV_TMR0_DATA:
372 /* two writes before we actually start the Timer
373 so I set a flag in the timerData */
374 if(timerData & 0x1000) {
375 timerData &= 0x1000;
376 timerData += *(uint8_t*)data << 8;
377 timer0.Program(timerData);
378 } else {
379 timerData = *(uint8_t*)data;
380 timerData |= 0x1000;
381 }
382 return No_Fault;
383 case TSDEV_RTC_ADDR:
384 RTCAddress = *(uint8_t*)data;
385 return No_Fault;
386 case TSDEV_RTC_DATA:
387 panic("RTC Write not implmented (rtc.o won't work)\n");
388 default:
389 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
390 }
391 case sizeof(uint16_t):
392 case sizeof(uint32_t):
393 case sizeof(uint64_t):
394 default:
395 panic("I/O Write - invalid size - va %#x size %d\n",
396 req->vaddr, req->size);
397 }
398
399
400 return No_Fault;
401 }
402
403 void
404 TsunamiIO::postPIC(uint8_t bitvector)
405 {
406 //PIC2 Is not implemented, because nothing of interest there
407 picr |= bitvector;
408 if (picr & mask1) {
409 tsunami->cchip->postDRIR(55);
410 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
411 }
412 }
413
414 void
415 TsunamiIO::clearPIC(uint8_t bitvector)
416 {
417 //PIC2 Is not implemented, because nothing of interest there
418 picr &= ~bitvector;
419 if (!(picr & mask1)) {
420 tsunami->cchip->clearDRIR(55);
421 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
422 }
423 }
424
425 Tick
426 TsunamiIO::cacheAccess(MemReqPtr &req)
427 {
428 return curTick + 1000;
429 }
430
431 void
432 TsunamiIO::serialize(std::ostream &os)
433 {
434 SERIALIZE_SCALAR(timerData);
435 SERIALIZE_SCALAR(uip);
436 SERIALIZE_SCALAR(mask1);
437 SERIALIZE_SCALAR(mask2);
438 SERIALIZE_SCALAR(mode1);
439 SERIALIZE_SCALAR(mode2);
440 SERIALIZE_SCALAR(picr);
441 SERIALIZE_SCALAR(picInterrupting);
442 SERIALIZE_SCALAR(RTCAddress);
443
444 // Serialize the timers
445 nameOut(os, csprintf("%s.timer0", name()));
446 timer0.serialize(os);
447 nameOut(os, csprintf("%s.timer2", name()));
448 timer2.serialize(os);
449 nameOut(os, csprintf("%s.rtc", name()));
450 rtc.serialize(os);
451 }
452
453 void
454 TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
455 {
456 UNSERIALIZE_SCALAR(timerData);
457 UNSERIALIZE_SCALAR(uip);
458 UNSERIALIZE_SCALAR(mask1);
459 UNSERIALIZE_SCALAR(mask2);
460 UNSERIALIZE_SCALAR(mode1);
461 UNSERIALIZE_SCALAR(mode2);
462 UNSERIALIZE_SCALAR(picr);
463 UNSERIALIZE_SCALAR(picInterrupting);
464 UNSERIALIZE_SCALAR(RTCAddress);
465
466 // Unserialize the timers
467 timer0.unserialize(cp, csprintf("%s.timer0", section));
468 timer2.unserialize(cp, csprintf("%s.timer2", section));
469 rtc.unserialize(cp, csprintf("%s.rtc", section));
470 }
471
472 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
473
474 SimObjectParam<Tsunami *> tsunami;
475 Param<time_t> time;
476 SimObjectParam<MemoryController *> mmu;
477 Param<Addr> addr;
478 SimObjectParam<Bus*> io_bus;
479 SimObjectParam<HierParams *> hier;
480
481 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
482
483 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
484
485 INIT_PARAM(tsunami, "Tsunami"),
486 INIT_PARAM_DFLT(time, "System time to use "
487 "(0 for actual time, default is 1/1/06", ULL(1136073600)),
488 INIT_PARAM(mmu, "Memory Controller"),
489 INIT_PARAM(addr, "Device Address"),
490 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
491 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
492
493 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
494
495 CREATE_SIM_OBJECT(TsunamiIO)
496 {
497 return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier,
498 io_bus);
499 }
500
501 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)