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