diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mem/bus.cc | 98 | ||||
-rw-r--r-- | src/mem/bus.hh | 20 | ||||
-rw-r--r-- | src/mem/packet.hh | 7 | ||||
-rw-r--r-- | src/mem/tport.cc | 8 |
4 files changed, 75 insertions, 58 deletions
diff --git a/src/mem/bus.cc b/src/mem/bus.cc index 7584ffffd..3efaa93ac 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -68,13 +68,11 @@ Bus::init() } Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) -{ - assert(!scheduled()); -} +{} void Bus::BusFreeEvent::process() { - bus->recvRetry(0); + bus->recvRetry(-1); } const char * Bus::BusFreeEvent::description() @@ -82,33 +80,6 @@ const char * Bus::BusFreeEvent::description() return "bus became available"; } -void -Bus::occupyBus(int numCycles) -{ - //Move up when the bus will next be free - //We avoid the use of divide by adding repeatedly - //This should be faster if the value is updated frequently, but should - //be may be slower otherwise. - - //Bring tickNextIdle up to the present tick - //There is some potential ambiguity where a cycle starts, which might make - //a difference when devices are acting right around a cycle boundary. Using - //a < allows things which happen exactly on a cycle boundary to take up only - //the following cycle. Anthing that happens later will have to "wait" for the - //end of that cycle, and then start using the bus after that. - while (tickNextIdle < curTick) - tickNextIdle += clock; - //Advance it numCycles bus cycles. - //XXX Should this use the repeating add trick as well? - tickNextIdle += (numCycles * clock); - if (!busIdle.scheduled()) { - busIdle.schedule(tickNextIdle); - } else { - busIdle.reschedule(tickNextIdle); - } - DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", curTick, tickNextIdle); -} - /** Function called by the port when the bus is receiving a Timing * transaction.*/ bool @@ -120,6 +91,14 @@ Bus::recvTiming(Packet *pkt) Port *pktPort = interfaces[pkt->getSrc()]; + // If the bus is busy, or other devices are in line ahead of the current + // one, put this device on the retry list. + if (tickNextIdle > curTick || + (retryList.size() && (!inRetry || pktPort != retryList.front()))) { + addToRetryList(pktPort); + return false; + } + short dest = pkt->getDest(); if (dest == Packet::Broadcast) { if (timingSnoop(pkt)) { @@ -128,9 +107,9 @@ Bus::recvTiming(Packet *pkt) assert(success); if (pkt->flags & SATISFIED) { //Cache-Cache transfer occuring - if (retryingPort) { + if (inRetry) { retryList.pop_front(); - retryingPort = NULL; + inRetry = false; } return true; } @@ -146,7 +125,17 @@ Bus::recvTiming(Packet *pkt) port = interfaces[dest]; } - // The packet will be sent. Figure out how long it occupies the bus. + //Bring tickNextIdle up to the present tick + //There is some potential ambiguity where a cycle starts, which might make + //a difference when devices are acting right around a cycle boundary. Using + //a < allows things which happen exactly on a cycle boundary to take up only + //the following cycle. Anthing that happens later will have to "wait" for + //the end of that cycle, and then start using the bus after that. + while (tickNextIdle < curTick) + tickNextIdle += clock; + + // The packet will be sent. Figure out how long it occupies the bus, and + // how much of that time is for the first "word", aka bus width. int numCycles = 0; // Requests need one cycle to send an address if (pkt->isRequest()) @@ -167,14 +156,33 @@ Bus::recvTiming(Packet *pkt) } } - occupyBus(numCycles); + // The first word will be delivered after the current tick, the delivery + // of the address if any, and one bus cycle to deliver the data + pkt->firstWordTime = + tickNextIdle + + pkt->isRequest() ? clock : 0 + + clock; + + //Advance it numCycles bus cycles. + //XXX Should this use the repeated addition trick as well? + tickNextIdle += (numCycles * clock); + if (!busIdle.scheduled()) { + busIdle.schedule(tickNextIdle); + } else { + busIdle.reschedule(tickNextIdle); + } + DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", + curTick, tickNextIdle); + + // The bus will become idle once the current packet is delivered. + pkt->finishTime = tickNextIdle; if (port->sendTiming(pkt)) { // Packet was successfully sent. Return true. // Also take care of retries - if (retryingPort) { + if (inRetry) { retryList.pop_front(); - retryingPort = NULL; + inRetry = false; } return true; } @@ -189,14 +197,14 @@ Bus::recvRetry(int id) { // If there's anything waiting... if (retryList.size()) { - retryingPort = retryList.front(); - retryingPort->sendRetry(); - // If the retryingPort pointer isn't null, sendTiming wasn't called - if (retryingPort) { - warn("sendRetry didn't call sendTiming\n"); - retryList.pop_front(); - retryingPort = NULL; - } + //retryingPort = retryList.front(); + inRetry = true; + retryList.front()->sendRetry(); + // If inRetry is still true, sendTiming wasn't called + if (inRetry) + panic("Port %s didn't call sendTiming in it's recvRetry\n",\ + retryList.front()->getPeer()->name()); + //assert(!inRetry); } } diff --git a/src/mem/bus.hh b/src/mem/bus.hh index a89738775..4affcd6ae 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -195,9 +195,7 @@ class Bus : public MemObject BusFreeEvent busIdle; - void occupyBus(int numCycles); - - Port * retryingPort; + bool inRetry; /** An array of pointers to the peer port interfaces connected to this bus.*/ @@ -209,18 +207,18 @@ class Bus : public MemObject void addToRetryList(Port * port) { - if (!retryingPort) { + if (!inRetry) { // The device wasn't retrying a packet, or wasn't at an appropriate // time. retryList.push_back(port); } else { // The device was retrying a packet. It didn't work, so we'll leave // it at the head of the retry list. - retryingPort = NULL; + inRetry = false; - // We shouldn't be receiving a packet from one port when a different +/* // We shouldn't be receiving a packet from one port when a different // one is retrying. - assert(port == retryingPort); + assert(port == retryingPort);*/ } } @@ -236,11 +234,13 @@ class Bus : public MemObject Bus(const std::string &n, int bus_id, int _clock, int _width) : MemObject(n), busId(bus_id), clock(_clock), width(_width), - tickNextIdle(0), busIdle(this), retryingPort(NULL), defaultPort(NULL) + tickNextIdle(0), busIdle(this), inRetry(false), defaultPort(NULL) { //Both the width and clock period must be positive - assert(width); - assert(clock); + if (width <= 0) + fatal("Bus width must be positive\n"); + if (clock <= 0) + fatal("Bus clock period must be positive\n"); } }; diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 7ec061710..3a7286a69 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -92,7 +92,6 @@ class Packet * be called on it rather than simply delete.*/ bool arrayData; - /** The address of the request. This address could be virtual or * physical, depending on the system configuration. */ Addr addr; @@ -124,6 +123,12 @@ class Packet /** Used to calculate latencies for each packet.*/ Tick time; + /** The time at which the packet will be fully transmitted */ + Tick finishTime; + + /** The time at which the first chunk of the packet will be transmitted */ + Tick firstWordTime; + /** The special destination address indicating that the packet * should be routed based on its address. */ static const short Broadcast = -1; diff --git a/src/mem/tport.cc b/src/mem/tport.cc index cef7a2a5b..528067170 100644 --- a/src/mem/tport.cc +++ b/src/mem/tport.cc @@ -59,6 +59,8 @@ void SimpleTimingPort::recvRetry() { bool result = true; + + assert(transmitList.size()); while (result && transmitList.size()) { result = sendTiming(transmitList.front()); if (result) @@ -75,8 +77,10 @@ SimpleTimingPort::SendEvent::process() { port->outTiming--; assert(port->outTiming >= 0); - if (port->sendTiming(packet)) { - // send successfule + if (port->transmitList.size()) { + port->transmitList.push_back(packet); + } else if (port->sendTiming(packet)) { + // send successful if (port->transmitList.size() == 0 && port->drainEvent) { port->drainEvent->process(); port->drainEvent = NULL; |