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