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