/*
- * Copyright (c) 2010-2013 ARM Limited
+ * Copyright (c) 2010-2013, 2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#include "base/random.hh"
#include "mem/simple_mem.hh"
+#include "debug/Drain.hh"
using namespace std;
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)
+ releaseEvent(this), dequeueEvent(this)
{
}
void
SimpleMemory::init()
{
+ AbstractMemory::init();
+
// allow unconnected memories as this is used in several ruby
// systems at the moment
if (port.isConnected()) {
SimpleMemory::recvAtomic(PacketPtr pkt)
{
access(pkt);
- return pkt->memInhibitAsserted() ? 0 : getLatency();
+ return pkt->cacheResponding() ? 0 : getLatency();
}
void
bool
SimpleMemory::recvTimingReq(PacketPtr pkt)
{
- /// @todo temporary hack to deal with memory corruption issues until
- /// 4-phase transactions are complete
- for (int x = 0; x < pendingDelete.size(); x++)
- delete pendingDelete[x];
- pendingDelete.clear();
-
- if (pkt->memInhibitAsserted()) {
- // snooper will supply based on copy of packet
- // still target's responsibility to delete packet
- pendingDelete.push_back(pkt);
+ // if a cache is responding, sink the packet without further action
+ if (pkt->cacheResponding()) {
+ pendingDelete.reset(pkt);
return true;
}
- // we should never get a new request after committing to retry the
- // current one, the bus violates the rule as it simply sends a
- // retry to the next one waiting on the retry list, so simply
- // ignore it
+ // we should not get a new request after committing to retry the
+ // current one, but unfortunately the CPU violates this rule, so
+ // simply ignore it for now
if (retryReq)
return false;
return false;
}
- // @todo someone should pay for this
- pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+ // technically the packet only reaches us after the header delay,
+ // and since this is a memory controller we also need to
+ // deserialise the payload before performing any write operation
+ Tick receive_delay = pkt->headerDelay + pkt->payloadDelay;
+ pkt->headerDelay = pkt->payloadDelay = 0;
// update the release time according to the bandwidth limit, and
// do so with respect to the time it takes to finish this request
// recvAtomic() should already have turned packet into
// atomic response
assert(pkt->isResponse());
- // 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()));
+
+ Tick when_to_send = curTick() + receive_delay + getLatency();
+
+ // typically this should be added at the end, so start the
+ // insertion sort with the last element, also make sure not to
+ // re-order in front of some existing packet with the same
+ // address, the latter is important as this memory effectively
+ // hands out exclusive copies (shared is not asserted)
+ auto i = packetQueue.end();
+ --i;
+ while (i != packetQueue.begin() && when_to_send < i->tick &&
+ i->pkt->getAddr() != pkt->getAddr())
+ --i;
+
+ // emplace inserts the element before the position pointed to by
+ // the iterator, so advance it one step
+ packetQueue.emplace(++i, pkt, when_to_send);
+
if (!retryResp && !dequeueEvent.scheduled())
schedule(dequeueEvent, packetQueue.back().tick);
} else {
- pendingDelete.push_back(pkt);
+ pendingDelete.reset(pkt);
}
return true;
isBusy = false;
if (retryReq) {
retryReq = false;
- port.sendRetry();
+ port.sendRetryReq();
}
}
// 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;
+ } else if (drainState() == DrainState::Draining) {
+ DPRINTF(Drain, "Draining of SimpleMemory complete\n");
+ signalDrainDone();
}
}
}
}
void
-SimpleMemory::recvRetry()
+SimpleMemory::recvRespRetry()
{
assert(retryResp);
}
}
-unsigned int
-SimpleMemory::drain(DrainManager *dm)
+DrainState
+SimpleMemory::drain()
{
- int count = 0;
-
- // also track our internal queue
if (!packetQueue.empty()) {
- count += 1;
- drainManager = dm;
+ DPRINTF(Drain, "SimpleMemory Queue has requests, waiting to drain\n");
+ return DrainState::Draining;
+ } else {
+ return DrainState::Drained;
}
-
- if (count)
- setDrainState(Drainable::Draining);
- else
- setDrainState(Drainable::Drained);
- return count;
}
SimpleMemory::MemoryPort::MemoryPort(const std::string& _name,
}
void
-SimpleMemory::MemoryPort::recvRetry()
+SimpleMemory::MemoryPort::recvRespRetry()
{
- memory.recvRetry();
+ memory.recvRespRetry();
}
SimpleMemory*