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