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.
34 * Tsunami I/O including PIC, PIT, RTC, DMA
43 #include "base/time.hh"
44 #include "base/trace.hh"
45 #include "dev/pitreg.h"
46 #include "dev/rtcreg.h"
47 #include "dev/alpha/tsunami_cchip.hh"
48 #include "dev/alpha/tsunami.hh"
49 #include "dev/alpha/tsunami_io.hh"
50 #include "dev/alpha/tsunamireg.h"
51 #include "mem/packet.hh"
52 #include "mem/packet_access.hh"
53 #include "mem/port.hh"
54 #include "sim/system.hh"
57 //Should this be AlphaISA?
58 using namespace TheISA
;
60 TsunamiIO::RTC::RTC(const string
&n
, Tsunami
* tsunami
,
61 const TsunamiIO::Params
*p
)
62 : _name(n
), event(tsunami
, p
->frequency
), addr(0)
64 memset(clock_data
, 0, sizeof(clock_data
));
65 stat_regA
= RTCA_32768HZ
| RTCA_1024HZ
;
66 stat_regB
= RTCB_PRDC_IE
|RTCB_BIN
| RTCB_24HR
;
68 year
= p
->time
.tm_year
;
71 // The datasheet says that the year field can be either BCD or
72 // years since 1900. Linux seems to be happy with years since
77 year
= (tens
<< 4) + ones
;
80 // Unix is 0-11 for month, data seet says start at 1
81 mon
= p
->time
.tm_mon
+ 1;
82 mday
= p
->time
.tm_mday
;
83 hour
= p
->time
.tm_hour
;
87 // Datasheet says 1 is sunday
88 wday
= p
->time
.tm_wday
+ 1;
90 DPRINTFN("Real-time clock set to %s", asctime(&p
->time
));
94 TsunamiIO::RTC::writeAddr(const uint8_t data
)
96 if (data
<= RTC_STAT_REGD
)
99 panic("RTC addresses over 0xD are not implemented.\n");
103 TsunamiIO::RTC::writeData(const uint8_t data
)
105 if (addr
< RTC_STAT_REGA
)
106 clock_data
[addr
] = data
;
110 if (data
!= (RTCA_32768HZ
| RTCA_1024HZ
))
111 panic("Unimplemented RTC register A value write!\n");
115 if ((data
& ~(RTCB_PRDC_IE
| RTCB_SQWE
)) != (RTCB_BIN
| RTCB_24HR
))
116 panic("Write to RTC reg B bits that are not implemented!\n");
118 if (data
& RTCB_PRDC_IE
) {
119 if (!event
.scheduled())
120 event
.scheduleIntr();
122 if (event
.scheduled())
129 panic("RTC status registers C and D are not implemented.\n");
136 TsunamiIO::RTC::readData()
138 if (addr
< RTC_STAT_REGA
)
139 return clock_data
[addr
];
143 // toggle UIP bit for linux
144 stat_regA
^= RTCA_UIP
;
155 panic("Shouldn't be here");
161 TsunamiIO::RTC::serialize(const string
&base
, ostream
&os
)
163 paramOut(os
, base
+ ".addr", addr
);
164 arrayParamOut(os
, base
+ ".clock_data", clock_data
, sizeof(clock_data
));
165 paramOut(os
, base
+ ".stat_regA", stat_regA
);
166 paramOut(os
, base
+ ".stat_regB", stat_regB
);
170 TsunamiIO::RTC::unserialize(const string
&base
, Checkpoint
*cp
,
171 const string
§ion
)
173 paramIn(cp
, section
, base
+ ".addr", addr
);
174 arrayParamIn(cp
, section
, base
+ ".clock_data", clock_data
,
176 paramIn(cp
, section
, base
+ ".stat_regA", stat_regA
);
177 paramIn(cp
, section
, base
+ ".stat_regB", stat_regB
);
179 // We're not unserializing the event here, but we need to
180 // rescehedule the event since curTick was moved forward by the
182 event
.reschedule(curTick
+ event
.interval
);
185 TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami
*t
, Tick i
)
186 : Event(&mainEventQueue
), tsunami(t
), interval(i
)
188 DPRINTF(MC146818
, "RTC Event Initilizing\n");
189 schedule(curTick
+ interval
);
193 TsunamiIO::RTC::RTCEvent::scheduleIntr()
195 schedule(curTick
+ interval
);
199 TsunamiIO::RTC::RTCEvent::process()
201 DPRINTF(MC146818
, "RTC Timer Interrupt\n");
202 schedule(curTick
+ interval
);
203 //Actually interrupt the processor here
204 tsunami
->cchip
->postRTC();
208 TsunamiIO::RTC::RTCEvent::description()
210 return "tsunami RTC interrupt";
213 TsunamiIO::PITimer::PITimer(const string
&name
)
214 : _name(name
), counter0(name
+ ".counter0"), counter1(name
+ ".counter1"),
215 counter2(name
+ ".counter2")
217 counter
[0] = &counter0
;
218 counter
[1] = &counter0
;
219 counter
[2] = &counter0
;
223 TsunamiIO::PITimer::writeControl(const uint8_t data
)
228 sel
= GET_CTRL_SEL(data
);
230 if (sel
== PIT_READ_BACK
)
231 panic("PITimer Read-Back Command is not implemented.\n");
233 rw
= GET_CTRL_RW(data
);
235 if (rw
== PIT_RW_LATCH_COMMAND
)
236 counter
[sel
]->latchCount();
238 counter
[sel
]->setRW(rw
);
239 counter
[sel
]->setMode(GET_CTRL_MODE(data
));
240 counter
[sel
]->setBCD(GET_CTRL_BCD(data
));
245 TsunamiIO::PITimer::serialize(const string
&base
, ostream
&os
)
247 // serialize the counters
248 counter0
.serialize(base
+ ".counter0", os
);
249 counter1
.serialize(base
+ ".counter1", os
);
250 counter2
.serialize(base
+ ".counter2", os
);
254 TsunamiIO::PITimer::unserialize(const string
&base
, Checkpoint
*cp
,
255 const string
§ion
)
257 // unserialze the counters
258 counter0
.unserialize(base
+ ".counter0", cp
, section
);
259 counter1
.unserialize(base
+ ".counter1", cp
, section
);
260 counter2
.unserialize(base
+ ".counter2", cp
, section
);
263 TsunamiIO::PITimer::Counter::Counter(const string
&name
)
264 : _name(name
), event(this), count(0), latched_count(0), period(0),
265 mode(0), output_high(false), latch_on(false), read_byte(LSB
),
272 TsunamiIO::PITimer::Counter::latchCount()
274 // behave like a real latch
278 latched_count
= count
;
283 TsunamiIO::PITimer::Counter::read()
289 return (uint8_t)latched_count
;
294 return latched_count
>> 8;
297 panic("Shouldn't be here");
303 return (uint8_t)count
;
310 panic("Shouldn't be here");
316 TsunamiIO::PITimer::Counter::write(const uint8_t data
)
318 switch (write_byte
) {
320 count
= (count
& 0xFF00) | data
;
322 if (event
.scheduled())
329 count
= (count
& 0x00FF) | (data
<< 8);
333 DPRINTF(Tsunami
, "Timer set to curTick + %d\n",
334 count
* event
.interval
);
335 event
.schedule(curTick
+ count
* event
.interval
);
343 TsunamiIO::PITimer::Counter::setRW(int rw_val
)
345 if (rw_val
!= PIT_RW_16BIT
)
346 panic("Only LSB/MSB read/write is implemented.\n");
350 TsunamiIO::PITimer::Counter::setMode(int mode_val
)
352 if(mode_val
!= PIT_MODE_INTTC
&& mode_val
!= PIT_MODE_RATEGEN
&&
353 mode_val
!= PIT_MODE_SQWAVE
)
354 panic("PIT mode %#x is not implemented: \n", mode_val
);
360 TsunamiIO::PITimer::Counter::setBCD(int bcd_val
)
362 if (bcd_val
!= PIT_BCD_FALSE
)
363 panic("PITimer does not implement BCD counts.\n");
367 TsunamiIO::PITimer::Counter::outputHigh()
373 TsunamiIO::PITimer::Counter::serialize(const string
&base
, ostream
&os
)
375 paramOut(os
, base
+ ".count", count
);
376 paramOut(os
, base
+ ".latched_count", latched_count
);
377 paramOut(os
, base
+ ".period", period
);
378 paramOut(os
, base
+ ".mode", mode
);
379 paramOut(os
, base
+ ".output_high", output_high
);
380 paramOut(os
, base
+ ".latch_on", latch_on
);
381 paramOut(os
, base
+ ".read_byte", read_byte
);
382 paramOut(os
, base
+ ".write_byte", write_byte
);
385 if (event
.scheduled())
386 event_tick
= event
.when();
387 paramOut(os
, base
+ ".event_tick", event_tick
);
391 TsunamiIO::PITimer::Counter::unserialize(const string
&base
, Checkpoint
*cp
,
392 const string
§ion
)
394 paramIn(cp
, section
, base
+ ".count", count
);
395 paramIn(cp
, section
, base
+ ".latched_count", latched_count
);
396 paramIn(cp
, section
, base
+ ".period", period
);
397 paramIn(cp
, section
, base
+ ".mode", mode
);
398 paramIn(cp
, section
, base
+ ".output_high", output_high
);
399 paramIn(cp
, section
, base
+ ".latch_on", latch_on
);
400 paramIn(cp
, section
, base
+ ".read_byte", read_byte
);
401 paramIn(cp
, section
, base
+ ".write_byte", write_byte
);
404 paramIn(cp
, section
, base
+ ".event_tick", event_tick
);
406 event
.schedule(event_tick
);
409 TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter
* c_ptr
)
410 : Event(&mainEventQueue
)
412 interval
= (Tick
)(Clock::Float::s
/ 1193180.0);
417 TsunamiIO::PITimer::Counter::CounterEvent::process()
419 DPRINTF(Tsunami
, "Timer Interrupt\n");
420 switch (counter
->mode
) {
422 counter
->output_high
= true;
423 case PIT_MODE_RATEGEN
:
424 case PIT_MODE_SQWAVE
:
427 panic("Unimplemented PITimer mode.\n");
432 TsunamiIO::PITimer::Counter::CounterEvent::description()
434 return "tsunami 8254 Interval timer";
437 TsunamiIO::TsunamiIO(const Params
*p
)
438 : BasicPioDevice(p
), tsunami(p
->tsunami
), pitimer(p
->name
+ "pitimer"),
439 rtc(p
->name
+ ".rtc", p
->tsunami
, p
)
443 // set the back pointer from tsunami to myself
448 picInterrupting
= false;
452 TsunamiIO::frequency() const
454 return Clock::Frequency
/ params()->frequency
;
458 TsunamiIO::read(PacketPtr pkt
)
460 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
462 Addr daddr
= pkt
->getAddr() - pioAddr
;
464 DPRINTF(Tsunami
, "io read va=%#x size=%d IOPorrt=%#x\n", pkt
->getAddr(),
465 pkt
->getSize(), daddr
);
469 if (pkt
->getSize() == sizeof(uint8_t)) {
472 case TSDEV_PIC1_MASK
:
475 case TSDEV_PIC2_MASK
:
479 // !!! If this is modified 64bit case needs to be too
480 // Pal code has to do a 64 bit physical read because there is
481 // no load physical byte instruction
485 // PIC2 not implemnted... just return 0
488 case TSDEV_TMR0_DATA
:
489 pkt
->set(pitimer
.counter0
.read());
491 case TSDEV_TMR1_DATA
:
492 pkt
->set(pitimer
.counter1
.read());
494 case TSDEV_TMR2_DATA
:
495 pkt
->set(pitimer
.counter2
.read());
498 pkt
->set(rtc
.readData());
500 case TSDEV_CTRL_PORTB
:
501 if (pitimer
.counter2
.outputHigh())
502 pkt
->set(PORTB_SPKR_HIGH
);
507 panic("I/O Read - va%#x size %d\n", pkt
->getAddr(), pkt
->getSize());
509 } else if (pkt
->getSize() == sizeof(uint64_t)) {
510 if (daddr
== TSDEV_PIC1_ISR
)
511 pkt
->set
<uint64_t>(picr
);
513 panic("I/O Read - invalid addr - va %#x size %d\n",
514 pkt
->getAddr(), pkt
->getSize());
516 panic("I/O Read - invalid size - va %#x size %d\n", pkt
->getAddr(), pkt
->getSize());
518 pkt
->makeAtomicResponse();
523 TsunamiIO::write(PacketPtr pkt
)
525 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
526 Addr daddr
= pkt
->getAddr() - pioAddr
;
528 DPRINTF(Tsunami
, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
529 pkt
->getAddr(), pkt
->getSize(), pkt
->getAddr() & 0xfff, (uint32_t)pkt
->get
<uint8_t>());
531 assert(pkt
->getSize() == sizeof(uint8_t));
534 case TSDEV_PIC1_MASK
:
535 mask1
= ~(pkt
->get
<uint8_t>());
536 if ((picr
& mask1
) && !picInterrupting
) {
537 picInterrupting
= true;
538 tsunami
->cchip
->postDRIR(55);
539 DPRINTF(Tsunami
, "posting pic interrupt to cchip\n");
541 if ((!(picr
& mask1
)) && picInterrupting
) {
542 picInterrupting
= false;
543 tsunami
->cchip
->clearDRIR(55);
544 DPRINTF(Tsunami
, "clearing pic interrupt\n");
547 case TSDEV_PIC2_MASK
:
548 mask2
= pkt
->get
<uint8_t>();
549 //PIC2 Not implemented to interrupt
552 // clear the interrupt on the PIC
553 picr
&= ~(1 << (pkt
->get
<uint8_t>() & 0xF));
555 tsunami
->cchip
->clearDRIR(55);
557 case TSDEV_DMA1_MODE
:
558 mode1
= pkt
->get
<uint8_t>();
560 case TSDEV_DMA2_MODE
:
561 mode2
= pkt
->get
<uint8_t>();
563 case TSDEV_TMR0_DATA
:
564 pitimer
.counter0
.write(pkt
->get
<uint8_t>());
566 case TSDEV_TMR1_DATA
:
567 pitimer
.counter1
.write(pkt
->get
<uint8_t>());
569 case TSDEV_TMR2_DATA
:
570 pitimer
.counter2
.write(pkt
->get
<uint8_t>());
573 pitimer
.writeControl(pkt
->get
<uint8_t>());
576 rtc
.writeAddr(pkt
->get
<uint8_t>());
579 rtc
.writeData(pkt
->get
<uint8_t>());
582 case TSDEV_DMA1_CMND
:
583 case TSDEV_DMA2_CMND
:
584 case TSDEV_DMA1_MMASK
:
585 case TSDEV_DMA2_MMASK
:
587 case TSDEV_DMA1_RESET
:
588 case TSDEV_DMA2_RESET
:
589 case TSDEV_DMA1_MASK
:
590 case TSDEV_DMA2_MASK
:
591 case TSDEV_CTRL_PORTB
:
594 panic("I/O Write - va%#x size %d data %#x\n", pkt
->getAddr(), pkt
->getSize(), pkt
->get
<uint8_t>());
597 pkt
->makeAtomicResponse();
602 TsunamiIO::postPIC(uint8_t bitvector
)
604 //PIC2 Is not implemented, because nothing of interest there
607 tsunami
->cchip
->postDRIR(55);
608 DPRINTF(Tsunami
, "posting pic interrupt to cchip\n");
613 TsunamiIO::clearPIC(uint8_t bitvector
)
615 //PIC2 Is not implemented, because nothing of interest there
617 if (!(picr
& mask1
)) {
618 tsunami
->cchip
->clearDRIR(55);
619 DPRINTF(Tsunami
, "clearing pic interrupt to cchip\n");
624 TsunamiIO::serialize(ostream
&os
)
626 SERIALIZE_SCALAR(timerData
);
627 SERIALIZE_SCALAR(mask1
);
628 SERIALIZE_SCALAR(mask2
);
629 SERIALIZE_SCALAR(mode1
);
630 SERIALIZE_SCALAR(mode2
);
631 SERIALIZE_SCALAR(picr
);
632 SERIALIZE_SCALAR(picInterrupting
);
634 // Serialize the timers
635 pitimer
.serialize("pitimer", os
);
636 rtc
.serialize("rtc", os
);
640 TsunamiIO::unserialize(Checkpoint
*cp
, const string
§ion
)
642 UNSERIALIZE_SCALAR(timerData
);
643 UNSERIALIZE_SCALAR(mask1
);
644 UNSERIALIZE_SCALAR(mask2
);
645 UNSERIALIZE_SCALAR(mode1
);
646 UNSERIALIZE_SCALAR(mode2
);
647 UNSERIALIZE_SCALAR(picr
);
648 UNSERIALIZE_SCALAR(picInterrupting
);
650 // Unserialize the timers
651 pitimer
.unserialize("pitimer", cp
, section
);
652 rtc
.unserialize("rtc", cp
, section
);
656 TsunamiIOParams::create()
658 return new TsunamiIO(this);