tsunami_io.cc revision 5336:c7e21f4e5a2e
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/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"
55
56using namespace std;
57//Should this be AlphaISA?
58using namespace TheISA;
59
60TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami,
61                    const TsunamiIO::Params *p)
62    : _name(n), event(tsunami, p->frequency), addr(0)
63{
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;
67
68    year = p->time.tm_year;
69
70    if (p->year_is_bcd) {
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
73        // 1900.
74        year = year % 100;
75        int tens = year / 10;
76        int ones = year % 10;
77        year = (tens << 4) + ones;
78    }
79
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;
84    min = p->time.tm_min;
85    sec = p->time.tm_sec;
86
87    // Datasheet says 1 is sunday
88    wday = p->time.tm_wday + 1;
89
90    DPRINTFN("Real-time clock set to %s", asctime(&p->time));
91}
92
93void
94TsunamiIO::RTC::writeAddr(const uint8_t data)
95{
96    if (data <= RTC_STAT_REGD)
97        addr = data;
98    else
99        panic("RTC addresses over 0xD are not implemented.\n");
100}
101
102void
103TsunamiIO::RTC::writeData(const uint8_t data)
104{
105    if (addr < RTC_STAT_REGA)
106        clock_data[addr] = data;
107    else {
108        switch (addr) {
109          case RTC_STAT_REGA:
110            if (data != (RTCA_32768HZ | RTCA_1024HZ))
111                panic("Unimplemented RTC register A value write!\n");
112            stat_regA = data;
113            break;
114          case RTC_STAT_REGB:
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");
117
118            if (data & RTCB_PRDC_IE) {
119                if (!event.scheduled())
120                    event.scheduleIntr();
121            } else {
122                if (event.scheduled())
123                    event.deschedule();
124            }
125            stat_regB = data;
126            break;
127          case RTC_STAT_REGC:
128          case RTC_STAT_REGD:
129            panic("RTC status registers C and D are not implemented.\n");
130            break;
131        }
132    }
133}
134
135uint8_t
136TsunamiIO::RTC::readData()
137{
138    if (addr < RTC_STAT_REGA)
139        return clock_data[addr];
140    else {
141        switch (addr) {
142          case RTC_STAT_REGA:
143            // toggle UIP bit for linux
144            stat_regA ^= RTCA_UIP;
145            return stat_regA;
146            break;
147          case RTC_STAT_REGB:
148            return stat_regB;
149            break;
150          case RTC_STAT_REGC:
151          case RTC_STAT_REGD:
152            return 0x00;
153            break;
154          default:
155            panic("Shouldn't be here");
156        }
157    }
158}
159
160void
161TsunamiIO::RTC::serialize(const string &base, ostream &os)
162{
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);
167}
168
169void
170TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
171                            const string &section)
172{
173    paramIn(cp, section, base + ".addr", addr);
174    arrayParamIn(cp, section, base + ".clock_data", clock_data,
175                 sizeof(clock_data));
176    paramIn(cp, section, base + ".stat_regA", stat_regA);
177    paramIn(cp, section, base + ".stat_regB", stat_regB);
178
179    // We're not unserializing the event here, but we need to
180    // rescehedule the event since curTick was moved forward by the
181    // checkpoint
182    event.reschedule(curTick + event.interval);
183}
184
185TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
186    : Event(&mainEventQueue), tsunami(t), interval(i)
187{
188    DPRINTF(MC146818, "RTC Event Initilizing\n");
189    schedule(curTick + interval);
190}
191
192void
193TsunamiIO::RTC::RTCEvent::scheduleIntr()
194{
195  schedule(curTick + interval);
196}
197
198void
199TsunamiIO::RTC::RTCEvent::process()
200{
201    DPRINTF(MC146818, "RTC Timer Interrupt\n");
202    schedule(curTick + interval);
203    //Actually interrupt the processor here
204    tsunami->cchip->postRTC();
205}
206
207const char *
208TsunamiIO::RTC::RTCEvent::description() const
209{
210    return "tsunami RTC interrupt";
211}
212
213TsunamiIO::PITimer::PITimer(const string &name)
214    : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
215      counter2(name + ".counter2")
216{
217    counter[0] = &counter0;
218    counter[1] = &counter0;
219    counter[2] = &counter0;
220}
221
222void
223TsunamiIO::PITimer::writeControl(const uint8_t data)
224{
225    int rw;
226    int sel;
227
228    sel = GET_CTRL_SEL(data);
229
230    if (sel == PIT_READ_BACK)
231       panic("PITimer Read-Back Command is not implemented.\n");
232
233    rw = GET_CTRL_RW(data);
234
235    if (rw == PIT_RW_LATCH_COMMAND)
236        counter[sel]->latchCount();
237    else {
238        counter[sel]->setRW(rw);
239        counter[sel]->setMode(GET_CTRL_MODE(data));
240        counter[sel]->setBCD(GET_CTRL_BCD(data));
241    }
242}
243
244void
245TsunamiIO::PITimer::serialize(const string &base, ostream &os)
246{
247    // serialize the counters
248    counter0.serialize(base + ".counter0", os);
249    counter1.serialize(base + ".counter1", os);
250    counter2.serialize(base + ".counter2", os);
251}
252
253void
254TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
255                                const string &section)
256{
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);
261}
262
263TsunamiIO::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),
266      write_byte(LSB)
267{
268
269}
270
271void
272TsunamiIO::PITimer::Counter::latchCount()
273{
274    // behave like a real latch
275    if(!latch_on) {
276        latch_on = true;
277        read_byte = LSB;
278        latched_count = count;
279    }
280}
281
282uint8_t
283TsunamiIO::PITimer::Counter::read()
284{
285    if (latch_on) {
286        switch (read_byte) {
287          case LSB:
288            read_byte = MSB;
289            return (uint8_t)latched_count;
290            break;
291          case MSB:
292            read_byte = LSB;
293            latch_on = false;
294            return latched_count >> 8;
295            break;
296          default:
297            panic("Shouldn't be here");
298        }
299    } else {
300        switch (read_byte) {
301          case LSB:
302            read_byte = MSB;
303            return (uint8_t)count;
304            break;
305          case MSB:
306            read_byte = LSB;
307            return count >> 8;
308            break;
309          default:
310            panic("Shouldn't be here");
311        }
312    }
313}
314
315void
316TsunamiIO::PITimer::Counter::write(const uint8_t data)
317{
318    switch (write_byte) {
319      case LSB:
320        count = (count & 0xFF00) | data;
321
322        if (event.scheduled())
323          event.deschedule();
324        output_high = false;
325        write_byte = MSB;
326        break;
327
328      case MSB:
329        count = (count & 0x00FF) | (data << 8);
330        period = count;
331
332        if (period > 0) {
333            DPRINTF(Tsunami, "Timer set to curTick + %d\n",
334                    count * event.interval);
335            event.schedule(curTick + count * event.interval);
336        }
337        write_byte = LSB;
338        break;
339    }
340}
341
342void
343TsunamiIO::PITimer::Counter::setRW(int rw_val)
344{
345    if (rw_val != PIT_RW_16BIT)
346        panic("Only LSB/MSB read/write is implemented.\n");
347}
348
349void
350TsunamiIO::PITimer::Counter::setMode(int mode_val)
351{
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);
355
356    mode = mode_val;
357}
358
359void
360TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
361{
362    if (bcd_val != PIT_BCD_FALSE)
363        panic("PITimer does not implement BCD counts.\n");
364}
365
366bool
367TsunamiIO::PITimer::Counter::outputHigh()
368{
369    return output_high;
370}
371
372void
373TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
374{
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);
383
384    Tick event_tick = 0;
385    if (event.scheduled())
386        event_tick = event.when();
387    paramOut(os, base + ".event_tick", event_tick);
388}
389
390void
391TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
392                                         const string &section)
393{
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);
402
403    Tick event_tick;
404    paramIn(cp, section, base + ".event_tick", event_tick);
405    if (event_tick)
406        event.schedule(event_tick);
407}
408
409TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
410    : Event(&mainEventQueue)
411{
412    interval = (Tick)(Clock::Float::s / 1193180.0);
413    counter = c_ptr;
414}
415
416void
417TsunamiIO::PITimer::Counter::CounterEvent::process()
418{
419    DPRINTF(Tsunami, "Timer Interrupt\n");
420    switch (counter->mode) {
421      case PIT_MODE_INTTC:
422        counter->output_high = true;
423      case PIT_MODE_RATEGEN:
424      case PIT_MODE_SQWAVE:
425        break;
426      default:
427        panic("Unimplemented PITimer mode.\n");
428    }
429}
430
431const char *
432TsunamiIO::PITimer::Counter::CounterEvent::description() const
433{
434    return "tsunami 8254 Interval timer";
435}
436
437TsunamiIO::TsunamiIO(const Params *p)
438    : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
439      rtc(p->name + ".rtc", p->tsunami, p)
440{
441    pioSize = 0x100;
442
443    // set the back pointer from tsunami to myself
444    tsunami->io = this;
445
446    timerData = 0;
447    picr = 0;
448    picInterrupting = false;
449}
450
451Tick
452TsunamiIO::frequency() const
453{
454    return Clock::Frequency / params()->frequency;
455}
456
457Tick
458TsunamiIO::read(PacketPtr pkt)
459{
460    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
461
462    Addr daddr = pkt->getAddr() - pioAddr;
463
464    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(),
465            pkt->getSize(), daddr);
466
467    pkt->allocate();
468
469    if (pkt->getSize() == sizeof(uint8_t)) {
470        switch(daddr) {
471          // PIC1 mask read
472          case TSDEV_PIC1_MASK:
473            pkt->set(~mask1);
474            break;
475          case TSDEV_PIC2_MASK:
476            pkt->set(~mask2);
477            break;
478          case TSDEV_PIC1_ISR:
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
482              pkt->set(picr);
483              break;
484          case TSDEV_PIC2_ISR:
485              // PIC2 not implemnted... just return 0
486              pkt->set(0x00);
487              break;
488          case TSDEV_TMR0_DATA:
489            pkt->set(pitimer.counter0.read());
490            break;
491          case TSDEV_TMR1_DATA:
492            pkt->set(pitimer.counter1.read());
493            break;
494          case TSDEV_TMR2_DATA:
495            pkt->set(pitimer.counter2.read());
496            break;
497          case TSDEV_RTC_DATA:
498            pkt->set(rtc.readData());
499            break;
500          case TSDEV_CTRL_PORTB:
501            if (pitimer.counter2.outputHigh())
502                pkt->set(PORTB_SPKR_HIGH);
503            else
504                pkt->set(0x00);
505            break;
506          default:
507            panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize());
508        }
509    } else if (pkt->getSize() == sizeof(uint64_t)) {
510        if (daddr == TSDEV_PIC1_ISR)
511            pkt->set<uint64_t>(picr);
512        else
513           panic("I/O Read - invalid addr - va %#x size %d\n",
514                   pkt->getAddr(), pkt->getSize());
515    } else {
516       panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize());
517    }
518    pkt->makeAtomicResponse();
519    return pioDelay;
520}
521
522Tick
523TsunamiIO::write(PacketPtr pkt)
524{
525    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
526    Addr daddr = pkt->getAddr() - pioAddr;
527
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>());
530
531    assert(pkt->getSize() == sizeof(uint8_t));
532
533    switch(daddr) {
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");
540        }
541        if ((!(picr & mask1)) && picInterrupting) {
542            picInterrupting = false;
543            tsunami->cchip->clearDRIR(55);
544            DPRINTF(Tsunami, "clearing pic interrupt\n");
545        }
546        break;
547      case TSDEV_PIC2_MASK:
548        mask2 = pkt->get<uint8_t>();
549        //PIC2 Not implemented to interrupt
550        break;
551      case TSDEV_PIC1_ACK:
552        // clear the interrupt on the PIC
553        picr &= ~(1 << (pkt->get<uint8_t>() & 0xF));
554        if (!(picr & mask1))
555            tsunami->cchip->clearDRIR(55);
556        break;
557      case TSDEV_DMA1_MODE:
558        mode1 = pkt->get<uint8_t>();
559        break;
560      case TSDEV_DMA2_MODE:
561        mode2 = pkt->get<uint8_t>();
562        break;
563      case TSDEV_TMR0_DATA:
564        pitimer.counter0.write(pkt->get<uint8_t>());
565        break;
566      case TSDEV_TMR1_DATA:
567        pitimer.counter1.write(pkt->get<uint8_t>());
568        break;
569      case TSDEV_TMR2_DATA:
570        pitimer.counter2.write(pkt->get<uint8_t>());
571        break;
572      case TSDEV_TMR_CTRL:
573        pitimer.writeControl(pkt->get<uint8_t>());
574        break;
575      case TSDEV_RTC_ADDR:
576        rtc.writeAddr(pkt->get<uint8_t>());
577        break;
578      case TSDEV_RTC_DATA:
579        rtc.writeData(pkt->get<uint8_t>());
580        break;
581      case TSDEV_KBD:
582      case TSDEV_DMA1_CMND:
583      case TSDEV_DMA2_CMND:
584      case TSDEV_DMA1_MMASK:
585      case TSDEV_DMA2_MMASK:
586      case TSDEV_PIC2_ACK:
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:
592        break;
593      default:
594        panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>());
595    }
596
597    pkt->makeAtomicResponse();
598    return pioDelay;
599}
600
601void
602TsunamiIO::postPIC(uint8_t bitvector)
603{
604    //PIC2 Is not implemented, because nothing of interest there
605    picr |= bitvector;
606    if (picr & mask1) {
607        tsunami->cchip->postDRIR(55);
608        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
609    }
610}
611
612void
613TsunamiIO::clearPIC(uint8_t bitvector)
614{
615    //PIC2 Is not implemented, because nothing of interest there
616    picr &= ~bitvector;
617    if (!(picr & mask1)) {
618        tsunami->cchip->clearDRIR(55);
619        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
620    }
621}
622
623void
624TsunamiIO::serialize(ostream &os)
625{
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);
633
634    // Serialize the timers
635    pitimer.serialize("pitimer", os);
636    rtc.serialize("rtc", os);
637}
638
639void
640TsunamiIO::unserialize(Checkpoint *cp, const string &section)
641{
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);
649
650    // Unserialize the timers
651    pitimer.unserialize("pitimer", cp, section);
652    rtc.unserialize("rtc", cp, section);
653}
654
655TsunamiIO *
656TsunamiIOParams::create()
657{
658    return new TsunamiIO(this);
659}
660