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