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