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