tsunami_io.cc revision 3885:fd4067a5b903
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 * Authors: Ali Saidi
29 *          Andrew Schultz
30 *          Miguel Serrano
31 */
32
33/** @file
34 * Tsunami I/O including PIC, PIT, RTC, DMA
35 */
36
37#include <sys/time.h>
38
39#include <deque>
40#include <string>
41#include <vector>
42
43#include "base/trace.hh"
44#include "dev/pitreg.h"
45#include "dev/rtcreg.h"
46#include "dev/alpha/tsunami_cchip.hh"
47#include "dev/alpha/tsunami.hh"
48#include "dev/alpha/tsunami_io.hh"
49#include "dev/alpha/tsunamireg.h"
50#include "mem/packet.hh"
51#include "mem/packet_access.hh"
52#include "mem/port.hh"
53#include "sim/builder.hh"
54#include "sim/system.hh"
55
56using namespace std;
57//Should this be AlphaISA?
58using namespace TheISA;
59
60TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami, time_t t, Tick i)
61    : _name(n), event(tsunami, i), addr(0)
62{
63    memset(clock_data, 0, sizeof(clock_data));
64    stat_regA = RTCA_32768HZ | RTCA_1024HZ;
65    stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
66
67    struct tm tm;
68    gmtime_r(&t, &tm);
69
70    sec = tm.tm_sec;
71    min = tm.tm_min;
72    hour = tm.tm_hour;
73    wday = tm.tm_wday + 1;
74    mday = tm.tm_mday;
75    mon = tm.tm_mon + 1;
76    year = tm.tm_year;
77
78    DPRINTFN("Real-time clock set to %s", asctime(&tm));
79}
80
81void
82TsunamiIO::RTC::writeAddr(const uint8_t data)
83{
84    if (data <= RTC_STAT_REGD)
85        addr = data;
86    else
87        panic("RTC addresses over 0xD are not implemented.\n");
88}
89
90void
91TsunamiIO::RTC::writeData(const uint8_t data)
92{
93    if (addr < RTC_STAT_REGA)
94        clock_data[addr] = data;
95    else {
96        switch (addr) {
97          case RTC_STAT_REGA:
98            if (data != (RTCA_32768HZ | RTCA_1024HZ))
99                panic("Unimplemented RTC register A value write!\n");
100            stat_regA = data;
101            break;
102          case RTC_STAT_REGB:
103            if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
104                panic("Write to RTC reg B bits that are not implemented!\n");
105
106            if (data & RTCB_PRDC_IE) {
107                if (!event.scheduled())
108                    event.scheduleIntr();
109            } else {
110                if (event.scheduled())
111                    event.deschedule();
112            }
113            stat_regB = data;
114            break;
115          case RTC_STAT_REGC:
116          case RTC_STAT_REGD:
117            panic("RTC status registers C and D are not implemented.\n");
118            break;
119        }
120    }
121}
122
123uint8_t
124TsunamiIO::RTC::readData()
125{
126    if (addr < RTC_STAT_REGA)
127        return clock_data[addr];
128    else {
129        switch (addr) {
130          case RTC_STAT_REGA:
131            // toggle UIP bit for linux
132            stat_regA ^= RTCA_UIP;
133            return stat_regA;
134            break;
135          case RTC_STAT_REGB:
136            return stat_regB;
137            break;
138          case RTC_STAT_REGC:
139          case RTC_STAT_REGD:
140            return 0x00;
141            break;
142          default:
143            panic("Shouldn't be here");
144        }
145    }
146}
147
148void
149TsunamiIO::RTC::serialize(const string &base, ostream &os)
150{
151    paramOut(os, base + ".addr", addr);
152    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
153    paramOut(os, base + ".stat_regA", stat_regA);
154    paramOut(os, base + ".stat_regB", stat_regB);
155}
156
157void
158TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
159                            const string &section)
160{
161    paramIn(cp, section, base + ".addr", addr);
162    arrayParamIn(cp, section, base + ".clock_data", clock_data,
163                 sizeof(clock_data));
164    paramIn(cp, section, base + ".stat_regA", stat_regA);
165    paramIn(cp, section, base + ".stat_regB", stat_regB);
166
167    // We're not unserializing the event here, but we need to
168    // rescehedule the event since curTick was moved forward by the
169    // checkpoint
170    event.reschedule(curTick + event.interval);
171}
172
173TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
174    : Event(&mainEventQueue), tsunami(t), interval(i)
175{
176    DPRINTF(MC146818, "RTC Event Initilizing\n");
177    schedule(curTick + interval);
178}
179
180void
181TsunamiIO::RTC::RTCEvent::scheduleIntr()
182{
183  schedule(curTick + interval);
184}
185
186void
187TsunamiIO::RTC::RTCEvent::process()
188{
189    DPRINTF(MC146818, "RTC Timer Interrupt\n");
190    schedule(curTick + interval);
191    //Actually interrupt the processor here
192    tsunami->cchip->postRTC();
193}
194
195const char *
196TsunamiIO::RTC::RTCEvent::description()
197{
198    return "tsunami RTC interrupt";
199}
200
201TsunamiIO::PITimer::PITimer(const string &name)
202    : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
203      counter2(name + ".counter2")
204{
205    counter[0] = &counter0;
206    counter[1] = &counter0;
207    counter[2] = &counter0;
208}
209
210void
211TsunamiIO::PITimer::writeControl(const uint8_t data)
212{
213    int rw;
214    int sel;
215
216    sel = GET_CTRL_SEL(data);
217
218    if (sel == PIT_READ_BACK)
219       panic("PITimer Read-Back Command is not implemented.\n");
220
221    rw = GET_CTRL_RW(data);
222
223    if (rw == PIT_RW_LATCH_COMMAND)
224        counter[sel]->latchCount();
225    else {
226        counter[sel]->setRW(rw);
227        counter[sel]->setMode(GET_CTRL_MODE(data));
228        counter[sel]->setBCD(GET_CTRL_BCD(data));
229    }
230}
231
232void
233TsunamiIO::PITimer::serialize(const string &base, ostream &os)
234{
235    // serialize the counters
236    counter0.serialize(base + ".counter0", os);
237    counter1.serialize(base + ".counter1", os);
238    counter2.serialize(base + ".counter2", os);
239}
240
241void
242TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
243                                const string &section)
244{
245    // unserialze the counters
246    counter0.unserialize(base + ".counter0", cp, section);
247    counter1.unserialize(base + ".counter1", cp, section);
248    counter2.unserialize(base + ".counter2", cp, section);
249}
250
251TsunamiIO::PITimer::Counter::Counter(const string &name)
252    : _name(name), event(this), count(0), latched_count(0), period(0),
253      mode(0), output_high(false), latch_on(false), read_byte(LSB),
254      write_byte(LSB)
255{
256
257}
258
259void
260TsunamiIO::PITimer::Counter::latchCount()
261{
262    // behave like a real latch
263    if(!latch_on) {
264        latch_on = true;
265        read_byte = LSB;
266        latched_count = count;
267    }
268}
269
270uint8_t
271TsunamiIO::PITimer::Counter::read()
272{
273    if (latch_on) {
274        switch (read_byte) {
275          case LSB:
276            read_byte = MSB;
277            return (uint8_t)latched_count;
278            break;
279          case MSB:
280            read_byte = LSB;
281            latch_on = false;
282            return latched_count >> 8;
283            break;
284          default:
285            panic("Shouldn't be here");
286        }
287    } else {
288        switch (read_byte) {
289          case LSB:
290            read_byte = MSB;
291            return (uint8_t)count;
292            break;
293          case MSB:
294            read_byte = LSB;
295            return count >> 8;
296            break;
297          default:
298            panic("Shouldn't be here");
299        }
300    }
301}
302
303void
304TsunamiIO::PITimer::Counter::write(const uint8_t data)
305{
306    switch (write_byte) {
307      case LSB:
308        count = (count & 0xFF00) | data;
309
310        if (event.scheduled())
311          event.deschedule();
312        output_high = false;
313        write_byte = MSB;
314        break;
315
316      case MSB:
317        count = (count & 0x00FF) | (data << 8);
318        period = count;
319
320        if (period > 0) {
321            DPRINTF(Tsunami, "Timer set to curTick + %d\n",
322                    count * event.interval);
323            event.schedule(curTick + count * event.interval);
324        }
325        write_byte = LSB;
326        break;
327    }
328}
329
330void
331TsunamiIO::PITimer::Counter::setRW(int rw_val)
332{
333    if (rw_val != PIT_RW_16BIT)
334        panic("Only LSB/MSB read/write is implemented.\n");
335}
336
337void
338TsunamiIO::PITimer::Counter::setMode(int mode_val)
339{
340    if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
341       mode_val != PIT_MODE_SQWAVE)
342        panic("PIT mode %#x is not implemented: \n", mode_val);
343
344    mode = mode_val;
345}
346
347void
348TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
349{
350    if (bcd_val != PIT_BCD_FALSE)
351        panic("PITimer does not implement BCD counts.\n");
352}
353
354bool
355TsunamiIO::PITimer::Counter::outputHigh()
356{
357    return output_high;
358}
359
360void
361TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
362{
363    paramOut(os, base + ".count", count);
364    paramOut(os, base + ".latched_count", latched_count);
365    paramOut(os, base + ".period", period);
366    paramOut(os, base + ".mode", mode);
367    paramOut(os, base + ".output_high", output_high);
368    paramOut(os, base + ".latch_on", latch_on);
369    paramOut(os, base + ".read_byte", read_byte);
370    paramOut(os, base + ".write_byte", write_byte);
371
372    Tick event_tick = 0;
373    if (event.scheduled())
374        event_tick = event.when();
375    paramOut(os, base + ".event_tick", event_tick);
376}
377
378void
379TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
380                                         const string &section)
381{
382    paramIn(cp, section, base + ".count", count);
383    paramIn(cp, section, base + ".latched_count", latched_count);
384    paramIn(cp, section, base + ".period", period);
385    paramIn(cp, section, base + ".mode", mode);
386    paramIn(cp, section, base + ".output_high", output_high);
387    paramIn(cp, section, base + ".latch_on", latch_on);
388    paramIn(cp, section, base + ".read_byte", read_byte);
389    paramIn(cp, section, base + ".write_byte", write_byte);
390
391    Tick event_tick;
392    paramIn(cp, section, base + ".event_tick", event_tick);
393    if (event_tick)
394        event.schedule(event_tick);
395}
396
397TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
398    : Event(&mainEventQueue)
399{
400    interval = (Tick)(Clock::Float::s / 1193180.0);
401    counter = c_ptr;
402}
403
404void
405TsunamiIO::PITimer::Counter::CounterEvent::process()
406{
407    DPRINTF(Tsunami, "Timer Interrupt\n");
408    switch (counter->mode) {
409      case PIT_MODE_INTTC:
410        counter->output_high = true;
411      case PIT_MODE_RATEGEN:
412      case PIT_MODE_SQWAVE:
413        break;
414      default:
415        panic("Unimplemented PITimer mode.\n");
416    }
417}
418
419const char *
420TsunamiIO::PITimer::Counter::CounterEvent::description()
421{
422    return "tsunami 8254 Interval timer";
423}
424
425TsunamiIO::TsunamiIO(Params *p)
426    : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
427      rtc(p->name + ".rtc", p->tsunami, p->init_time, p->frequency)
428{
429    pioSize = 0x100;
430
431    // set the back pointer from tsunami to myself
432    tsunami->io = this;
433
434    timerData = 0;
435    picr = 0;
436    picInterrupting = false;
437}
438
439Tick
440TsunamiIO::frequency() const
441{
442    return Clock::Frequency / params()->frequency;
443}
444
445Tick
446TsunamiIO::read(PacketPtr pkt)
447{
448    assert(pkt->result == Packet::Unknown);
449    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
450
451    Addr daddr = pkt->getAddr() - pioAddr;
452
453    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(),
454            pkt->getSize(), daddr);
455
456    pkt->allocate();
457
458    if (pkt->getSize() == sizeof(uint8_t)) {
459        switch(daddr) {
460          // PIC1 mask read
461          case TSDEV_PIC1_MASK:
462            pkt->set(~mask1);
463            break;
464          case TSDEV_PIC2_MASK:
465            pkt->set(~mask2);
466            break;
467          case TSDEV_PIC1_ISR:
468              // !!! If this is modified 64bit case needs to be too
469              // Pal code has to do a 64 bit physical read because there is
470              // no load physical byte instruction
471              pkt->set(picr);
472              break;
473          case TSDEV_PIC2_ISR:
474              // PIC2 not implemnted... just return 0
475              pkt->set(0x00);
476              break;
477          case TSDEV_TMR0_DATA:
478            pkt->set(pitimer.counter0.read());
479            break;
480          case TSDEV_TMR1_DATA:
481            pkt->set(pitimer.counter1.read());
482            break;
483          case TSDEV_TMR2_DATA:
484            pkt->set(pitimer.counter2.read());
485            break;
486          case TSDEV_RTC_DATA:
487            pkt->set(rtc.readData());
488            break;
489          case TSDEV_CTRL_PORTB:
490            if (pitimer.counter2.outputHigh())
491                pkt->set(PORTB_SPKR_HIGH);
492            else
493                pkt->set(0x00);
494            break;
495          default:
496            panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize());
497        }
498    } else if (pkt->getSize() == sizeof(uint64_t)) {
499        if (daddr == TSDEV_PIC1_ISR)
500            pkt->set<uint64_t>(picr);
501        else
502           panic("I/O Read - invalid addr - va %#x size %d\n",
503                   pkt->getAddr(), pkt->getSize());
504    } else {
505       panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize());
506    }
507    pkt->result = Packet::Success;
508    return pioDelay;
509}
510
511Tick
512TsunamiIO::write(PacketPtr pkt)
513{
514    assert(pkt->result == Packet::Unknown);
515    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
516    Addr daddr = pkt->getAddr() - pioAddr;
517
518    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
519            pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>());
520
521    assert(pkt->getSize() == sizeof(uint8_t));
522
523    switch(daddr) {
524      case TSDEV_PIC1_MASK:
525        mask1 = ~(pkt->get<uint8_t>());
526        if ((picr & mask1) && !picInterrupting) {
527            picInterrupting = true;
528            tsunami->cchip->postDRIR(55);
529            DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
530        }
531        if ((!(picr & mask1)) && picInterrupting) {
532            picInterrupting = false;
533            tsunami->cchip->clearDRIR(55);
534            DPRINTF(Tsunami, "clearing pic interrupt\n");
535        }
536        break;
537      case TSDEV_PIC2_MASK:
538        mask2 = pkt->get<uint8_t>();
539        //PIC2 Not implemented to interrupt
540        break;
541      case TSDEV_PIC1_ACK:
542        // clear the interrupt on the PIC
543        picr &= ~(1 << (pkt->get<uint8_t>() & 0xF));
544        if (!(picr & mask1))
545            tsunami->cchip->clearDRIR(55);
546        break;
547      case TSDEV_DMA1_MODE:
548        mode1 = pkt->get<uint8_t>();
549        break;
550      case TSDEV_DMA2_MODE:
551        mode2 = pkt->get<uint8_t>();
552        break;
553      case TSDEV_TMR0_DATA:
554        pitimer.counter0.write(pkt->get<uint8_t>());
555        break;
556      case TSDEV_TMR1_DATA:
557        pitimer.counter1.write(pkt->get<uint8_t>());
558        break;
559      case TSDEV_TMR2_DATA:
560        pitimer.counter2.write(pkt->get<uint8_t>());
561        break;
562      case TSDEV_TMR_CTRL:
563        pitimer.writeControl(pkt->get<uint8_t>());
564        break;
565      case TSDEV_RTC_ADDR:
566        rtc.writeAddr(pkt->get<uint8_t>());
567        break;
568      case TSDEV_RTC_DATA:
569        rtc.writeData(pkt->get<uint8_t>());
570        break;
571      case TSDEV_KBD:
572      case TSDEV_DMA1_CMND:
573      case TSDEV_DMA2_CMND:
574      case TSDEV_DMA1_MMASK:
575      case TSDEV_DMA2_MMASK:
576      case TSDEV_PIC2_ACK:
577      case TSDEV_DMA1_RESET:
578      case TSDEV_DMA2_RESET:
579      case TSDEV_DMA1_MASK:
580      case TSDEV_DMA2_MASK:
581      case TSDEV_CTRL_PORTB:
582        break;
583      default:
584        panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>());
585    }
586
587    pkt->result = Packet::Success;
588    return pioDelay;
589}
590
591void
592TsunamiIO::postPIC(uint8_t bitvector)
593{
594    //PIC2 Is not implemented, because nothing of interest there
595    picr |= bitvector;
596    if (picr & mask1) {
597        tsunami->cchip->postDRIR(55);
598        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
599    }
600}
601
602void
603TsunamiIO::clearPIC(uint8_t bitvector)
604{
605    //PIC2 Is not implemented, because nothing of interest there
606    picr &= ~bitvector;
607    if (!(picr & mask1)) {
608        tsunami->cchip->clearDRIR(55);
609        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
610    }
611}
612
613void
614TsunamiIO::serialize(ostream &os)
615{
616    SERIALIZE_SCALAR(timerData);
617    SERIALIZE_SCALAR(mask1);
618    SERIALIZE_SCALAR(mask2);
619    SERIALIZE_SCALAR(mode1);
620    SERIALIZE_SCALAR(mode2);
621    SERIALIZE_SCALAR(picr);
622    SERIALIZE_SCALAR(picInterrupting);
623
624    // Serialize the timers
625    pitimer.serialize("pitimer", os);
626    rtc.serialize("rtc", os);
627}
628
629void
630TsunamiIO::unserialize(Checkpoint *cp, const string &section)
631{
632    UNSERIALIZE_SCALAR(timerData);
633    UNSERIALIZE_SCALAR(mask1);
634    UNSERIALIZE_SCALAR(mask2);
635    UNSERIALIZE_SCALAR(mode1);
636    UNSERIALIZE_SCALAR(mode2);
637    UNSERIALIZE_SCALAR(picr);
638    UNSERIALIZE_SCALAR(picInterrupting);
639
640    // Unserialize the timers
641    pitimer.unserialize("pitimer", cp, section);
642    rtc.unserialize("rtc", cp, section);
643}
644
645BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
646
647    Param<Addr> pio_addr;
648    Param<Tick> pio_latency;
649    Param<Tick> frequency;
650    SimObjectParam<Platform *> platform;
651    SimObjectParam<System *> system;
652    Param<time_t> time;
653    SimObjectParam<Tsunami *> tsunami;
654
655END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
656
657BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
658
659    INIT_PARAM(pio_addr, "Device Address"),
660    INIT_PARAM(pio_latency, "Programmed IO latency"),
661    INIT_PARAM(frequency, "clock interrupt frequency"),
662    INIT_PARAM(platform, "platform"),
663    INIT_PARAM(system, "system object"),
664    INIT_PARAM(time, "System time to use (0 for actual time"),
665    INIT_PARAM(tsunami, "Tsunami")
666
667END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
668
669CREATE_SIM_OBJECT(TsunamiIO)
670{
671    TsunamiIO::Params *p = new TsunamiIO::Params;
672    p->frequency = frequency;
673    p->name = getInstanceName();
674    p->pio_addr = pio_addr;
675    p->pio_delay = pio_latency;
676    p->platform = platform;
677    p->system = system;
678    p->init_time = time;
679    p->tsunami = tsunami;
680    return new TsunamiIO(p);
681}
682
683REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
684