memory mode information now contained in system object

States are now running, draining, or drained. memory state information moved into system object
system parameter is not fs only for cpus
Implement drain() support in devices
Update for drain() call that returns number of times drain_event->process() will be called

Break O3 CPU! No sense in putting in a hack change that kevin is going to remove in a few minutes i imagine

src/cpu/simple/atomic.cc:
src/cpu/simple/atomic.hh:
    Since se mode has a system, allow access to it
    Verify that the atomic cpu is connected to an atomic system on resume
src/cpu/simple/base.cc:
    Since se mode has a system, allow access to it
src/cpu/simple/timing.cc:
src/cpu/simple/timing.hh:
    Update for new drain() call that returns number of times drain_event->process() will be called and memory state being moved into the system
    Since se mode has a system, allow access to it
    Verify that the timing cpu is connected to an timing system on resume
src/dev/ide_disk.cc:
src/dev/io_device.cc:
src/dev/io_device.hh:
src/dev/ns_gige.cc:
src/dev/ns_gige.hh:
src/dev/pcidev.cc:
src/dev/pcidev.hh:
src/dev/sinic.cc:
src/dev/sinic.hh:
    Implement drain() support in devices
src/python/m5/config.py:
    Allow drain to return number of times drain_event->process() will be called. Normally 0 or 1 but things like O3 cpu or devices with multiple ports may want to call it many times
src/python/m5/objects/BaseCPU.py:
    move system parameter out of fs to everyone
src/sim/sim_object.cc:
src/sim/sim_object.hh:
    States are now running, draining, or drained. memory state information moved into system object
src/sim/system.cc:
src/sim/system.hh:
    memory mode information now contained in system object

--HG--
extra : convert_revision : 1389c77e66ee6d9710bf77b4306fb47e107b21cf
This commit is contained in:
Ali Saidi 2006-07-12 20:22:07 -04:00
parent bbfe1db6b3
commit 2bc9229ea7
20 changed files with 270 additions and 118 deletions

View file

