Changed timer functionality, ide disk interrupts, and TsunamiFake class to improve...
[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 struct tm TsunamiIO::tm = { 0 };
56
57 // Timer Event for Periodic interrupt of RTC
58 TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i)
59 : Event(&mainEventQueue), tsunami(t), interval(i)
60 {
61 DPRINTF(MC146818, "RTC Event Initilizing\n");
62 schedule(curTick + interval);
63 }
64
65 void
66 TsunamiIO::RTCEvent::process()
67 {
68 static int intr_count = 0;
69 DPRINTF(MC146818, "RTC Timer Interrupt\n");
70 schedule(curTick + interval);
71 //Actually interrupt the processor here
72 tsunami->cchip->postRTC();
73 if (intr_count == 1023)
74 tm.tm_sec = (tm.tm_sec + 1) % 60;
75
76 intr_count = (intr_count + 1) % 1024;
77
78 }
79
80 const char *
81 TsunamiIO::RTCEvent::description()
82 {
83 return "tsunami RTC interrupt";
84 }
85
86 void
87 TsunamiIO::RTCEvent::serialize(std::ostream &os)
88 {
89 Tick time = when();
90 SERIALIZE_SCALAR(time);
91 }
92
93 void
94 TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string &section)
95 {
96 Tick time;
97 UNSERIALIZE_SCALAR(time);
98 reschedule(time);
99 }
100
101
102 // Timer Event for PIT Timers
103 TsunamiIO::ClockEvent::ClockEvent()
104 : Event(&mainEventQueue)
105 {
106 /* This is the PIT Tick Rate. A constant for the 8254 timer. The
107 * Tsunami platform has one of these cycle counters on the Cypress
108 * South Bridge and it is used by linux for estimating the cycle
109 * frequency of the machine it is running on. --Ali
110 */
111 interval = (Tick)(Clock::Float::s / 1193180.0);
112
113 DPRINTF(Tsunami, "Clock Event Initilizing\n");
114 mode = 0;
115
116 current_count.whole = 0;
117 latched_count.whole = 0;
118 latch_on = false;
119 read_msb = false;
120 }
121
122 void
123 TsunamiIO::ClockEvent::process()
124 {
125 DPRINTF(Tsunami, "Timer Interrupt\n");
126 if (mode == 0)
127 status = 0x20; // set bit that linux is looking for
128 else
129 schedule(curTick + interval);
130
131 current_count.whole--; //decrement count
132 }
133
134 void
135 TsunamiIO::ClockEvent::Program(int count)
136 {
137 DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * interval);
138 schedule(curTick + count * interval);
139 status = 0;
140
141 current_count.whole = count;
142 }
143
144 const char *
145 TsunamiIO::ClockEvent::description()
146 {
147 return "tsunami 8254 Interval timer";
148 }
149
150 void
151 TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
152 {
153 mode = md;
154 }
155
156 uint8_t
157 TsunamiIO::ClockEvent::Status()
158 {
159 return status;
160 }
161
162 void
163 TsunamiIO::ClockEvent::LatchCount()
164 {
165 if(!latch_on) {
166 latch_on = true;
167 read_msb = false;
168 latched_count.whole = current_count.whole;
169 }
170 }
171
172 uint8_t
173 TsunamiIO::ClockEvent::Read()
174 {
175 if(latch_on) {
176 if(!read_msb) {
177 read_msb = true;
178 return latched_count.half.lsb;
179 } else {
180 latch_on = false;
181 return latched_count.half.msb;
182 }
183 } else {
184 if(!read_msb) {
185 read_msb = true;
186 return current_count.half.lsb;
187 } else {
188 return current_count.half.msb;
189 }
190 }
191 }
192
193
194 void
195 TsunamiIO::ClockEvent::serialize(std::ostream &os)
196 {
197 Tick time = scheduled() ? when() : 0;
198 SERIALIZE_SCALAR(time);
199 SERIALIZE_SCALAR(status);
200 SERIALIZE_SCALAR(mode);
201 SERIALIZE_SCALAR(interval);
202 }
203
204 void
205 TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string &section)
206 {
207 Tick time;
208 UNSERIALIZE_SCALAR(time);
209 UNSERIALIZE_SCALAR(status);
210 UNSERIALIZE_SCALAR(mode);
211 UNSERIALIZE_SCALAR(interval);
212 if (time)
213 schedule(time);
214 }
215
216 TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
217 Addr a, MemoryController *mmu, HierParams *hier, Bus *bus,
218 Tick pio_latency, Tick ci)
219 : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t), rtc(t, ci)
220 {
221 mmu->add_child(this, RangeSize(addr, size));
222
223 if (bus) {
224 pioInterface = newPioInterface(name, hier, bus, this,
225 &TsunamiIO::cacheAccess);
226 pioInterface->addAddrRange(RangeSize(addr, size));
227 pioLatency = pio_latency * bus->clockRate;
228 }
229
230 // set the back pointer from tsunami to myself
231 tsunami->io = this;
232
233 timerData = 0;
234 set_time(init_time == 0 ? time(NULL) : init_time);
235 uip = 1;
236 picr = 0;
237 picInterrupting = false;
238 }
239
240 Tick
241 TsunamiIO::frequency() const
242 {
243 return Clock::Frequency / clockInterval;
244 }
245
246 void
247 TsunamiIO::set_time(time_t t)
248 {
249 gmtime_r(&t, &tm);
250 DPRINTFN("Real-time clock set to %s", asctime(&tm));
251 }
252
253 Fault
254 TsunamiIO::read(MemReqPtr &req, uint8_t *data)
255 {
256 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n",
257 req->vaddr, req->size, req->vaddr & 0xfff);
258
259 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) + 0x20;
260
261
262 switch(req->size) {
263 case sizeof(uint8_t):
264 switch(daddr) {
265 // PIC1 mask read
266 case TSDEV_PIC1_MASK:
267 *(uint8_t*)data = ~mask1;
268 return No_Fault;
269 case TSDEV_PIC2_MASK:
270 *(uint8_t*)data = ~mask2;
271 return No_Fault;
272 case TSDEV_PIC1_ISR:
273 // !!! If this is modified 64bit case needs to be too
274 // Pal code has to do a 64 bit physical read because there is
275 // no load physical byte instruction
276 *(uint8_t*)data = picr;
277 return No_Fault;
278 case TSDEV_PIC2_ISR:
279 // PIC2 not implemnted... just return 0
280 *(uint8_t*)data = 0x00;
281 return No_Fault;
282 case TSDEV_TMR_CTL:
283 *(uint8_t*)data = timer2.Status();
284 return No_Fault;
285 case TSDEV_TMR0_DATA:
286 *(uint8_t *)data = timer0.Read();
287 return No_Fault;
288 case TSDEV_RTC_DATA:
289 switch(RTCAddress) {
290 case RTC_CNTRL_REGA:
291 *(uint8_t*)data = uip << 7 | 0x26;
292 uip = !uip;
293 return No_Fault;
294 case RTC_CNTRL_REGB:
295 // DM and 24/12 and UIE
296 *(uint8_t*)data = 0x46;
297 return No_Fault;
298 case RTC_CNTRL_REGC:
299 // If we want to support RTC user access in linux
300 // This won't work, but for now it's fine
301 *(uint8_t*)data = 0x00;
302 return No_Fault;
303 case RTC_CNTRL_REGD:
304 panic("RTC Control Register D not implemented");
305 case RTC_SEC:
306 *(uint8_t *)data = tm.tm_sec;
307 return No_Fault;
308 case RTC_MIN:
309 *(uint8_t *)data = tm.tm_min;
310 return No_Fault;
311 case RTC_HR:
312 *(uint8_t *)data = tm.tm_hour;
313 return No_Fault;
314 case RTC_DOW:
315 *(uint8_t *)data = tm.tm_wday;
316 return No_Fault;
317 case RTC_DOM:
318 *(uint8_t *)data = tm.tm_mday;
319 return No_Fault;
320 case RTC_MON:
321 *(uint8_t *)data = tm.tm_mon + 1;
322 return No_Fault;
323 case RTC_YEAR:
324 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
325 return No_Fault;
326 default:
327 panic("Unknown RTC Address\n");
328 }
329
330 /* Added for keyboard reads */
331 case TSDEV_KBD:
332 *(uint8_t *)data = 0x00;
333 return No_Fault;
334 /* Added for ATA PCI DMA */
335 case ATA_PCI_DMA:
336 *(uint8_t *)data = 0x00;
337 return No_Fault;
338 default:
339 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
340 }
341 case sizeof(uint16_t):
342 case sizeof(uint32_t):
343 panic("I/O Read - invalid size - va %#x size %d\n",
344 req->vaddr, req->size);
345
346 case sizeof(uint64_t):
347 switch(daddr) {
348 case TSDEV_PIC1_ISR:
349 // !!! If this is modified 8bit case needs to be too
350 // Pal code has to do a 64 bit physical read because there is
351 // no load physical byte instruction
352 *(uint64_t*)data = (uint64_t)picr;
353 return No_Fault;
354 default:
355 panic("I/O Read - invalid size - va %#x size %d\n",
356 req->vaddr, req->size);
357 }
358
359 default:
360 panic("I/O Read - invalid size - va %#x size %d\n",
361 req->vaddr, req->size);
362 }
363 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
364
365 return No_Fault;
366 }
367
368 Fault
369 TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
370 {
371
372 #if TRACING_ON
373 uint8_t dt = *(uint8_t*)data;
374 uint64_t dt64 = dt;
375 #endif
376
377 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
378 req->vaddr, req->size, req->vaddr & 0xfff, dt64);
379
380 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) + 0x20;
381
382 switch(req->size) {
383 case sizeof(uint8_t):
384 switch(daddr) {
385 case TSDEV_PIC1_MASK:
386 mask1 = ~(*(uint8_t*)data);
387 if ((picr & mask1) && !picInterrupting) {
388 picInterrupting = true;
389 tsunami->cchip->postDRIR(55);
390 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
391 }
392 if ((!(picr & mask1)) && picInterrupting) {
393 picInterrupting = false;
394 tsunami->cchip->clearDRIR(55);
395 DPRINTF(Tsunami, "clearing pic interrupt\n");
396 }
397 return No_Fault;
398 case TSDEV_PIC2_MASK:
399 mask2 = *(uint8_t*)data;
400 //PIC2 Not implemented to interrupt
401 return No_Fault;
402 case TSDEV_PIC1_ACK:
403 // clear the interrupt on the PIC
404 picr &= ~(1 << (*(uint8_t*)data & 0xF));
405 if (!(picr & mask1))
406 tsunami->cchip->clearDRIR(55);
407 return No_Fault;
408 case TSDEV_PIC2_ACK:
409 return No_Fault;
410 case TSDEV_DMA1_RESET:
411 return No_Fault;
412 case TSDEV_DMA2_RESET:
413 return No_Fault;
414 case TSDEV_DMA1_MODE:
415 mode1 = *(uint8_t*)data;
416 return No_Fault;
417 case TSDEV_DMA2_MODE:
418 mode2 = *(uint8_t*)data;
419 return No_Fault;
420 case TSDEV_DMA1_MASK:
421 case TSDEV_DMA2_MASK:
422 return No_Fault;
423 case TSDEV_TMR_CTL:
424 return No_Fault;
425 case TSDEV_TMR2_CTL:
426 switch((*(uint8_t*)data >> 4) & 0x3) {
427 case 0x0:
428 switch(*(uint8_t*)data >> 6) {
429 case 0:
430 timer0.LatchCount();
431 break;
432 case 2:
433 timer2.LatchCount();
434 break;
435 default:
436 panic("Read Back Command not implemented\n");
437 }
438 break;
439 case 0x3:
440 break;
441 default:
442 panic("Only L/M write and Counter-Latch read supported\n");
443 }
444
445 switch(*(uint8_t*)data >> 6) {
446 case 0:
447 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
448 break;
449 case 2:
450 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
451 break;
452 default:
453 panic("Read Back Command not implemented\n");
454 }
455 return No_Fault;
456 case TSDEV_TMR2_DATA:
457 /* two writes before we actually start the Timer
458 so I set a flag in the timerData */
459 if(timerData & 0x1000) {
460 timerData &= 0x1000;
461 timerData += *(uint8_t*)data << 8;
462 timer2.Program(timerData);
463 } else {
464 timerData = *(uint8_t*)data;
465 timerData |= 0x1000;
466 }
467 return No_Fault;
468 case TSDEV_TMR0_DATA:
469 /* two writes before we actually start the Timer
470 so I set a flag in the timerData */
471 if(timerData & 0x1000) {
472 timerData &= 0x1000;
473 timerData += *(uint8_t*)data << 8;
474 timer0.Program(timerData);
475 } else {
476 timerData = *(uint8_t*)data;
477 timerData |= 0x1000;
478 }
479 return No_Fault;
480 case TSDEV_RTC_ADDR:
481 RTCAddress = *(uint8_t*)data;
482 return No_Fault;
483 case TSDEV_KBD:
484 return No_Fault;
485 case TSDEV_RTC_DATA:
486 switch(RTCAddress) {
487 case RTC_CNTRL_REGA:
488 return No_Fault;
489 case RTC_CNTRL_REGB:
490 return No_Fault;
491 case RTC_CNTRL_REGC:
492 return No_Fault;
493 case RTC_CNTRL_REGD:
494 return No_Fault;
495 case RTC_SEC:
496 tm.tm_sec = *(uint8_t *)data;
497 return No_Fault;
498 case RTC_MIN:
499 tm.tm_min = *(uint8_t *)data;
500 return No_Fault;
501 case RTC_HR:
502 tm.tm_hour = *(uint8_t *)data;
503 return No_Fault;
504 case RTC_DOW:
505 tm.tm_wday = *(uint8_t *)data;
506 return No_Fault;
507 case RTC_DOM:
508 tm.tm_mday = *(uint8_t *)data;
509 return No_Fault;
510 case RTC_MON:
511 tm.tm_mon = *(uint8_t *)data - 1;
512 return No_Fault;
513 case RTC_YEAR:
514 tm.tm_year = *(uint8_t *)data + UNIX_YEAR_OFFSET;
515 return No_Fault;
516 //panic("RTC Write not implmented (rtc.o won't work)\n");
517 }
518 default:
519 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
520 }
521 case sizeof(uint16_t):
522 case sizeof(uint32_t):
523 case sizeof(uint64_t):
524 default:
525 panic("I/O Write - invalid size - va %#x size %d\n",
526 req->vaddr, req->size);
527 }
528
529
530 return No_Fault;
531 }
532
533 void
534 TsunamiIO::postPIC(uint8_t bitvector)
535 {
536 //PIC2 Is not implemented, because nothing of interest there
537 picr |= bitvector;
538 if (picr & mask1) {
539 tsunami->cchip->postDRIR(55);
540 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
541 }
542 }
543
544 void
545 TsunamiIO::clearPIC(uint8_t bitvector)
546 {
547 //PIC2 Is not implemented, because nothing of interest there
548 picr &= ~bitvector;
549 if (!(picr & mask1)) {
550 tsunami->cchip->clearDRIR(55);
551 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
552 }
553 }
554
555 Tick
556 TsunamiIO::cacheAccess(MemReqPtr &req)
557 {
558 return curTick + pioLatency;
559 }
560
561 void
562 TsunamiIO::serialize(std::ostream &os)
563 {
564 SERIALIZE_SCALAR(timerData);
565 SERIALIZE_SCALAR(uip);
566 SERIALIZE_SCALAR(mask1);
567 SERIALIZE_SCALAR(mask2);
568 SERIALIZE_SCALAR(mode1);
569 SERIALIZE_SCALAR(mode2);
570 SERIALIZE_SCALAR(picr);
571 SERIALIZE_SCALAR(picInterrupting);
572 SERIALIZE_SCALAR(RTCAddress);
573
574 // Serialize the timers
575 nameOut(os, csprintf("%s.timer0", name()));
576 timer0.serialize(os);
577 nameOut(os, csprintf("%s.timer2", name()));
578 timer2.serialize(os);
579 nameOut(os, csprintf("%s.rtc", name()));
580 rtc.serialize(os);
581 }
582
583 void
584 TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
585 {
586 UNSERIALIZE_SCALAR(timerData);
587 UNSERIALIZE_SCALAR(uip);
588 UNSERIALIZE_SCALAR(mask1);
589 UNSERIALIZE_SCALAR(mask2);
590 UNSERIALIZE_SCALAR(mode1);
591 UNSERIALIZE_SCALAR(mode2);
592 UNSERIALIZE_SCALAR(picr);
593 UNSERIALIZE_SCALAR(picInterrupting);
594 UNSERIALIZE_SCALAR(RTCAddress);
595
596 // Unserialize the timers
597 timer0.unserialize(cp, csprintf("%s.timer0", section));
598 timer2.unserialize(cp, csprintf("%s.timer2", section));
599 rtc.unserialize(cp, csprintf("%s.rtc", section));
600 }
601
602 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
603
604 SimObjectParam<Tsunami *> tsunami;
605 Param<time_t> time;
606 SimObjectParam<MemoryController *> mmu;
607 Param<Addr> addr;
608 SimObjectParam<Bus*> io_bus;
609 Param<Tick> pio_latency;
610 SimObjectParam<HierParams *> hier;
611 Param<Tick> frequency;
612
613 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
614
615 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
616
617 INIT_PARAM(tsunami, "Tsunami"),
618 INIT_PARAM(time, "System time to use (0 for actual time"),
619 INIT_PARAM(mmu, "Memory Controller"),
620 INIT_PARAM(addr, "Device Address"),
621 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
622 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
623 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
624 INIT_PARAM(frequency, "clock interrupt frequency")
625
626 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
627
628 CREATE_SIM_OBJECT(TsunamiIO)
629 {
630 return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier,
631 io_bus, pio_latency, frequency);
632 }
633
634 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)