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