@ -33,6 +33,7 @@
#include "cpu/simple/atomic.hh" #include "cpu/simple/atomic.hh"
#include "mem/packet_impl.hh" #include "mem/packet_impl.hh"
#include "sim/builder.hh" #include "sim/builder.hh"
#include "sim/system.hh"
using namespace std; using namespace std;
using namespace TheISA; using namespace TheISA;
@ -172,6 +173,13 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
} }
void
AtomicSimpleCPU::resume()
{
assert(system->getMemoryMode() == System::Atomic);
changeState(SimObject::Running);
}
void void
AtomicSimpleCPU::switchOut() AtomicSimpleCPU::switchOut()
{ {
@ -451,11 +459,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
Param<Counter> max_loads_any_thread; Param<Counter> max_loads_any_thread;
Param<Counter> max_loads_all_threads; Param<Counter> max_loads_all_threads;
SimObjectParam<MemObject *> mem; SimObjectParam<MemObject *> mem;
SimObjectParam<System *> system;
#if FULL_SYSTEM #if FULL_SYSTEM
SimObjectParam<AlphaITB *> itb; SimObjectParam<AlphaITB *> itb;
SimObjectParam<AlphaDTB *> dtb; SimObjectParam<AlphaDTB *> dtb;
SimObjectParam<System *> system;
Param<int> cpu_id; Param<int> cpu_id;
Param<Tick> profile; Param<Tick> profile;
#else #else
@ -483,11 +491,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
INIT_PARAM(max_loads_all_threads, INIT_PARAM(max_loads_all_threads,
"terminate when all threads have reached this load count"), "terminate when all threads have reached this load count"),
INIT_PARAM(mem, "memory"), INIT_PARAM(mem, "memory"),
INIT_PARAM(system, "system object"),
#if FULL_SYSTEM #if FULL_SYSTEM
INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(itb, "Instruction TLB"),
INIT_PARAM(dtb, "Data TLB"), INIT_PARAM(dtb, "Data TLB"),
INIT_PARAM(system, "system object"),
INIT_PARAM(cpu_id, "processor ID"), INIT_PARAM(cpu_id, "processor ID"),
INIT_PARAM(profile, ""), INIT_PARAM(profile, ""),
#else #else
@ -520,11 +528,11 @@ CREATE_SIM_OBJECT(AtomicSimpleCPU)
params->width = width; params->width = width;
params->simulate_stalls = simulate_stalls; params->simulate_stalls = simulate_stalls;
params->mem = mem; params->mem = mem;
params->system = system;
#if FULL_SYSTEM #if FULL_SYSTEM
params->itb = itb; params->itb = itb;
params->dtb = dtb; params->dtb = dtb;
params->system = system;
params->cpu_id = cpu_id; params->cpu_id = cpu_id;
params->profile = profile; params->profile = profile;
#else #else

View file

@ -127,6 +127,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU
virtual void serialize(std::ostream &os); virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section); virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual void resume();
void switchOut(); void switchOut();
void takeOverFrom(BaseCPU *oldCPU); void takeOverFrom(BaseCPU *oldCPU);

View file

@ -55,10 +55,10 @@
#include "sim/sim_events.hh" #include "sim/sim_events.hh"
#include "sim/sim_object.hh" #include "sim/sim_object.hh"
#include "sim/stats.hh" #include "sim/stats.hh"
#include "sim/system.hh"
#if FULL_SYSTEM #if FULL_SYSTEM
#include "base/remote_gdb.hh" #include "base/remote_gdb.hh"
#include "sim/system.hh"
#include "arch/tlb.hh" #include "arch/tlb.hh"
#include "arch/stacktrace.hh" #include "arch/stacktrace.hh"
#include "arch/vtophys.hh" #include "arch/vtophys.hh"

View file

@ -33,6 +33,7 @@
#include "cpu/simple/timing.hh" #include "cpu/simple/timing.hh"
#include "mem/packet_impl.hh" #include "mem/packet_impl.hh"
#include "sim/builder.hh" #include "sim/builder.hh"
#include "sim/system.hh"
using namespace std; using namespace std;
using namespace TheISA; using namespace TheISA;
@ -91,7 +92,7 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
ifetch_pkt = dcache_pkt = NULL; ifetch_pkt = dcache_pkt = NULL;
drainEvent = NULL; drainEvent = NULL;
fetchEvent = NULL; fetchEvent = NULL;
state = SimObject::Timing; changeState(SimObject::Running);
} }
@ -113,18 +114,18 @@ TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
BaseSimpleCPU::unserialize(cp, section); BaseSimpleCPU::unserialize(cp, section);
} }
bool unsigned int
TimingSimpleCPU::drain(Event *drain_event) TimingSimpleCPU::drain(Event *drain_event)
{ {
// TimingSimpleCPU is ready to drain if it's not waiting for // TimingSimpleCPU is ready to drain if it's not waiting for
// an access to complete. // an access to complete.
if (status() == Idle || status() == Running || status() == SwitchedOut) { if (status() == Idle || status() == Running || status() == SwitchedOut) {
changeState(SimObject::DrainedTiming); changeState(SimObject::Drained);
return true; return 0;
} else { } else {
changeState(SimObject::Draining); changeState(SimObject::Draining);
drainEvent = drain_event; drainEvent = drain_event;
return false; return 1;
} }
} }
@ -142,12 +143,9 @@ TimingSimpleCPU::resume()
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
fetchEvent->schedule(curTick); fetchEvent->schedule(curTick);
} }
}
void assert(system->getMemoryMode() == System::Timing);
TimingSimpleCPU::setMemoryMode(State new_mode) changeState(SimObject::Running);
{
assert(new_mode == SimObject::Timing);
} }
void void
@ -514,7 +512,7 @@ void
TimingSimpleCPU::completeDrain() TimingSimpleCPU::completeDrain()
{ {
DPRINTF(Config, "Done draining\n"); DPRINTF(Config, "Done draining\n");
changeState(SimObject::DrainedTiming); changeState(SimObject::Drained);
drainEvent->process(); drainEvent->process();
} }
@ -551,11 +549,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
Param<Counter> max_loads_any_thread; Param<Counter> max_loads_any_thread;
Param<Counter> max_loads_all_threads; Param<Counter> max_loads_all_threads;
SimObjectParam<MemObject *> mem; SimObjectParam<MemObject *> mem;
SimObjectParam<System *> system;
#if FULL_SYSTEM #if FULL_SYSTEM
SimObjectParam<AlphaITB *> itb; SimObjectParam<AlphaITB *> itb;
SimObjectParam<AlphaDTB *> dtb; SimObjectParam<AlphaDTB *> dtb;
SimObjectParam<System *> system;
Param<int> cpu_id; Param<int> cpu_id;
Param<Tick> profile; Param<Tick> profile;
#else #else
@ -583,11 +581,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
INIT_PARAM(max_loads_all_threads, INIT_PARAM(max_loads_all_threads,
"terminate when all threads have reached this load count"), "terminate when all threads have reached this load count"),
INIT_PARAM(mem, "memory"), INIT_PARAM(mem, "memory"),
INIT_PARAM(system, "system object"),
#if FULL_SYSTEM #if FULL_SYSTEM
INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(itb, "Instruction TLB"),
INIT_PARAM(dtb, "Data TLB"), INIT_PARAM(dtb, "Data TLB"),
INIT_PARAM(system, "system object"),
INIT_PARAM(cpu_id, "processor ID"), INIT_PARAM(cpu_id, "processor ID"),
INIT_PARAM(profile, ""), INIT_PARAM(profile, ""),
#else #else
@ -618,11 +616,11 @@ CREATE_SIM_OBJECT(TimingSimpleCPU)
params->functionTrace = function_trace; params->functionTrace = function_trace;
params->functionTraceStart = function_trace_start; params->functionTraceStart = function_trace_start;
params->mem = mem; params->mem = mem;
params->system = system;
#if FULL_SYSTEM #if FULL_SYSTEM
params->itb = itb; params->itb = itb;
params->dtb = dtb; params->dtb = dtb;
params->system = system;
params->cpu_id = cpu_id; params->cpu_id = cpu_id;
params->profile = profile; params->profile = profile;
#else #else

