2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
30 * Tsunami I/O including PIC, PIT, RTC, DMA
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"
53 #define UNIX_YEAR_OFFSET 52
55 struct tm
TsunamiIO::tm
= { 0 };
57 // Timer Event for Periodic interrupt of RTC
58 TsunamiIO::RTCEvent::RTCEvent(Tsunami
* t
, Tick i
)
59 : Event(&mainEventQueue
), tsunami(t
), interval(i
)
61 DPRINTF(MC146818
, "RTC Event Initilizing\n");
63 schedule(curTick
+ interval
);
67 TsunamiIO::RTCEvent::process()
69 DPRINTF(MC146818
, "RTC Timer Interrupt\n");
70 schedule(curTick
+ interval
);
71 //Actually interrupt the processor here
72 tsunami
->cchip
->postRTC();
74 if (intr_count
== 1023)
75 tm
.tm_sec
= (tm
.tm_sec
+ 1) % 60;
77 intr_count
= (intr_count
+ 1) % 1024;
82 TsunamiIO::RTCEvent::description()
84 return "tsunami RTC interrupt";
88 TsunamiIO::RTCEvent::serialize(std::ostream
&os
)
91 SERIALIZE_SCALAR(time
);
95 TsunamiIO::RTCEvent::unserialize(Checkpoint
*cp
, const std::string
§ion
)
98 UNSERIALIZE_SCALAR(time
);
103 // Timer Event for PIT Timers
104 TsunamiIO::ClockEvent::ClockEvent()
105 : Event(&mainEventQueue
)
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
112 interval
= (Tick
)(Clock::Float::s
/ 1193180.0);
114 DPRINTF(Tsunami
, "Clock Event Initilizing\n");
120 read_byte
= READ_LSB
;
124 TsunamiIO::ClockEvent::process()
126 DPRINTF(Tsunami
, "Timer Interrupt\n");
128 status
= 0x20; // set bit that linux is looking for
130 schedule(curTick
+ interval
);
132 current_count
--; //decrement count
136 TsunamiIO::ClockEvent::Program(int count
)
138 DPRINTF(Tsunami
, "Timer set to curTick + %d\n", count
* interval
);
139 schedule(curTick
+ count
* interval
);
142 current_count
= (uint16_t)count
;
146 TsunamiIO::ClockEvent::description()
148 return "tsunami 8254 Interval timer";
152 TsunamiIO::ClockEvent::ChangeMode(uint8_t md
)
158 TsunamiIO::ClockEvent::Status()
164 TsunamiIO::ClockEvent::LatchCount()
166 // behave like a real latch
169 read_byte
= READ_LSB
;
170 latched_count
= current_count
;
175 TsunamiIO::ClockEvent::Read()
182 read_byte
= READ_MSB
;
183 result
= (uint8_t)latched_count
;
186 read_byte
= READ_LSB
;
188 result
= latched_count
>> 8;
194 read_byte
= READ_MSB
;
195 result
= (uint8_t)current_count
;
198 read_byte
= READ_LSB
;
199 result
= current_count
>> 8;
209 TsunamiIO::ClockEvent::serialize(std::ostream
&os
)
211 Tick time
= scheduled() ? when() : 0;
212 SERIALIZE_SCALAR(time
);
213 SERIALIZE_SCALAR(status
);
214 SERIALIZE_SCALAR(mode
);
215 SERIALIZE_SCALAR(interval
);
219 TsunamiIO::ClockEvent::unserialize(Checkpoint
*cp
, const std::string
§ion
)
222 UNSERIALIZE_SCALAR(time
);
223 UNSERIALIZE_SCALAR(status
);
224 UNSERIALIZE_SCALAR(mode
);
225 UNSERIALIZE_SCALAR(interval
);
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
)
235 mmu
->add_child(this, RangeSize(addr
, size
));
238 pioInterface
= newPioInterface(name
, hier
, bus
, this,
239 &TsunamiIO::cacheAccess
);
240 pioInterface
->addAddrRange(RangeSize(addr
, size
));
241 pioLatency
= pio_latency
* bus
->clockRate
;
244 // set the back pointer from tsunami to myself
248 set_time(init_time
== 0 ? time(NULL
) : init_time
);
251 picInterrupting
= false;
255 TsunamiIO::frequency() const
257 return Clock::Frequency
/ clockInterval
;
261 TsunamiIO::set_time(time_t t
)
264 DPRINTFN("Real-time clock set to %s", asctime(&tm
));
268 TsunamiIO::read(MemReqPtr
&req
, uint8_t *data
)
270 DPRINTF(Tsunami
, "io read va=%#x size=%d IOPorrt=%#x\n",
271 req
->vaddr
, req
->size
, req
->vaddr
& 0xfff);
273 Addr daddr
= (req
->paddr
- (addr
& EV5::PAddrImplMask
));
277 case sizeof(uint8_t):
280 case TSDEV_PIC1_MASK
:
281 *(uint8_t*)data
= ~mask1
;
283 case TSDEV_PIC2_MASK
:
284 *(uint8_t*)data
= ~mask2
;
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
;
293 // PIC2 not implemnted... just return 0
294 *(uint8_t*)data
= 0x00;
297 *(uint8_t*)data
= timer2
.Status();
299 case TSDEV_TMR0_DATA
:
300 *(uint8_t *)data
= timer0
.Read();
305 *(uint8_t*)data
= uip
<< 7 | 0x26;
309 // DM and 24/12 and UIE
310 *(uint8_t*)data
= 0x46;
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;
318 panic("RTC Control Register D not implemented");
320 *(uint8_t *)data
= tm
.tm_sec
;
325 // RTC alarm functionality is not currently implemented
326 *(uint8_t *)data
= 0x00;
329 *(uint8_t *)data
= tm
.tm_min
;
332 *(uint8_t *)data
= tm
.tm_hour
;
335 *(uint8_t *)data
= tm
.tm_wday
;
338 *(uint8_t *)data
= tm
.tm_mday
;
341 *(uint8_t *)data
= tm
.tm_mon
+ 1;
344 *(uint8_t *)data
= tm
.tm_year
- UNIX_YEAR_OFFSET
;
347 panic("Unknown RTC Address\n");
350 /* Added for keyboard reads */
352 *(uint8_t *)data
= 0x00;
354 /* Added for ATA PCI DMA */
356 *(uint8_t *)data
= 0x00;
359 panic("I/O Read - va%#x size %d\n", req
->vaddr
, req
->size
);
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
);
366 case sizeof(uint64_t):
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
;
375 panic("I/O Read - invalid size - va %#x size %d\n",
376 req
->vaddr
, req
->size
);
380 panic("I/O Read - invalid size - va %#x size %d\n",
381 req
->vaddr
, req
->size
);
383 panic("I/O Read - va%#x size %d\n", req
->vaddr
, req
->size
);
389 TsunamiIO::write(MemReqPtr
&req
, const uint8_t *data
)
393 uint8_t dt
= *(uint8_t*)data
;
397 DPRINTF(Tsunami
, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
398 req
->vaddr
, req
->size
, req
->vaddr
& 0xfff, dt64
);
400 Addr daddr
= (req
->paddr
- (addr
& EV5::PAddrImplMask
));
403 case sizeof(uint8_t):
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");
412 if ((!(picr
& mask1
)) && picInterrupting
) {
413 picInterrupting
= false;
414 tsunami
->cchip
->clearDRIR(55);
415 DPRINTF(Tsunami
, "clearing pic interrupt\n");
418 case TSDEV_PIC2_MASK
:
419 mask2
= *(uint8_t*)data
;
420 //PIC2 Not implemented to interrupt
423 // clear the interrupt on the PIC
424 picr
&= ~(1 << (*(uint8_t*)data
& 0xF));
426 tsunami
->cchip
->clearDRIR(55);
430 case TSDEV_DMA1_RESET
:
432 case TSDEV_DMA2_RESET
:
434 case TSDEV_DMA1_MODE
:
435 mode1
= *(uint8_t*)data
;
437 case TSDEV_DMA2_MODE
:
438 mode2
= *(uint8_t*)data
;
440 case TSDEV_DMA1_MASK
:
441 case TSDEV_DMA2_MASK
:
446 switch((*(uint8_t*)data
>> 4) & 0x3) {
448 switch(*(uint8_t*)data
>> 6) {
456 panic("Read Back Command not implemented\n");
462 panic("Only L/M write and Counter-Latch read supported\n");
465 switch(*(uint8_t*)data
>> 6) {
467 timer0
.ChangeMode((*(uint8_t*)data
& 0xF) >> 1);
470 timer2
.ChangeMode((*(uint8_t*)data
& 0xF) >> 1);
473 panic("Read Back Command not implemented\n");
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) {
481 timerData
+= *(uint8_t*)data
<< 8;
482 timer2
.Program(timerData
);
484 timerData
= *(uint8_t*)data
;
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) {
493 timerData
+= *(uint8_t*)data
<< 8;
494 timer0
.Program(timerData
);
496 timerData
= *(uint8_t*)data
;
501 RTCAddress
= *(uint8_t*)data
;
516 tm
.tm_sec
= *(uint8_t *)data
;
519 tm
.tm_min
= *(uint8_t *)data
;
522 tm
.tm_hour
= *(uint8_t *)data
;
525 tm
.tm_wday
= *(uint8_t *)data
;
528 tm
.tm_mday
= *(uint8_t *)data
;
531 tm
.tm_mon
= *(uint8_t *)data
- 1;
534 tm
.tm_year
= *(uint8_t *)data
+ UNIX_YEAR_OFFSET
;
536 //panic("RTC Write not implmented (rtc.o won't work)\n");
539 panic("I/O Write - va%#x size %d\n", req
->vaddr
, req
->size
);
541 case sizeof(uint16_t):
542 case sizeof(uint32_t):
543 case sizeof(uint64_t):
545 panic("I/O Write - invalid size - va %#x size %d\n",
546 req
->vaddr
, req
->size
);
554 TsunamiIO::postPIC(uint8_t bitvector
)
556 //PIC2 Is not implemented, because nothing of interest there
559 tsunami
->cchip
->postDRIR(55);
560 DPRINTF(Tsunami
, "posting pic interrupt to cchip\n");
565 TsunamiIO::clearPIC(uint8_t bitvector
)
567 //PIC2 Is not implemented, because nothing of interest there
569 if (!(picr
& mask1
)) {
570 tsunami
->cchip
->clearDRIR(55);
571 DPRINTF(Tsunami
, "clearing pic interrupt to cchip\n");
576 TsunamiIO::cacheAccess(MemReqPtr
&req
)
578 return curTick
+ pioLatency
;
582 TsunamiIO::serialize(std::ostream
&os
)
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
);
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()));
604 TsunamiIO::unserialize(Checkpoint
*cp
, const std::string
§ion
)
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
);
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
));
622 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO
)
624 SimObjectParam
<Tsunami
*> tsunami
;
626 SimObjectParam
<MemoryController
*> mmu
;
628 SimObjectParam
<Bus
*> io_bus
;
629 Param
<Tick
> pio_latency
;
630 SimObjectParam
<HierParams
*> hier
;
631 Param
<Tick
> frequency
;
633 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO
)
635 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO
)
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")
646 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO
)
648 CREATE_SIM_OBJECT(TsunamiIO
)
650 return new TsunamiIO(getInstanceName(), tsunami
, time
, addr
, mmu
, hier
,
651 io_bus
, pio_latency
, frequency
);
654 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO
)