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 "dev/pitreg.h"
43 #include "mem/bus/bus.hh"
44 #include "mem/bus/pio_interface.hh"
45 #include "mem/bus/pio_interface_impl.hh"
46 #include "sim/builder.hh"
47 #include "dev/tsunami_cchip.hh"
48 #include "dev/tsunamireg.h"
49 #include "dev/rtcreg.h"
50 #include "mem/functional/memory_control.hh"
54 TsunamiIO::RTC::RTC(Tsunami
* t
, Tick i
)
55 : SimObject("RTC"), event(t
, i
), addr(0)
57 memset(clock_data
, 0, sizeof(clock_data
));
58 stat_regA
= RTCA_32768HZ
| RTCA_1024HZ
;
59 stat_regB
= RTCB_PRDC_IE
|RTCB_BIN
| RTCB_24HR
;
63 TsunamiIO::RTC::set_time(time_t t
)
71 wday
= tm
.tm_wday
+ 1;
76 DPRINTFN("Real-time clock set to %s", asctime(&tm
));
80 TsunamiIO::RTC::writeAddr(const uint8_t *data
)
82 if (*data
<= RTC_STAT_REGD
)
85 panic("RTC addresses over 0xD are not implemented.\n");
89 TsunamiIO::RTC::writeData(const uint8_t *data
)
91 if (addr
< RTC_STAT_REGA
)
92 clock_data
[addr
] = *data
;
96 if (*data
!= (RTCA_32768HZ
| RTCA_1024HZ
))
97 panic("Unimplemented RTC register A value write!\n");
101 if ((*data
& ~(RTCB_PRDC_IE
| RTCB_SQWE
)) != (RTCB_BIN
| RTCB_24HR
))
102 panic("Write to RTC reg B bits that are not implemented!\n");
104 if (*data
& RTCB_PRDC_IE
) {
105 if (!event
.scheduled())
106 event
.scheduleIntr();
108 if (event
.scheduled())
115 panic("RTC status registers C and D are not implemented.\n");
122 TsunamiIO::RTC::readData(uint8_t *data
)
124 if (addr
< RTC_STAT_REGA
)
125 *data
= clock_data
[addr
];
129 // toggle UIP bit for linux
130 stat_regA
^= RTCA_UIP
;
145 TsunamiIO::RTC::serialize(std::ostream
&os
)
147 SERIALIZE_SCALAR(addr
);
148 SERIALIZE_ARRAY(clock_data
, sizeof(clock_data
));
149 SERIALIZE_SCALAR(stat_regA
);
150 SERIALIZE_SCALAR(stat_regB
);
152 // serialize the RTC event
153 nameOut(os
, csprintf("%s.event", name()));
158 TsunamiIO::RTC::unserialize(Checkpoint
*cp
, const std::string
§ion
)
160 UNSERIALIZE_SCALAR(addr
);
161 UNSERIALIZE_ARRAY(clock_data
, sizeof(clock_data
));
162 UNSERIALIZE_SCALAR(stat_regA
);
163 UNSERIALIZE_SCALAR(stat_regB
);
165 // unserialze the event
166 event
.unserialize(cp
, csprintf("%s.event", section
));
169 TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami
*t
, Tick i
)
170 : Event(&mainEventQueue
), tsunami(t
), interval(i
)
172 DPRINTF(MC146818
, "RTC Event Initilizing\n");
173 schedule(curTick
+ interval
);
177 TsunamiIO::RTC::RTCEvent::scheduleIntr()
179 schedule(curTick
+ interval
);
183 TsunamiIO::RTC::RTCEvent::process()
185 DPRINTF(MC146818
, "RTC Timer Interrupt\n");
186 schedule(curTick
+ interval
);
187 //Actually interrupt the processor here
188 tsunami
->cchip
->postRTC();
192 TsunamiIO::RTC::RTCEvent::description()
194 return "tsunami RTC interrupt";
198 TsunamiIO::RTC::RTCEvent::serialize(std::ostream
&os
)
201 SERIALIZE_SCALAR(time
);
205 TsunamiIO::RTC::RTCEvent::unserialize(Checkpoint
*cp
, const std::string
§ion
)
208 UNSERIALIZE_SCALAR(time
);
212 TsunamiIO::PITimer::PITimer()
213 : SimObject("PITimer"), counter0(counter
[0]), counter1(counter
[1]),
220 TsunamiIO::PITimer::writeControl(const uint8_t *data
)
225 sel
= GET_CTRL_SEL(*data
);
227 if (sel
== PIT_READ_BACK
)
228 panic("PITimer Read-Back Command is not implemented.\n");
230 rw
= GET_CTRL_RW(*data
);
232 if (rw
== PIT_RW_LATCH_COMMAND
)
233 counter
[sel
].latchCount();
235 counter
[sel
].setRW(rw
);
236 counter
[sel
].setMode(GET_CTRL_MODE(*data
));
237 counter
[sel
].setBCD(GET_CTRL_BCD(*data
));
242 TsunamiIO::PITimer::serialize(std::ostream
&os
)
244 // serialize the counters
245 nameOut(os
, csprintf("%s.counter0", name()));
246 counter0
.serialize(os
);
248 nameOut(os
, csprintf("%s.counter1", name()));
249 counter1
.serialize(os
);
251 nameOut(os
, csprintf("%s.counter2", name()));
252 counter2
.serialize(os
);
256 TsunamiIO::PITimer::unserialize(Checkpoint
*cp
, const std::string
§ion
)
258 // unserialze the counters
259 counter0
.unserialize(cp
, csprintf("%s.counter0", section
));
260 counter1
.unserialize(cp
, csprintf("%s.counter1", section
));
261 counter2
.unserialize(cp
, csprintf("%s.counter2", section
));
264 TsunamiIO::PITimer::Counter::Counter()
265 : SimObject("Counter"), event(this), count(0), latched_count(0), period(0),
266 mode(0), output_high(false), latch_on(false), read_byte(LSB
),
273 TsunamiIO::PITimer::Counter::latchCount()
275 // behave like a real latch
279 latched_count
= count
;
284 TsunamiIO::PITimer::Counter::read(uint8_t *data
)
290 *data
= (uint8_t)latched_count
;
295 *data
= latched_count
>> 8;
302 *data
= (uint8_t)count
;
313 TsunamiIO::PITimer::Counter::write(const uint8_t *data
)
315 switch (write_byte
) {
317 count
= (count
& 0xFF00) | *data
;
319 if (event
.scheduled())
326 count
= (count
& 0x00FF) | (*data
<< 8);
330 DPRINTF(Tsunami
, "Timer set to curTick + %d\n", count
* event
.interval
);
331 event
.schedule(curTick
+ count
* event
.interval
);
339 TsunamiIO::PITimer::Counter::setRW(int rw_val
)
341 if (rw_val
!= PIT_RW_16BIT
)
342 panic("Only LSB/MSB read/write is implemented.\n");
346 TsunamiIO::PITimer::Counter::setMode(int mode_val
)
348 if(mode_val
!= PIT_MODE_INTTC
&& mode_val
!= PIT_MODE_RATEGEN
&&
349 mode_val
!= PIT_MODE_SQWAVE
)
350 panic("PIT mode %#x is not implemented: \n", mode_val
);
356 TsunamiIO::PITimer::Counter::setBCD(int bcd_val
)
358 if (bcd_val
!= PIT_BCD_FALSE
)
359 panic("PITimer does not implement BCD counts.\n");
363 TsunamiIO::PITimer::Counter::outputHigh()
369 TsunamiIO::PITimer::Counter::serialize(std::ostream
&os
)
371 SERIALIZE_SCALAR(count
);
372 SERIALIZE_SCALAR(latched_count
);
373 SERIALIZE_SCALAR(period
);
374 SERIALIZE_SCALAR(mode
);
375 SERIALIZE_SCALAR(output_high
);
376 SERIALIZE_SCALAR(latch_on
);
377 SERIALIZE_SCALAR(read_byte
);
378 SERIALIZE_SCALAR(write_byte
);
380 // serialize the counter event
381 nameOut(os
, csprintf("%s.event", name()));
386 TsunamiIO::PITimer::Counter::unserialize(Checkpoint
*cp
, const std::string
§ion
)
388 UNSERIALIZE_SCALAR(count
);
389 UNSERIALIZE_SCALAR(latched_count
);
390 UNSERIALIZE_SCALAR(period
);
391 UNSERIALIZE_SCALAR(mode
);
392 UNSERIALIZE_SCALAR(output_high
);
393 UNSERIALIZE_SCALAR(latch_on
);
394 UNSERIALIZE_SCALAR(read_byte
);
395 UNSERIALIZE_SCALAR(write_byte
);
397 // unserialze the counter event
398 event
.unserialize(cp
, csprintf("%s.event", section
));
401 TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter
* c_ptr
)
402 : Event(&mainEventQueue
)
404 interval
= (Tick
)(Clock::Float::s
/ 1193180.0);
409 TsunamiIO::PITimer::Counter::CounterEvent::process()
411 DPRINTF(Tsunami
, "Timer Interrupt\n");
412 switch (counter
->mode
) {
414 counter
->output_high
= true;
415 case PIT_MODE_RATEGEN
:
416 case PIT_MODE_SQWAVE
:
419 panic("Unimplemented PITimer mode.\n");
424 TsunamiIO::PITimer::Counter::CounterEvent::description()
426 return "tsunami 8254 Interval timer";
430 TsunamiIO::PITimer::Counter::CounterEvent::serialize(std::ostream
&os
)
432 Tick time
= scheduled() ? when() : 0;
433 SERIALIZE_SCALAR(time
);
434 SERIALIZE_SCALAR(interval
);
438 TsunamiIO::PITimer::Counter::CounterEvent::unserialize(Checkpoint
*cp
, const std::string
§ion
)
441 UNSERIALIZE_SCALAR(time
);
442 UNSERIALIZE_SCALAR(interval
);
447 TsunamiIO::TsunamiIO(const string
&name
, Tsunami
*t
, time_t init_time
,
448 Addr a
, MemoryController
*mmu
, HierParams
*hier
, Bus
*bus
,
449 Tick pio_latency
, Tick ci
)
450 : PioDevice(name
, t
), addr(a
), clockInterval(ci
), tsunami(t
), rtc(t
, ci
)
452 mmu
->add_child(this, RangeSize(addr
, size
));
455 pioInterface
= newPioInterface(name
, hier
, bus
, this,
456 &TsunamiIO::cacheAccess
);
457 pioInterface
->addAddrRange(RangeSize(addr
, size
));
458 pioLatency
= pio_latency
* bus
->clockRate
;
461 // set the back pointer from tsunami to myself
465 rtc
.set_time(init_time
== 0 ? time(NULL
) : init_time
);
467 picInterrupting
= false;
471 TsunamiIO::frequency() const
473 return Clock::Frequency
/ clockInterval
;
477 TsunamiIO::read(MemReqPtr
&req
, uint8_t *data
)
479 DPRINTF(Tsunami
, "io read va=%#x size=%d IOPorrt=%#x\n",
480 req
->vaddr
, req
->size
, req
->vaddr
& 0xfff);
482 Addr daddr
= (req
->paddr
- (addr
& EV5::PAddrImplMask
));
486 case sizeof(uint8_t):
489 case TSDEV_PIC1_MASK
:
490 *(uint8_t*)data
= ~mask1
;
492 case TSDEV_PIC2_MASK
:
493 *(uint8_t*)data
= ~mask2
;
496 // !!! If this is modified 64bit case needs to be too
497 // Pal code has to do a 64 bit physical read because there is
498 // no load physical byte instruction
499 *(uint8_t*)data
= picr
;
502 // PIC2 not implemnted... just return 0
503 *(uint8_t*)data
= 0x00;
505 case TSDEV_TMR0_DATA
:
506 pitimer
.counter0
.read(data
);
508 case TSDEV_TMR1_DATA
:
509 pitimer
.counter1
.read(data
);
511 case TSDEV_TMR2_DATA
:
512 pitimer
.counter2
.read(data
);
517 case TSDEV_CTRL_PORTB
:
518 if (pitimer
.counter2
.outputHigh())
519 *data
= PORTB_SPKR_HIGH
;
524 panic("I/O Read - va%#x size %d\n", req
->vaddr
, req
->size
);
526 case sizeof(uint16_t):
527 case sizeof(uint32_t):
528 panic("I/O Read - invalid size - va %#x size %d\n",
529 req
->vaddr
, req
->size
);
531 case sizeof(uint64_t):
534 // !!! If this is modified 8bit case needs to be too
535 // Pal code has to do a 64 bit physical read because there is
536 // no load physical byte instruction
537 *(uint64_t*)data
= (uint64_t)picr
;
540 panic("I/O Read - invalid size - va %#x size %d\n",
541 req
->vaddr
, req
->size
);
545 panic("I/O Read - invalid size - va %#x size %d\n",
546 req
->vaddr
, req
->size
);
548 panic("I/O Read - va%#x size %d\n", req
->vaddr
, req
->size
);
554 TsunamiIO::write(MemReqPtr
&req
, const uint8_t *data
)
558 uint8_t dt
= *(uint8_t*)data
;
562 DPRINTF(Tsunami
, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
563 req
->vaddr
, req
->size
, req
->vaddr
& 0xfff, dt64
);
565 Addr daddr
= (req
->paddr
- (addr
& EV5::PAddrImplMask
));
568 case sizeof(uint8_t):
570 case TSDEV_PIC1_MASK
:
571 mask1
= ~(*(uint8_t*)data
);
572 if ((picr
& mask1
) && !picInterrupting
) {
573 picInterrupting
= true;
574 tsunami
->cchip
->postDRIR(55);
575 DPRINTF(Tsunami
, "posting pic interrupt to cchip\n");
577 if ((!(picr
& mask1
)) && picInterrupting
) {
578 picInterrupting
= false;
579 tsunami
->cchip
->clearDRIR(55);
580 DPRINTF(Tsunami
, "clearing pic interrupt\n");
583 case TSDEV_PIC2_MASK
:
584 mask2
= *(uint8_t*)data
;
585 //PIC2 Not implemented to interrupt
588 // clear the interrupt on the PIC
589 picr
&= ~(1 << (*(uint8_t*)data
& 0xF));
591 tsunami
->cchip
->clearDRIR(55);
593 case TSDEV_DMA1_CMND
:
595 case TSDEV_DMA2_CMND
:
597 case TSDEV_DMA1_MMASK
:
599 case TSDEV_DMA2_MMASK
:
603 case TSDEV_DMA1_RESET
:
605 case TSDEV_DMA2_RESET
:
607 case TSDEV_DMA1_MODE
:
608 mode1
= *(uint8_t*)data
;
610 case TSDEV_DMA2_MODE
:
611 mode2
= *(uint8_t*)data
;
613 case TSDEV_DMA1_MASK
:
614 case TSDEV_DMA2_MASK
:
616 case TSDEV_TMR0_DATA
:
617 pitimer
.counter0
.write(data
);
619 case TSDEV_TMR1_DATA
:
620 pitimer
.counter1
.write(data
);
622 case TSDEV_TMR2_DATA
:
623 pitimer
.counter2
.write(data
);
626 pitimer
.writeControl(data
);
636 case TSDEV_CTRL_PORTB
:
637 // System Control Port B not implemented
640 panic("I/O Write - va%#x size %d data %#x\n", req
->vaddr
, req
->size
, (int)*data
);
642 case sizeof(uint16_t):
643 case sizeof(uint32_t):
644 case sizeof(uint64_t):
646 panic("I/O Write - invalid size - va %#x size %d\n",
647 req
->vaddr
, req
->size
);
655 TsunamiIO::postPIC(uint8_t bitvector
)
657 //PIC2 Is not implemented, because nothing of interest there
660 tsunami
->cchip
->postDRIR(55);
661 DPRINTF(Tsunami
, "posting pic interrupt to cchip\n");
666 TsunamiIO::clearPIC(uint8_t bitvector
)
668 //PIC2 Is not implemented, because nothing of interest there
670 if (!(picr
& mask1
)) {
671 tsunami
->cchip
->clearDRIR(55);
672 DPRINTF(Tsunami
, "clearing pic interrupt to cchip\n");
677 TsunamiIO::cacheAccess(MemReqPtr
&req
)
679 return curTick
+ pioLatency
;
683 TsunamiIO::serialize(std::ostream
&os
)
685 SERIALIZE_SCALAR(timerData
);
686 SERIALIZE_SCALAR(mask1
);
687 SERIALIZE_SCALAR(mask2
);
688 SERIALIZE_SCALAR(mode1
);
689 SERIALIZE_SCALAR(mode2
);
690 SERIALIZE_SCALAR(picr
);
691 SERIALIZE_SCALAR(picInterrupting
);
693 // Serialize the timers
694 nameOut(os
, csprintf("%s.pitimer", name()));
695 pitimer
.serialize(os
);
696 nameOut(os
, csprintf("%s.rtc", name()));
701 TsunamiIO::unserialize(Checkpoint
*cp
, const std::string
§ion
)
703 UNSERIALIZE_SCALAR(timerData
);
704 UNSERIALIZE_SCALAR(mask1
);
705 UNSERIALIZE_SCALAR(mask2
);
706 UNSERIALIZE_SCALAR(mode1
);
707 UNSERIALIZE_SCALAR(mode2
);
708 UNSERIALIZE_SCALAR(picr
);
709 UNSERIALIZE_SCALAR(picInterrupting
);
711 // Unserialize the timers
712 pitimer
.unserialize(cp
, csprintf("%s.pitimer", section
));
713 rtc
.unserialize(cp
, csprintf("%s.rtc", section
));
716 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO
)
718 SimObjectParam
<Tsunami
*> tsunami
;
720 SimObjectParam
<MemoryController
*> mmu
;
722 SimObjectParam
<Bus
*> io_bus
;
723 Param
<Tick
> pio_latency
;
724 SimObjectParam
<HierParams
*> hier
;
725 Param
<Tick
> frequency
;
727 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO
)
729 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO
)
731 INIT_PARAM(tsunami
, "Tsunami"),
732 INIT_PARAM(time
, "System time to use (0 for actual time"),
733 INIT_PARAM(mmu
, "Memory Controller"),
734 INIT_PARAM(addr
, "Device Address"),
735 INIT_PARAM_DFLT(io_bus
, "The IO Bus to attach to", NULL
),
736 INIT_PARAM_DFLT(pio_latency
, "Programmed IO latency in bus cycles", 1),
737 INIT_PARAM_DFLT(hier
, "Hierarchy global variables", &defaultHierParams
),
738 INIT_PARAM(frequency
, "clock interrupt frequency")
740 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO
)
742 CREATE_SIM_OBJECT(TsunamiIO
)
744 return new TsunamiIO(getInstanceName(), tsunami
, time
, addr
, mmu
, hier
,
745 io_bus
, pio_latency
, frequency
);
748 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO
)