View file

@ -137,9 +137,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
virtual void serialize(std::ostream &os); virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section); virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual bool drain(Event *drain_event); virtual unsigned int drain(Event *drain_event);
virtual void resume(); virtual void resume();
virtual void setMemoryMode(State new_mode);
void switchOut(); void switchOut();
void takeOverFrom(BaseCPU *oldCPU); void takeOverFrom(BaseCPU *oldCPU);

View file

@ -318,7 +318,7 @@ IdeDisk::doDmaTransfer()
panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
dmaState, devState); dmaState, devState);
if (ctrl->dmaPending()) { if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return; return;
} else } else
@ -398,8 +398,7 @@ IdeDisk::doDmaRead()
curPrd.getByteCount(), TheISA::PageBytes); curPrd.getByteCount(), TheISA::PageBytes);
} }
if (ctrl->dmaPending()) { if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
panic("shouldn't be reentant??");
dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return; return;
} else if (!dmaReadCG->done()) { } else if (!dmaReadCG->done()) {
@ -474,8 +473,7 @@ IdeDisk::doDmaWrite()
dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
curPrd.getByteCount(), TheISA::PageBytes); curPrd.getByteCount(), TheISA::PageBytes);
} }
if (ctrl->dmaPending()) { if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
panic("shouldn't be reentant??");
dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return; return;
} else if (!dmaWriteCG->done()) { } else if (!dmaWriteCG->done()) {

View file

@ -32,10 +32,12 @@
#include "base/trace.hh" #include "base/trace.hh"
#include "dev/io_device.hh" #include "dev/io_device.hh"
#include "sim/builder.hh" #include "sim/builder.hh"
#include "sim/system.hh"
PioPort::PioPort(PioDevice *dev, Platform *p, std::string pname) PioPort::PioPort(PioDevice *dev, System *s, std::string pname)
: Port(dev->name() + pname), device(dev), platform(p) : Port(dev->name() + pname), device(dev), sys(s),
outTiming(0), drainEvent(NULL)
{ } { }
@ -68,12 +70,22 @@ PioPort::recvRetry()
if (result) if (result)
transmitList.pop_front(); transmitList.pop_front();
} }
if (transmitList.size() == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
} }
void void
PioPort::SendEvent::process() PioPort::SendEvent::process()
{ {
port->outTiming--;
assert(port->outTiming >= 0);
if (port->Port::sendTiming(packet)) if (port->Port::sendTiming(packet))
if (port->transmitList.size() == 0 && port->drainEvent) {
port->drainEvent->process();
port->drainEvent = NULL;
}
return; return;
port->transmitList.push_back(packet); port->transmitList.push_back(packet);
@ -105,6 +117,15 @@ PioPort::recvTiming(Packet *pkt)
return true; return true;
} }
unsigned int
PioPort::drain(Event *de)
{
if (outTiming == 0 && transmitList.size() == 0)
return 0;
drainEvent = de;
return 1;
}
PioDevice::~PioDevice() PioDevice::~PioDevice()
{ {
if (pioPort) if (pioPort)
@ -119,6 +140,19 @@ PioDevice::init()
pioPort->sendStatusChange(Port::RangeChange); pioPort->sendStatusChange(Port::RangeChange);
} }
unsigned int
PioDevice::drain(Event *de)
{
unsigned int count;
count = pioPort->drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
return count;
}
void void
BasicPioDevice::addressRanges(AddrRangeList &range_list) BasicPioDevice::addressRanges(AddrRangeList &range_list)
{ {
@ -128,8 +162,9 @@ BasicPioDevice::addressRanges(AddrRangeList &range_list)
} }
DmaPort::DmaPort(DmaDevice *dev, Platform *p) DmaPort::DmaPort(DmaDevice *dev, System *s)
: Port(dev->name() + "-dmaport"), device(dev), platform(p), pendingCount(0) : Port(dev->name() + "-dmaport"), device(dev), sys(s), pendingCount(0),
actionInProgress(0), drainEvent(NULL)
{ } { }
bool bool
@ -159,6 +194,11 @@ DmaPort::recvTiming(Packet *pkt)
} }
delete pkt->req; delete pkt->req;
delete pkt; delete pkt;
if (pendingCount == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
} else { } else {
panic("Got packet without sender state... huh?\n"); panic("Got packet without sender state... huh?\n");
} }
@ -170,6 +210,29 @@ DmaDevice::DmaDevice(Params *p)
: PioDevice(p), dmaPort(NULL) : PioDevice(p), dmaPort(NULL)
{ } { }
unsigned int
DmaDevice::drain(Event *de)
{
unsigned int count;
count = pioPort->drain(de) + dmaPort->drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
return count;
}
unsigned int
DmaPort::drain(Event *de)
{
if (pendingCount == 0)
return 0;
drainEvent = de;
return 1;
}
void void
DmaPort::recvRetry() DmaPort::recvRetry()
{ {
@ -195,6 +258,8 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
{ {
assert(event); assert(event);
assert(device->getState() == SimObject::Running);
DmaReqState *reqState = new DmaReqState(event, this, size); DmaReqState *reqState = new DmaReqState(event, this, size);
for (ChunkGenerator gen(addr, size, peerBlockSize()); for (ChunkGenerator gen(addr, size, peerBlockSize());
@ -212,6 +277,7 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
pendingCount++; pendingCount++;
sendDma(pkt); sendDma(pkt);
} }
} }
@ -221,9 +287,8 @@ DmaPort::sendDma(Packet *pkt, bool front)
// some kind of selction between access methods // some kind of selction between access methods
// more work is going to have to be done to make // more work is going to have to be done to make
// switching actually work // switching actually work
/* MemState state = device->platform->system->memState; System::MemoryMode state = sys->getMemoryMode();
if (state == System::Timing) {
if (state == Timing) { */
DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n",
pkt, pkt->getAddr()); pkt, pkt->getAddr());
if (transmitList.size() || !sendTiming(pkt)) { if (transmitList.size() || !sendTiming(pkt)) {
@ -235,28 +300,30 @@ DmaPort::sendDma(Packet *pkt, bool front)
} else { } else {
DPRINTF(DMA, "-- Done\n"); DPRINTF(DMA, "-- Done\n");
} }
/* } else if (state == Atomic) { } else if (state == System::Atomic) {
sendAtomic(pkt); sendAtomic(pkt);
if (pkt->senderState) { assert(pkt->senderState);
DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
assert(state); assert(state);
state->completionEvent->schedule(curTick + (pkt->time -
pkt->req->getTime()) +1); state->numBytes += pkt->req->getSize();
if (state->totBytes == state->numBytes) {
state->completionEvent->schedule(curTick +
(pkt->time - pkt->req->getTime()) +1);
delete state; delete state;
delete pkt->req;
} }
pendingCount--; pendingCount--;
assert(pendingCount >= 0); assert(pendingCount >= 0);
delete pkt->req;
delete pkt; delete pkt;
} else if (state == Functional) { if (pendingCount == 0 && drainEvent) {
sendFunctional(pkt); drainEvent->process();
// Is this correct??? drainEvent = NULL;
completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime); }
completionEvent == NULL;
} else } else
panic("Unknown memory command state."); panic("Unknown memory command state.");
*/
} }
DmaDevice::~DmaDevice() DmaDevice::~DmaDevice()

