the bridge never returns false when recvTiming() is called on its ports now, it always returns true and nacks the packet if there isn't sufficient buffer space

fix the timing cpu to handle receiving a nacked packet

src/cpu/simple/timing.cc:
    make the timing cpu handle receiving a nacked packet
src/mem/bridge.cc:
src/mem/bridge.hh:
    the bridge never returns false when recvTiming() is called on its ports now, it always returns true and nacks the packet if there isn't sufficient buffer space

--HG--
extra : convert_revision : 5e12d0cf6ce985a5f72bcb7ce26c83a76c34c50a
This commit is contained in:
Ali Saidi 2007-05-07 18:58:38 -04:00
parent 0dfc29a023
commit a38c79ec22
3 changed files with 99 additions and 34 deletions

View file

@ -574,11 +574,17 @@ TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
return true; return true;
} }
else { else if (pkt->result == Packet::Nacked) {
assert(cpu->_status == IcacheWaitResponse);
pkt->reinitNacked();
if (!sendTiming(pkt)) {
cpu->_status = IcacheRetry;
cpu->ifetch_pkt = pkt;
}
}
//Snooping a Coherence Request, do nothing //Snooping a Coherence Request, do nothing
return true; return true;
} }
}
void void
TimingSimpleCPU::IcachePort::recvRetry() TimingSimpleCPU::IcachePort::recvRetry()
@ -663,11 +669,17 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
return true; return true;
} }
else { else if (pkt->result == Packet::Nacked) {
//Snooping a coherence req, do nothing assert(cpu->_status == DcacheWaitResponse);
return true; pkt->reinitNacked();
if (!sendTiming(pkt)) {
cpu->_status = DcacheRetry;
cpu->dcache_pkt = pkt;
} }
} }
//Snooping a Coherence Request, do nothing
return true;
}
void void
TimingSimpleCPU::DcachePort::DTickEvent::process() TimingSimpleCPU::DcachePort::DTickEvent::process()

View file

