Updated serialization code and added #if tracing so that make fast
[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 = when();
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 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 }
445
446 void
447 TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
448 {
449 UNSERIALIZE_SCALAR(timerData);
450 UNSERIALIZE_SCALAR(uip);
451 UNSERIALIZE_SCALAR(mask1);
452 UNSERIALIZE_SCALAR(mask2);
453 UNSERIALIZE_SCALAR(mode1);
454 UNSERIALIZE_SCALAR(mode2);
455 UNSERIALIZE_SCALAR(picr);
456 UNSERIALIZE_SCALAR(picInterrupting);
457 UNSERIALIZE_SCALAR(RTCAddress);
458 }
459
460 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
461
462 SimObjectParam<Tsunami *> tsunami;
463 Param<time_t> time;
464 SimObjectParam<MemoryController *> mmu;
465 Param<Addr> addr;
466 SimObjectParam<Bus*> io_bus;
467 SimObjectParam<HierParams *> hier;
468
469 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
470
471 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
472
473 INIT_PARAM(tsunami, "Tsunami"),
474 INIT_PARAM_DFLT(time, "System time to use "
475 "(0 for actual time, default is 1/1/06", ULL(1136073600)),
476 INIT_PARAM(mmu, "Memory Controller"),
477 INIT_PARAM(addr, "Device Address"),
478 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
479 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
480
481 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
482
483 CREATE_SIM_OBJECT(TsunamiIO)
484 {
485 return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier,
486 io_bus);
487 }
488
489 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)