summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mem/bus.cc98
-rw-r--r--src/mem/bus.hh20
-rw-r--r--src/mem/packet.hh7
-rw-r--r--src/mem/tport.cc8
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;