gem5/dev/tsunami_io.cc
Nathan Binkert 43a9caa221 expose variables for number of global events per simulated second,
millisecond, microsecond, etc. so that the user can explicitly
convert between system ticks and time and know what sorts of
expensive operations are being used for that conversion.

arch/alpha/alpha_tru64_process.cc:
arch/alpha/pseudo_inst.cc:
dev/etherdump.cc:
dev/etherlink.cc:
dev/ns_gige.cc:
dev/sinic.cc:
dev/tsunami_io.cc:
dev/uart.cc:
sim/stat_control.cc:
sim/syscall_emul.hh:
    Use the new variables for getting the event clock
dev/etherdump.hh:
    delete variables that are no longer needed.

--HG--
extra : convert_revision : d95fc7d44909443e1b7952a24ef822ef051c7cf2
2005-03-29 07:55:44 -05:00

511 lines
15 KiB
C++

/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* @file
* Tsunami I/O including PIC, PIT, RTC, DMA
*/
#include <sys/time.h>
#include <deque>
#include <string>
#include <vector>
#include "base/trace.hh"
#include "dev/tsunami_io.hh"
#include "dev/tsunami.hh"
#include "mem/bus/bus.hh"
#include "mem/bus/pio_interface.hh"
#include "mem/bus/pio_interface_impl.hh"
#include "sim/builder.hh"
#include "dev/tsunami_cchip.hh"
#include "dev/tsunamireg.h"
#include "dev/rtcreg.h"
#include "mem/functional_mem/memory_control.hh"
using namespace std;
#define UNIX_YEAR_OFFSET 52
// Timer Event for Periodic interrupt of RTC
TsunamiIO::RTCEvent::RTCEvent(Tsunami* t)
: Event(&mainEventQueue), tsunami(t)
{
DPRINTF(MC146818, "RTC Event Initilizing\n");
schedule(curTick + ticksPerSecond/RTC_RATE);
}
void
TsunamiIO::RTCEvent::process()
{
DPRINTF(MC146818, "RTC Timer Interrupt\n");
schedule(curTick + ticksPerSecond/RTC_RATE);
//Actually interrupt the processor here
tsunami->cchip->postRTC();
}
const char *
TsunamiIO::RTCEvent::description()
{
return "tsunami RTC 1024Hz interrupt";
}
void
TsunamiIO::RTCEvent::serialize(std::ostream &os)
{
Tick time = when();
SERIALIZE_SCALAR(time);
}
void
TsunamiIO::RTCEvent::unserialize(Checkpoint *cp, const std::string &section)
{
Tick time;
UNSERIALIZE_SCALAR(time);
reschedule(time);
}
// Timer Event for PIT Timers
TsunamiIO::ClockEvent::ClockEvent()
: Event(&mainEventQueue)
{
/* This is the PIT Tick Rate. A constant for the 8254 timer. The
* Tsunami platform has one of these cycle counters on the Cypress
* South Bridge and it is used by linux for estimating the cycle
* frequency of the machine it is running on. --Ali
*/
interval = (Tick)(Clock::Float::s / 1193180.0);
DPRINTF(Tsunami, "Clock Event Initilizing\n");
mode = 0;
}
void
TsunamiIO::ClockEvent::process()
{
DPRINTF(Tsunami, "Timer Interrupt\n");
if (mode == 0)
status = 0x20; // set bit that linux is looking for
else
schedule(curTick + interval);
}
void
TsunamiIO::ClockEvent::Program(int count)
{
DPRINTF(Tsunami, "Timer set to curTick + %d\n", count);
schedule(curTick + count * interval);
status = 0;
}
const char *
TsunamiIO::ClockEvent::description()
{
return "tsunami 8254 Interval timer";
}
void
TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
{
mode = md;
}
uint8_t
TsunamiIO::ClockEvent::Status()
{
return status;
}
void
TsunamiIO::ClockEvent::serialize(std::ostream &os)
{
Tick time = scheduled() ? when() : 0;
SERIALIZE_SCALAR(time);
SERIALIZE_SCALAR(status);
SERIALIZE_SCALAR(mode);
SERIALIZE_SCALAR(interval);
}
void
TsunamiIO::ClockEvent::unserialize(Checkpoint *cp, const std::string &section)
{
Tick time;
UNSERIALIZE_SCALAR(time);
UNSERIALIZE_SCALAR(status);
UNSERIALIZE_SCALAR(mode);
UNSERIALIZE_SCALAR(interval);
if (time)
schedule(time);
}
TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
Addr a, MemoryController *mmu, HierParams *hier, Bus *bus,
Tick pio_latency)
: PioDevice(name, t), addr(a), tsunami(t), rtc(t)
{
mmu->add_child(this, RangeSize(addr, size));
if (bus) {
pioInterface = newPioInterface(name, hier, bus, this,
&TsunamiIO::cacheAccess);
pioInterface->addAddrRange(RangeSize(addr, size));
pioLatency = pio_latency * bus->clockRatio;
}
// set the back pointer from tsunami to myself
tsunami->io = this;
timerData = 0;
set_time(init_time == 0 ? time(NULL) : init_time);
uip = 1;
picr = 0;
picInterrupting = false;
}
void
TsunamiIO::set_time(time_t t)
{
gmtime_r(&t, &tm);
DPRINTFN("Real-time clock set to %s", asctime(&tm));
}
Fault
TsunamiIO::read(MemReqPtr &req, uint8_t *data)
{
DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n",
req->vaddr, req->size, req->vaddr & 0xfff);
Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
switch(req->size) {
case sizeof(uint8_t):
switch(daddr) {
case TSDEV_PIC1_ISR:
// !!! If this is modified 64bit case needs to be too
// Pal code has to do a 64 bit physical read because there is
// no load physical byte instruction
*(uint8_t*)data = picr;
return No_Fault;
case TSDEV_PIC2_ISR:
// PIC2 not implemnted... just return 0
*(uint8_t*)data = 0x00;
return No_Fault;
case TSDEV_TMR_CTL:
*(uint8_t*)data = timer2.Status();
return No_Fault;
case TSDEV_RTC_DATA:
switch(RTCAddress) {
case RTC_CNTRL_REGA:
*(uint8_t*)data = uip << 7 | 0x26;
uip = !uip;
return No_Fault;
case RTC_CNTRL_REGB:
// DM and 24/12 and UIE
*(uint8_t*)data = 0x46;
return No_Fault;
case RTC_CNTRL_REGC:
// If we want to support RTC user access in linux
// This won't work, but for now it's fine
*(uint8_t*)data = 0x00;
return No_Fault;
case RTC_CNTRL_REGD:
panic("RTC Control Register D not implemented");
case RTC_SEC:
*(uint8_t *)data = tm.tm_sec;
return No_Fault;
case RTC_MIN:
*(uint8_t *)data = tm.tm_min;
return No_Fault;
case RTC_HR:
*(uint8_t *)data = tm.tm_hour;
return No_Fault;
case RTC_DOW:
*(uint8_t *)data = tm.tm_wday;
return No_Fault;
case RTC_DOM:
*(uint8_t *)data = tm.tm_mday;
case RTC_MON:
*(uint8_t *)data = tm.tm_mon + 1;
return No_Fault;
case RTC_YEAR:
*(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
return No_Fault;
default:
panic("Unknown RTC Address\n");
}
default:
panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
}
case sizeof(uint16_t):
case sizeof(uint32_t):
panic("I/O Read - invalid size - va %#x size %d\n",
req->vaddr, req->size);
case sizeof(uint64_t):
switch(daddr) {
case TSDEV_PIC1_ISR:
// !!! If this is modified 8bit case needs to be too
// Pal code has to do a 64 bit physical read because there is
// no load physical byte instruction
*(uint64_t*)data = (uint64_t)picr;
return No_Fault;
default:
panic("I/O Read - invalid size - va %#x size %d\n",
req->vaddr, req->size);
}
default:
panic("I/O Read - invalid size - va %#x size %d\n",
req->vaddr, req->size);
}
panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
return No_Fault;
}
Fault
TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
{
#if TRACING_ON
uint8_t dt = *(uint8_t*)data;
uint64_t dt64 = dt;
#endif
DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
req->vaddr, req->size, req->vaddr & 0xfff, dt64);
Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask));
switch(req->size) {
case sizeof(uint8_t):
switch(daddr) {
case TSDEV_PIC1_MASK:
mask1 = ~(*(uint8_t*)data);
if ((picr & mask1) && !picInterrupting) {
picInterrupting = true;
tsunami->cchip->postDRIR(55);
DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
}
if ((!(picr & mask1)) && picInterrupting) {
picInterrupting = false;
tsunami->cchip->clearDRIR(55);
DPRINTF(Tsunami, "clearing pic interrupt\n");
}
return No_Fault;
case TSDEV_PIC2_MASK:
mask2 = *(uint8_t*)data;
//PIC2 Not implemented to interrupt
return No_Fault;
case TSDEV_PIC1_ACK:
// clear the interrupt on the PIC
picr &= ~(1 << (*(uint8_t*)data & 0xF));
if (!(picr & mask1))
tsunami->cchip->clearDRIR(55);
return No_Fault;
case TSDEV_PIC2_ACK:
return No_Fault;
case TSDEV_DMA1_RESET:
return No_Fault;
case TSDEV_DMA2_RESET:
return No_Fault;
case TSDEV_DMA1_MODE:
mode1 = *(uint8_t*)data;
return No_Fault;
case TSDEV_DMA2_MODE:
mode2 = *(uint8_t*)data;
return No_Fault;
case TSDEV_DMA1_MASK:
case TSDEV_DMA2_MASK:
return No_Fault;
case TSDEV_TMR_CTL:
return No_Fault;
case TSDEV_TMR2_CTL:
if ((*(uint8_t*)data & 0x30) != 0x30)
panic("Only L/M write supported\n");
switch(*(uint8_t*)data >> 6) {
case 0:
timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
break;
case 2:
timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
break;
default:
panic("Read Back Command not implemented\n");
}
return No_Fault;
case TSDEV_TMR2_DATA:
/* two writes before we actually start the Timer
so I set a flag in the timerData */
if(timerData & 0x1000) {
timerData &= 0x1000;
timerData += *(uint8_t*)data << 8;
timer2.Program(timerData);
} else {
timerData = *(uint8_t*)data;
timerData |= 0x1000;
}
return No_Fault;
case TSDEV_TMR0_DATA:
/* two writes before we actually start the Timer
so I set a flag in the timerData */
if(timerData & 0x1000) {
timerData &= 0x1000;
timerData += *(uint8_t*)data << 8;
timer0.Program(timerData);
} else {
timerData = *(uint8_t*)data;
timerData |= 0x1000;
}
return No_Fault;
case TSDEV_RTC_ADDR:
RTCAddress = *(uint8_t*)data;
return No_Fault;
case TSDEV_RTC_DATA:
panic("RTC Write not implmented (rtc.o won't work)\n");
default:
panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
}
case sizeof(uint16_t):
case sizeof(uint32_t):
case sizeof(uint64_t):
default:
panic("I/O Write - invalid size - va %#x size %d\n",
req->vaddr, req->size);
}
return No_Fault;
}
void
TsunamiIO::postPIC(uint8_t bitvector)
{
//PIC2 Is not implemented, because nothing of interest there
picr |= bitvector;
if (picr & mask1) {
tsunami->cchip->postDRIR(55);
DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
}
}
void
TsunamiIO::clearPIC(uint8_t bitvector)
{
//PIC2 Is not implemented, because nothing of interest there
picr &= ~bitvector;
if (!(picr & mask1)) {
tsunami->cchip->clearDRIR(55);
DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
}
}
Tick
TsunamiIO::cacheAccess(MemReqPtr &req)
{
return curTick + pioLatency;
}
void
TsunamiIO::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(timerData);
SERIALIZE_SCALAR(uip);
SERIALIZE_SCALAR(mask1);
SERIALIZE_SCALAR(mask2);
SERIALIZE_SCALAR(mode1);
SERIALIZE_SCALAR(mode2);
SERIALIZE_SCALAR(picr);
SERIALIZE_SCALAR(picInterrupting);
SERIALIZE_SCALAR(RTCAddress);
// Serialize the timers
nameOut(os, csprintf("%s.timer0", name()));
timer0.serialize(os);
nameOut(os, csprintf("%s.timer2", name()));
timer2.serialize(os);
nameOut(os, csprintf("%s.rtc", name()));
rtc.serialize(os);
}
void
TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(timerData);
UNSERIALIZE_SCALAR(uip);
UNSERIALIZE_SCALAR(mask1);
UNSERIALIZE_SCALAR(mask2);
UNSERIALIZE_SCALAR(mode1);
UNSERIALIZE_SCALAR(mode2);
UNSERIALIZE_SCALAR(picr);
UNSERIALIZE_SCALAR(picInterrupting);
UNSERIALIZE_SCALAR(RTCAddress);
// Unserialize the timers
timer0.unserialize(cp, csprintf("%s.timer0", section));
timer2.unserialize(cp, csprintf("%s.timer2", section));
rtc.unserialize(cp, csprintf("%s.rtc", section));
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
SimObjectParam<Tsunami *> tsunami;
Param<time_t> time;
SimObjectParam<MemoryController *> mmu;
Param<Addr> addr;
SimObjectParam<Bus*> io_bus;
Param<Tick> pio_latency;
SimObjectParam<HierParams *> hier;
END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
INIT_PARAM(tsunami, "Tsunami"),
INIT_PARAM_DFLT(time, "System time to use "
"(0 for actual time, default is 1/1/06", ULL(1136073600)),
INIT_PARAM(mmu, "Memory Controller"),
INIT_PARAM(addr, "Device Address"),
INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
CREATE_SIM_OBJECT(TsunamiIO)
{
return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier,
io_bus, pio_latency);
}
REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)