summaryrefslogtreecommitdiff
path: root/src/mem/simple_mem.cc
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2013-08-19 03:52:25 -0400
committerAndreas Hansson <andreas.hansson@arm.com>2013-08-19 03:52:25 -0400
commit2a675aecb904143327befde70704d87c85fe7ea5 (patch)
tree7d08e554bcbf6959316a7174e46a755009026894 /src/mem/simple_mem.cc
parent9b2effd9e2d30c5e2a72bfe78214cd88689d89d9 (diff)
downloadgem5-2a675aecb904143327befde70704d87c85fe7ea5.tar.xz
mem: Add an internal packet queue in SimpleMemory
This patch adds a packet queue in SimpleMemory to avoid using the packet queue in the port (and thus have no involvement in the flow control). The port queue was bound to 100 packets, and as the SimpleMemory is modelling both a controller and an actual RAM, it potentially has a large number of packets in flight. There is currently no limit on the number of packets in the memory controller, but this could easily be added in a follow-on patch. As a result of the added internal storage, the functional access and draining is updated. Some minor cleaning up and renaming has also been done. The memtest regression changes as a result of this patch and the stats will be updated.
Diffstat (limited to 'src/mem/simple_mem.cc')
-rw-r--r--src/mem/simple_mem.cc117
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()
{