View file

@ -60,9 +60,9 @@ class PioPort : public Port
/** The device that this port serves. */ /** The device that this port serves. */
PioDevice *device; PioDevice *device;
/** The platform that device/port are in. This is used to select which mode /** The system that device/port are in. This is used to select which mode
* we are currently operating in. */ * we are currently operating in. */
Platform *platform; System *sys;
/** A list of outgoing timing response packets that haven't been serviced /** A list of outgoing timing response packets that haven't been serviced
* yet. */ * yet. */
@ -106,16 +106,27 @@ class PioPort : public Port
friend class PioPort; friend class PioPort;
}; };
/** Number of timing requests that are emulating the device timing before
* attempting to end up on the bus.
*/
int outTiming;
/** If we need to drain, keep the drain event around until we're done
* here.*/
Event *drainEvent;
/** Schedule a sendTiming() event to be called in the future. */ /** Schedule a sendTiming() event to be called in the future. */
void sendTiming(Packet *pkt, Tick time) void sendTiming(Packet *pkt, Tick time)
{ new PioPort::SendEvent(this, pkt, time); } { outTiming++; new PioPort::SendEvent(this, pkt, time); }
/** This function is notification that the device should attempt to send a /** This function is notification that the device should attempt to send a
* packet again. */ * packet again. */
virtual void recvRetry(); virtual void recvRetry();
public: public:
PioPort(PioDevice *dev, Platform *p, std::string pname = "-pioport"); PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");
unsigned int drain(Event *de);
friend class PioPort::SendEvent; friend class PioPort::SendEvent;
}; };
@ -147,13 +158,20 @@ class DmaPort : public Port
DmaDevice *device; DmaDevice *device;
std::list<Packet*> transmitList; std::list<Packet*> transmitList;
/** The platform that device/port are in. This is used to select which mode /** The system that device/port are in. This is used to select which mode
* we are currently operating in. */ * we are currently operating in. */
Platform *platform; System *sys;
/** Number of outstanding packets the dma port has. */ /** Number of outstanding packets the dma port has. */
int pendingCount; int pendingCount;
/** If a dmaAction is in progress. */
int actionInProgress;
/** If we need to drain, keep the drain event around until we're done
* here.*/
Event *drainEvent;
virtual bool recvTiming(Packet *pkt); virtual bool recvTiming(Packet *pkt);
virtual Tick recvAtomic(Packet *pkt) virtual Tick recvAtomic(Packet *pkt)
{ panic("dma port shouldn't be used for pio access."); } { panic("dma port shouldn't be used for pio access."); }
@ -171,13 +189,14 @@ class DmaPort : public Port
void sendDma(Packet *pkt, bool front = false); void sendDma(Packet *pkt, bool front = false);
public: public:
DmaPort(DmaDevice *dev, Platform *p); DmaPort(DmaDevice *dev, System *s);
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
uint8_t *data = NULL); uint8_t *data = NULL);
bool dmaPending() { return pendingCount > 0; } bool dmaPending() { return pendingCount > 0; }
unsigned int drain(Event *de);
}; };
/** /**
@ -196,6 +215,8 @@ class PioDevice : public MemObject
* transaction we should perform. */ * transaction we should perform. */
Platform *platform; Platform *platform;
System *sys;
/** The pioPort that handles the requests for us and provides us requests /** The pioPort that handles the requests for us and provides us requests
* that it sees. */ * that it sees. */
PioPort *pioPort; PioPort *pioPort;
@ -240,20 +261,22 @@ class PioDevice : public MemObject
const Params *params() const { return _params; } const Params *params() const { return _params; }
PioDevice(Params *p) PioDevice(Params *p)
: MemObject(p->name), platform(p->platform), pioPort(NULL), : MemObject(p->name), platform(p->platform), sys(p->system),
_params(p) pioPort(NULL), _params(p)
{} {}
virtual ~PioDevice(); virtual ~PioDevice();
virtual void init(); virtual void init();
virtual unsigned int drain(Event *de);
virtual Port *getPort(const std::string &if_name, int idx = -1) virtual Port *getPort(const std::string &if_name, int idx = -1)
{ {
if (if_name == "pio") { if (if_name == "pio") {
if (pioPort != NULL) if (pioPort != NULL)
panic("pio port already connected to."); panic("pio port already connected to.");
pioPort = new PioPort(this, params()->platform); pioPort = new PioPort(this, sys);
return pioPort; return pioPort;
} else } else
return NULL; return NULL;
@ -310,17 +333,19 @@ class DmaDevice : public PioDevice
bool dmaPending() { return dmaPort->dmaPending(); } bool dmaPending() { return dmaPort->dmaPending(); }
virtual unsigned int drain(Event *de);
virtual Port *getPort(const std::string &if_name, int idx = -1) virtual Port *getPort(const std::string &if_name, int idx = -1)
{ {
if (if_name == "pio") { if (if_name == "pio") {
if (pioPort != NULL) if (pioPort != NULL)
panic("pio port already connected to."); panic("pio port already connected to.");
pioPort = new PioPort(this, params()->platform); pioPort = new PioPort(this, sys);
return pioPort; return pioPort;
} else if (if_name == "dma") { } else if (if_name == "dma") {
if (dmaPort != NULL) if (dmaPort != NULL)
panic("dma port already connected to."); panic("dma port already connected to.");
dmaPort = new DmaPort(this, params()->platform); dmaPort = new DmaPort(this, sys);
return dmaPort; return dmaPort;
} else } else
return NULL; return NULL;

View file

@ -1377,7 +1377,7 @@ NSGigE::doRxDmaRead()
assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
rxDmaState = dmaReading; rxDmaState = dmaReading;
if (dmaPending()) if (dmaPending() || getState() != Running)
rxDmaState = dmaReadWaiting; rxDmaState = dmaReadWaiting;
else else
dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
@ -1408,7 +1408,7 @@ NSGigE::doRxDmaWrite()
assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
rxDmaState = dmaWriting; rxDmaState = dmaWriting;
if (dmaPending()) if (dmaPending() || getState() != Running)
rxDmaState = dmaWriteWaiting; rxDmaState = dmaWriteWaiting;
else else
dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
@ -1826,7 +1826,7 @@ NSGigE::doTxDmaRead()
assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
txDmaState = dmaReading; txDmaState = dmaReading;
if (dmaPending()) if (dmaPending() || getState() != Running)
txDmaState = dmaReadWaiting; txDmaState = dmaReadWaiting;
else else
dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
@ -1857,7 +1857,7 @@ NSGigE::doTxDmaWrite()
assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
txDmaState = dmaWriting; txDmaState = dmaWriting;
if (dmaPending()) if (dmaPending() || getState() != Running)
txDmaState = dmaWriteWaiting; txDmaState = dmaWriteWaiting;
else else
dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
@ -2406,6 +2406,20 @@ NSGigE::recvPacket(EthPacketPtr packet)
return true; return true;
} }
void
NSGigE::resume()
{
SimObject::resume();
// During drain we could have left the state machines in a waiting state and
// they wouldn't get out until some other event occured to kick them.
// This way they'll get out immediately
txKick();
rxKick();
}
//===================================================================== //=====================================================================
// //
// //

View file

@ -391,6 +391,8 @@ class NSGigE : public PciDev
virtual void serialize(std::ostream &os); virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section); virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual void resume();
public: public:
void regStats(); void regStats();

View file

@ -56,8 +56,8 @@ using namespace std;
PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
int funcid, Platform *p) int funcid, Platform *p)
: PioPort(dev,p,"-pciconf"), device(dev), busId(busid), deviceId(devid), : PioPort(dev,p->system,"-pciconf"), device(dev), platform(p),
functionId(funcid) busId(busid), deviceId(devid), functionId(funcid)
{ {
configAddr = platform->calcConfigAddr(busId, deviceId, functionId); configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
} }
@ -132,6 +132,18 @@ PciDev::init()
PioDevice::init(); PioDevice::init();
} }
unsigned int
PciDev::drain(Event *de)
{
unsigned int count;
count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
return count;
}
Tick Tick
PciDev::readConfig(Packet *pkt) PciDev::readConfig(Packet *pkt)
{ {

View file

@ -95,6 +95,8 @@ class PciDev : public DmaDevice
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
Platform *platform;
int busId; int busId;
int deviceId; int deviceId;
int functionId; int functionId;
@ -249,6 +251,9 @@ class PciDev : public DmaDevice
*/ */
virtual void unserialize(Checkpoint *cp, const std::string &section); virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *de);
virtual Port *getPort(const std::string &if_name, int idx = -1) virtual Port *getPort(const std::string &if_name, int idx = -1)
{ {
if (if_name == "config") { if (if_name == "config") {

View file

@ -921,7 +921,7 @@ Device::rxKick()
break; break;
case rxBeginCopy: case rxBeginCopy:
if (dmaPending()) if (dmaPending() || getState() != Running)
goto exit; goto exit;
rxDmaAddr = params()->platform->pciToDma( rxDmaAddr = params()->platform->pciToDma(
@ -1109,7 +1109,7 @@ Device::txKick()
break; break;
case txBeginCopy: case txBeginCopy:
if (dmaPending()) if (dmaPending() || getState() != Running)
goto exit; goto exit;
txDmaAddr = params()->platform->pciToDma( txDmaAddr = params()->platform->pciToDma(
@ -1287,6 +1287,18 @@ Device::recvPacket(EthPacketPtr packet)
return true; return true;
} }
void
Device::resume()
{
SimObject::resume();
// During drain we could have left the state machines in a waiting state and
// they wouldn't get out until some other event occured to kick them.
// This way they'll get out immediately
txKick();
rxKick();
}
//===================================================================== //=====================================================================
// //
// //

View file

@ -266,6 +266,7 @@ class Device : public Base
public: public:
virtual Tick read(Packet *pkt); virtual Tick read(Packet *pkt);
virtual Tick write(Packet *pkt); virtual Tick write(Packet *pkt);
virtual void resume();
void prepareIO(int cpu, int index); void prepareIO(int cpu, int index);
void prepareRead(int cpu, int index); void prepareRead(int cpu, int index);

View file

@ -547,8 +547,7 @@ class SimObject(object):
count = 0 count = 0
# ParamContexts don't serialize # ParamContexts don't serialize
if isinstance(self, SimObject) and not isinstance(self, ParamContext): if isinstance(self, SimObject) and not isinstance(self, ParamContext):
if not self._ccObject.drain(drain_event): count += self._ccObject.drain(drain_event)
count = 1
if recursive: if recursive:
for child in self._children.itervalues(): for child in self._children.itervalues():
count += child.startDrain(drain_event, True) count += child.startDrain(drain_event, True)
@ -561,7 +560,7 @@ class SimObject(object):
child.resume() child.resume()
def changeTiming(self, mode): def changeTiming(self, mode):
if isinstance(self, SimObject) and not isinstance(self, ParamContext): if isinstance(self, System):
self._ccObject.setMemoryMode(mode) self._ccObject.setMemoryMode(mode)
for child in self._children.itervalues(): for child in self._children.itervalues():
child.changeTiming(mode) child.changeTiming(mode)

View file

@ -6,10 +6,10 @@ class BaseCPU(SimObject):
abstract = True abstract = True
mem = Param.MemObject("memory") mem = Param.MemObject("memory")
system = Param.System(Parent.any, "system object")
if build_env['FULL_SYSTEM']: if build_env['FULL_SYSTEM']:
dtb = Param.AlphaDTB("Data TLB") dtb = Param.AlphaDTB("Data TLB")
itb = Param.AlphaITB("Instruction TLB") itb = Param.AlphaITB("Instruction TLB")
system = Param.System(Parent.any, "system object")
cpu_id = Param.Int(-1, "CPU identifier") cpu_id = Param.Int(-1, "CPU identifier")
else: else:
workload = VectorParam.Process("processes to run") workload = VectorParam.Process("processes to run")

View file

@ -72,7 +72,7 @@ SimObject::SimObject(Params *p)
doRecordEvent = !Stats::event_ignore.match(name()); doRecordEvent = !Stats::event_ignore.match(name());
simObjectList.push_back(this); simObjectList.push_back(this);
state = Atomic; state = Running;
} }
// //
@ -88,7 +88,7 @@ SimObject::SimObject(const string &_name)
doRecordEvent = !Stats::event_ignore.match(name()); doRecordEvent = !Stats::event_ignore.match(name());
simObjectList.push_back(this); simObjectList.push_back(this);
state = Atomic; state = Running;
} }
void void
@ -269,38 +269,23 @@ SimObject::recordEvent(const std::string &stat)
Stats::recordEvent(stat); Stats::recordEvent(stat);
} }
bool unsigned int
SimObject::drain(Event *drain_event) SimObject::drain(Event *drain_event)
{ {
if (state != DrainedAtomic && state != Atomic) { state = Drained;
panic("Must implement your own drain function if it is to be used " return 0;
"in timing mode!");
}
state = DrainedAtomic;
return true;
} }
void void
SimObject::resume() SimObject::resume()
{ {
if (state == DrainedAtomic) { state = Running;
state = Atomic;
} else if (state == DrainedTiming) {
state = Timing;
}
} }
void void
SimObject::setMemoryMode(State new_mode) SimObject::setMemoryMode(State new_mode)
{ {
assert(new_mode == Timing || new_mode == Atomic); panic("setMemoryMode() should only be called on systems");
if (state == DrainedAtomic && new_mode == Timing) {
state = DrainedTiming;
} else if (state == DrainedTiming && new_mode == Atomic) {
state = DrainedAtomic;
} else {
state = new_mode;
}
} }
void void

View file

@ -60,16 +60,15 @@ class SimObject : public Serializable, protected StartupCallback
}; };
enum State { enum State {
Atomic, Running,
Timing,
Draining, Draining,
DrainedAtomic, Drained
DrainedTiming
}; };
private:
State state;
protected: protected:
Params *_params; Params *_params;
State state;
void changeState(State new_state) { state = new_state; } void changeState(State new_state) { state = new_state; }
@ -116,8 +115,10 @@ class SimObject : public Serializable, protected StartupCallback
// Methods to drain objects in order to take checkpoints // Methods to drain objects in order to take checkpoints
// Or switch from timing -> atomic memory model // Or switch from timing -> atomic memory model
// Drain returns false if the SimObject cannot drain immediately. // Drain returns 0 if the simobject can drain immediately or
virtual bool drain(Event *drain_event); // the number of times the drain_event's process function will be called
// before the object will be done draining. Normally this should be 1
virtual unsigned int drain(Event *drain_event);
virtual void resume(); virtual void resume();
virtual void setMemoryMode(State new_mode); virtual void setMemoryMode(State new_mode);
virtual void switchOut(); virtual void switchOut();

View file

@ -143,6 +143,14 @@ int rgdb_wait = -1;
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
void
System::setMemoryMode(MemoryMode mode)
{
assert(getState() == Drained);
memoryMode = mode;
}
int int
System::registerThreadContext(ThreadContext *tc, int id) System::registerThreadContext(ThreadContext *tc, int id)
{ {

View file

@ -61,6 +61,21 @@ class RemoteGDB;
class System : public SimObject class System : public SimObject
{ {
public: public:
enum MemoryMode {
Invalid=0,
Atomic,
Timing
};
MemoryMode getMemoryMode() { assert(memoryMode); return memoryMode; }
/** Change the memory mode of the system. This should only be called by the
* python!!
* @param mode Mode to change to (atomic/timing)
*/
void setMemoryMode(MemoryMode mode);
PhysicalMemory *physmem; PhysicalMemory *physmem;
PCEventQueue pcEventQueue; PCEventQueue pcEventQueue;
@ -108,6 +123,8 @@ class System : public SimObject
protected: protected:
MemoryMode memoryMode;
#if FULL_SYSTEM #if FULL_SYSTEM
/** /**
* Fix up an address used to match PCs for hooking simulator * Fix up an address used to match PCs for hooking simulator