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