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