@ -47,7 +47,8 @@ Bridge::BridgePort::BridgePort(const std::string &_name,
bool fix_partial_write) bool fix_partial_write)
: Port(_name), bridge(_bridge), otherPort(_otherPort), : Port(_name), bridge(_bridge), otherPort(_otherPort),
delay(_delay), fixPartialWrite(fix_partial_write), delay(_delay), fixPartialWrite(fix_partial_write),
outstandingResponses(0), queueLimit(_queueLimit), sendEvent(this) outstandingResponses(0), queuedRequests(0),
queueLimit(_queueLimit), sendEvent(this)
{ {
} }
@ -92,34 +93,70 @@ Bridge::init()
fatal("Busses don't have the same block size... Not supported.\n"); fatal("Busses don't have the same block size... Not supported.\n");
} }
bool
Bridge::BridgePort::queueFull()
{
// use >= here because sendQueue could get larger because of
// nacks getting inserted
return queuedRequests + outstandingResponses >= queueLimit;
}
/** Function called by the port when the bus is receiving a Timing /** Function called by the port when the bus is receiving a Timing
* transaction.*/ * transaction.*/
bool bool
Bridge::BridgePort::recvTiming(PacketPtr pkt) Bridge::BridgePort::recvTiming(PacketPtr pkt)
{ {
if (pkt->flags & SNOOP_COMMIT) { if (!(pkt->flags & SNOOP_COMMIT))
return true;
DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr()); pkt->getSrc(), pkt->getDest(), pkt->getAddr());
return otherPort->queueForSendTiming(pkt); if (pkt->isRequest() && otherPort->queueFull()) {
DPRINTF(BusBridge, "Remote queue full, nacking\n");
nackRequest(pkt);
return true;
} }
else {
// Else it's just a snoop, properly return if we are blocking if (pkt->needsResponse() && pkt->result != Packet::Nacked)
return !queueFull(); if (queueFull()) {
DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
sendQueue.size(), queuedRequests, outstandingResponses);
nackRequest(pkt);
return true;
} else {
DPRINTF(BusBridge, "Request Needs response, reserving space\n");
++outstandingResponses;
} }
otherPort->queueForSendTiming(pkt);
return true;
}
void
Bridge::BridgePort::nackRequest(PacketPtr pkt)
{
// Nack the packet
pkt->result = Packet::Nacked;
pkt->setDest(pkt->getSrc());
//put it on the list to send
Tick readyTime = curTick + delay;
PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true);
if (sendQueue.empty()) {
sendEvent.schedule(readyTime);
}
sendQueue.push_back(buf);
} }
bool void
Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
{ {
if (queueFull()) { if (pkt->isResponse() || pkt->result == Packet::Nacked) {
DPRINTF(BusBridge, "Queue full, returning false\n");
return false;
}
if (pkt->isResponse()) {
// This is a response for a request we forwarded earlier. The // This is a response for a request we forwarded earlier. The
// corresponding PacketBuffer should be stored in the packet's // corresponding PacketBuffer should be stored in the packet's
// senderState field. // senderState field.
@ -128,6 +165,13 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
// set up new packet dest & senderState based on values saved // set up new packet dest & senderState based on values saved
// from original request // from original request
buf->fixResponse(pkt); buf->fixResponse(pkt);
// Check if this packet was expecting a response (this is either it or
// its a nacked packet and we won't be seeing that response)
if (buf->expectResponse)
--outstandingResponses;
DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n",
pkt->senderState, buf); pkt->senderState, buf);
DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest());
@ -146,10 +190,8 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
if (sendQueue.empty()) { if (sendQueue.empty()) {
sendEvent.schedule(readyTime); sendEvent.schedule(readyTime);
} }
++queuedRequests;
sendQueue.push_back(buf); sendQueue.push_back(buf);
return true;
} }
void void
@ -169,7 +211,8 @@ Bridge::BridgePort::trySend()
pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
pkt->getOffset(pbs) && pkt->getSize() != pbs) { pkt->result != Packet::Nacked && pkt->getOffset(pbs) &&
pkt->getSize() != pbs) {
buf->partialWriteFix(this); buf->partialWriteFix(this);
pkt = buf->pkt; pkt = buf->pkt;
} }
@ -184,10 +227,7 @@ Bridge::BridgePort::trySend()
buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it
if (buf->expectResponse) { if (buf->expectResponse) {
// Must wait for response. We just need to count outstanding // Must wait for response
// responses (in case we want to cap them); PacketBuffer
// pointer will be recovered on response.
++outstandingResponses;
DPRINTF(BusBridge, " successful: awaiting response (%d)\n", DPRINTF(BusBridge, " successful: awaiting response (%d)\n",
outstandingResponses); outstandingResponses);
} else { } else {
@ -196,13 +236,17 @@ Bridge::BridgePort::trySend()
delete buf; delete buf;
} }
if (!buf->nacked)
--queuedRequests;
// If there are more packets to send, schedule event to try again. // If there are more packets to send, schedule event to try again.
if (!sendQueue.empty()) { if (!sendQueue.empty()) {
buf = sendQueue.front(); buf = sendQueue.front();
DPRINTF(BusBridge, "Scheduling next send\n");
sendEvent.schedule(std::max(buf->ready, curTick + 1)); sendEvent.schedule(std::max(buf->ready, curTick + 1));
} }
// Let things start sending again // Let things start sending again
if (was_full) { if (was_full && !queueFull()) {
DPRINTF(BusBridge, "Queue was full, sending retry\n"); DPRINTF(BusBridge, "Queue was full, sending retry\n");
otherPort->sendRetry(); otherPort->sendRetry();
} }
@ -211,6 +255,8 @@ Bridge::BridgePort::trySend()
DPRINTF(BusBridge, " unsuccessful\n"); DPRINTF(BusBridge, " unsuccessful\n");
buf->undoPartialWriteFix(); buf->undoPartialWriteFix();
} }
DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
sendQueue.size(), queuedRequests, outstandingResponses);
} }
@ -290,3 +336,4 @@ CREATE_SIM_OBJECT(Bridge)
} }
REGISTER_SIM_OBJECT("Bridge", Bridge) REGISTER_SIM_OBJECT("Bridge", Bridge)

View file

@ -79,13 +79,16 @@ class Bridge : public MemObject
bool partialWriteFixed; bool partialWriteFixed;
PacketPtr oldPkt; PacketPtr oldPkt;
bool nacked;
PacketBuffer(PacketPtr _pkt, Tick t) PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
: ready(t), pkt(_pkt), : ready(t), pkt(_pkt),
origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
expectResponse(_pkt->needsResponse()), partialWriteFixed(false) expectResponse(_pkt->needsResponse() && !nack),
partialWriteFixed(false), nacked(nack)
{ {
if (!pkt->isResponse()) if (!pkt->isResponse() && !nack)
pkt->senderState = this; pkt->senderState = this;
} }
@ -144,6 +147,7 @@ class Bridge : public MemObject
std::list<PacketBuffer*> sendQueue; std::list<PacketBuffer*> sendQueue;
int outstandingResponses; int outstandingResponses;
int queuedRequests;
/** Max queue size for outbound packets */ /** Max queue size for outbound packets */
int queueLimit; int queueLimit;
@ -151,12 +155,14 @@ class Bridge : public MemObject
/** /**
* Is this side blocked from accepting outbound packets? * Is this side blocked from accepting outbound packets?
*/ */
bool queueFull() { return (sendQueue.size() == queueLimit); } bool queueFull();
bool queueForSendTiming(PacketPtr pkt); void queueForSendTiming(PacketPtr pkt);
void finishSend(PacketBuffer *buf); void finishSend(PacketBuffer *buf);
void nackRequest(PacketPtr pkt);
/** /**
* Handle send event, scheduled when the packet at the head of * Handle send event, scheduled when the packet at the head of
* the outbound queue is ready to transmit (for timing * the outbound queue is ready to transmit (for timing