mem: Enforce strict use of busFirst- and busLastWordTime

This patch adds a check to ensure that the delay incurred by
the bus is not simply disregarded, but accounted for by someone. At
this point, all the modules do is to zero it out, and no additional
time is spent. This highlights where the bus timing is simply dropped
instead of being paid for.

As a follow up, the locations identified in this patch should add this
additional time to the packets in one way or another. For now it
simply acts as a sanity check and highlights where the delay is simply
ignored.

Since no time is added, all regressions remain the same.
This commit is contained in:
Andreas Hansson 2013-02-19 05:56:06 -05:00
parent 40d0e6c899
commit 860155a5fc
10 changed files with 53 additions and 0 deletions

View file

@ -54,6 +54,9 @@ PioPort::PioPort(PioDevice *dev)
Tick
PioPort::recvAtomic(PacketPtr pkt)
{
// @todo: We need to pay for this and not just zero it out
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
return pkt->isRead() ? device->read(pkt) : device->write(pkt);
}

View file

@ -67,6 +67,8 @@ PciDev::PciConfigPort::recvAtomic(PacketPtr pkt)
{
assert(pkt->getAddr() >= configAddr &&
pkt->getAddr() < configAddr + PCI_CONFIG_SIZE);
// @todo someone should pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt);
}

View file

@ -81,6 +81,8 @@ class IntDev
Tick recvMessage(PacketPtr pkt)
{
// @todo someone should pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
return device->recvMessage(pkt);
}
};

View file

@ -141,6 +141,9 @@ Bridge::BridgeMasterPort::recvTimingResp(PacketPtr pkt)
DPRINTF(Bridge, "Request queue size: %d\n", transmitList.size());
// @todo: We need to pay for this and not just zero it out
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
slavePort.schedTimingResp(pkt, bridge.clockEdge(delay));
return true;
@ -171,6 +174,10 @@ Bridge::BridgeSlavePort::recvTimingReq(PacketPtr pkt)
assert(outstandingResponses != respQueueLimit);
++outstandingResponses;
retryReq = false;
// @todo: We need to pay for this and not just zero it out
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
masterPort.schedTimingReq(pkt, bridge.clockEdge(delay));
}
}

View file

@ -140,6 +140,13 @@ BaseBus::calcPacketTiming(PacketPtr pkt)
// determine how many cycles are needed to send the data
unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0;
// before setting the bus delay fields of the packet, ensure that
// the delay from any previous bus has been accounted for
if (pkt->busFirstWordDelay != 0 || pkt->busLastWordDelay != 0)
panic("Packet %s already has bus delay (%d, %d) that should be "
"accounted for.\n", pkt->cmdString(), pkt->busFirstWordDelay,
pkt->busLastWordDelay);
// The first word will be delivered on the cycle after the header.
pkt->busFirstWordDelay = (headerCycles + 1) * clockPeriod() + offset;

View file

@ -381,6 +381,8 @@ Cache<TagStore>::recvTimingSnoopResp(PacketPtr pkt)
pkt->setDest(rec->prevSrc);
delete rec;
// @todo someone should pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
memSidePort->schedTimingSnoopResp(pkt, time);
}
@ -419,6 +421,9 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
// supplier had exclusive copy to begin with.
if (pkt->needsExclusive() && !pkt->isSupplyExclusive()) {
Packet *snoopPkt = new Packet(pkt, true); // clear flags
// also reset the bus time that the original packet has
// not yet paid for
snoopPkt->busFirstWordDelay = snoopPkt->busLastWordDelay = 0;
snoopPkt->setExpressSnoop();
snoopPkt->assertMemInhibit();
memSidePort->sendTimingReq(snoopPkt);
@ -437,6 +442,9 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
if (pkt->req->isUncacheable()) {
uncacheableFlush(pkt);
// @todo: someone should pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
// writes go in write buffer, reads use MSHR
if (pkt->isWrite() && !pkt->isRead()) {
allocateWriteBuffer(pkt, time, true);
@ -489,6 +497,8 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
if (needsResponse) {
pkt->makeTimingResponse();
// @todo: Make someone pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
cpuSidePort->schedTimingResp(pkt, clockEdge(lat));
} else {
/// @todo nominally we should just delete the packet here,
@ -499,6 +509,9 @@ Cache<TagStore>::recvTimingReq(PacketPtr pkt)
} else {
// miss
// @todo: Make someone pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
Addr blk_addr = blockAlign(pkt->getAddr());
MSHR *mshr = mshrQueue.findMatch(blk_addr);
@ -946,6 +959,8 @@ Cache<TagStore>::recvTimingResp(PacketPtr pkt)
// isInvalidate() set otherwise.
target->pkt->cmd = MemCmd::ReadRespWithInvalidate;
}
// reset the bus additional time as it is now accounted for
target->pkt->busFirstWordDelay = target->pkt->busLastWordDelay = 0;
cpuSidePort->schedTimingResp(target->pkt, completion_time);
break;
@ -1250,6 +1265,8 @@ doTimingSupplyResponse(PacketPtr req_pkt, uint8_t *blk_data,
assert(req_pkt->isInvalidate() || pkt->sharedAsserted());
pkt->allocate();
pkt->makeTimingResponse();
// @todo Make someone pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
if (pkt->isRead()) {
pkt->setDataFromBlock(blk_data, blkSize);
}
@ -1293,6 +1310,9 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk,
Packet snoopPkt(pkt, true); // clear flags
snoopPkt.setExpressSnoop();
snoopPkt.pushSenderState(new ForwardResponseRecord(pkt->getSrc()));
// the snoop packet does not need to wait any additional
// time
snoopPkt.busFirstWordDelay = snoopPkt.busLastWordDelay = 0;
cpuSidePort->sendTimingSnoopReq(&snoopPkt);
if (snoopPkt.memInhibitAsserted()) {
// cache-to-cache response from some upper cache

View file

@ -179,6 +179,9 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
if (add_outstanding)
outstandingReq.erase(pkt->req);
// undo the calculation so we can check for 0 again
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());

View file

@ -124,6 +124,9 @@ NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
// undo the calculation so we can check for 0 again
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
// occupy until the header is sent
reqLayer.failedTiming(src_port, clockEdge(Cycles(headerCycles)));

View file

@ -741,6 +741,9 @@ SimpleDRAM::accessAndRespond(PacketPtr pkt)
// access already turned the packet into a response
assert(pkt->isResponse());
// @todo someone should pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
// queue the packet in the response queue to be sent out the
// next tick
port.schedTimingResp(pkt, curTick() + 1);

View file

@ -121,6 +121,9 @@ SimpleMemory::recvTimingReq(PacketPtr pkt)
return false;
}
// @todo someone should pay for this
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
// update the release time according to the bandwidth limit, and
// do so with respect to the time it takes to finish this request
// rather than long term as it is the short term data rate that is