tsunami_io.cc revision 5392:c3a45fac35f8
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::TsunamiRTC::TsunamiRTC(const string &n, const TsunamiIOParams *p) :
61    MC146818(n, p->time, p->year_is_bcd, p->frequency), tsunami(p->tsunami)
62{
63}
64
65TsunamiIO::PITimer::PITimer(const string &name)
66    : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
67      counter2(name + ".counter2")
68{
69    counter[0] = &counter0;
70    counter[1] = &counter0;
71    counter[2] = &counter0;
72}
73
74void
75TsunamiIO::PITimer::writeControl(const uint8_t data)
76{
77    int rw;
78    int sel;
79
80    sel = GET_CTRL_SEL(data);
81
82    if (sel == PIT_READ_BACK)
83       panic("PITimer Read-Back Command is not implemented.\n");
84
85    rw = GET_CTRL_RW(data);
86
87    if (rw == PIT_RW_LATCH_COMMAND)
88        counter[sel]->latchCount();
89    else {
90        counter[sel]->setRW(rw);
91        counter[sel]->setMode(GET_CTRL_MODE(data));
92        counter[sel]->setBCD(GET_CTRL_BCD(data));
93    }
94}
95
96void
97TsunamiIO::PITimer::serialize(const string &base, ostream &os)
98{
99    // serialize the counters
100    counter0.serialize(base + ".counter0", os);
101    counter1.serialize(base + ".counter1", os);
102    counter2.serialize(base + ".counter2", os);
103}
104
105void
106TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
107                                const string &section)
108{
109    // unserialze the counters
110    counter0.unserialize(base + ".counter0", cp, section);
111    counter1.unserialize(base + ".counter1", cp, section);
112    counter2.unserialize(base + ".counter2", cp, section);
113}
114
115TsunamiIO::PITimer::Counter::Counter(const string &name)
116    : _name(name), event(this), count(0), latched_count(0), period(0),
117      mode(0), output_high(false), latch_on(false), read_byte(LSB),
118      write_byte(LSB)
119{
120
121}
122
123void
124TsunamiIO::PITimer::Counter::latchCount()
125{
126    // behave like a real latch
127    if(!latch_on) {
128        latch_on = true;
129        read_byte = LSB;
130        latched_count = count;
131    }
132}
133
134uint8_t
135TsunamiIO::PITimer::Counter::read()
136{
137    if (latch_on) {
138        switch (read_byte) {
139          case LSB:
140            read_byte = MSB;
141            return (uint8_t)latched_count;
142            break;
143          case MSB:
144            read_byte = LSB;
145            latch_on = false;
146            return latched_count >> 8;
147            break;
148          default:
149            panic("Shouldn't be here");
150        }
151    } else {
152        switch (read_byte) {
153          case LSB:
154            read_byte = MSB;
155            return (uint8_t)count;
156            break;
157          case MSB:
158            read_byte = LSB;
159            return count >> 8;
160            break;
161          default:
162            panic("Shouldn't be here");
163        }
164    }
165}
166
167void
168TsunamiIO::PITimer::Counter::write(const uint8_t data)
169{
170    switch (write_byte) {
171      case LSB:
172        count = (count & 0xFF00) | data;
173
174        if (event.scheduled())
175          event.deschedule();
176        output_high = false;
177        write_byte = MSB;
178        break;
179
180      case MSB:
181        count = (count & 0x00FF) | (data << 8);
182        period = count;
183
184        if (period > 0) {
185            DPRINTF(Tsunami, "Timer set to curTick + %d\n",
186                    count * event.interval);
187            event.schedule(curTick + count * event.interval);
188        }
189        write_byte = LSB;
190        break;
191    }
192}
193
194void
195TsunamiIO::PITimer::Counter::setRW(int rw_val)
196{
197    if (rw_val != PIT_RW_16BIT)
198        panic("Only LSB/MSB read/write is implemented.\n");
199}
200
201void
202TsunamiIO::PITimer::Counter::setMode(int mode_val)
203{
204    if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
205       mode_val != PIT_MODE_SQWAVE)
206        panic("PIT mode %#x is not implemented: \n", mode_val);
207
208    mode = mode_val;
209}
210
211void
212TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
213{
214    if (bcd_val != PIT_BCD_FALSE)
215        panic("PITimer does not implement BCD counts.\n");
216}
217
218bool
219TsunamiIO::PITimer::Counter::outputHigh()
220{
221    return output_high;
222}
223
224void
225TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
226{
227    paramOut(os, base + ".count", count);
228    paramOut(os, base + ".latched_count", latched_count);
229    paramOut(os, base + ".period", period);
230    paramOut(os, base + ".mode", mode);
231    paramOut(os, base + ".output_high", output_high);
232    paramOut(os, base + ".latch_on", latch_on);
233    paramOut(os, base + ".read_byte", read_byte);
234    paramOut(os, base + ".write_byte", write_byte);
235
236    Tick event_tick = 0;
237    if (event.scheduled())
238        event_tick = event.when();
239    paramOut(os, base + ".event_tick", event_tick);
240}
241
242void
243TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
244                                         const string &section)
245{
246    paramIn(cp, section, base + ".count", count);
247    paramIn(cp, section, base + ".latched_count", latched_count);
248    paramIn(cp, section, base + ".period", period);
249    paramIn(cp, section, base + ".mode", mode);
250    paramIn(cp, section, base + ".output_high", output_high);
251    paramIn(cp, section, base + ".latch_on", latch_on);
252    paramIn(cp, section, base + ".read_byte", read_byte);
253    paramIn(cp, section, base + ".write_byte", write_byte);
254
255    Tick event_tick;
256    paramIn(cp, section, base + ".event_tick", event_tick);
257    if (event_tick)
258        event.schedule(event_tick);
259}
260
261TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
262    : Event(&mainEventQueue)
263{
264    interval = (Tick)(Clock::Float::s / 1193180.0);
265    counter = c_ptr;
266}
267
268void
269TsunamiIO::PITimer::Counter::CounterEvent::process()
270{
271    DPRINTF(Tsunami, "Timer Interrupt\n");
272    switch (counter->mode) {
273      case PIT_MODE_INTTC:
274        counter->output_high = true;
275      case PIT_MODE_RATEGEN:
276      case PIT_MODE_SQWAVE:
277        break;
278      default:
279        panic("Unimplemented PITimer mode.\n");
280    }
281}
282
283const char *
284TsunamiIO::PITimer::Counter::CounterEvent::description() const
285{
286    return "tsunami 8254 Interval timer";
287}
288
289TsunamiIO::TsunamiIO(const Params *p)
290    : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
291      rtc(p->name + ".rtc", p)
292{
293    pioSize = 0x100;
294
295    // set the back pointer from tsunami to myself
296    tsunami->io = this;
297
298    timerData = 0;
299    picr = 0;
300    picInterrupting = false;
301}
302
303Tick
304TsunamiIO::frequency() const
305{
306    return Clock::Frequency / params()->frequency;
307}
308
309Tick
310TsunamiIO::read(PacketPtr pkt)
311{
312    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
313
314    Addr daddr = pkt->getAddr() - pioAddr;
315
316    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(),
317            pkt->getSize(), daddr);
318
319    pkt->allocate();
320
321    if (pkt->getSize() == sizeof(uint8_t)) {
322        switch(daddr) {
323          // PIC1 mask read
324          case TSDEV_PIC1_MASK:
325            pkt->set(~mask1);
326            break;
327          case TSDEV_PIC2_MASK:
328            pkt->set(~mask2);
329            break;
330          case TSDEV_PIC1_ISR:
331              // !!! If this is modified 64bit case needs to be too
332              // Pal code has to do a 64 bit physical read because there is
333              // no load physical byte instruction
334              pkt->set(picr);
335              break;
336          case TSDEV_PIC2_ISR:
337              // PIC2 not implemnted... just return 0
338              pkt->set(0x00);
339              break;
340          case TSDEV_TMR0_DATA:
341            pkt->set(pitimer.counter0.read());
342            break;
343          case TSDEV_TMR1_DATA:
344            pkt->set(pitimer.counter1.read());
345            break;
346          case TSDEV_TMR2_DATA:
347            pkt->set(pitimer.counter2.read());
348            break;
349          case TSDEV_RTC_DATA:
350            pkt->set(rtc.readData(rtcAddr));
351            break;
352          case TSDEV_CTRL_PORTB:
353            if (pitimer.counter2.outputHigh())
354                pkt->set(PORTB_SPKR_HIGH);
355            else
356                pkt->set(0x00);
357            break;
358          default:
359            panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize());
360        }
361    } else if (pkt->getSize() == sizeof(uint64_t)) {
362        if (daddr == TSDEV_PIC1_ISR)
363            pkt->set<uint64_t>(picr);
364        else
365           panic("I/O Read - invalid addr - va %#x size %d\n",
366                   pkt->getAddr(), pkt->getSize());
367    } else {
368       panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize());
369    }
370    pkt->makeAtomicResponse();
371    return pioDelay;
372}
373
374Tick
375TsunamiIO::write(PacketPtr pkt)
376{
377    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
378    Addr daddr = pkt->getAddr() - pioAddr;
379
380    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
381            pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>());
382
383    assert(pkt->getSize() == sizeof(uint8_t));
384
385    switch(daddr) {
386      case TSDEV_PIC1_MASK:
387        mask1 = ~(pkt->get<uint8_t>());
388        if ((picr & mask1) && !picInterrupting) {
389            picInterrupting = true;
390            tsunami->cchip->postDRIR(55);
391            DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
392        }
393        if ((!(picr & mask1)) && picInterrupting) {
394            picInterrupting = false;
395            tsunami->cchip->clearDRIR(55);
396            DPRINTF(Tsunami, "clearing pic interrupt\n");
397        }
398        break;
399      case TSDEV_PIC2_MASK:
400        mask2 = pkt->get<uint8_t>();
401        //PIC2 Not implemented to interrupt
402        break;
403      case TSDEV_PIC1_ACK:
404        // clear the interrupt on the PIC
405        picr &= ~(1 << (pkt->get<uint8_t>() & 0xF));
406        if (!(picr & mask1))
407            tsunami->cchip->clearDRIR(55);
408        break;
409      case TSDEV_DMA1_MODE:
410        mode1 = pkt->get<uint8_t>();
411        break;
412      case TSDEV_DMA2_MODE:
413        mode2 = pkt->get<uint8_t>();
414        break;
415      case TSDEV_TMR0_DATA:
416        pitimer.counter0.write(pkt->get<uint8_t>());
417        break;
418      case TSDEV_TMR1_DATA:
419        pitimer.counter1.write(pkt->get<uint8_t>());
420        break;
421      case TSDEV_TMR2_DATA:
422        pitimer.counter2.write(pkt->get<uint8_t>());
423        break;
424      case TSDEV_TMR_CTRL:
425        pitimer.writeControl(pkt->get<uint8_t>());
426        break;
427      case TSDEV_RTC_ADDR:
428        rtcAddr = pkt->get<uint8_t>();
429        break;
430      case TSDEV_RTC_DATA:
431        rtc.writeData(rtcAddr, pkt->get<uint8_t>());
432        break;
433      case TSDEV_KBD:
434      case TSDEV_DMA1_CMND:
435      case TSDEV_DMA2_CMND:
436      case TSDEV_DMA1_MMASK:
437      case TSDEV_DMA2_MMASK:
438      case TSDEV_PIC2_ACK:
439      case TSDEV_DMA1_RESET:
440      case TSDEV_DMA2_RESET:
441      case TSDEV_DMA1_MASK:
442      case TSDEV_DMA2_MASK:
443      case TSDEV_CTRL_PORTB:
444        break;
445      default:
446        panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>());
447    }
448
449    pkt->makeAtomicResponse();
450    return pioDelay;
451}
452
453void
454TsunamiIO::postPIC(uint8_t bitvector)
455{
456    //PIC2 Is not implemented, because nothing of interest there
457    picr |= bitvector;
458    if (picr & mask1) {
459        tsunami->cchip->postDRIR(55);
460        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
461    }
462}
463
464void
465TsunamiIO::clearPIC(uint8_t bitvector)
466{
467    //PIC2 Is not implemented, because nothing of interest there
468    picr &= ~bitvector;
469    if (!(picr & mask1)) {
470        tsunami->cchip->clearDRIR(55);
471        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
472    }
473}
474
475void
476TsunamiIO::serialize(ostream &os)
477{
478    SERIALIZE_SCALAR(rtcAddr);
479    SERIALIZE_SCALAR(timerData);
480    SERIALIZE_SCALAR(mask1);
481    SERIALIZE_SCALAR(mask2);
482    SERIALIZE_SCALAR(mode1);
483    SERIALIZE_SCALAR(mode2);
484    SERIALIZE_SCALAR(picr);
485    SERIALIZE_SCALAR(picInterrupting);
486
487    // Serialize the timers
488    pitimer.serialize("pitimer", os);
489    rtc.serialize("rtc", os);
490}
491
492void
493TsunamiIO::unserialize(Checkpoint *cp, const string &section)
494{
495    UNSERIALIZE_SCALAR(rtcAddr);
496    UNSERIALIZE_SCALAR(timerData);
497    UNSERIALIZE_SCALAR(mask1);
498    UNSERIALIZE_SCALAR(mask2);
499    UNSERIALIZE_SCALAR(mode1);
500    UNSERIALIZE_SCALAR(mode2);
501    UNSERIALIZE_SCALAR(picr);
502    UNSERIALIZE_SCALAR(picInterrupting);
503
504    // Unserialize the timers
505    pitimer.unserialize("pitimer", cp, section);
506    rtc.unserialize("rtc", cp, section);
507}
508
509TsunamiIO *
510TsunamiIOParams::create()
511{
512    return new TsunamiIO(this);
513}
514