diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -364,6 +364,9 @@ /** Port to issue translation requests from */ SnoopingDmaPort port; + /** If we're draining keep the drain event around until we're drained */ + Event *drainEvent; + /** TLB that is initiating these table walks */ TLB *tlb; @@ -389,6 +392,8 @@ return dynamic_cast(_params); } + /** Checks if all state is cleared and if so, completes drain */ + void completeDrain(); virtual unsigned int drain(Event *de); virtual void resume(); virtual MasterPort& getMasterPort(const std::string &if_name, diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -51,7 +51,7 @@ TableWalker::TableWalker(const Params *p) : MemObject(p), port(this, params()->sys, params()->min_backoff, - params()->max_backoff), + params()->max_backoff), drainEvent(NULL), tlb(NULL), currState(NULL), pending(false), masterId(p->sys->getMasterId(name())), doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this) @@ -64,20 +64,31 @@ ; } +void +TableWalker::completeDrain() +{ + if (drainEvent && !(stateQueueL1.size() || stateQueueL2.size() || + pendingQueue.size())) { + changeState(Drained); + drainEvent->process(); + drainEvent = NULL; + } +} + unsigned int TableWalker::drain(Event *de) { - if (stateQueueL1.size() || stateQueueL2.size() || pendingQueue.size()) - { + unsigned int count = port.drain(de); + + if (stateQueueL1.size() || stateQueueL2.size() || pendingQueue.size()) { + drainEvent = de; changeState(Draining); DPRINTF(Checkpoint, "TableWalker busy, wait to drain\n"); - return 1; - } - else - { + return ++count; + } else { changeState(Drained); DPRINTF(Checkpoint, "TableWalker free, no need to drain\n"); - return 0; + return count; } } @@ -667,6 +678,7 @@ doL1Descriptor(); stateQueueL1.pop_front(); + completeDrain(); // Check if fault was generated if (currState->fault != NoFault) { currState->transState->finish(currState->fault, currState->req, @@ -723,6 +735,7 @@ stateQueueL2.pop_front(); + completeDrain(); pending = false; nextWalk(currState->tc); diff --git a/src/cpu/base.cc b/src/cpu/base.cc --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -383,8 +383,6 @@ { assert(threadContexts.size() == oldCPU->threadContexts.size()); - _cpuId = oldCPU->cpuId(); - ThreadID size = threadContexts.size(); for (ThreadID i = 0; i < size; ++i) { ThreadContext *newTC = threadContexts[i]; @@ -415,11 +413,13 @@ assert(old_itb_port); SlavePort &slavePort = old_itb_port->getSlavePort(); new_itb_port->bind(slavePort); + old_itb_port->unBind(); } if (new_dtb_port && !new_dtb_port->isConnected()) { assert(old_dtb_port); SlavePort &slavePort = old_dtb_port->getSlavePort(); new_dtb_port->bind(slavePort); + old_dtb_port->unBind(); } // Checker whether or not we have to transfer CheckerCPU @@ -441,18 +441,25 @@ assert(old_checker_itb_port); SlavePort &slavePort = old_checker_itb_port->getSlavePort();; new_checker_itb_port->bind(slavePort); + old_checker_itb_port->unBind(); } if (new_checker_dtb_port && !new_checker_dtb_port->isConnected()) { assert(old_checker_dtb_port); SlavePort &slavePort = old_checker_dtb_port->getSlavePort();; new_checker_dtb_port->bind(slavePort); + old_checker_dtb_port->unBind(); } } } + int tmpId = _cpuId; + _cpuId = oldCPU->cpuId(); + interrupts = oldCPU->interrupts; interrupts->setCPU(this); + oldCPU->_cpuId = tmpId; + if (FullSystem) { for (ThreadID i = 0; i < size; ++i) threadContexts[i]->profileClear(); @@ -466,10 +473,12 @@ // CPU. if (!getInstPort().isConnected()) { getInstPort().bind(oldCPU->getInstPort().getSlavePort()); + oldCPU->getInstPort().unBind(); } if (!getDataPort().isConnected()) { getDataPort().bind(oldCPU->getDataPort().getSlavePort()); + oldCPU->getDataPort().unBind(); } } diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -631,7 +631,8 @@ wroteToTimeBuffer = false; _nextStatus = Inactive; - if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) { + if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB() && + !iewStage->hasWBOutstanding()) { cpu->signalDrained(); drainPending = false; return; diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -260,7 +260,7 @@ if (!deferRegistration) { _status = Running; } else { - _status = Idle; + _status = SwitchedOut; } if (params->checker) { @@ -1119,9 +1119,8 @@ DPRINTF(O3CPU, "Switching out\n"); // If the CPU isn't doing anything, then return immediately. - if (_status == Idle || _status == SwitchedOut) { + if (_status == SwitchedOut) return 0; - } drainCount = 0; fetch.drain(); @@ -1160,7 +1159,7 @@ changeState(SimObject::Running); - if (_status == SwitchedOut || _status == Idle) + if (_status == SwitchedOut) return; assert(system->getMemoryMode() == Enums::timing); diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -132,6 +132,9 @@ // Get the size of an instruction. instSize = sizeof(TheISA::MachInst); + + for (int i = 0; i < Impl::MaxThreads; ++i) + cacheData[i] = NULL; } template diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -217,6 +217,9 @@ /** Returns if the LSQ has any stores to writeback. */ bool hasStoresToWB(ThreadID tid) { return ldstQueue.hasStoresToWB(tid); } + /** Returns if there are any oustanding WBs. */ + bool hasWBOutstanding() { return wbOutstanding > 0; } + void incrWb(InstSeqNum &sn) { if (++wbOutstanding == wbMax) diff --git a/src/dev/dma_device.cc b/src/dev/dma_device.cc --- a/src/dev/dma_device.cc +++ b/src/dev/dma_device.cc @@ -182,7 +182,8 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, uint8_t *data, Tick delay, Request::Flags flag) { - assert(device->getState() == SimObject::Running); + assert(device->getState() == SimObject::Running || + device->getState() == SimObject::Draining); DmaReqState *reqState = new DmaReqState(event, size, delay); diff --git a/src/mem/packet_queue.cc b/src/mem/packet_queue.cc --- a/src/mem/packet_queue.cc +++ b/src/mem/packet_queue.cc @@ -168,7 +168,7 @@ em.schedule(&sendEvent, std::max(nextReady, curTick() + 1)); } else { // no more to send, so if we're draining, we may be done - if (drainEvent && !sendEvent.scheduled()) { + if (drainEvent && transmitList.empty() && !sendEvent.scheduled()) { drainEvent->process(); drainEvent = NULL; } diff --git a/src/mem/port.hh b/src/mem/port.hh --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -170,6 +170,7 @@ PortId id = INVALID_PORT_ID); virtual ~MasterPort(); + void unBind(); void bind(SlavePort& slave_port); SlavePort& getSlavePort() const; bool isConnected() const; @@ -308,6 +309,7 @@ PortId id = INVALID_PORT_ID); virtual ~SlavePort(); + void unBind(); void bind(MasterPort& master_port); MasterPort& getMasterPort() const; bool isConnected() const; diff --git a/src/mem/port.cc b/src/mem/port.cc --- a/src/mem/port.cc +++ b/src/mem/port.cc @@ -82,6 +82,13 @@ } void +MasterPort::unBind() +{ + _slavePort = NULL; + peer = NULL; +} + +void MasterPort::bind(SlavePort& slave_port) { // master port keeps track of the slave port @@ -156,6 +163,13 @@ } void +SlavePort::unBind() +{ + _masterPort = NULL; + peer = NULL; +} + +void SlavePort::bind(MasterPort& master_port) { _masterPort = &master_port;