Standardize clock parameter names to 'clock'.
[gem5.git] / dev / tsunami_io.cc
1 /*
2 * Copyright (c) 2004-2005 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/tsunami_io.hh"
41 #include "dev/tsunami.hh"
42 #include "mem/bus/bus.hh"
43 #include "mem/bus/pio_interface.hh"
44 #include "mem/bus/pio_interface_impl.hh"
45 #include "sim/builder.hh"
46 #include "dev/tsunami_cchip.hh"
47 #include "dev/tsunamireg.h"
48 #include "dev/rtcreg.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, Tick i)
57 : Event(&mainEventQueue), tsunami(t), interval(i)
58 {
59 DPRINTF(MC146818, "RTC Event Initilizing\n");
60 schedule(curTick + interval);
61 }
62
63 void
64 TsunamiIO::RTCEvent::process()
65 {
66 DPRINTF(MC146818, "RTC Timer Interrupt\n");
67 schedule(curTick + interval);
68 //Actually interrupt the processor here
69 tsunami->cchip->postRTC();
70 }
71
72 const char *
73 TsunamiIO::RTCEvent::description()
74 {
75 return "tsunami RTC interrupt";
76 }
77
78 void
79 TsunamiIO::RTCEvent::serialize(std::ostream &os)
80 {
81 Tick time = when();
82 SERIALIZE_SCALAR(time);
83 }
84
85 void
86 TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string &section)
87 {
88 Tick time;
89 UNSERIALIZE_SCALAR(time);
90 reschedule(time);
91 }
92
93
94 // Timer Event for PIT Timers
95 TsunamiIO::ClockEvent::ClockEvent()
96 : Event(&mainEventQueue)
97 {
98 /* This is the PIT Tick Rate. A constant for the 8254 timer. The
99 * Tsunami platform has one of these cycle counters on the Cypress
100 * South Bridge and it is used by linux for estimating the cycle
101 * frequency of the machine it is running on. --Ali
102 */
103 interval = (Tick)(Clock::Float::s / 1193180.0);
104
105 DPRINTF(Tsunami, "Clock Event Initilizing\n");
106 mode = 0;
107 }
108
109 void
110 TsunamiIO::ClockEvent::process()
111 {
112 DPRINTF(Tsunami, "Timer Interrupt\n");
113 if (mode == 0)
114 status = 0x20; // set bit that linux is looking for
115 else
116 schedule(curTick + interval);
117 }
118
119 void
120 TsunamiIO::ClockEvent::Program(int count)
121 {
122 DPRINTF(Tsunami, "Timer set to curTick + %d\n", count * interval);
123 schedule(curTick + count * interval);
124 status = 0;
125 }
126
127 const char *
128 TsunamiIO::ClockEvent::description()
129 {
130 return "tsunami 8254 Interval timer";
131 }
132
133 void
134 TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
135 {
136 mode = md;
137 }
138
139 uint8_t
140 TsunamiIO::ClockEvent::Status()
141 {
142 return status;
143 }
144
145 void
146 TsunamiIO::ClockEvent::serialize(std::ostream &os)
147 {
148 Tick time = scheduled() ? when() : 0;
149 SERIALIZE_SCALAR(time);
150 SERIALIZE_SCALAR(status);
151 SERIALIZE_SCALAR(mode);
152 SERIALIZE_SCALAR(interval);
153 }
154
155 void
156 TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string &section)
157 {
158 Tick time;
159 UNSERIALIZE_SCALAR(time);
160 UNSERIALIZE_SCALAR(status);
161 UNSERIALIZE_SCALAR(mode);
162 UNSERIALIZE_SCALAR(interval);
163 if (time)
164 schedule(time);
165 }
166
167 TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
168 Addr a, MemoryController *mmu, HierParams *hier, Bus *bus,
169 Tick pio_latency, Tick ci)
170 : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t), rtc(t, ci)
171 {
172 mmu->add_child(this, RangeSize(addr, size));
173
174 if (bus) {
175 pioInterface = newPioInterface(name, hier, bus, this,
176 &TsunamiIO::cacheAccess);
177 pioInterface->addAddrRange(RangeSize(addr, size));
178 pioLatency = pio_latency * bus->clockRate;
179 }
180
181 // set the back pointer from tsunami to myself
182 tsunami->io = this;
183
184 timerData = 0;
185 set_time(init_time == 0 ? time(NULL) : init_time);
186 uip = 1;
187 picr = 0;
188 picInterrupting = false;
189 }
190
191 Tick
192 TsunamiIO::frequency() const
193 {
194 return Clock::Frequency / clockInterval;
195 }
196
197 void
198 TsunamiIO::set_time(time_t t)
199 {
200 gmtime_r(&t, &tm);
201 DPRINTFN("Real-time clock set to %s", asctime(&tm));
202 }
203
204 Fault
205 TsunamiIO::read(MemReqPtr &req, uint8_t *data)
206 {
207 DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n",
208 req->vaddr, req->size, req->vaddr & 0xfff);
209
210 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
211
212
213 switch(req->size) {
214 case sizeof(uint8_t):
215 switch(daddr) {
216 case TSDEV_PIC1_ISR:
217 // !!! If this is modified 64bit case needs to be too
218 // Pal code has to do a 64 bit physical read because there is
219 // no load physical byte instruction
220 *(uint8_t*)data = picr;
221 return No_Fault;
222 case TSDEV_PIC2_ISR:
223 // PIC2 not implemnted... just return 0
224 *(uint8_t*)data = 0x00;
225 return No_Fault;
226 case TSDEV_TMR_CTL:
227 *(uint8_t*)data = timer2.Status();
228 return No_Fault;
229 case TSDEV_RTC_DATA:
230 switch(RTCAddress) {
231 case RTC_CNTRL_REGA:
232 *(uint8_t*)data = uip << 7 | 0x26;
233 uip = !uip;
234 return No_Fault;
235 case RTC_CNTRL_REGB:
236 // DM and 24/12 and UIE
237 *(uint8_t*)data = 0x46;
238 return No_Fault;
239 case RTC_CNTRL_REGC:
240 // If we want to support RTC user access in linux
241 // This won't work, but for now it's fine
242 *(uint8_t*)data = 0x00;
243 return No_Fault;
244 case RTC_CNTRL_REGD:
245 panic("RTC Control Register D not implemented");
246 case RTC_SEC:
247 *(uint8_t *)data = tm.tm_sec;
248 return No_Fault;
249 case RTC_MIN:
250 *(uint8_t *)data = tm.tm_min;
251 return No_Fault;
252 case RTC_HR:
253 *(uint8_t *)data = tm.tm_hour;
254 return No_Fault;
255 case RTC_DOW:
256 *(uint8_t *)data = tm.tm_wday;
257 return No_Fault;
258 case RTC_DOM:
259 *(uint8_t *)data = tm.tm_mday;
260 case RTC_MON:
261 *(uint8_t *)data = tm.tm_mon + 1;
262 return No_Fault;
263 case RTC_YEAR:
264 *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
265 return No_Fault;
266 default:
267 panic("Unknown RTC Address\n");
268 }
269
270 default:
271 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
272 }
273 case sizeof(uint16_t):
274 case sizeof(uint32_t):
275 panic("I/O Read - invalid size - va %#x size %d\n",
276 req->vaddr, req->size);
277
278 case sizeof(uint64_t):
279 switch(daddr) {
280 case TSDEV_PIC1_ISR:
281 // !!! If this is modified 8bit case needs to be too
282 // Pal code has to do a 64 bit physical read because there is
283 // no load physical byte instruction
284 *(uint64_t*)data = (uint64_t)picr;
285 return No_Fault;
286 default:
287 panic("I/O Read - invalid size - va %#x size %d\n",
288 req->vaddr, req->size);
289 }
290
291 default:
292 panic("I/O Read - invalid size - va %#x size %d\n",
293 req->vaddr, req->size);
294 }
295 panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
296
297 return No_Fault;
298 }
299
300 Fault
301 TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
302 {
303
304 #if TRACING_ON
305 uint8_t dt = *(uint8_t*)data;
306 uint64_t dt64 = dt;
307 #endif
308
309 DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
310 req->vaddr, req->size, req->vaddr & 0xfff, dt64);
311
312 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
313
314 switch(req->size) {
315 case sizeof(uint8_t):
316 switch(daddr) {
317 case TSDEV_PIC1_MASK:
318 mask1 = ~(*(uint8_t*)data);
319 if ((picr & mask1) && !picInterrupting) {
320 picInterrupting = true;
321 tsunami->cchip->postDRIR(55);
322 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
323 }
324 if ((!(picr & mask1)) && picInterrupting) {
325 picInterrupting = false;
326 tsunami->cchip->clearDRIR(55);
327 DPRINTF(Tsunami, "clearing pic interrupt\n");
328 }
329 return No_Fault;
330 case TSDEV_PIC2_MASK:
331 mask2 = *(uint8_t*)data;
332 //PIC2 Not implemented to interrupt
333 return No_Fault;
334 case TSDEV_PIC1_ACK:
335 // clear the interrupt on the PIC
336 picr &= ~(1 << (*(uint8_t*)data & 0xF));
337 if (!(picr & mask1))
338 tsunami->cchip->clearDRIR(55);
339 return No_Fault;
340 case TSDEV_PIC2_ACK:
341 return No_Fault;
342 case TSDEV_DMA1_RESET:
343 return No_Fault;
344 case TSDEV_DMA2_RESET:
345 return No_Fault;
346 case TSDEV_DMA1_MODE:
347 mode1 = *(uint8_t*)data;
348 return No_Fault;
349 case TSDEV_DMA2_MODE:
350 mode2 = *(uint8_t*)data;
351 return No_Fault;
352 case TSDEV_DMA1_MASK:
353 case TSDEV_DMA2_MASK:
354 return No_Fault;
355 case TSDEV_TMR_CTL:
356 return No_Fault;
357 case TSDEV_TMR2_CTL:
358 if ((*(uint8_t*)data & 0x30) != 0x30)
359 panic("Only L/M write supported\n");
360
361 switch(*(uint8_t*)data >> 6) {
362 case 0:
363 timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
364 break;
365 case 2:
366 timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
367 break;
368 default:
369 panic("Read Back Command not implemented\n");
370 }
371 return No_Fault;
372 case TSDEV_TMR2_DATA:
373 /* two writes before we actually start the Timer
374 so I set a flag in the timerData */
375 if(timerData & 0x1000) {
376 timerData &= 0x1000;
377 timerData += *(uint8_t*)data << 8;
378 timer2.Program(timerData);
379 } else {
380 timerData = *(uint8_t*)data;
381 timerData |= 0x1000;
382 }
383 return No_Fault;
384 case TSDEV_TMR0_DATA:
385 /* two writes before we actually start the Timer
386 so I set a flag in the timerData */
387 if(timerData & 0x1000) {
388 timerData &= 0x1000;
389 timerData += *(uint8_t*)data << 8;
390 timer0.Program(timerData);
391 } else {
392 timerData = *(uint8_t*)data;
393 timerData |= 0x1000;
394 }
395 return No_Fault;
396 case TSDEV_RTC_ADDR:
397 RTCAddress = *(uint8_t*)data;
398 return No_Fault;
399 case TSDEV_RTC_DATA:
400 panic("RTC Write not implmented (rtc.o won't work)\n");
401 default:
402 panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
403 }
404 case sizeof(uint16_t):
405 case sizeof(uint32_t):
406 case sizeof(uint64_t):
407 default:
408 panic("I/O Write - invalid size - va %#x size %d\n",
409 req->vaddr, req->size);
410 }
411
412
413 return No_Fault;
414 }
415
416 void
417 TsunamiIO::postPIC(uint8_t bitvector)
418 {
419 //PIC2 Is not implemented, because nothing of interest there
420 picr |= bitvector;
421 if (picr & mask1) {
422 tsunami->cchip->postDRIR(55);
423 DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
424 }
425 }
426
427 void
428 TsunamiIO::clearPIC(uint8_t bitvector)
429 {
430 //PIC2 Is not implemented, because nothing of interest there
431 picr &= ~bitvector;
432 if (!(picr & mask1)) {
433 tsunami->cchip->clearDRIR(55);
434 DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
435 }
436 }
437
438 Tick
439 TsunamiIO::cacheAccess(MemReqPtr &req)
440 {
441 return curTick + pioLatency;
442 }
443
444 void
445 TsunamiIO::serialize(std::ostream &os)
446 {
447 SERIALIZE_SCALAR(timerData);
448 SERIALIZE_SCALAR(uip);
449 SERIALIZE_SCALAR(mask1);
450 SERIALIZE_SCALAR(mask2);
451 SERIALIZE_SCALAR(mode1);
452 SERIALIZE_SCALAR(mode2);
453 SERIALIZE_SCALAR(picr);
454 SERIALIZE_SCALAR(picInterrupting);
455 SERIALIZE_SCALAR(RTCAddress);
456
457 // Serialize the timers
458 nameOut(os, csprintf("%s.timer0", name()));
459 timer0.serialize(os);
460 nameOut(os, csprintf("%s.timer2", name()));
461 timer2.serialize(os);
462 nameOut(os, csprintf("%s.rtc", name()));
463 rtc.serialize(os);
464 }
465
466 void
467 TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
468 {
469 UNSERIALIZE_SCALAR(timerData);
470 UNSERIALIZE_SCALAR(uip);
471 UNSERIALIZE_SCALAR(mask1);
472 UNSERIALIZE_SCALAR(mask2);
473 UNSERIALIZE_SCALAR(mode1);
474 UNSERIALIZE_SCALAR(mode2);
475 UNSERIALIZE_SCALAR(picr);
476 UNSERIALIZE_SCALAR(picInterrupting);
477 UNSERIALIZE_SCALAR(RTCAddress);
478
479 // Unserialize the timers
480 timer0.unserialize(cp, csprintf("%s.timer0", section));
481 timer2.unserialize(cp, csprintf("%s.timer2", section));
482 rtc.unserialize(cp, csprintf("%s.rtc", section));
483 }
484
485 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
486
487 SimObjectParam<Tsunami *> tsunami;
488 Param<time_t> time;
489 SimObjectParam<MemoryController *> mmu;
490 Param<Addr> addr;
491 SimObjectParam<Bus*> io_bus;
492 Param<Tick> pio_latency;
493 SimObjectParam<HierParams *> hier;
494 Param<Tick> frequency;
495
496 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
497
498 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
499
500 INIT_PARAM(tsunami, "Tsunami"),
501 INIT_PARAM(time, "System time to use (0 for actual time"),
502 INIT_PARAM(mmu, "Memory Controller"),
503 INIT_PARAM(addr, "Device Address"),
504 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
505 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
506 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
507 INIT_PARAM(frequency, "clock interrupt frequency")
508
509 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
510
511 CREATE_SIM_OBJECT(TsunamiIO)
512 {
513 return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier,
514 io_bus, pio_latency, frequency);
515 }
516
517 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)