diff options
Diffstat (limited to 'src/mem/simple_mem.cc')
-rw-r--r-- | src/mem/simple_mem.cc | 117 |
1 files changed, 80 insertions, 37 deletions
diff --git a/src/mem/simple_mem.cc b/src/mem/simple_mem.cc index 3492360cd..74d5c4ab2 100644 --- a/src/mem/simple_mem.cc +++ b/src/mem/simple_mem.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 ARM Limited + * Copyright (c) 2010-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -49,9 +49,10 @@ using namespace std; SimpleMemory::SimpleMemory(const SimpleMemoryParams* p) : AbstractMemory(p), - port(name() + ".port", *this), lat(p->latency), - lat_var(p->latency_var), bandwidth(p->bandwidth), - isBusy(false), retryReq(false), releaseEvent(this) + port(name() + ".port", *this), latency(p->latency), + latency_var(p->latency_var), bandwidth(p->bandwidth), isBusy(false), + retryReq(false), retryResp(false), + releaseEvent(this), dequeueEvent(this), drainManager(NULL) { } @@ -66,29 +67,24 @@ SimpleMemory::init() } Tick -SimpleMemory::calculateLatency(PacketPtr pkt) -{ - if (pkt->memInhibitAsserted()) { - return 0; - } else { - Tick latency = lat; - if (lat_var != 0) - latency += random_mt.random<Tick>(0, lat_var); - return latency; - } -} - -Tick -SimpleMemory::doAtomicAccess(PacketPtr pkt) +SimpleMemory::recvAtomic(PacketPtr pkt) { access(pkt); - return calculateLatency(pkt); + return pkt->memInhibitAsserted() ? 0 : getLatency(); } void -SimpleMemory::doFunctionalAccess(PacketPtr pkt) +SimpleMemory::recvFunctional(PacketPtr pkt) { + pkt->pushLabel(name()); + functionalAccess(pkt); + + // potentially update the packets in our packet queue as well + for (auto i = packetQueue.begin(); i != packetQueue.end(); ++i) + pkt->checkFunctional(i->pkt); + + pkt->popLabel(); } bool @@ -149,13 +145,18 @@ SimpleMemory::recvTimingReq(PacketPtr pkt) // go ahead and deal with the packet and put the response in the // queue if there is one bool needsResponse = pkt->needsResponse(); - Tick latency = doAtomicAccess(pkt); + recvAtomic(pkt); // turn packet around to go back to requester if response expected if (needsResponse) { - // doAtomicAccess() should already have turned packet into + // recvAtomic() should already have turned packet into // atomic response assert(pkt->isResponse()); - port.schedTimingResp(pkt, curTick() + latency); + // to keep things simple (and in order), we put the packet at + // the end even if the latency suggests it should be sent + // before the packet(s) before it + packetQueue.push_back(DeferredPacket(pkt, curTick() + getLatency())); + if (!dequeueEvent.scheduled()) + schedule(dequeueEvent, packetQueue.back().tick); } else { pendingDelete.push_back(pkt); } @@ -174,6 +175,46 @@ SimpleMemory::release() } } +void +SimpleMemory::dequeue() +{ + assert(!packetQueue.empty()); + DeferredPacket deferred_pkt = packetQueue.front(); + + retryResp = !port.sendTimingResp(deferred_pkt.pkt); + + if (!retryResp) { + packetQueue.pop_front(); + + // if the queue is not empty, schedule the next dequeue event, + // otherwise signal that we are drained if we were asked to do so + if (!packetQueue.empty()) { + // if there were packets that got in-between then we + // already have an event scheduled, so use re-schedule + reschedule(dequeueEvent, + std::max(packetQueue.front().tick, curTick()), true); + } else if (drainManager) { + drainManager->signalDrainDone(); + drainManager = NULL; + } + } +} + +Tick +SimpleMemory::getLatency() const +{ + return latency + + (latency_var ? random_mt.random<Tick>(0, latency_var) : 0); +} + +void +SimpleMemory::recvRetry() +{ + assert(retryResp); + + dequeue(); +} + BaseSlavePort & SimpleMemory::getSlavePort(const std::string &if_name, PortID idx) { @@ -187,7 +228,13 @@ SimpleMemory::getSlavePort(const std::string &if_name, PortID idx) unsigned int SimpleMemory::drain(DrainManager *dm) { - int count = port.drain(dm); + int count = 0; + + // also track our internal queue + if (!packetQueue.empty()) { + count += 1; + drainManager = dm; + } if (count) setDrainState(Drainable::Draining); @@ -198,8 +245,7 @@ SimpleMemory::drain(DrainManager *dm) SimpleMemory::MemoryPort::MemoryPort(const std::string& _name, SimpleMemory& _memory) - : QueuedSlavePort(_name, &_memory, queueImpl), - queueImpl(_memory, *this), memory(_memory) + : SlavePort(_name, &_memory), memory(_memory) { } AddrRangeList @@ -213,22 +259,13 @@ SimpleMemory::MemoryPort::getAddrRanges() const Tick SimpleMemory::MemoryPort::recvAtomic(PacketPtr pkt) { - return memory.doAtomicAccess(pkt); + return memory.recvAtomic(pkt); } void SimpleMemory::MemoryPort::recvFunctional(PacketPtr pkt) { - pkt->pushLabel(memory.name()); - - if (!queue.checkFunctional(pkt)) { - // Default implementation of SimpleTimingPort::recvFunctional() - // calls recvAtomic() and throws away the latency; we can save a - // little here by just not calculating the latency. - memory.doFunctionalAccess(pkt); - } - - pkt->popLabel(); + memory.recvFunctional(pkt); } bool @@ -237,6 +274,12 @@ SimpleMemory::MemoryPort::recvTimingReq(PacketPtr pkt) return memory.recvTimingReq(pkt); } +void +SimpleMemory::MemoryPort::recvRetry() +{ + memory.recvRetry(); +} + SimpleMemory* SimpleMemoryParams::create() { |