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