mem-ruby: AbstractController can send retry req to mem controller
Prior to this patch, when a memory controller was failing at sending a response to AbstractController, it would not wakeup until the next request. This patch gives the opportunity to Ruby models to notify memory response buffer dequeue so that AbstractController can send a retry request if necessary. A dequeueMemRspQueue function has been added AbstractController to automate the dequeue+notify operation. Note that models that don't notify AbstractController will continue working as before. Change-Id: I261bb4593c126208c98825e54f538638d818d16b Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/67658 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu> Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
This commit is contained in:
committed by
Gabriel B.
parent
b4687aa7d9
commit
833afc3451
@@ -62,8 +62,10 @@ AbstractController::AbstractController(const Params &p)
|
||||
m_buffer_size(p.buffer_size), m_recycle_latency(p.recycle_latency),
|
||||
m_mandatory_queue_latency(p.mandatory_queue_latency),
|
||||
m_waiting_mem_retry(false),
|
||||
m_mem_ctrl_waiting_retry(false),
|
||||
memoryPort(csprintf("%s.memory", name()), this),
|
||||
addrRanges(p.addr_ranges.begin(), p.addr_ranges.end()),
|
||||
mRetryRespEvent{*this, false},
|
||||
stats(this)
|
||||
{
|
||||
if (m_version == 0) {
|
||||
@@ -367,11 +369,17 @@ AbstractController::functionalMemoryWrite(PacketPtr pkt)
|
||||
return num_functional_writes + 1;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
AbstractController::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
assert(getMemRespQueue());
|
||||
assert(pkt->isResponse());
|
||||
auto* memRspQueue = getMemRespQueue();
|
||||
gem5_assert(memRspQueue);
|
||||
gem5_assert(pkt->isResponse());
|
||||
|
||||
if (!memRspQueue->areNSlotsAvailable(1, curTick())) {
|
||||
m_mem_ctrl_waiting_retry = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MemoryMsg> msg = std::make_shared<MemoryMsg>(clockEdge());
|
||||
(*msg).m_addr = pkt->getAddr();
|
||||
@@ -395,8 +403,9 @@ AbstractController::recvTimingResp(PacketPtr pkt)
|
||||
panic("Incorrect packet type received from memory controller!");
|
||||
}
|
||||
|
||||
getMemRespQueue()->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)));
|
||||
memRspQueue->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)));
|
||||
delete pkt;
|
||||
return true;
|
||||
}
|
||||
|
||||
Tick
|
||||
@@ -438,11 +447,33 @@ const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AbstractController::memRespQueueDequeued() {
|
||||
if (m_mem_ctrl_waiting_retry && !mRetryRespEvent.scheduled()) {
|
||||
schedule(mRetryRespEvent, clockEdge(Cycles{1}));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AbstractController::dequeueMemRespQueue() {
|
||||
auto* q = getMemRespQueue();
|
||||
gem5_assert(q);
|
||||
q->dequeue(clockEdge());
|
||||
memRespQueueDequeued();
|
||||
}
|
||||
|
||||
void
|
||||
AbstractController::sendRetryRespToMem() {
|
||||
if (m_mem_ctrl_waiting_retry) {
|
||||
m_mem_ctrl_waiting_retry = false;
|
||||
memoryPort.sendRetryResp();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AbstractController::MemoryPort::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
controller->recvTimingResp(pkt);
|
||||
return true;
|
||||
return controller->recvTimingResp(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#include "mem/ruby/system/CacheRecorder.hh"
|
||||
#include "params/RubyController.hh"
|
||||
#include "sim/clocked_object.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
namespace gem5
|
||||
{
|
||||
@@ -100,6 +101,14 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
virtual MessageBuffer* getMandatoryQueue() const = 0;
|
||||
virtual MessageBuffer* getMemReqQueue() const = 0;
|
||||
virtual MessageBuffer* getMemRespQueue() const = 0;
|
||||
|
||||
// That function must be called by controller when dequeuing mem resp queue
|
||||
// for memory controller to receive the retry request in time
|
||||
void memRespQueueDequeued();
|
||||
// Or that function can be called to perform both dequeue and notification
|
||||
// at once.
|
||||
void dequeueMemRespQueue();
|
||||
|
||||
virtual AccessPermission getAccessPermission(const Addr &addr) = 0;
|
||||
|
||||
virtual void print(std::ostream & out) const = 0;
|
||||
@@ -165,7 +174,7 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
Port &getPort(const std::string &if_name,
|
||||
PortID idx=InvalidPortID);
|
||||
|
||||
void recvTimingResp(PacketPtr pkt);
|
||||
bool recvTimingResp(PacketPtr pkt);
|
||||
Tick recvAtomic(PacketPtr pkt);
|
||||
|
||||
const AddrRangeList &getAddrRanges() const { return addrRanges; }
|
||||
@@ -364,6 +373,7 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
Cycles m_recycle_latency;
|
||||
const Cycles m_mandatory_queue_latency;
|
||||
bool m_waiting_mem_retry;
|
||||
bool m_mem_ctrl_waiting_retry;
|
||||
|
||||
/**
|
||||
* Port that forwards requests and receives responses from the
|
||||
@@ -411,6 +421,9 @@ class AbstractController : public ClockedObject, public Consumer
|
||||
NetDest downstreamDestinations;
|
||||
NetDest upstreamDestinations;
|
||||
|
||||
void sendRetryRespToMem();
|
||||
MemberEventWrapper<&AbstractController::sendRetryRespToMem> mRetryRespEvent;
|
||||
|
||||
public:
|
||||
struct ControllerStats : public statistics::Group
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user