tsunami_io.cc revision 1634
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
29/* @file
30 * Tsunami I/O including PIC, PIT, RTC, DMA
31 */
32
33#include <sys/time.h>
34
35#include <deque>
36#include <string>
37#include <vector>
38
39#include "base/trace.hh"
40#include "dev/tsunami_io.hh"
41#include "dev/tsunami.hh"
42#include "mem/bus/bus.hh"
43#include "mem/bus/pio_interface.hh"
44#include "mem/bus/pio_interface_impl.hh"
45#include "sim/builder.hh"
46#include "dev/tsunami_cchip.hh"
47#include "dev/tsunamireg.h"
48#include "dev/rtcreg.h"
49#include "mem/functional_mem/memory_control.hh"
50
51using namespace std;
52
53#define UNIX_YEAR_OFFSET 52
54
55// Timer Event for Periodic interrupt of RTC
56TsunamiIO::RTCEvent::RTCEvent(Tsunami* t, Tick i)
57    : Event(&mainEventQueue), tsunami(t), interval(i)
58{
59    DPRINTF(MC146818, "RTC Event Initilizing\n");
60    schedule(curTick + interval);
61}
62
63void
64TsunamiIO::RTCEvent::process()
65{
66    DPRINTF(MC146818, "RTC Timer Interrupt\n");
67    schedule(curTick + interval);
68    //Actually interrupt the processor here
69    tsunami->cchip->postRTC();
70}
71
72const char *
73TsunamiIO::RTCEvent::description()
74{
75    return "tsunami RTC interrupt";
76}
77
78void
79TsunamiIO::RTCEvent::serialize(std::ostream &os)
80{
81    Tick time = when();
82    SERIALIZE_SCALAR(time);
83}
84
85void
86TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string &section)
87{
88    Tick time;
89    UNSERIALIZE_SCALAR(time);
90    reschedule(time);
91}
92
93
94// Timer Event for PIT Timers
95TsunamiIO::ClockEvent::ClockEvent()
96    : Event(&mainEventQueue)
97{
98    /* This is the PIT Tick Rate. A constant for the 8254 timer. The
99     * Tsunami platform has one of these cycle counters on the Cypress
100     * South Bridge and it is used by linux for estimating the cycle
101     * frequency of the machine it is running on. --Ali
102     */
103    interval = (Tick)(Clock::Float::s / 1193180.0);
104
105    DPRINTF(Tsunami, "Clock Event Initilizing\n");
106    mode = 0;
107}
108
109void
110TsunamiIO::ClockEvent::process()
111{
112    DPRINTF(Tsunami, "Timer Interrupt\n");
113    if (mode == 0)
114        status = 0x20; // set bit that linux is looking for
115    else
116        schedule(curTick + interval);
117}
118
119void
120TsunamiIO::ClockEvent::Program(int count)
121{
122    DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * interval);
123    schedule(curTick + count * interval);
124    status = 0;
125}
126
127const char *
128TsunamiIO::ClockEvent::description()
129{
130    return "tsunami 8254 Interval timer";
131}
132
133void
134TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
135{
136    mode = md;
137}
138
139uint8_t
140TsunamiIO::ClockEvent::Status()
141{
142    return status;
143}
144
145void
146TsunamiIO::ClockEvent::serialize(std::ostream &os)
147{
148    Tick time = scheduled() ? when() : 0;
149    SERIALIZE_SCALAR(time);
150    SERIALIZE_SCALAR(status);
151    SERIALIZE_SCALAR(mode);
152    SERIALIZE_SCALAR(interval);
153}
154
155void
156TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string &section)
157{
158    Tick time;
159    UNSERIALIZE_SCALAR(time);
160    UNSERIALIZE_SCALAR(status);
161    UNSERIALIZE_SCALAR(mode);
162    UNSERIALIZE_SCALAR(interval);
163    if (time)
164        schedule(time);
165}
166
167TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
168                     Addr a, MemoryController *mmu, HierParams *hier, Bus *bus,
169                     Tick pio_latency, Tick ci)
170    : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t), rtc(t, ci)
171{
172    mmu->add_child(this, RangeSize(addr, size));
173
174    if (bus) {
175        pioInterface = newPioInterface(name, hier, bus, this,
176                                       &TsunamiIO::cacheAccess);
177        pioInterface->addAddrRange(RangeSize(addr, size));
178        pioLatency = pio_latency * bus->clockRatio;
179    }
180
181    // set the back pointer from tsunami to myself
182    tsunami->io = this;
183
184    timerData = 0;
185    set_time(init_time == 0 ? time(NULL) : init_time);
186    uip = 1;
187    picr = 0;
188    picInterrupting = false;
189}
190
191Tick
192TsunamiIO::frequency() const
193{
194    return Clock::Frequency / clockInterval;
195}
196
197void
198TsunamiIO::set_time(time_t t)
199{
200    gmtime_r(&t, &tm);
201    DPRINTFN("Real-time clock set to %s", asctime(&tm));
202}
203
204Fault
205TsunamiIO::read(MemReqPtr &req, uint8_t *data)
206{
207    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n",
208            req->vaddr, req->size, req->vaddr & 0xfff);
209
210    Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
211
212
213    switch(req->size) {
214      case sizeof(uint8_t):
215        switch(daddr) {
216          case TSDEV_PIC1_ISR:
217              // !!! If this is modified 64bit case needs to be too
218              // Pal code has to do a 64 bit physical read because there is
219              // no load physical byte instruction
220              *(uint8_t*)data = picr;
221              return No_Fault;
222          case TSDEV_PIC2_ISR:
223              // PIC2 not implemnted... just return 0
224              *(uint8_t*)data = 0x00;
225              return No_Fault;
226          case TSDEV_TMR_CTL:
227            *(uint8_t*)data = timer2.Status();
228            return No_Fault;
229          case TSDEV_RTC_DATA:
230            switch(RTCAddress) {
231              case RTC_CNTRL_REGA:
232                *(uint8_t*)data = uip << 7 | 0x26;
233                uip = !uip;
234                return No_Fault;
235              case RTC_CNTRL_REGB:
236                // DM and 24/12 and UIE
237                *(uint8_t*)data = 0x46;
238                return No_Fault;
239              case RTC_CNTRL_REGC:
240                // If we want to support RTC user access in linux
241                // This won't work, but for now it's fine
242                *(uint8_t*)data = 0x00;
243                return No_Fault;
244              case RTC_CNTRL_REGD:
245                panic("RTC Control Register D not implemented");
246              case RTC_SEC:
247                *(uint8_t *)data = tm.tm_sec;
248                return No_Fault;
249              case RTC_MIN:
250                *(uint8_t *)data = tm.tm_min;
251                return No_Fault;
252              case RTC_HR:
253                *(uint8_t *)data = tm.tm_hour;
254                return No_Fault;
255              case RTC_DOW:
256                *(uint8_t *)data = tm.tm_wday;
257                return No_Fault;
258              case RTC_DOM:
259                *(uint8_t *)data = tm.tm_mday;
260              case RTC_MON:
261                *(uint8_t *)data = tm.tm_mon + 1;
262                return No_Fault;
263              case RTC_YEAR:
264                *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
265                return No_Fault;
266              default:
267                panic("Unknown RTC Address\n");
268            }
269
270          default:
271            panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
272        }
273      case sizeof(uint16_t):
274      case sizeof(uint32_t):
275        panic("I/O Read - invalid size - va %#x size %d\n",
276              req->vaddr, req->size);
277
278      case sizeof(uint64_t):
279       switch(daddr) {
280          case TSDEV_PIC1_ISR:
281              // !!! If this is modified 8bit case needs to be too
282              // Pal code has to do a 64 bit physical read because there is
283              // no load physical byte instruction
284              *(uint64_t*)data = (uint64_t)picr;
285              return No_Fault;
286          default:
287              panic("I/O Read - invalid size - va %#x size %d\n",
288                    req->vaddr, req->size);
289       }
290
291      default:
292        panic("I/O Read - invalid size - va %#x size %d\n",
293              req->vaddr, req->size);
294    }
295    panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
296
297    return No_Fault;
298}
299
300Fault
301TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
302{
303
304#if TRACING_ON
305    uint8_t dt = *(uint8_t*)data;
306    uint64_t dt64 = dt;
307#endif
308
309    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
310            req->vaddr, req->size, req->vaddr & 0xfff, dt64);
311
312    Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
313
314    switch(req->size) {
315      case sizeof(uint8_t):
316        switch(daddr) {
317          case TSDEV_PIC1_MASK:
318            mask1 = ~(*(uint8_t*)data);
319            if ((picr & mask1) && !picInterrupting) {
320                picInterrupting = true;
321                tsunami->cchip->postDRIR(55);
322                DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
323            }
324            if ((!(picr & mask1)) && picInterrupting) {
325                picInterrupting = false;
326                tsunami->cchip->clearDRIR(55);
327                DPRINTF(Tsunami, "clearing pic interrupt\n");
328            }
329            return No_Fault;
330          case TSDEV_PIC2_MASK:
331            mask2 = *(uint8_t*)data;
332            //PIC2 Not implemented to interrupt
333            return No_Fault;
334          case TSDEV_PIC1_ACK:
335            // clear the interrupt on the PIC
336            picr &= ~(1 << (*(uint8_t*)data & 0xF));
337            if (!(picr & mask1))
338                tsunami->cchip->clearDRIR(55);
339            return No_Fault;
340          case TSDEV_PIC2_ACK:
341            return No_Fault;
342          case TSDEV_DMA1_RESET:
343            return No_Fault;
344          case TSDEV_DMA2_RESET:
345            return No_Fault;
346          case TSDEV_DMA1_MODE:
347            mode1 = *(uint8_t*)data;
348            return No_Fault;
349          case TSDEV_DMA2_MODE:
350            mode2 = *(uint8_t*)data;
351            return No_Fault;
352          case TSDEV_DMA1_MASK:
353          case TSDEV_DMA2_MASK:
354            return No_Fault;
355          case TSDEV_TMR_CTL:
356            return No_Fault;
357          case TSDEV_TMR2_CTL:
358            if ((*(uint8_t*)data & 0x30) != 0x30)
359                panic("Only L/M write supported\n");
360
361            switch(*(uint8_t*)data >> 6) {
362              case 0:
363                timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
364                break;
365              case 2:
366                timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
367                break;
368              default:
369                panic("Read Back Command not implemented\n");
370            }
371            return No_Fault;
372          case TSDEV_TMR2_DATA:
373            /* two writes before we actually start the Timer
374               so I set a flag in the timerData */
375            if(timerData & 0x1000) {
376                timerData &= 0x1000;
377                timerData += *(uint8_t*)data << 8;
378                timer2.Program(timerData);
379            } else {
380                timerData = *(uint8_t*)data;
381                timerData |= 0x1000;
382            }
383            return No_Fault;
384          case TSDEV_TMR0_DATA:
385            /* two writes before we actually start the Timer
386               so I set a flag in the timerData */
387            if(timerData & 0x1000) {
388                timerData &= 0x1000;
389                timerData += *(uint8_t*)data << 8;
390                timer0.Program(timerData);
391            } else {
392                timerData = *(uint8_t*)data;
393                timerData |= 0x1000;
394            }
395            return No_Fault;
396          case TSDEV_RTC_ADDR:
397            RTCAddress = *(uint8_t*)data;
398            return No_Fault;
399          case TSDEV_RTC_DATA:
400            panic("RTC Write not implmented (rtc.o won't work)\n");
401          default:
402            panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
403        }
404      case sizeof(uint16_t):
405      case sizeof(uint32_t):
406      case sizeof(uint64_t):
407      default:
408        panic("I/O Write - invalid size - va %#x size %d\n",
409              req->vaddr, req->size);
410    }
411
412
413    return No_Fault;
414}
415
416void
417TsunamiIO::postPIC(uint8_t bitvector)
418{
419    //PIC2 Is not implemented, because nothing of interest there
420    picr |= bitvector;
421    if (picr & mask1) {
422        tsunami->cchip->postDRIR(55);
423        DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
424    }
425}
426
427void
428TsunamiIO::clearPIC(uint8_t bitvector)
429{
430    //PIC2 Is not implemented, because nothing of interest there
431    picr &= ~bitvector;
432    if (!(picr & mask1)) {
433        tsunami->cchip->clearDRIR(55);
434        DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
435    }
436}
437
438Tick
439TsunamiIO::cacheAccess(MemReqPtr &req)
440{
441    return curTick + pioLatency;
442}
443
444void
445TsunamiIO::serialize(std::ostream &os)
446{
447    SERIALIZE_SCALAR(timerData);
448    SERIALIZE_SCALAR(uip);
449    SERIALIZE_SCALAR(mask1);
450    SERIALIZE_SCALAR(mask2);
451    SERIALIZE_SCALAR(mode1);
452    SERIALIZE_SCALAR(mode2);
453    SERIALIZE_SCALAR(picr);
454    SERIALIZE_SCALAR(picInterrupting);
455    SERIALIZE_SCALAR(RTCAddress);
456
457    // Serialize the timers
458    nameOut(os, csprintf("%s.timer0", name()));
459    timer0.serialize(os);
460    nameOut(os, csprintf("%s.timer2", name()));
461    timer2.serialize(os);
462    nameOut(os, csprintf("%s.rtc", name()));
463    rtc.serialize(os);
464}
465
466void
467TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
468{
469    UNSERIALIZE_SCALAR(timerData);
470    UNSERIALIZE_SCALAR(uip);
471    UNSERIALIZE_SCALAR(mask1);
472    UNSERIALIZE_SCALAR(mask2);
473    UNSERIALIZE_SCALAR(mode1);
474    UNSERIALIZE_SCALAR(mode2);
475    UNSERIALIZE_SCALAR(picr);
476    UNSERIALIZE_SCALAR(picInterrupting);
477    UNSERIALIZE_SCALAR(RTCAddress);
478
479    // Unserialize the timers
480    timer0.unserialize(cp, csprintf("%s.timer0", section));
481    timer2.unserialize(cp, csprintf("%s.timer2", section));
482    rtc.unserialize(cp, csprintf("%s.rtc", section));
483}
484
485BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
486
487    SimObjectParam<Tsunami *> tsunami;
488    Param<time_t> time;
489    SimObjectParam<MemoryController *> mmu;
490    Param<Addr> addr;
491    SimObjectParam<Bus*> io_bus;
492    Param<Tick> pio_latency;
493    SimObjectParam<HierParams *> hier;
494    Param<Tick> frequency;
495
496END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
497
498BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
499
500    INIT_PARAM(tsunami, "Tsunami"),
501    INIT_PARAM(time, "System time to use (0 for actual time"),
502    INIT_PARAM(mmu, "Memory Controller"),
503    INIT_PARAM(addr, "Device Address"),
504    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
505    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
506    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
507    INIT_PARAM(frequency, "clock interrupt frequency")
508
509END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
510
511CREATE_SIM_OBJECT(TsunamiIO)
512{
513    return new TsunamiIO(getInstanceName(), tsunami, time,  addr, mmu, hier,
514                         io_bus, pio_latency, frequency);
515}
516
517REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
518