// put it on the list to send
Tick readyTime = curTick() + nackDelay;
- PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true);
+ DeferredResponse resp(pkt, readyTime, true);
// nothing on the list, add it and we're done
if (responseQueue.empty()) {
assert(!sendEvent.scheduled());
bridge->schedule(sendEvent, readyTime);
- responseQueue.push_back(buf);
+ responseQueue.push_back(resp);
return;
}
assert(sendEvent.scheduled() || inRetry);
// does it go at the end?
- if (readyTime >= responseQueue.back()->ready) {
- responseQueue.push_back(buf);
+ if (readyTime >= responseQueue.back().ready) {
+ responseQueue.push_back(resp);
return;
}
// ok, somewhere in the middle, fun
- std::list<PacketBuffer*>::iterator i = responseQueue.begin();
- std::list<PacketBuffer*>::iterator end = responseQueue.end();
- std::list<PacketBuffer*>::iterator begin = responseQueue.begin();
+ std::list<DeferredResponse>::iterator i = responseQueue.begin();
+ std::list<DeferredResponse>::iterator end = responseQueue.end();
+ std::list<DeferredResponse>::iterator begin = responseQueue.begin();
bool done = false;
while (i != end && !done) {
- if (readyTime < (*i)->ready) {
+ if (readyTime < (*i).ready) {
if (i == begin)
bridge->reschedule(sendEvent, readyTime);
- responseQueue.insert(i,buf);
+ responseQueue.insert(i, resp);
done = true;
}
i++;
Bridge::BridgeMasterPort::queueForSendTiming(PacketPtr pkt)
{
Tick readyTime = curTick() + delay;
- PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
+
+ // If we expect to see a response, we need to restore the source
+ // and destination field that is potentially changed by a second
+ // bus
+ if (!pkt->memInhibitAsserted() && pkt->needsResponse()) {
+ // Update the sender state so we can deal with the response
+ // appropriately
+ RequestState *req_state = new RequestState(pkt);
+ pkt->senderState = req_state;
+ }
// If we're about to put this packet at the head of the queue, we
// need to schedule an event to do the transmit. Otherwise there
assert(requestQueue.size() != reqQueueLimit);
- requestQueue.push_back(buf);
+ requestQueue.push_back(DeferredRequest(pkt, readyTime));
}
Bridge::BridgeSlavePort::queueForSendTiming(PacketPtr pkt)
{
// This is a response for a request we forwarded earlier. The
- // corresponding PacketBuffer should be stored in the packet's
+ // corresponding request state should be stored in the packet's
// senderState field.
- PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
- assert(buf != NULL);
+ RequestState *req_state = dynamic_cast<RequestState*>(pkt->senderState);
+ assert(req_state != NULL);
// set up new packet dest & senderState based on values saved
// from original request
- buf->fixResponse(pkt);
+ req_state->fixResponse(pkt);
// the bridge assumes that at least one bus has set the
// destination field of the packet
assert(pkt->isDestValid());
DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
- delete buf;
+ delete req_state;
Tick readyTime = curTick() + delay;
- buf = new PacketBuffer(pkt, readyTime);
// If we're about to put this packet at the head of the queue, we
// need to schedule an event to do the transmit. Otherwise there
if (responseQueue.empty()) {
bridge->schedule(sendEvent, readyTime);
}
- responseQueue.push_back(buf);
+ responseQueue.push_back(DeferredResponse(pkt, readyTime));
}
void
{
assert(!requestQueue.empty());
- PacketBuffer *buf = requestQueue.front();
-
- assert(buf->ready <= curTick());
-
- PacketPtr pkt = buf->pkt;
+ DeferredRequest req = requestQueue.front();
- DPRINTF(BusBridge, "trySend: origSrc %d addr 0x%x\n",
- buf->origSrc, pkt->getAddr());
+ assert(req.ready <= curTick());
- // If the send was successful, make sure sender state was set to NULL
- // otherwise we could get a NACK back of a packet that didn't expect a
- // response and we would try to use freed memory.
+ PacketPtr pkt = req.pkt;
- Packet::SenderState *old_sender_state = pkt->senderState;
- if (!buf->expectResponse)
- pkt->senderState = NULL;
+ DPRINTF(BusBridge, "trySend request: addr 0x%x\n", pkt->getAddr());
if (sendTimingReq(pkt)) {
// send successful
requestQueue.pop_front();
- // we no longer own packet, so it's not safe to look at it
- buf->pkt = NULL;
-
- if (!buf->expectResponse) {
- // no response expected... deallocate packet buffer now.
- DPRINTF(BusBridge, " successful: no response expected\n");
- delete buf;
- }
// If there are more packets to send, schedule event to try again.
if (!requestQueue.empty()) {
- buf = requestQueue.front();
+ req = requestQueue.front();
DPRINTF(BusBridge, "Scheduling next send\n");
- bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
+ bridge->schedule(sendEvent,
+ std::max(req.ready, curTick() + 1));
}
} else {
- DPRINTF(BusBridge, " unsuccessful\n");
- pkt->senderState = old_sender_state;
inRetry = true;
}
{
assert(!responseQueue.empty());
- PacketBuffer *buf = responseQueue.front();
-
- assert(buf->ready <= curTick());
+ DeferredResponse resp = responseQueue.front();
- PacketPtr pkt = buf->pkt;
+ assert(resp.ready <= curTick());
- DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
- buf->origSrc, pkt->getDest(), pkt->getAddr());
+ PacketPtr pkt = resp.pkt;
- bool was_nacked_here = buf->nackedHere;
+ DPRINTF(BusBridge, "trySend response: dest %d addr 0x%x\n",
+ pkt->getDest(), pkt->getAddr());
- // no need to worry about the sender state since we are not
- // modifying it
+ bool was_nacked_here = resp.nackedHere;
if (sendTimingResp(pkt)) {
DPRINTF(BusBridge, " successful\n");
// send successful
responseQueue.pop_front();
- // this is a response... deallocate packet buffer now.
- delete buf;
if (!was_nacked_here) {
assert(outstandingResponses != 0);
// If there are more packets to send, schedule event to try again.
if (!responseQueue.empty()) {
- buf = responseQueue.front();
+ resp = responseQueue.front();
DPRINTF(BusBridge, "Scheduling next send\n");
- bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
+ bridge->schedule(sendEvent,
+ std::max(resp.ready, curTick() + 1));
}
} else {
DPRINTF(BusBridge, " unsuccessful\n");
Bridge::BridgeMasterPort::recvRetry()
{
inRetry = false;
- Tick nextReady = requestQueue.front()->ready;
+ Tick nextReady = requestQueue.front().ready;
if (nextReady <= curTick())
trySend();
else
Bridge::BridgeSlavePort::recvRetry()
{
inRetry = false;
- Tick nextReady = responseQueue.front()->ready;
+ Tick nextReady = responseQueue.front().ready;
if (nextReady <= curTick())
trySend();
else
void
Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt)
{
- std::list<PacketBuffer*>::iterator i;
+ std::list<DeferredResponse>::iterator i;
pkt->pushLabel(name());
// check the response queue
for (i = responseQueue.begin(); i != responseQueue.end(); ++i) {
- if (pkt->checkFunctional((*i)->pkt)) {
+ if (pkt->checkFunctional((*i).pkt)) {
pkt->makeResponse();
return;
}
Bridge::BridgeMasterPort::checkFunctional(PacketPtr pkt)
{
bool found = false;
- std::list<PacketBuffer*>::iterator i = requestQueue.begin();
+ std::list<DeferredRequest>::iterator i = requestQueue.begin();
while(i != requestQueue.end() && !found) {
- if (pkt->checkFunctional((*i)->pkt)) {
+ if (pkt->checkFunctional((*i).pkt)) {
pkt->makeResponse();
found = true;
}
protected:
/**
- * A packet buffer stores packets along with their sender state
- * and scheduled time for transmission.
+ * A bridge request state stores packets along with their sender
+ * state and original source. It has enough information to also
+ * restore the response once it comes back to the bridge.
*/
- class PacketBuffer : public Packet::SenderState, public FastAlloc {
+ class RequestState : public Packet::SenderState, public FastAlloc
+ {
public:
- Tick ready;
- PacketPtr pkt;
- bool nackedHere;
+
Packet::SenderState *origSenderState;
Packet::NodeID origSrc;
- bool expectResponse;
- PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
- : ready(t), pkt(_pkt), nackedHere(nack),
- origSenderState(_pkt->senderState),
- origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ),
- expectResponse(_pkt->needsResponse() && !nack)
-
- {
- if (!pkt->isResponse() && !nack)
- pkt->senderState = this;
- }
+ RequestState(PacketPtr _pkt)
+ : origSenderState(_pkt->senderState),
+ origSrc(_pkt->getSrc())
+ { }
void fixResponse(PacketPtr pkt)
{
}
};
+ /**
+ * A deferred request stores a packet along with its scheduled
+ * transmission time, and whether we can expect to see a response
+ * or not.
+ */
+ class DeferredRequest
+ {
+
+ public:
+
+ Tick ready;
+ PacketPtr pkt;
+ bool expectResponse;
+
+ DeferredRequest(PacketPtr _pkt, Tick t)
+ : ready(t), pkt(_pkt), expectResponse(_pkt->needsResponse())
+ { }
+ };
+
+ /**
+ * A deferred response stores a packet along with its scheduled
+ * transmission time. It also contains information of whether the
+ * bridge NACKed the packet to be able to correctly maintain
+ * counters of outstanding responses.
+ */
+ class DeferredResponse {
+
+ public:
+
+ Tick ready;
+ PacketPtr pkt;
+ bool nackedHere;
+
+ DeferredResponse(PacketPtr _pkt, Tick t, bool nack = false)
+ : ready(t), pkt(_pkt), nackedHere(nack)
+ { }
+ };
+
// Forward declaration to allow the slave port to have a pointer
class BridgeMasterPort;
* queue for a specified delay to model the processing delay
* of the bridge.
*/
- std::list<PacketBuffer*> responseQueue;
+ std::list<DeferredResponse> responseQueue;
/** Counter to track the outstanding responses. */
unsigned int outstandingResponses;
* queue for a specified delay to model the processing delay
* of the bridge.
*/
- std::list<PacketBuffer*> requestQueue;
+ std::list<DeferredRequest> requestQueue;
/** If we're waiting for a retry to happen. */
bool inRetry;