From 2bc9229ea7195b307222bad6de966ea4a27a3f6b Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Wed, 12 Jul 2006 20:22:07 -0400 Subject: 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 --- src/cpu/simple/atomic.cc | 14 +++- src/cpu/simple/atomic.hh | 1 + src/cpu/simple/base.cc | 2 +- src/cpu/simple/timing.cc | 26 ++++--- src/cpu/simple/timing.hh | 3 +- src/dev/ide_disk.cc | 8 +-- src/dev/io_device.cc | 151 ++++++++++++++++++++++++++++----------- src/dev/io_device.hh | 49 +++++++++---- src/dev/ns_gige.cc | 22 ++++-- src/dev/ns_gige.hh | 2 + src/dev/pcidev.cc | 16 ++++- src/dev/pcidev.hh | 5 ++ src/dev/sinic.cc | 16 ++++- src/dev/sinic.hh | 1 + src/python/m5/config.py | 5 +- src/python/m5/objects/BaseCPU.py | 2 +- src/sim/sim_object.cc | 29 ++------ src/sim/sim_object.hh | 15 ++-- src/sim/system.cc | 8 +++ src/sim/system.hh | 17 +++++ 20 files changed, 272 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 12bfdeb9b..1752b2b5b 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -33,6 +33,7 @@ #include "cpu/simple/atomic.hh" #include "mem/packet_impl.hh" #include "sim/builder.hh" +#include "sim/system.hh" using namespace std; using namespace TheISA; @@ -172,6 +173,13 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); } +void +AtomicSimpleCPU::resume() +{ + assert(system->getMemoryMode() == System::Atomic); + changeState(SimObject::Running); +} + void AtomicSimpleCPU::switchOut() { @@ -451,11 +459,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU) Param max_loads_any_thread; Param max_loads_all_threads; SimObjectParam mem; + SimObjectParam system; #if FULL_SYSTEM SimObjectParam itb; SimObjectParam dtb; - SimObjectParam system; Param cpu_id; Param profile; #else @@ -483,11 +491,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU) INIT_PARAM(max_loads_all_threads, "terminate when all threads have reached this load count"), INIT_PARAM(mem, "memory"), + INIT_PARAM(system, "system object"), #if FULL_SYSTEM INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(system, "system object"), INIT_PARAM(cpu_id, "processor ID"), INIT_PARAM(profile, ""), #else @@ -520,11 +528,11 @@ CREATE_SIM_OBJECT(AtomicSimpleCPU) params->width = width; params->simulate_stalls = simulate_stalls; params->mem = mem; + params->system = system; #if FULL_SYSTEM params->itb = itb; params->dtb = dtb; - params->system = system; params->cpu_id = cpu_id; params->profile = profile; #else diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 179b4a721..d59ca01aa 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -127,6 +127,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); + virtual void resume(); void switchOut(); void takeOverFrom(BaseCPU *oldCPU); diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index a50541189..af10e64d7 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -55,10 +55,10 @@ #include "sim/sim_events.hh" #include "sim/sim_object.hh" #include "sim/stats.hh" +#include "sim/system.hh" #if FULL_SYSTEM #include "base/remote_gdb.hh" -#include "sim/system.hh" #include "arch/tlb.hh" #include "arch/stacktrace.hh" #include "arch/vtophys.hh" diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index e55301c6b..d2c2c7c47 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -33,6 +33,7 @@ #include "cpu/simple/timing.hh" #include "mem/packet_impl.hh" #include "sim/builder.hh" +#include "sim/system.hh" using namespace std; using namespace TheISA; @@ -91,7 +92,7 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p) ifetch_pkt = dcache_pkt = NULL; drainEvent = NULL; fetchEvent = NULL; - state = SimObject::Timing; + changeState(SimObject::Running); } @@ -113,18 +114,18 @@ TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) BaseSimpleCPU::unserialize(cp, section); } -bool +unsigned int TimingSimpleCPU::drain(Event *drain_event) { // TimingSimpleCPU is ready to drain if it's not waiting for // an access to complete. if (status() == Idle || status() == Running || status() == SwitchedOut) { - changeState(SimObject::DrainedTiming); - return true; + changeState(SimObject::Drained); + return 0; } else { changeState(SimObject::Draining); drainEvent = drain_event; - return false; + return 1; } } @@ -142,12 +143,9 @@ TimingSimpleCPU::resume() new EventWrapper(this, false); fetchEvent->schedule(curTick); } -} -void -TimingSimpleCPU::setMemoryMode(State new_mode) -{ - assert(new_mode == SimObject::Timing); + assert(system->getMemoryMode() == System::Timing); + changeState(SimObject::Running); } void @@ -514,7 +512,7 @@ void TimingSimpleCPU::completeDrain() { DPRINTF(Config, "Done draining\n"); - changeState(SimObject::DrainedTiming); + changeState(SimObject::Drained); drainEvent->process(); } @@ -551,11 +549,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) Param max_loads_any_thread; Param max_loads_all_threads; SimObjectParam mem; + SimObjectParam system; #if FULL_SYSTEM SimObjectParam itb; SimObjectParam dtb; - SimObjectParam system; Param cpu_id; Param profile; #else @@ -583,11 +581,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) INIT_PARAM(max_loads_all_threads, "terminate when all threads have reached this load count"), INIT_PARAM(mem, "memory"), + INIT_PARAM(system, "system object"), #if FULL_SYSTEM INIT_PARAM(itb, "Instruction TLB"), INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(system, "system object"), INIT_PARAM(cpu_id, "processor ID"), INIT_PARAM(profile, ""), #else @@ -618,11 +616,11 @@ CREATE_SIM_OBJECT(TimingSimpleCPU) params->functionTrace = function_trace; params->functionTraceStart = function_trace_start; params->mem = mem; + params->system = system; #if FULL_SYSTEM params->itb = itb; params->dtb = dtb; - params->system = system; params->cpu_id = cpu_id; params->profile = profile; #else diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 0a3f91e6c..ac36e5c99 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -137,9 +137,8 @@ class TimingSimpleCPU : public BaseSimpleCPU virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - virtual bool drain(Event *drain_event); + virtual unsigned int drain(Event *drain_event); virtual void resume(); - virtual void setMemoryMode(State new_mode); void switchOut(); void takeOverFrom(BaseCPU *oldCPU); diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc index dc78021f8..12564ddd0 100644 --- a/src/dev/ide_disk.cc +++ b/src/dev/ide_disk.cc @@ -318,7 +318,7 @@ IdeDisk::doDmaTransfer() panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", dmaState, devState); - if (ctrl->dmaPending()) { + if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); return; } else @@ -398,8 +398,7 @@ IdeDisk::doDmaRead() curPrd.getByteCount(), TheISA::PageBytes); } - if (ctrl->dmaPending()) { - panic("shouldn't be reentant??"); + if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); return; } else if (!dmaReadCG->done()) { @@ -474,8 +473,7 @@ IdeDisk::doDmaWrite() dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), curPrd.getByteCount(), TheISA::PageBytes); } - if (ctrl->dmaPending()) { - panic("shouldn't be reentant??"); + if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) { dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); return; } else if (!dmaWriteCG->done()) { diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc index cb4850108..ed2862065 100644 --- a/src/dev/io_device.cc +++ b/src/dev/io_device.cc @@ -32,10 +32,12 @@ #include "base/trace.hh" #include "dev/io_device.hh" #include "sim/builder.hh" +#include "sim/system.hh" -PioPort::PioPort(PioDevice *dev, Platform *p, std::string pname) - : Port(dev->name() + pname), device(dev), platform(p) +PioPort::PioPort(PioDevice *dev, System *s, std::string pname) + : Port(dev->name() + pname), device(dev), sys(s), + outTiming(0), drainEvent(NULL) { } @@ -68,13 +70,23 @@ PioPort::recvRetry() if (result) transmitList.pop_front(); } + if (transmitList.size() == 0 && drainEvent) { + drainEvent->process(); + drainEvent = NULL; + } } void PioPort::SendEvent::process() { + port->outTiming--; + assert(port->outTiming >= 0); if (port->Port::sendTiming(packet)) - return; + if (port->transmitList.size() == 0 && port->drainEvent) { + port->drainEvent->process(); + port->drainEvent = NULL; + } + return; port->transmitList.push_back(packet); } @@ -105,6 +117,15 @@ PioPort::recvTiming(Packet *pkt) return true; } +unsigned int +PioPort::drain(Event *de) +{ + if (outTiming == 0 && transmitList.size() == 0) + return 0; + drainEvent = de; + return 1; +} + PioDevice::~PioDevice() { if (pioPort) @@ -119,6 +140,19 @@ PioDevice::init() 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 BasicPioDevice::addressRanges(AddrRangeList &range_list) { @@ -128,8 +162,9 @@ BasicPioDevice::addressRanges(AddrRangeList &range_list) } -DmaPort::DmaPort(DmaDevice *dev, Platform *p) - : Port(dev->name() + "-dmaport"), device(dev), platform(p), pendingCount(0) +DmaPort::DmaPort(DmaDevice *dev, System *s) + : Port(dev->name() + "-dmaport"), device(dev), sys(s), pendingCount(0), + actionInProgress(0), drainEvent(NULL) { } bool @@ -159,6 +194,11 @@ DmaPort::recvTiming(Packet *pkt) } delete pkt->req; delete pkt; + + if (pendingCount == 0 && drainEvent) { + drainEvent->process(); + drainEvent = NULL; + } } else { panic("Got packet without sender state... huh?\n"); } @@ -170,6 +210,29 @@ DmaDevice::DmaDevice(Params *p) : 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 DmaPort::recvRetry() { @@ -195,6 +258,8 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, { assert(event); + assert(device->getState() == SimObject::Running); + DmaReqState *reqState = new DmaReqState(event, this, size); for (ChunkGenerator gen(addr, size, peerBlockSize()); @@ -212,51 +277,53 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, pendingCount++; sendDma(pkt); } + } void DmaPort::sendDma(Packet *pkt, bool front) { - // some kind of selction between access methods - // more work is going to have to be done to make - // switching actually work - /* MemState state = device->platform->system->memState; - - if (state == Timing) { */ - DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", - pkt, pkt->getAddr()); - if (transmitList.size() || !sendTiming(pkt)) { - if (front) - transmitList.push_front(pkt); - else - transmitList.push_back(pkt); - DPRINTF(DMA, "-- Failed: queued\n"); - } else { - DPRINTF(DMA, "-- Done\n"); - } - /* } else if (state == Atomic) { - sendAtomic(pkt); - if (pkt->senderState) { - DmaReqState *state = dynamic_cast(pkt->senderState); - assert(state); - state->completionEvent->schedule(curTick + (pkt->time - - pkt->req->getTime()) +1); - delete state; - } - pendingCount--; - assert(pendingCount >= 0); - delete pkt->req; - delete pkt; - - } else if (state == Functional) { - sendFunctional(pkt); - // Is this correct??? - completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime); - completionEvent == NULL; + // some kind of selction between access methods + // more work is going to have to be done to make + // switching actually work + System::MemoryMode state = sys->getMemoryMode(); + if (state == System::Timing) { + DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", + pkt, pkt->getAddr()); + if (transmitList.size() || !sendTiming(pkt)) { + if (front) + transmitList.push_front(pkt); + else + transmitList.push_back(pkt); + DPRINTF(DMA, "-- Failed: queued\n"); + } else { + DPRINTF(DMA, "-- Done\n"); + } + } else if (state == System::Atomic) { + sendAtomic(pkt); + assert(pkt->senderState); + DmaReqState *state = dynamic_cast(pkt->senderState); + assert(state); + + state->numBytes += pkt->req->getSize(); + if (state->totBytes == state->numBytes) { + state->completionEvent->schedule(curTick + + (pkt->time - pkt->req->getTime()) +1); + delete state; + delete pkt->req; + } + pendingCount--; + assert(pendingCount >= 0); + delete pkt; + + if (pendingCount == 0 && drainEvent) { + drainEvent->process(); + drainEvent = NULL; + } + } else panic("Unknown memory command state."); - */ } DmaDevice::~DmaDevice() diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh index 40edf6875..fa3f98247 100644 --- a/src/dev/io_device.hh +++ b/src/dev/io_device.hh @@ -60,9 +60,9 @@ class PioPort : public Port /** The device that this port serves. */ 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. */ - Platform *platform; + System *sys; /** A list of outgoing timing response packets that haven't been serviced * yet. */ @@ -106,16 +106,27 @@ class PioPort : public Port 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. */ 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 * packet again. */ virtual void recvRetry(); 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; }; @@ -147,13 +158,20 @@ class DmaPort : public Port DmaDevice *device; std::list 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. */ - Platform *platform; + System *sys; /** Number of outstanding packets the dma port has. */ 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 Tick recvAtomic(Packet *pkt) { 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); public: - DmaPort(DmaDevice *dev, Platform *p); + DmaPort(DmaDevice *dev, System *s); void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, uint8_t *data = NULL); bool dmaPending() { return pendingCount > 0; } + unsigned int drain(Event *de); }; /** @@ -196,6 +215,8 @@ class PioDevice : public MemObject * transaction we should perform. */ Platform *platform; + System *sys; + /** The pioPort that handles the requests for us and provides us requests * that it sees. */ PioPort *pioPort; @@ -240,20 +261,22 @@ class PioDevice : public MemObject const Params *params() const { return _params; } PioDevice(Params *p) - : MemObject(p->name), platform(p->platform), pioPort(NULL), - _params(p) + : MemObject(p->name), platform(p->platform), sys(p->system), + pioPort(NULL), _params(p) {} virtual ~PioDevice(); virtual void init(); + virtual unsigned int drain(Event *de); + virtual Port *getPort(const std::string &if_name, int idx = -1) { if (if_name == "pio") { if (pioPort != NULL) panic("pio port already connected to."); - pioPort = new PioPort(this, params()->platform); + pioPort = new PioPort(this, sys); return pioPort; } else return NULL; @@ -310,17 +333,19 @@ class DmaDevice : public PioDevice bool dmaPending() { return dmaPort->dmaPending(); } + virtual unsigned int drain(Event *de); + virtual Port *getPort(const std::string &if_name, int idx = -1) { if (if_name == "pio") { if (pioPort != NULL) panic("pio port already connected to."); - pioPort = new PioPort(this, params()->platform); + pioPort = new PioPort(this, sys); return pioPort; } else if (if_name == "dma") { if (dmaPort != NULL) panic("dma port already connected to."); - dmaPort = new DmaPort(this, params()->platform); + dmaPort = new DmaPort(this, sys); return dmaPort; } else return NULL; diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc index 179a2c62d..bf2279d93 100644 --- a/src/dev/ns_gige.cc +++ b/src/dev/ns_gige.cc @@ -1377,7 +1377,7 @@ NSGigE::doRxDmaRead() assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); rxDmaState = dmaReading; - if (dmaPending()) + if (dmaPending() || getState() != Running) rxDmaState = dmaReadWaiting; else dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); @@ -1408,7 +1408,7 @@ NSGigE::doRxDmaWrite() assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); rxDmaState = dmaWriting; - if (dmaPending()) + if (dmaPending() || getState() != Running) rxDmaState = dmaWriteWaiting; else dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); @@ -1826,7 +1826,7 @@ NSGigE::doTxDmaRead() assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); txDmaState = dmaReading; - if (dmaPending()) + if (dmaPending() || getState() != Running) txDmaState = dmaReadWaiting; else dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); @@ -1857,7 +1857,7 @@ NSGigE::doTxDmaWrite() assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); txDmaState = dmaWriting; - if (dmaPending()) + if (dmaPending() || getState() != Running) txDmaState = dmaWriteWaiting; else dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); @@ -2406,6 +2406,20 @@ NSGigE::recvPacket(EthPacketPtr packet) 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(); +} + + //===================================================================== // // diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh index ea7243777..080c0b1f3 100644 --- a/src/dev/ns_gige.hh +++ b/src/dev/ns_gige.hh @@ -391,6 +391,8 @@ class NSGigE : public PciDev virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); + virtual void resume(); + public: void regStats(); diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc index 62a7324ad..e81e0d1ee 100644 --- a/src/dev/pcidev.cc +++ b/src/dev/pcidev.cc @@ -56,8 +56,8 @@ using namespace std; PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, int funcid, Platform *p) - : PioPort(dev,p,"-pciconf"), device(dev), busId(busid), deviceId(devid), - functionId(funcid) + : PioPort(dev,p->system,"-pciconf"), device(dev), platform(p), + busId(busid), deviceId(devid), functionId(funcid) { configAddr = platform->calcConfigAddr(busId, deviceId, functionId); } @@ -132,6 +132,18 @@ PciDev::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 PciDev::readConfig(Packet *pkt) { diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh index 20ab9364a..847fb07d0 100644 --- a/src/dev/pcidev.hh +++ b/src/dev/pcidev.hh @@ -95,6 +95,8 @@ class PciDev : public DmaDevice virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); + Platform *platform; + int busId; int deviceId; int functionId; @@ -249,6 +251,9 @@ class PciDev : public DmaDevice */ virtual void unserialize(Checkpoint *cp, const std::string §ion); + + virtual unsigned int drain(Event *de); + virtual Port *getPort(const std::string &if_name, int idx = -1) { if (if_name == "config") { diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc index dddda1f1c..815cecca5 100644 --- a/src/dev/sinic.cc +++ b/src/dev/sinic.cc @@ -921,7 +921,7 @@ Device::rxKick() break; case rxBeginCopy: - if (dmaPending()) + if (dmaPending() || getState() != Running) goto exit; rxDmaAddr = params()->platform->pciToDma( @@ -1109,7 +1109,7 @@ Device::txKick() break; case txBeginCopy: - if (dmaPending()) + if (dmaPending() || getState() != Running) goto exit; txDmaAddr = params()->platform->pciToDma( @@ -1287,6 +1287,18 @@ Device::recvPacket(EthPacketPtr packet) 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(); +} + //===================================================================== // // diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh index f6c229039..eece4ba6b 100644 --- a/src/dev/sinic.hh +++ b/src/dev/sinic.hh @@ -266,6 +266,7 @@ class Device : public Base public: virtual Tick read(Packet *pkt); virtual Tick write(Packet *pkt); + virtual void resume(); void prepareIO(int cpu, int index); void prepareRead(int cpu, int index); diff --git a/src/python/m5/config.py b/src/python/m5/config.py index 8291e1e1b..8eed28dcc 100644 --- a/src/python/m5/config.py +++ b/src/python/m5/config.py @@ -547,8 +547,7 @@ class SimObject(object): count = 0 # ParamContexts don't serialize if isinstance(self, SimObject) and not isinstance(self, ParamContext): - if not self._ccObject.drain(drain_event): - count = 1 + count += self._ccObject.drain(drain_event) if recursive: for child in self._children.itervalues(): count += child.startDrain(drain_event, True) @@ -561,7 +560,7 @@ class SimObject(object): child.resume() def changeTiming(self, mode): - if isinstance(self, SimObject) and not isinstance(self, ParamContext): + if isinstance(self, System): self._ccObject.setMemoryMode(mode) for child in self._children.itervalues(): child.changeTiming(mode) diff --git a/src/python/m5/objects/BaseCPU.py b/src/python/m5/objects/BaseCPU.py index 2e78578df..5bf98be9c 100644 --- a/src/python/m5/objects/BaseCPU.py +++ b/src/python/m5/objects/BaseCPU.py @@ -6,10 +6,10 @@ class BaseCPU(SimObject): abstract = True mem = Param.MemObject("memory") + system = Param.System(Parent.any, "system object") if build_env['FULL_SYSTEM']: dtb = Param.AlphaDTB("Data TLB") itb = Param.AlphaITB("Instruction TLB") - system = Param.System(Parent.any, "system object") cpu_id = Param.Int(-1, "CPU identifier") else: workload = VectorParam.Process("processes to run") diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc index a0278dba0..d12b06b7a 100644 --- a/src/sim/sim_object.cc +++ b/src/sim/sim_object.cc @@ -72,7 +72,7 @@ SimObject::SimObject(Params *p) doRecordEvent = !Stats::event_ignore.match(name()); simObjectList.push_back(this); - state = Atomic; + state = Running; } // @@ -88,7 +88,7 @@ SimObject::SimObject(const string &_name) doRecordEvent = !Stats::event_ignore.match(name()); simObjectList.push_back(this); - state = Atomic; + state = Running; } void @@ -269,38 +269,23 @@ SimObject::recordEvent(const std::string &stat) Stats::recordEvent(stat); } -bool +unsigned int SimObject::drain(Event *drain_event) { - if (state != DrainedAtomic && state != Atomic) { - panic("Must implement your own drain function if it is to be used " - "in timing mode!"); - } - state = DrainedAtomic; - return true; + state = Drained; + return 0; } void SimObject::resume() { - if (state == DrainedAtomic) { - state = Atomic; - } else if (state == DrainedTiming) { - state = Timing; - } + state = Running; } void SimObject::setMemoryMode(State new_mode) { - assert(new_mode == Timing || new_mode == Atomic); - if (state == DrainedAtomic && new_mode == Timing) { - state = DrainedTiming; - } else if (state == DrainedTiming && new_mode == Atomic) { - state = DrainedAtomic; - } else { - state = new_mode; - } + panic("setMemoryMode() should only be called on systems"); } void diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh index 7ecc00958..38f2bdd23 100644 --- a/src/sim/sim_object.hh +++ b/src/sim/sim_object.hh @@ -60,16 +60,15 @@ class SimObject : public Serializable, protected StartupCallback }; enum State { - Atomic, - Timing, + Running, Draining, - DrainedAtomic, - DrainedTiming + Drained }; + private: + State state; protected: Params *_params; - State 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 // Or switch from timing -> atomic memory model - // Drain returns false if the SimObject cannot drain immediately. - virtual bool drain(Event *drain_event); + // Drain returns 0 if the simobject can drain immediately or + // 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 setMemoryMode(State new_mode); virtual void switchOut(); diff --git a/src/sim/system.cc b/src/sim/system.cc index 89e7b8542..2780d0fda 100644 --- a/src/sim/system.cc +++ b/src/sim/system.cc @@ -143,6 +143,14 @@ int rgdb_wait = -1; #endif // FULL_SYSTEM + +void +System::setMemoryMode(MemoryMode mode) +{ + assert(getState() == Drained); + memoryMode = mode; +} + int System::registerThreadContext(ThreadContext *tc, int id) { diff --git a/src/sim/system.hh b/src/sim/system.hh index 059dc92dc..77777aed4 100644 --- a/src/sim/system.hh +++ b/src/sim/system.hh @@ -61,6 +61,21 @@ class RemoteGDB; class System : public SimObject { 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; PCEventQueue pcEventQueue; @@ -108,6 +123,8 @@ class System : public SimObject protected: + MemoryMode memoryMode; + #if FULL_SYSTEM /** * Fix up an address used to match PCs for hooking simulator -- cgit v1.2.3 From 63c999edef982e995ab65e0a3d672b0d7900c6f3 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Thu, 13 Jul 2006 12:21:21 -0400 Subject: Fix help message printing. Might need to clean up the handling of the sys.exit() call, as right now it prints out "None" at the end (not sure why). src/python/m5/main.py: Fix help message printing. --HG-- extra : convert_revision : 6906234101eb7ff7df7933e9aede0362b5a991bd --- src/python/m5/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/m5/main.py b/src/python/m5/main.py index 54c54c1d5..aae74d371 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -182,7 +182,7 @@ options = attrdict() arguments = [] def usage(exitcode=None): - print parser.help + print parser.print_help() if exitcode is not None: sys.exit(exitcode) -- cgit v1.2.3 From a0a952d5ff8e27d34c7fa68fe5199c57670c53d1 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Thu, 13 Jul 2006 13:08:58 -0400 Subject: Update for changes to draining. --HG-- extra : convert_revision : 5038dd8be72827f40cf89318db0b2bb4f9bbd864 --- src/cpu/o3/cpu.cc | 16 +++++++++------- src/cpu/o3/cpu.hh | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 7d2727401..6e9b425c0 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -441,7 +441,7 @@ FullO3CPU::tick() if (!tickEvent.scheduled()) { if (_status == SwitchedOut || - getState() == SimObject::DrainedTiming) { + getState() == SimObject::Drained) { // increment stat lastRunningCycle = curTick; } else if (!activityRec.active()) { @@ -803,7 +803,7 @@ FullO3CPU::unserialize(Checkpoint *cp, const std::string §ion) } template -bool +unsigned int FullO3CPU::drain(Event *drain_event) { drainCount = 0; @@ -815,7 +815,7 @@ FullO3CPU::drain(Event *drain_event) // Wake the CPU and record activity so everything can drain out if // the CPU was not able to immediately drain. - if (getState() != SimObject::DrainedTiming) { + if (getState() != SimObject::Drained) { // A bit of a hack...set the drainEvent after all the drain() // calls have been made, that way if all of the stages drain // immediately, the signalDrained() function knows not to call @@ -825,9 +825,9 @@ FullO3CPU::drain(Event *drain_event) wakeCPU(); activityRec.activity(); - return false; + return 1; } else { - return true; + return 0; } } @@ -835,19 +835,21 @@ template void FullO3CPU::resume() { + assert(system->getMemoryMode() == System::Timing); fetch.resume(); decode.resume(); rename.resume(); iew.resume(); commit.resume(); + changeState(SimObject::Running); + if (_status == SwitchedOut || _status == Idle) return; if (!tickEvent.scheduled()) tickEvent.schedule(curTick); _status = Running; - changeState(SimObject::Timing); } template @@ -858,7 +860,7 @@ FullO3CPU::signalDrained() if (tickEvent.scheduled()) tickEvent.squash(); - changeState(SimObject::DrainedTiming); + changeState(SimObject::Drained); if (drainEvent) { drainEvent->process(); diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 2fbd013ac..83cb966e3 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -330,7 +330,7 @@ class FullO3CPU : public BaseO3CPU /** Starts draining the CPU's pipeline of all instructions in * order to stop all memory accesses. */ - virtual bool drain(Event *drain_event); + virtual unsigned int drain(Event *drain_event); /** Resumes execution after a drain. */ virtual void resume(); -- cgit v1.2.3 From 2af213022ce6d58eee2809f300d7450e89a4bce9 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Thu, 13 Jul 2006 13:09:29 -0400 Subject: Fix for bug when squashing and the fetching. Now fetch checks if the cache data is valid. --HG-- extra : convert_revision : 07b8eda3e90bbbb3ed470c8cc3cf1b63371ab529 --- src/cpu/o3/fetch.hh | 3 +++ src/cpu/o3/fetch_impl.hh | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 0331cf07f..931919af8 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -407,6 +407,9 @@ class DefaultFetch /** The PC of the cacheline that has been loaded. */ Addr cacheDataPC[Impl::MaxThreads]; + /** Whether or not the cache data is valid. */ + bool cacheDataValid[Impl::MaxThreads]; + /** Size of instructions. */ int instSize; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 4045492ca..4184e1867 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -162,6 +162,8 @@ DefaultFetch::DefaultFetch(Params *params) // Create space to store a cache line. cacheData[tid] = new uint8_t[cacheBlkSize]; + cacheDataPC[tid] = 0; + cacheDataValid[tid] = false; stalls[tid].decode = 0; stalls[tid].rename = 0; @@ -358,6 +360,7 @@ DefaultFetch::processCacheCompletion(PacketPtr pkt) } memcpy(cacheData[tid], pkt->getPtr(), cacheBlkSize); + cacheDataValid[tid] = true; if (!drainPending) { // Wake up the CPU (if it went to sleep and was waiting on @@ -520,7 +523,7 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid fetch_PC = icacheBlockAlignPC(fetch_PC); // If we've already got the block, no need to try to fetch it again. - if (fetch_PC == cacheDataPC[tid]) { + if (cacheDataValid[tid] && fetch_PC == cacheDataPC[tid]) { return true; } @@ -555,9 +558,10 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid // Build packet here. PacketPtr data_pkt = new Packet(mem_req, Packet::ReadReq, Packet::Broadcast); - data_pkt->dataDynamic(new uint8_t[cacheBlkSize]); + data_pkt->dataDynamicArray(new uint8_t[cacheBlkSize]); cacheDataPC[tid] = fetch_PC; + cacheDataValid[tid] = false; DPRINTF(Fetch, "Fetch: Doing instruction read.\n"); -- cgit v1.2.3 From 1e4acb8e017ce81694c514af21ad817e9b1a078e Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Thu, 13 Jul 2006 13:12:51 -0400 Subject: Move Dcache port creation from LSQUnit to LSQ in order to support Ron's recent changes, and using the O3CPU in SMT mode. src/cpu/o3/lsq.hh: Update to have LSQ work with only one dcache port for all LSQ Units. LSQ has the dcache port, and the LSQ Units must tell the LSQ if the cache has become blocked. src/cpu/o3/lsq_impl.hh: Updates to have the LSQ work with only one dcache port for all LSQUnits. src/cpu/o3/lsq_unit.hh: src/cpu/o3/lsq_unit_impl.hh: Update for LSQ to create dcache port instead of LSQUnits. Now LSQUnits are given the dcache port from the LSQ, and also must check the LSQ if the cache is blocked prior to accessing the cache. --HG-- extra : convert_revision : 2708adbf323f4e7647dc0c1e31ef5bb4596b89f8 --- src/cpu/o3/lsq.hh | 59 ++++++++++++++++++++++++++++-- src/cpu/o3/lsq_impl.hh | 53 +++++++++++++++++++++++++-- src/cpu/o3/lsq_unit.hh | 88 ++++++++++++++------------------------------- src/cpu/o3/lsq_unit_impl.hh | 51 ++++---------------------- 4 files changed, 139 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index d5890950f..190734dc2 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -70,7 +70,7 @@ class LSQ { * to work. For now it just returns the port from one of the * threads. */ - Port *getDcachePort() { return thread[0].getDcachePort(); } + Port *getDcachePort() { return &dcachePort; } /** Sets the pointer to the list of active threads. */ void setActiveThreads(std::list *at_ptr); @@ -258,6 +258,15 @@ class LSQ { bool willWB(unsigned tid) { return thread[tid].willWB(); } + /** Returns if the cache is currently blocked. */ + bool cacheBlocked() + { return retryTid != -1; } + + /** Sets the retry thread id, indicating that one of the LSQUnits + * tried to access the cache but the cache was blocked. */ + void setRetryTid(int tid) + { retryTid = tid; } + /** Debugging function to print out all instructions. */ void dumpInsts(); /** Debugging function to print out instructions from a specific thread. */ @@ -274,7 +283,49 @@ class LSQ { template Fault write(RequestPtr req, T &data, int store_idx); - private: + /** DcachePort class for this LSQ. Handles doing the + * communication with the cache/memory. + */ + class DcachePort : public Port + { + protected: + /** Pointer to LSQ. */ + LSQ *lsq; + + public: + /** Default constructor. */ + DcachePort(LSQ *_lsq) + : lsq(_lsq) + { } + + protected: + /** Atomic version of receive. Panics. */ + virtual Tick recvAtomic(PacketPtr pkt); + + /** Functional version of receive. Panics. */ + virtual void recvFunctional(PacketPtr pkt); + + /** Receives status change. Other than range changing, panics. */ + virtual void recvStatusChange(Status status); + + /** Returns the address ranges of this device. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + /** Timing version of receive. Handles writing back and + * completing the load or store that has returned from + * memory. */ + virtual bool recvTiming(PacketPtr pkt); + + /** Handles doing a retry of the previous send. */ + virtual void recvRetry(); + }; + + /** D-cache port. */ + DcachePort dcachePort; + + protected: /** The LSQ policy for SMT mode. */ LSQPolicy lsqPolicy; @@ -303,6 +354,10 @@ class LSQ { /** Number of Threads. */ unsigned numThreads; + + /** The thread id of the LSQ Unit that is currently waiting for a + * retry. */ + int retryTid; }; template diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh index 89fd1a71d..4e3957029 100644 --- a/src/cpu/o3/lsq_impl.hh +++ b/src/cpu/o3/lsq_impl.hh @@ -35,10 +35,54 @@ using namespace std; +template +Tick +LSQ::DcachePort::recvAtomic(PacketPtr pkt) +{ + panic("O3CPU model does not work with atomic mode!"); + return curTick; +} + +template +void +LSQ::DcachePort::recvFunctional(PacketPtr pkt) +{ + panic("O3CPU doesn't expect recvFunctional callback!"); +} + +template +void +LSQ::DcachePort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("O3CPU doesn't expect recvStatusChange callback!"); +} + +template +bool +LSQ::DcachePort::recvTiming(PacketPtr pkt) +{ + lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt); + return true; +} + +template +void +LSQ::DcachePort::recvRetry() +{ + lsq->thread[lsq->retryTid].recvRetry(); + // Speculatively clear the retry Tid. This will get set again if + // the LSQUnit was unable to complete its access. + lsq->retryTid = -1; +} + template LSQ::LSQ(Params *params) - : LQEntries(params->LQEntries), SQEntries(params->SQEntries), - numThreads(params->numberOfThreads) + : dcachePort(this), LQEntries(params->LQEntries), + SQEntries(params->SQEntries), numThreads(params->numberOfThreads), + retryTid(-1) { DPRINTF(LSQ, "Creating LSQ object.\n"); @@ -94,7 +138,8 @@ LSQ::LSQ(Params *params) //Initialize LSQs for (int tid=0; tid < numThreads; tid++) { - thread[tid].init(params, maxLQEntries, maxSQEntries, tid); + thread[tid].init(params, this, maxLQEntries, maxSQEntries, tid); + thread[tid].setDcachePort(&dcachePort); } } @@ -130,6 +175,8 @@ LSQ::setCPU(O3CPU *cpu_ptr) { cpu = cpu_ptr; + dcachePort.setName(name()); + for (int tid=0; tid < numThreads; tid++) { thread[tid].setCPU(cpu_ptr); } diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 4d7a8350b..a76a73f0c 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -64,6 +64,7 @@ class LSQUnit { typedef typename Impl::O3CPU O3CPU; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::CPUPol::IEW IEW; + typedef typename Impl::CPUPol::LSQ LSQ; typedef typename Impl::CPUPol::IssueStruct IssueStruct; public: @@ -71,17 +72,12 @@ class LSQUnit { LSQUnit(); /** Initializes the LSQ unit with the specified number of entries. */ - void init(Params *params, unsigned maxLQEntries, + void init(Params *params, LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, unsigned id); /** Returns the name of the LSQ unit. */ std::string name() const; - /** Returns the dcache port. - * @todo: Remove this once the port moves up to the LSQ level. - */ - Port *getDcachePort() { return dcachePort; } - /** Registers statistics. */ void regStats(); @@ -92,6 +88,10 @@ class LSQUnit { void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; } + /** Sets the pointer to the dcache port. */ + void setDcachePort(Port *dcache_port) + { dcachePort = dcache_port; } + /** Switches out LSQ unit. */ void switchOut(); @@ -211,6 +211,9 @@ class LSQUnit { !storeQueue[storeWBIdx].completed && !isStoreBlocked; } + /** Handles doing the retry. */ + void recvRetry(); + private: /** Writes back the instruction, sending it to IEW. */ void writeback(DynInstPtr &inst, PacketPtr pkt); @@ -221,9 +224,6 @@ class LSQUnit { /** Completes the store at the specified index. */ void completeStore(int store_idx); - /** Handles doing the retry. */ - void recvRetry(); - /** Increments the given store index (circular queue). */ inline void incrStIdx(int &store_idx); /** Decrements the given store index (circular queue). */ @@ -244,54 +244,11 @@ class LSQUnit { /** Pointer to the IEW stage. */ IEW *iewStage; - /** Pointer to memory object. */ - MemObject *mem; + /** Pointer to the LSQ. */ + LSQ *lsq; - /** DcachePort class for this LSQ Unit. Handles doing the - * communication with the cache/memory. - * @todo: Needs to be moved to the LSQ level and have some sort - * of arbitration. - */ - class DcachePort : public Port - { - protected: - /** Pointer to CPU. */ - O3CPU *cpu; - /** Pointer to LSQ. */ - LSQUnit *lsq; - - public: - /** Default constructor. */ - DcachePort(O3CPU *_cpu, LSQUnit *_lsq) - : Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq) - { } - - protected: - /** Atomic version of receive. Panics. */ - virtual Tick recvAtomic(PacketPtr pkt); - - /** Functional version of receive. Panics. */ - virtual void recvFunctional(PacketPtr pkt); - - /** Receives status change. Other than range changing, panics. */ - virtual void recvStatusChange(Status status); - - /** Returns the address ranges of this device. */ - virtual void getDeviceAddressRanges(AddrRangeList &resp, - AddrRangeList &snoop) - { resp.clear(); snoop.clear(); } - - /** Timing version of receive. Handles writing back and - * completing the load or store that has returned from - * memory. */ - virtual bool recvTiming(PacketPtr pkt); - - /** Handles doing a retry of the previous send. */ - virtual void recvRetry(); - }; - - /** Pointer to the D-cache. */ - DcachePort *dcachePort; + /** Pointer to the dcache port. Used only for sending. */ + Port *dcachePort; /** Derived class to hold any sender state the LSQ needs. */ class LSQSenderState : public Packet::SenderState @@ -658,7 +615,7 @@ LSQUnit::read(Request *req, T &data, int load_idx) } // If there's no forwarding case, then go access memory - DPRINTF(LSQUnit, "Doing functional access for inst [sn:%lli] PC %#x\n", + DPRINTF(LSQUnit, "Doing memory access for inst [sn:%lli] PC %#x\n", load_inst->seqNum, load_inst->readPC()); assert(!load_inst->memData); @@ -666,9 +623,6 @@ LSQUnit::read(Request *req, T &data, int load_idx) ++usedPorts; - DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n", - load_inst->readPC()); - PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast); data_pkt->dataStatic(load_inst->memData); @@ -678,8 +632,18 @@ LSQUnit::read(Request *req, T &data, int load_idx) state->inst = load_inst; data_pkt->senderState = state; - // if we have a cache, do cache access too - if (!dcachePort->sendTiming(data_pkt)) { + // if we the cache is not blocked, do cache access + if (!lsq->cacheBlocked()) { + if (!dcachePort->sendTiming(data_pkt)) { + // If the access didn't succeed, tell the LSQ by setting + // the retry thread id. + lsq->setRetryTid(lsqID); + } + } + + // If the cache was blocked, or has become blocked due to the access, + // handle it. + if (lsq->cacheBlocked()) { ++lsqCacheBlocked; // There's an older load that's already going to squash. if (isLoadBlocked && blockedLoadSeqNum < load_inst->seqNum) diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index 8e951534f..85b150cd9 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -31,6 +31,7 @@ #include "config/use_checker.hh" +#include "cpu/o3/lsq.hh" #include "cpu/o3/lsq_unit.hh" #include "base/str.hh" #include "mem/packet.hh" @@ -95,46 +96,6 @@ LSQUnit::completeDataAccess(PacketPtr pkt) delete pkt; } -template -Tick -LSQUnit::DcachePort::recvAtomic(PacketPtr pkt) -{ - panic("O3CPU model does not work with atomic mode!"); - return curTick; -} - -template -void -LSQUnit::DcachePort::recvFunctional(PacketPtr pkt) -{ - panic("O3CPU doesn't expect recvFunctional callback!"); -} - -template -void -LSQUnit::DcachePort::recvStatusChange(Status status) -{ - if (status == RangeChange) - return; - - panic("O3CPU doesn't expect recvStatusChange callback!"); -} - -template -bool -LSQUnit::DcachePort::recvTiming(PacketPtr pkt) -{ - lsq->completeDataAccess(pkt); - return true; -} - -template -void -LSQUnit::DcachePort::recvRetry() -{ - lsq->recvRetry(); -} - template LSQUnit::LSQUnit() : loads(0), stores(0), storesToWB(0), stalled(false), @@ -145,13 +106,15 @@ LSQUnit::LSQUnit() template void -LSQUnit::init(Params *params, unsigned maxLQEntries, +LSQUnit::init(Params *params, LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries, unsigned id) { DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); switchedOut = false; + lsq = lsq_ptr; + lsqID = id; // Add 1 for the sentinel entry (they are circular queues). @@ -168,8 +131,6 @@ LSQUnit::init(Params *params, unsigned maxLQEntries, usedPorts = 0; cachePorts = params->cachePorts; - mem = params->mem; - memDepViolator = NULL; blockedLoadSeqNum = 0; @@ -180,7 +141,6 @@ void LSQUnit::setCPU(O3CPU *cpu_ptr) { cpu = cpu_ptr; - dcachePort = new DcachePort(cpu, this); #if USE_CHECKER if (cpu->checker) { @@ -588,7 +548,7 @@ LSQUnit::writebackStores() storeQueue[storeWBIdx].canWB && usedPorts < cachePorts) { - if (isStoreBlocked) { + if (isStoreBlocked || lsq->cacheBlocked()) { DPRINTF(LSQUnit, "Unable to write back any more stores, cache" " is blocked!\n"); break; @@ -911,6 +871,7 @@ LSQUnit::recvRetry() } else { // Still blocked! ++lsqCacheBlocked; + lsq->setRetryTid(lsqID); } } else if (isLoadBlocked) { DPRINTF(LSQUnit, "Loads squash themselves and all younger insts, " -- cgit v1.2.3 From c368ff0bd8d36ba001f523bd03f56f99d9ecd452 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Thu, 13 Jul 2006 15:48:17 -0400 Subject: add system.mem_mode = ['timing', 'atomic'] update scripts acordingly configs/test/SysPaths.py: new syspaths from nate, this one allows you to set script, binary, and disk paths like system.dir = 'aouaou' in your script configs/test/fs.py: update for system mem_mode Put small checkpoint example Make clock 1THz configs/test/test.py: src/arch/alpha/freebsd/system.cc: src/arch/alpha/linux/system.cc: src/arch/alpha/system.cc: src/arch/alpha/tru64/system.cc: src/arch/sparc/system.cc: src/python/m5/objects/System.py: src/sim/system.cc: src/sim/system.hh: update for system mem_mode src/dev/io_device.cc: Use time returned from sendAtomic to delay --HG-- extra : convert_revision : 67eedb3c84ab2584613faf88a534e793926fc92f --- src/arch/alpha/freebsd/system.cc | 4 ++++ src/arch/alpha/linux/system.cc | 4 ++++ src/arch/alpha/system.cc | 4 ++++ src/arch/alpha/tru64/system.cc | 4 ++++ src/arch/sparc/system.cc | 4 ++++ src/dev/io_device.cc | 7 ++++--- src/python/m5/objects/System.py | 3 +++ src/sim/system.cc | 11 +++++++++-- src/sim/system.hh | 3 +++ 9 files changed, 39 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/arch/alpha/freebsd/system.cc b/src/arch/alpha/freebsd/system.cc index 7cf68e0db..8d50e1612 100644 --- a/src/arch/alpha/freebsd/system.cc +++ b/src/arch/alpha/freebsd/system.cc @@ -97,6 +97,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) Param boot_cpu_frequency; SimObjectParam physmem; + SimpleEnumParam mem_mode; Param kernel; Param console; @@ -115,6 +116,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), INIT_PARAM(physmem, "phsyical memory"), + INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", + System::MemoryModeStrings), INIT_PARAM(kernel, "file that contains the kernel code"), INIT_PARAM(console, "file that contains the console code"), INIT_PARAM(pal, "file that contains palcode"), @@ -133,6 +136,7 @@ CREATE_SIM_OBJECT(FreebsdAlphaSystem) p->name = getInstanceName(); p->boot_cpu_frequency = boot_cpu_frequency; p->physmem = physmem; + p->mem_mode = mem_mode; p->kernel_path = kernel; p->console_path = console; p->palcode = pal; diff --git a/src/arch/alpha/linux/system.cc b/src/arch/alpha/linux/system.cc index 9fe63c390..ef4e18cb5 100644 --- a/src/arch/alpha/linux/system.cc +++ b/src/arch/alpha/linux/system.cc @@ -191,6 +191,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) Param boot_cpu_frequency; SimObjectParam physmem; + SimpleEnumParam mem_mode; Param kernel; Param console; @@ -209,6 +210,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), INIT_PARAM(physmem, "phsyical memory"), + INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", + System::MemoryModeStrings), INIT_PARAM(kernel, "file that contains the kernel code"), INIT_PARAM(console, "file that contains the console code"), INIT_PARAM(pal, "file that contains palcode"), @@ -227,6 +230,7 @@ CREATE_SIM_OBJECT(LinuxAlphaSystem) p->name = getInstanceName(); p->boot_cpu_frequency = boot_cpu_frequency; p->physmem = physmem; + p->mem_mode = mem_mode; p->kernel_path = kernel; p->console_path = console; p->palcode = pal; diff --git a/src/arch/alpha/system.cc b/src/arch/alpha/system.cc index dce7365aa..a7e615531 100644 --- a/src/arch/alpha/system.cc +++ b/src/arch/alpha/system.cc @@ -221,6 +221,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) Param boot_cpu_frequency; SimObjectParam physmem; + SimpleEnumParam mem_mode; Param kernel; Param console; @@ -239,6 +240,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem) INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), INIT_PARAM(physmem, "phsyical memory"), + INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", + System::MemoryModeStrings), INIT_PARAM(kernel, "file that contains the kernel code"), INIT_PARAM(console, "file that contains the console code"), INIT_PARAM(pal, "file that contains palcode"), @@ -257,6 +260,7 @@ CREATE_SIM_OBJECT(AlphaSystem) p->name = getInstanceName(); p->boot_cpu_frequency = boot_cpu_frequency; p->physmem = physmem; + p->mem_mode = mem_mode; p->kernel_path = kernel; p->console_path = console; p->palcode = pal; diff --git a/src/arch/alpha/tru64/system.cc b/src/arch/alpha/tru64/system.cc index 6c0edc1ee..3ef1e4d3c 100644 --- a/src/arch/alpha/tru64/system.cc +++ b/src/arch/alpha/tru64/system.cc @@ -95,6 +95,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) Param boot_cpu_frequency; SimObjectParam physmem; + SimpleEnumParam mem_mode; Param kernel; Param console; @@ -113,6 +114,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"), INIT_PARAM(physmem, "phsyical memory"), + INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", + System::MemoryModeStrings), INIT_PARAM(kernel, "file that contains the kernel code"), INIT_PARAM(console, "file that contains the console code"), INIT_PARAM(pal, "file that contains palcode"), @@ -131,6 +134,7 @@ CREATE_SIM_OBJECT(Tru64AlphaSystem) p->name = getInstanceName(); p->boot_cpu_frequency = boot_cpu_frequency; p->physmem = physmem; + p->mem_mode = mem_mode; p->kernel_path = kernel; p->console_path = console; p->palcode = pal; diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc index e197e7918..63cbbe057 100644 --- a/src/arch/sparc/system.cc +++ b/src/arch/sparc/system.cc @@ -141,6 +141,7 @@ SparcSystem::unserialize(Checkpoint *cp, const std::string §ion) BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem) SimObjectParam physmem; + SimpleEnumParam mem_mode; Param kernel; Param reset_bin; @@ -161,6 +162,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem) INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), INIT_PARAM(physmem, "phsyical memory"), + INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", + System::MemoryModeStrings), INIT_PARAM(kernel, "file that contains the kernel code"), INIT_PARAM(reset_bin, "file that contains the reset code"), INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"), @@ -183,6 +186,7 @@ CREATE_SIM_OBJECT(SparcSystem) p->name = getInstanceName(); p->boot_cpu_frequency = boot_cpu_frequency; p->physmem = physmem; + p->mem_mode = mem_mode; p->kernel_path = kernel; p->reset_bin = reset_bin; p->hypervisor_bin = hypervisor_bin; diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc index ed2862065..660efabfd 100644 --- a/src/dev/io_device.cc +++ b/src/dev/io_device.cc @@ -287,6 +287,7 @@ DmaPort::sendDma(Packet *pkt, bool front) // some kind of selction between access methods // more work is going to have to be done to make // switching actually work + System::MemoryMode state = sys->getMemoryMode(); if (state == System::Timing) { DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", @@ -301,15 +302,15 @@ DmaPort::sendDma(Packet *pkt, bool front) DPRINTF(DMA, "-- Done\n"); } } else if (state == System::Atomic) { - sendAtomic(pkt); + Tick lat; + lat = sendAtomic(pkt); assert(pkt->senderState); DmaReqState *state = dynamic_cast(pkt->senderState); assert(state); state->numBytes += pkt->req->getSize(); if (state->totBytes == state->numBytes) { - state->completionEvent->schedule(curTick + - (pkt->time - pkt->req->getTime()) +1); + state->completionEvent->schedule(curTick + lat); delete state; delete pkt->req; } diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py index 9a1e1d690..386f39277 100644 --- a/src/python/m5/objects/System.py +++ b/src/python/m5/objects/System.py @@ -1,9 +1,12 @@ from m5 import build_env from m5.config import * +class MemoryMode(Enum): vals = ['invalid', 'atomic', 'timing'] + class System(SimObject): type = 'System' physmem = Param.PhysicalMemory(Parent.any, "phsyical memory") + mem_mode = Param.MemoryMode('atomic', "The mode the memory system is in") if build_env['FULL_SYSTEM']: boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency, "boot processor frequency") diff --git a/src/sim/system.cc b/src/sim/system.cc index 2780d0fda..ad70b9b03 100644 --- a/src/sim/system.cc +++ b/src/sim/system.cc @@ -63,7 +63,7 @@ System::System(Params *p) #else page_ptr(0), #endif - _params(p) + memoryMode(p->mem_mode), _params(p) { // add self to global system list systemList.push_back(this); @@ -257,6 +257,9 @@ printSystems() System::printSystems(); } +const char *System::MemoryModeStrings[3] = {"invalid", "atomic", + "timing"}; + #if FULL_SYSTEM // In full system mode, only derived classes (e.g. AlphaLinuxSystem) @@ -269,12 +272,15 @@ DEFINE_SIM_OBJECT_CLASS_NAME("System", System) BEGIN_DECLARE_SIM_OBJECT_PARAMS(System) SimObjectParam physmem; + SimpleEnumParam mem_mode; END_DECLARE_SIM_OBJECT_PARAMS(System) BEGIN_INIT_SIM_OBJECT_PARAMS(System) - INIT_PARAM(physmem, "physical memory") + INIT_PARAM(physmem, "physical memory"), + INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", + System::MemoryModeStrings) END_INIT_SIM_OBJECT_PARAMS(System) @@ -283,6 +289,7 @@ CREATE_SIM_OBJECT(System) System::Params *p = new System::Params; p->name = getInstanceName(); p->physmem = physmem; + p->mem_mode = mem_mode; return new System(p); } diff --git a/src/sim/system.hh b/src/sim/system.hh index 77777aed4..a1b53c2eb 100644 --- a/src/sim/system.hh +++ b/src/sim/system.hh @@ -67,6 +67,8 @@ class System : public SimObject Timing }; + static const char *MemoryModeStrings[3]; + MemoryMode getMemoryMode() { assert(memoryMode); return memoryMode; } @@ -170,6 +172,7 @@ class System : public SimObject { std::string name; PhysicalMemory *physmem; + MemoryMode mem_mode; #if FULL_SYSTEM Tick boot_cpu_frequency; -- cgit v1.2.3 From e1b8e71500b7b66b115345eeaef7216617487456 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Thu, 13 Jul 2006 15:48:41 -0400 Subject: fix help when no arguments are passed to m5 --HG-- extra : convert_revision : ee6614166fd5814654309298abe5a706ff02c4c2 --- src/python/m5/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/m5/main.py b/src/python/m5/main.py index 54c54c1d5..afe73d94c 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -182,7 +182,7 @@ options = attrdict() arguments = [] def usage(exitcode=None): - print parser.help + parser.print_help() if exitcode is not None: sys.exit(exitcode) -- cgit v1.2.3 From f1a7e0d3b3dcd04d8bde65ebb7f22b5bc6f98747 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Fri, 14 Jul 2006 04:52:08 -0400 Subject: MIPS specific fixes ... the main thing is that SMT threads get their own stack space instead of all stacks start to space src/arch/mips/isa_traits.hh: MaxAddr is defined in config.py now src/arch/mips/process.cc: adjust process so SMT threads get their own stack space src/arch/mips/process.hh: add stack_start static variable --HG-- extra : convert_revision : 73fdf3da9831d86536651835d209806c7f0d59da --- src/arch/mips/isa_traits.hh | 2 +- src/arch/mips/process.cc | 5 ++++- src/arch/mips/process.hh | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/arch/mips/isa_traits.hh b/src/arch/mips/isa_traits.hh index ff994bef9..2f485c7fd 100644 --- a/src/arch/mips/isa_traits.hh +++ b/src/arch/mips/isa_traits.hh @@ -129,7 +129,7 @@ namespace MipsISA template void zeroRegisters(TC *tc); - const Addr MaxAddr = (Addr)-1; +// const Addr MaxAddr = (Addr)-1; void copyRegs(ThreadContext *src, ThreadContext *dest); diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc index 031c2030e..cb847fe04 100644 --- a/src/arch/mips/process.cc +++ b/src/arch/mips/process.cc @@ -41,6 +41,8 @@ using namespace std; using namespace MipsISA; +Addr MipsLiveProcess::stack_start = 0x7FFFFFFF; + MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile, System *_system, int stdin_fd, int stdout_fd, int stderr_fd, std::vector &argv, std::vector &envp) @@ -49,10 +51,11 @@ MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile, { // Set up stack. On MIPS, stack starts at the top of kuseg // user address space. MIPS stack grows down from here - stack_base = 0x7FFFFFFF; + stack_base = stack_start; // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); + stack_start = next_thread_stack_base; // Set up break point (Top of Heap) brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); diff --git a/src/arch/mips/process.hh b/src/arch/mips/process.hh index b0ef20399..4baee134b 100644 --- a/src/arch/mips/process.hh +++ b/src/arch/mips/process.hh @@ -50,6 +50,9 @@ class MipsLiveProcess : public LiveProcess std::vector &envp); void startup(); + + + static Addr stack_start; }; -- cgit v1.2.3 From b2c51d064bc6e40e1723e04e300b8d623ef5c3d1 Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Fri, 14 Jul 2006 13:06:37 -0400 Subject: For now, halt context is the same as deallocating. suspend context will now take the thread off the activeThread list. src/arch/mips/isa_traits.cc: add in copy MiscRegs unimplemented function --HG-- extra : convert_revision : 3ed5320b3786f84d4bb242e3a32b6f415339c3ba --- src/arch/mips/isa_traits.cc | 6 ++++++ src/cpu/o3/cpu.cc | 32 ++++++-------------------------- 2 files changed, 12 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/arch/mips/isa_traits.cc b/src/arch/mips/isa_traits.cc index 85acc4e8c..a8b41270e 100644 --- a/src/arch/mips/isa_traits.cc +++ b/src/arch/mips/isa_traits.cc @@ -45,6 +45,12 @@ MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest) panic("Copy Regs Not Implemented Yet\n"); } +void +MipsISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) +{ + panic("Copy Misc. Regs Not Implemented Yet\n"); +} + void MipsISA::MiscRegFile::copyMiscRegs(ThreadContext *tc) { diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 6e9b425c0..349434c94 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -577,39 +577,19 @@ void FullO3CPU::suspendContext(int tid) { DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); - unscheduleTickEvent(); + deactivateThread(); + if (activeThreads.size() == 0) + unscheduleTickEvent(); _status = Idle; -/* - //Remove From Active List, if Active - list::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - } -*/ } template void FullO3CPU::haltContext(int tid) { - DPRINTF(O3CPU,"[tid:%i]: Halting Thread Context", tid); -/* - //Remove From Active List, if Active - list::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - - removeThread(tid); - } -*/ + //For now, this is the same as deallocate + DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid); + deallocateContext(tid, 1); } template -- cgit v1.2.3 From 07186de5a1b1df55a31329b2ca9c53ad168438ff Mon Sep 17 00:00:00 2001 From: Korey Sewell Date: Fri, 14 Jul 2006 13:22:35 -0400 Subject: forgot tid --HG-- extra : convert_revision : 272ef8f9cd0802770edc4dcef2c26dc44de71e47 --- src/cpu/o3/cpu.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index 349434c94..b407f4fcc 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -577,7 +577,7 @@ void FullO3CPU::suspendContext(int tid) { DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); - deactivateThread(); + deactivateThread(tid); if (activeThreads.size() == 0) unscheduleTickEvent(); _status = Idle; -- cgit v1.2.3