void
Bus::init()
{
- std::vector<Port*>::iterator intIter;
+ std::vector<BusPort*>::iterator intIter;
for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
(*intIter)->sendStatusChange(Port::RangeChange);
}
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()
return "bus became available";
}
-void
-Bus::occupyBus(int numCycles)
+void Bus::occupyBus(PacketPtr pkt)
{
- //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.
+ //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())
+ numCycles++;
+ else if (pkt->isResponse() || pkt->hasData()) {
+ // If a packet has data, it needs ceil(size/width) cycles to send it
+ // We're using the "adding instead of dividing" trick again here
+ if (pkt->hasData()) {
+ int dataSize = pkt->getSize();
+ for (int transmitted = 0; transmitted < dataSize;
+ transmitted += width) {
+ numCycles++;
+ }
+ } else {
+ // If the packet didn't have data, it must have been a response.
+ // Those use the bus for one cycle to send their data.
+ 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 repeating add trick as well?
+ //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);
+ 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;
}
/** Function called by the port when the bus is receiving a Timing
DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
- Port *pktPort = interfaces[pkt->getSrc()];
+ BusPort *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) {
assert(success);
if (pkt->flags & SATISFIED) {
//Cache-Cache transfer occuring
- if (retryingPort) {
+ if (inRetry) {
+ retryList.front()->onRetryList(false);
retryList.pop_front();
- retryingPort = NULL;
+ inRetry = false;
}
+ occupyBus(pkt);
return true;
}
port = findPort(pkt->getAddr(), pkt->getSrc());
port = interfaces[dest];
}
- // The packet will be sent. Figure out how long it occupies the bus.
- int numCycles = 0;
- // Requests need one cycle to send an address
- if (pkt->isRequest())
- numCycles++;
- else if (pkt->isResponse() || pkt->hasData()) {
- // If a packet has data, it needs ceil(size/width) cycles to send it
- // We're using the "adding instead of dividing" trick again here
- if (pkt->hasData()) {
- int dataSize = pkt->getSize();
- for (int transmitted = 0; transmitted < dataSize;
- transmitted += width) {
- numCycles++;
- }
- } else {
- // If the packet didn't have data, it must have been a response.
- // Those use the bus for one cycle to send their data.
- numCycles++;
- }
- }
-
- occupyBus(numCycles);
+ occupyBus(pkt);
if (port->sendTiming(pkt)) {
// Packet was successfully sent. Return true.
// Also take care of retries
- if (retryingPort) {
+ if (inRetry) {
+ DPRINTF(Bus, "Remove retry from list %i\n", retryList.front());
+ retryList.front()->onRetryList(false);
retryList.pop_front();
- retryingPort = NULL;
+ inRetry = false;
}
return true;
}
// Packet not successfully sent. Leave or put it on the retry list.
+ DPRINTF(Bus, "Adding a retry to RETRY list %i\n", pktPort);
addToRetryList(pktPort);
return false;
}
void
Bus::recvRetry(int id)
{
+ DPRINTF(Bus, "Received a retry\n");
// 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;
+ DPRINTF(Bus, "Sending a retry\n");
+ 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);
}
}
//Careful to not overlap ranges
//or snoop will be called more than once on the port
ports.push_back(portSnoopList[i].portId);
- DPRINTF(Bus, " found snoop addr %#llx on device%d\n", addr,
- portSnoopList[i].portId);
+// DPRINTF(Bus, " found snoop addr %#llx on device%d\n", addr,
+// portSnoopList[i].portId);
}
i++;
}