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