2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
30 * Tsunami I/O including PIC, PIT, RTC, DMA
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"
53 #define UNIX_YEAR_OFFSET 52
55 // Timer Event for Periodic interrupt of RTC
56 TsunamiIO::RTCEvent::RTCEvent(Tsunami
* t
)
57 : Event(&mainEventQueue
), tsunami(t
)
59 DPRINTF(MC146818
, "RTC Event Initilizing\n");
60 schedule(curTick
+ ticksPerSecond
/RTC_RATE
);
64 TsunamiIO::RTCEvent::process()
66 DPRINTF(MC146818
, "RTC Timer Interrupt\n");
67 schedule(curTick
+ ticksPerSecond
/RTC_RATE
);
68 //Actually interrupt the processor here
69 tsunami
->cchip
->postRTC();
74 TsunamiIO::RTCEvent::description()
76 return "tsunami RTC 1024Hz interrupt";
80 TsunamiIO::RTCEvent::serialize(std::ostream
&os
)
83 SERIALIZE_SCALAR(time
);
87 TsunamiIO::RTCEvent::unserialize(Checkpoint
*cp
, const std::string
§ion
)
90 UNSERIALIZE_SCALAR(time
);
95 // Timer Event for PIT Timers
96 TsunamiIO::ClockEvent::ClockEvent()
97 : Event(&mainEventQueue
)
99 DPRINTF(Tsunami
, "Clock Event Initilizing\n");
104 TsunamiIO::ClockEvent::process()
106 DPRINTF(Tsunami
, "Timer Interrupt\n");
108 status
= 0x20; // set bit that linux is looking for
110 schedule(curTick
+ interval
);
114 TsunamiIO::ClockEvent::Program(int count
)
116 DPRINTF(Tsunami
, "Timer set to curTick + %d\n", count
);
117 // should be count * (cpufreq/pitfreq)
118 interval
= count
* ticksPerSecond
/1193180UL;
119 schedule(curTick
+ interval
);
124 TsunamiIO::ClockEvent::description()
126 return "tsunami 8254 Interval timer";
130 TsunamiIO::ClockEvent::ChangeMode(uint8_t md
)
136 TsunamiIO::ClockEvent::Status()
142 TsunamiIO::ClockEvent::serialize(std::ostream
&os
)
144 Tick time
= scheduled() ? when() : 0;
145 SERIALIZE_SCALAR(time
);
146 SERIALIZE_SCALAR(status
);
147 SERIALIZE_SCALAR(mode
);
148 SERIALIZE_SCALAR(interval
);
152 TsunamiIO::ClockEvent::unserialize(Checkpoint
*cp
, const std::string
§ion
)
155 UNSERIALIZE_SCALAR(time
);
156 UNSERIALIZE_SCALAR(status
);
157 UNSERIALIZE_SCALAR(mode
);
158 UNSERIALIZE_SCALAR(interval
);
163 TsunamiIO::TsunamiIO(const string
&name
, Tsunami
*t
, time_t init_time
,
164 Addr a
, MemoryController
*mmu
, HierParams
*hier
, Bus
*bus
,
166 : PioDevice(name
, t
), addr(a
), tsunami(t
), rtc(t
)
168 mmu
->add_child(this, RangeSize(addr
, size
));
171 pioInterface
= newPioInterface(name
, hier
, bus
, this,
172 &TsunamiIO::cacheAccess
);
173 pioInterface
->addAddrRange(RangeSize(addr
, size
));
174 pioLatency
= pio_latency
* bus
->clockRatio
;
177 // set the back pointer from tsunami to myself
181 set_time(init_time
== 0 ? time(NULL
) : init_time
);
184 picInterrupting
= false;
188 TsunamiIO::set_time(time_t t
)
191 DPRINTFN("Real-time clock set to %s", asctime(&tm
));
195 TsunamiIO::read(MemReqPtr
&req
, uint8_t *data
)
197 DPRINTF(Tsunami
, "io read va=%#x size=%d IOPorrt=%#x\n",
198 req
->vaddr
, req
->size
, req
->vaddr
& 0xfff);
200 Addr daddr
= (req
->paddr
- (addr
& EV5::PAddrImplMask
));
204 case sizeof(uint8_t):
207 // !!! If this is modified 64bit case needs to be too
208 // Pal code has to do a 64 bit physical read because there is
209 // no load physical byte instruction
210 *(uint8_t*)data
= picr
;
213 // PIC2 not implemnted... just return 0
214 *(uint8_t*)data
= 0x00;
217 *(uint8_t*)data
= timer2
.Status();
222 *(uint8_t*)data
= uip
<< 7 | 0x26;
226 // DM and 24/12 and UIE
227 *(uint8_t*)data
= 0x46;
230 // If we want to support RTC user access in linux
231 // This won't work, but for now it's fine
232 *(uint8_t*)data
= 0x00;
235 panic("RTC Control Register D not implemented");
237 *(uint8_t *)data
= tm
.tm_sec
;
240 *(uint8_t *)data
= tm
.tm_min
;
243 *(uint8_t *)data
= tm
.tm_hour
;
246 *(uint8_t *)data
= tm
.tm_wday
;
249 *(uint8_t *)data
= tm
.tm_mday
;
251 *(uint8_t *)data
= tm
.tm_mon
+ 1;
254 *(uint8_t *)data
= tm
.tm_year
- UNIX_YEAR_OFFSET
;
257 panic("Unknown RTC Address\n");
261 panic("I/O Read - va%#x size %d\n", req
->vaddr
, req
->size
);
263 case sizeof(uint16_t):
264 case sizeof(uint32_t):
265 panic("I/O Read - invalid size - va %#x size %d\n",
266 req
->vaddr
, req
->size
);
268 case sizeof(uint64_t):
271 // !!! If this is modified 8bit case needs to be too
272 // Pal code has to do a 64 bit physical read because there is
273 // no load physical byte instruction
274 *(uint64_t*)data
= (uint64_t)picr
;
277 panic("I/O Read - invalid size - va %#x size %d\n",
278 req
->vaddr
, req
->size
);
282 panic("I/O Read - invalid size - va %#x size %d\n",
283 req
->vaddr
, req
->size
);
285 panic("I/O Read - va%#x size %d\n", req
->vaddr
, req
->size
);
291 TsunamiIO::write(MemReqPtr
&req
, const uint8_t *data
)
295 uint8_t dt
= *(uint8_t*)data
;
299 DPRINTF(Tsunami
, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
300 req
->vaddr
, req
->size
, req
->vaddr
& 0xfff, dt64
);
302 Addr daddr
= (req
->paddr
- (addr
& EV5::PAddrImplMask
));
305 case sizeof(uint8_t):
307 case TSDEV_PIC1_MASK
:
308 mask1
= ~(*(uint8_t*)data
);
309 if ((picr
& mask1
) && !picInterrupting
) {
310 picInterrupting
= true;
311 tsunami
->cchip
->postDRIR(55);
312 DPRINTF(Tsunami
, "posting pic interrupt to cchip\n");
314 if ((!(picr
& mask1
)) && picInterrupting
) {
315 picInterrupting
= false;
316 tsunami
->cchip
->clearDRIR(55);
317 DPRINTF(Tsunami
, "clearing pic interrupt\n");
320 case TSDEV_PIC2_MASK
:
321 mask2
= *(uint8_t*)data
;
322 //PIC2 Not implemented to interrupt
325 // clear the interrupt on the PIC
326 picr
&= ~(1 << (*(uint8_t*)data
& 0xF));
328 tsunami
->cchip
->clearDRIR(55);
332 case TSDEV_DMA1_RESET
:
334 case TSDEV_DMA2_RESET
:
336 case TSDEV_DMA1_MODE
:
337 mode1
= *(uint8_t*)data
;
339 case TSDEV_DMA2_MODE
:
340 mode2
= *(uint8_t*)data
;
342 case TSDEV_DMA1_MASK
:
343 case TSDEV_DMA2_MASK
:
348 if ((*(uint8_t*)data
& 0x30) != 0x30)
349 panic("Only L/M write supported\n");
351 switch(*(uint8_t*)data
>> 6) {
353 timer0
.ChangeMode((*(uint8_t*)data
& 0xF) >> 1);
356 timer2
.ChangeMode((*(uint8_t*)data
& 0xF) >> 1);
359 panic("Read Back Command not implemented\n");
362 case TSDEV_TMR2_DATA
:
363 /* two writes before we actually start the Timer
364 so I set a flag in the timerData */
365 if(timerData
& 0x1000) {
367 timerData
+= *(uint8_t*)data
<< 8;
368 timer2
.Program(timerData
);
370 timerData
= *(uint8_t*)data
;
374 case TSDEV_TMR0_DATA
:
375 /* two writes before we actually start the Timer
376 so I set a flag in the timerData */
377 if(timerData
& 0x1000) {
379 timerData
+= *(uint8_t*)data
<< 8;
380 timer0
.Program(timerData
);
382 timerData
= *(uint8_t*)data
;
387 RTCAddress
= *(uint8_t*)data
;
390 panic("RTC Write not implmented (rtc.o won't work)\n");
392 panic("I/O Write - va%#x size %d\n", req
->vaddr
, req
->size
);
394 case sizeof(uint16_t):
395 case sizeof(uint32_t):
396 case sizeof(uint64_t):
398 panic("I/O Write - invalid size - va %#x size %d\n",
399 req
->vaddr
, req
->size
);
407 TsunamiIO::postPIC(uint8_t bitvector
)
409 //PIC2 Is not implemented, because nothing of interest there
412 tsunami
->cchip
->postDRIR(55);
413 DPRINTF(Tsunami
, "posting pic interrupt to cchip\n");
418 TsunamiIO::clearPIC(uint8_t bitvector
)
420 //PIC2 Is not implemented, because nothing of interest there
422 if (!(picr
& mask1
)) {
423 tsunami
->cchip
->clearDRIR(55);
424 DPRINTF(Tsunami
, "clearing pic interrupt to cchip\n");
429 TsunamiIO::cacheAccess(MemReqPtr
&req
)
431 return curTick
+ pioLatency
;
435 TsunamiIO::serialize(std::ostream
&os
)
437 SERIALIZE_SCALAR(timerData
);
438 SERIALIZE_SCALAR(uip
);
439 SERIALIZE_SCALAR(mask1
);
440 SERIALIZE_SCALAR(mask2
);
441 SERIALIZE_SCALAR(mode1
);
442 SERIALIZE_SCALAR(mode2
);
443 SERIALIZE_SCALAR(picr
);
444 SERIALIZE_SCALAR(picInterrupting
);
445 SERIALIZE_SCALAR(RTCAddress
);
447 // Serialize the timers
448 nameOut(os
, csprintf("%s.timer0", name()));
449 timer0
.serialize(os
);
450 nameOut(os
, csprintf("%s.timer2", name()));
451 timer2
.serialize(os
);
452 nameOut(os
, csprintf("%s.rtc", name()));
457 TsunamiIO::unserialize(Checkpoint
*cp
, const std::string
§ion
)
459 UNSERIALIZE_SCALAR(timerData
);
460 UNSERIALIZE_SCALAR(uip
);
461 UNSERIALIZE_SCALAR(mask1
);
462 UNSERIALIZE_SCALAR(mask2
);
463 UNSERIALIZE_SCALAR(mode1
);
464 UNSERIALIZE_SCALAR(mode2
);
465 UNSERIALIZE_SCALAR(picr
);
466 UNSERIALIZE_SCALAR(picInterrupting
);
467 UNSERIALIZE_SCALAR(RTCAddress
);
469 // Unserialize the timers
470 timer0
.unserialize(cp
, csprintf("%s.timer0", section
));
471 timer2
.unserialize(cp
, csprintf("%s.timer2", section
));
472 rtc
.unserialize(cp
, csprintf("%s.rtc", section
));
475 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO
)
477 SimObjectParam
<Tsunami
*> tsunami
;
479 SimObjectParam
<MemoryController
*> mmu
;
481 SimObjectParam
<Bus
*> io_bus
;
482 Param
<Tick
> pio_latency
;
483 SimObjectParam
<HierParams
*> hier
;
485 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO
)
487 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO
)
489 INIT_PARAM(tsunami
, "Tsunami"),
490 INIT_PARAM_DFLT(time
, "System time to use "
491 "(0 for actual time, default is 1/1/06", ULL(1136073600)),
492 INIT_PARAM(mmu
, "Memory Controller"),
493 INIT_PARAM(addr
, "Device Address"),
494 INIT_PARAM_DFLT(io_bus
, "The IO Bus to attach to", NULL
),
495 INIT_PARAM_DFLT(pio_latency
, "Programmed IO latency in bus cycles", 1),
496 INIT_PARAM_DFLT(hier
, "Hierarchy global variables", &defaultHierParams
)
498 END_INIT_SIM_OBJECT_PARAMS(TsunamiIO
)
500 CREATE_SIM_OBJECT(TsunamiIO
)
502 return new TsunamiIO(getInstanceName(), tsunami
, time
, addr
, mmu
, hier
,
503 io_bus
, pio_latency
);
506 REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO
)