From 365e4ac37446c0ff58b035767f8047c8a8c4fd61 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Tue, 29 May 2007 22:23:41 -0700 Subject: [PATCH] A little more cleanup & refactoring of SimpleTimingPort. Make it a better base class for cache ports. --HG-- extra : convert_revision : 37d6de11545a68c1a7d11ce33fe5971c51434ee4 --- src/mem/tport.cc | 88 +++++++++++++++++++++++++----------------------- src/mem/tport.hh | 21 ++++++++++-- 2 files changed, 63 insertions(+), 46 deletions(-) diff --git a/src/mem/tport.cc b/src/mem/tport.cc index 8797cf6e6..7b1c14467 100644 --- a/src/mem/tport.cc +++ b/src/mem/tport.cc @@ -36,7 +36,7 @@ SimpleTimingPort::checkFunctional(PacketPtr pkt) DeferredPacketIterator i = transmitList.begin(); DeferredPacketIterator end = transmitList.end(); - while (i != end) { + for (; i != end; ++i) { PacketPtr target = i->pkt; // If the target contains data, and it overlaps the // probed request, need to update data @@ -46,8 +46,6 @@ SimpleTimingPort::checkFunctional(PacketPtr pkt) return; } } - - i++; } } @@ -74,7 +72,7 @@ SimpleTimingPort::recvTiming(PacketPtr pkt) // turn packet around to go back to requester if response expected if (pkt->needsResponse()) { pkt->makeTimingResponse(); - sendTiming(pkt, latency); + schedSendTiming(pkt, latency); } else if (pkt->cmd != MemCmd::UpgradeReq) { delete pkt->req; @@ -83,81 +81,85 @@ SimpleTimingPort::recvTiming(PacketPtr pkt) return true; } -void -SimpleTimingPort::recvRetry() -{ - assert(!transmitList.empty()); - if (Port::sendTiming(transmitList.front().pkt)) { - transmitList.pop_front(); - DPRINTF(Bus, "No Longer waiting on retry\n"); - if (!transmitList.empty()) { - Tick time = transmitList.front().tick; - sendEvent->schedule(time <= curTick ? curTick+1 : time); - } - } - - if (transmitList.empty() && drainEvent) { - drainEvent->process(); - drainEvent = NULL; - } -} void -SimpleTimingPort::sendTiming(PacketPtr pkt, Tick time) +SimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when) { + assert(when > curTick); + // Nothing is on the list: add it and schedule an event if (transmitList.empty()) { assert(!sendEvent->scheduled()); - sendEvent->schedule(curTick+time); - transmitList.push_back(DeferredPacket(time+curTick, pkt)); + sendEvent->schedule(when); + transmitList.push_back(DeferredPacket(when, pkt)); return; } // something is on the list and this belongs at the end - if (time+curTick >= transmitList.back().tick) { - transmitList.push_back(DeferredPacket(time+curTick, pkt)); + if (when >= transmitList.back().tick) { + transmitList.push_back(DeferredPacket(when, pkt)); return; } // Something is on the list and this belongs somewhere else DeferredPacketIterator i = transmitList.begin(); DeferredPacketIterator end = transmitList.end(); - bool done = false; - while (i != end && !done) { - if (time+curTick < i->tick) { + for (; i != end; ++i) { + if (when < i->tick) { if (i == transmitList.begin()) { //Inserting at begining, reschedule - sendEvent->reschedule(time+curTick); + sendEvent->reschedule(when); } - transmitList.insert(i, DeferredPacket(time+curTick, pkt)); - done = true; + transmitList.insert(i, DeferredPacket(when, pkt)); + return; } - i++; } - assert(done); + assert(false); // should never get here } + void -SimpleTimingPort::processSendEvent() +SimpleTimingPort::sendDeferredPacket() { - assert(transmitList.size()); - assert(transmitList.front().tick <= curTick); - if (Port::sendTiming(transmitList.front().pkt)) { + assert(deferredPacketReady()); + bool success = sendTiming(transmitList.front().pkt); + + if (success) { //send successful, remove packet transmitList.pop_front(); if (!transmitList.empty()) { Tick time = transmitList.front().tick; sendEvent->schedule(time <= curTick ? curTick+1 : time); } + if (transmitList.empty() && drainEvent) { drainEvent->process(); drainEvent = NULL; } - return; } - // send unsuccessful (due to flow control). Will get retry - // callback later; save for then if not already - DPRINTF(Bus, "Waiting on retry\n"); + + waitingOnRetry = !success; + + if (waitingOnRetry) { + DPRINTF(Bus, "Send failed, waiting on retry\n"); + } +} + + +void +SimpleTimingPort::recvRetry() +{ + DPRINTF(Bus, "Received retry\n"); + assert(waitingOnRetry); + sendDeferredPacket(); +} + + +void +SimpleTimingPort::processSendEvent() +{ + assert(!waitingOnRetry); + sendDeferredPacket(); } diff --git a/src/mem/tport.hh b/src/mem/tport.hh index 9e8a01786..ea0f05ed1 100644 --- a/src/mem/tport.hh +++ b/src/mem/tport.hh @@ -94,15 +94,29 @@ class SimpleTimingPort : public Port * here.*/ Event *drainEvent; + /** Remember whether we're awaiting a retry from the bus. */ + bool waitingOnRetry; + /** Check the list of buffered packets against the supplied * functional request. */ void checkFunctional(PacketPtr funcPkt); + /** Check whether we have a packet ready to go on the transmit list. */ + bool deferredPacketReady() + { return !transmitList.empty() && transmitList.front().tick <= curTick; } + /** Schedule a sendTiming() event to be called in the future. * @param pkt packet to send - * @param time increment from now (in ticks) to send packet + * @param absolute time (in ticks) to send packet */ - void sendTiming(PacketPtr pkt, Tick time); + void schedSendTiming(PacketPtr pkt, Tick when); + + /** Attempt to send the packet at the head of the deferred packet + * list. Caller must guarantee that the deferred packet list is + * non-empty and that the head packet is scheduled for curTick (or + * earlier). + */ + void sendDeferredPacket(); /** This function is notification that the device should attempt to send a * packet again. */ @@ -126,7 +140,8 @@ class SimpleTimingPort : public Port SimpleTimingPort(std::string pname, MemObject *_owner = NULL) : Port(pname, _owner), sendEvent(new SendEvent(this)), - drainEvent(NULL) + drainEvent(NULL), + waitingOnRetry(false) {} ~SimpleTimingPort() { delete sendEvent; }