tsunami_io.cc revision 773
1/* $Id$ */
2
3/* @file
4 * Tsunami I/O including PIC, PIT, RTC, DMA
5 */
6
7#include <sys/time.h>
8
9#include <deque>
10#include <string>
11#include <vector>
12
13#include "base/trace.hh"
14#include "cpu/exec_context.hh"
15#include "dev/console.hh"
16#include "dev/tlaser_clock.hh"
17#include "dev/tsunami_io.hh"
18#include "dev/tsunamireg.h"
19#include "dev/tsunami.hh"
20#include "mem/functional_mem/memory_control.hh"
21#include "sim/builder.hh"
22
23using namespace std;
24
25#define UNIX_YEAR_OFFSET 52
26
27//This will have to be dynamic if we want support usermode access of the RTC
28#define RTC_RATE  1024
29
30// Timer Event for Periodic interrupt of RTC
31TsunamiIO::RTCEvent::RTCEvent()
32    : Event(&mainEventQueue)
33{
34    DPRINTF(MC146818, "RTC Event Initilizing\n");
35    schedule(curTick + ticksPerSecond/RTC_RATE);
36}
37
38void
39TsunamiIO::RTCEvent::process()
40{
41    DPRINTF(MC146818, "Timer Interrupt\n");
42    schedule(curTick + ticksPerSecond/RTC_RATE);
43    //Actually interrupt the processor here
44}
45
46const char *
47TsunamiIO::RTCEvent::description()
48{
49    return "tsunami RTC 1024Hz interrupt";
50}
51
52// Timer Event for PIT Timers
53TsunamiIO::ClockEvent::ClockEvent()
54    : Event(&mainEventQueue)
55{
56    DPRINTF(Tsunami, "Clock Event Initilizing\n");
57    mode = 0;
58}
59
60void
61TsunamiIO::ClockEvent::process()
62{
63    DPRINTF(Tsunami, "Timer Interrupt\n");
64    if (mode == 0)
65       status = 0x20; // set bit that linux is looking for
66    else
67        schedule(curTick + interval);
68}
69
70void
71TsunamiIO::ClockEvent::Program(int count)
72{
73    DPRINTF(Tsunami, "Timer set to curTick + %d\n", count);
74    // should be count * (cpufreq/pitfreq)
75    interval = count * ticksPerSecond/1193180UL;
76    schedule(curTick + interval);
77    status = 0;
78}
79
80const char *
81TsunamiIO::ClockEvent::description()
82{
83    return "tsunami 8254 Interval timer";
84}
85
86void
87TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
88{
89    mode = md;
90}
91
92uint8_t
93TsunamiIO::ClockEvent::Status()
94{
95    return status;
96}
97
98
99
100
101TsunamiIO::TsunamiIO(const string &name, /*Tsunami *t,*/ time_t init_time,
102                       Addr addr, Addr mask, MemoryController *mmu)
103    : MmapDevice(name, addr, mask, mmu)/*, tsunami(t) */
104{
105    timerData = 0;
106    set_time(init_time == 0 ? time(NULL) : init_time);
107    uip = 1;
108}
109
110void
111TsunamiIO::set_time(time_t t)
112{
113    gmtime_r(&t, &tm);
114    DPRINTFN("Real-time clock set to %s", asctime(&tm));
115}
116
117Fault
118TsunamiIO::read(MemReqPtr req, uint8_t *data)
119{
120    DPRINTF(Tsunami, "io read  va=%#x size=%d IOPorrt=%#x\n",
121            req->vaddr, req->size, req->vaddr & 0xfff);
122
123    Addr daddr = (req->paddr & addr_mask);
124//    ExecContext *xc = req->xc;
125//    int cpuid = xc->cpu_id;
126
127    switch(req->size) {
128        case sizeof(uint8_t):
129            switch(daddr) {
130                case TSDEV_TMR_CTL:
131                    *(uint8_t*)data = timer2.Status();
132                    return No_Fault;
133                case TSDEV_RTC_DATA:
134                    switch(RTCAddress) {
135                        case RTC_CONTROL_REGISTERA:
136                            *(uint8_t*)data = uip << 7 | 0x26;
137                            uip = !uip;
138                            return No_Fault;
139                        case RTC_CONTROL_REGISTERB:
140                            // DM and 24/12 and UIE
141                            *(uint8_t*)data = 0x46;
142                            return No_Fault;
143                        case RTC_CONTROL_REGISTERC:
144                            // If we want to support RTC user access in linux
145                            // This won't work, but for now it's fine
146                            *(uint8_t*)data = 0x00;
147                            return No_Fault;
148                        case RTC_CONTROL_REGISTERD:
149                            panic("RTC Control Register D not implemented");
150                        case RTC_SECOND:
151                            *(uint8_t *)data = tm.tm_sec;
152                            return No_Fault;
153                        case RTC_MINUTE:
154                            *(uint8_t *)data = tm.tm_min;
155                            return No_Fault;
156                        case RTC_HOUR:
157                            *(uint8_t *)data = tm.tm_hour;
158                            return No_Fault;
159                        case RTC_DAY_OF_WEEK:
160                            *(uint8_t *)data = tm.tm_wday;
161                            return No_Fault;
162                        case RTC_DAY_OF_MONTH:
163                            *(uint8_t *)data = tm.tm_mday;
164                        case RTC_MONTH:
165                            *(uint8_t *)data = tm.tm_mon + 1;
166                            return No_Fault;
167                        case RTC_YEAR:
168                            *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
169                            return No_Fault;
170                        default:
171                            panic("Unknown RTC Address\n");
172                    }
173
174                default:
175                    panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
176            }
177        case sizeof(uint16_t):
178        case sizeof(uint32_t):
179        case sizeof(uint64_t):
180        default:
181            panic("I/O Read - invalid size - va %#x size %d\n", req->vaddr, req->size);
182    }
183     panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
184
185    return No_Fault;
186}
187
188Fault
189TsunamiIO::write(MemReqPtr req, const uint8_t *data)
190{
191    DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x\n",
192            req->vaddr, req->size, req->vaddr & 0xfff);
193
194    Addr daddr = (req->paddr & addr_mask);
195
196    switch(req->size) {
197        case sizeof(uint8_t):
198            switch(daddr) {
199                case TSDEV_PIC1_MASK:
200                    mask1 = *(uint8_t*)data;
201                    return No_Fault;
202                case TSDEV_PIC2_MASK:
203                    mask2 = *(uint8_t*)data;
204                    return No_Fault;
205                case TSDEV_DMA1_RESET:
206                    return No_Fault;
207                case TSDEV_DMA2_RESET:
208                    return No_Fault;
209                case TSDEV_DMA1_MODE:
210                    mode1 = *(uint8_t*)data;
211                    return No_Fault;
212                case TSDEV_DMA2_MODE:
213                    mode2 = *(uint8_t*)data;
214                    return No_Fault;
215                case TSDEV_DMA1_MASK:
216                case TSDEV_DMA2_MASK:
217                    return No_Fault;
218                case TSDEV_TMR_CTL:
219                    return No_Fault;
220                case TSDEV_TMR2_CTL:
221                    if ((*(uint8_t*)data & 0x30) != 0x30)
222                        panic("Only L/M write supported\n");
223
224                    switch(*(uint8_t*)data >> 6) {
225                        case 0:
226                            timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
227                            break;
228                        case 2:
229                            timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
230                            break;
231                        default:
232                            panic("Read Back Command not implemented\n");
233                    }
234                    return No_Fault;
235                case TSDEV_TMR2_DATA:
236                        /* two writes before we actually start the Timer
237                           so I set a flag in the timerData */
238                        if(timerData & 0x1000) {
239                            timerData &= 0x1000;
240                            timerData += *(uint8_t*)data << 8;
241                            timer2.Program(timerData);
242                        } else {
243                            timerData = *(uint8_t*)data;
244                            timerData |= 0x1000;
245                        }
246                        return No_Fault;
247                case TSDEV_TMR0_DATA:
248                        /* two writes before we actually start the Timer
249                           so I set a flag in the timerData */
250                        if(timerData & 0x1000) {
251                            timerData &= 0x1000;
252                            timerData += *(uint8_t*)data << 8;
253                            timer0.Program(timerData);
254                        } else {
255                            timerData = *(uint8_t*)data;
256                            timerData |= 0x1000;
257                        }
258                        return No_Fault;
259                case TSDEV_RTC_ADDR:
260                        RTCAddress = *(uint8_t*)data;
261                        return No_Fault;
262                case TSDEV_RTC_DATA:
263                        panic("RTC Write not implmented (rtc.o won't work)\n");
264                 default:
265                    panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
266            }
267        case sizeof(uint16_t):
268        case sizeof(uint32_t):
269        case sizeof(uint64_t):
270        default:
271            panic("I/O Write - invalid size - va %#x size %d\n", req->vaddr, req->size);
272    }
273
274
275    return No_Fault;
276}
277
278void
279TsunamiIO::serialize(std::ostream &os)
280{
281    // code should be written
282}
283
284void
285TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
286{
287    //code should be written
288}
289
290BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
291
292 //   SimObjectParam<Tsunami *> tsunami;
293    Param<time_t> time;
294    SimObjectParam<MemoryController *> mmu;
295    Param<Addr> addr;
296    Param<Addr> mask;
297
298END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
299
300BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
301
302//    INIT_PARAM(tsunami, "Tsunami"),
303    INIT_PARAM_DFLT(time, "System time to use "
304            "(0 for actual time, default is 1/1/06", ULL(1136073600)),
305    INIT_PARAM(mmu, "Memory Controller"),
306    INIT_PARAM(addr, "Device Address"),
307    INIT_PARAM(mask, "Address Mask")
308
309END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
310
311CREATE_SIM_OBJECT(TsunamiIO)
312{
313    return new TsunamiIO(getInstanceName(), /*tsunami,*/ time,  addr, mask, mmu);
314}
315
316REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
317