mem: Remove infinite queue between Ruby and memory

AbstractController sends requests using a QueuedMasterPort which has an
implicit buffer which is unbounded. Remove this by changing the port to
a MasterPort and implement a retry mechanism for AbstractController.
Although the request remains in the MessageBuffer if a retry is needed,
the additional retry logic optimizes serviceMemoryQueue slightly and
prevents the DRAMCtrl retry stats from being incorrect due to multiple
calls to sendTimingReq.

Change-Id: I8c592af92a1a499a418f34cfee16dd69d84803ad
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/28387
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Bradford Beckmann <brad.beckmann@amd.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Matthew Poremba
2020-05-08 17:16:28 -05:00
committed by Bradford Beckmann
parent 1e4a6b32b4
commit 27426fab83
2 changed files with 20 additions and 20 deletions

View File

@@ -56,7 +56,7 @@ AbstractController::AbstractController(const Params *p)
m_transitions_per_cycle(p->transitions_per_cycle),
m_buffer_size(p->buffer_size), m_recycle_latency(p->recycle_latency),
m_mandatory_queue_latency(p->mandatory_queue_latency),
memoryPort(csprintf("%s.memory", name()), this, ""),
memoryPort(csprintf("%s.memory", name()), this),
addrRanges(p->addr_ranges.begin(), p->addr_ranges.end())
{
if (m_version == 0) {
@@ -250,12 +250,15 @@ AbstractController::serviceMemoryQueue()
// to make more progress. Make sure it wakes up
scheduleEvent(Cycles(1));
recvTimingResp(pkt);
} else {
} else if (memoryPort.sendTimingReq(pkt)) {
mem_queue->dequeue(clockEdge());
memoryPort.schedTimingReq(pkt, clockEdge());
// Since the queue was popped the controller may be able
// to make more progress. Make sure it wakes up
scheduleEvent(Cycles(1));
} else {
scheduleEvent(Cycles(1));
delete pkt;
delete s;
}
return true;
@@ -306,11 +309,6 @@ AbstractController::functionalMemoryWrite(PacketPtr pkt)
{
int num_functional_writes = 0;
// Check the buffer from the controller to the memory.
if (memoryPort.trySatisfyFunctional(pkt)) {
num_functional_writes++;
}
// Update memory itself.
memoryPort.sendFunctional(pkt);
return num_functional_writes + 1;
@@ -369,12 +367,15 @@ AbstractController::MemoryPort::recvTimingResp(PacketPtr pkt)
return true;
}
void
AbstractController::MemoryPort::recvReqRetry()
{
controller->serviceMemoryQueue();
}
AbstractController::MemoryPort::MemoryPort(const std::string &_name,
AbstractController *_controller,
const std::string &_label)
: QueuedMasterPort(_name, _controller, reqQueue, snoopRespQueue),
reqQueue(*_controller, *this, _label),
snoopRespQueue(*_controller, *this, false, _label),
controller(_controller)
PortID id)
: MasterPort(_name, _controller, id), controller(_controller)
{
}

View File

@@ -228,26 +228,25 @@ class AbstractController : public ClockedObject, public Consumer
/**
* Port that forwards requests and receives responses from the
* memory controller. It has a queue of packets not yet sent.
* memory controller.
*/
class MemoryPort : public QueuedMasterPort
class MemoryPort : public MasterPort
{
private:
// Packet queues used to store outgoing requests and snoop responses.
ReqPacketQueue reqQueue;
SnoopRespPacketQueue snoopRespQueue;
// Controller that operates this port.
AbstractController *controller;
public:
MemoryPort(const std::string &_name, AbstractController *_controller,
const std::string &_label);
PortID id = InvalidPortID);
protected:
// Function for receiving a timing response from the peer port.
// Currently the pkt is handed to the coherence controller
// associated with this port.
bool recvTimingResp(PacketPtr pkt);
void recvReqRetry();
};
/* Master port to the memory controller. */