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