Bus: Fix the bus timing to be more realistic.

--HG--
extra : convert_revision : acd70dc98ab840e55b114706fbb6afb2a95e54bc
This commit is contained in:
Gabe Black 2008-02-26 02:20:08 -05:00
parent 2e079ce038
commit ec1a4cbbc7
3 changed files with 43 additions and 30 deletions

View file

@ -1,4 +1,4 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# Copyright (c) 2005-2008 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -39,6 +39,7 @@ class Bus(MemObject):
port = VectorPort("vector port for connecting devices")
bus_id = Param.Int(0, "blah")
clock = Param.Clock("1GHz", "bus clock speed")
header_cycles = Param.Int(1, "cycles of overhead per transaction")
width = Param.Int(64, "bus width (bytes)")
responder_set = Param.Bool(False, "Did the user specify a default responder.")
block_size = Param.Int(64, "The default block size if one isn't set by a device attached to the bus.")

View file

@ -110,7 +110,7 @@ const char * Bus::BusFreeEvent::description() const
return "bus became available";
}
void Bus::occupyBus(PacketPtr pkt)
void Bus::preparePacket(PacketPtr pkt, Tick & headerTime)
{
//Bring tickNextIdle up to the present tick
//There is some potential ambiguity where a cycle starts, which might make
@ -124,34 +124,30 @@ void Bus::occupyBus(PacketPtr pkt)
tickNextIdle = curTick - (curTick % clock) + clock;
}
headerTime = tickNextIdle + headerCycles * 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 (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();
numCycles += dataSize/width;
if (dataSize % 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.
int dataSize = pkt->getSize();
numCycles += dataSize/width;
if (dataSize % width)
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;
pkt->firstWordTime = headerTime + clock;
pkt->finishTime = headerTime + numCycles * clock;
}
void Bus::occupyBus(Tick until)
{
tickNextIdle = until;
//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 {
@ -159,9 +155,6 @@ void Bus::occupyBus(PacketPtr pkt)
}
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
@ -197,8 +190,10 @@ Bus::recvTiming(PacketPtr pkt)
DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
Tick headerTime = 0;
if (!pkt->isExpressSnoop()) {
occupyBus(pkt);
preparePacket(pkt, headerTime);
}
short dest = pkt->getDest();
@ -248,11 +243,18 @@ Bus::recvTiming(PacketPtr pkt)
DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
addToRetryList(src_port);
if (!pkt->isExpressSnoop()) {
occupyBus(headerTime);
}
return false;
}
// send OK, fall through
}
if (!pkt->isExpressSnoop()) {
occupyBus(pkt->finishTime);
}
// Packet was successfully sent.
// Also take care of retries
if (inRetry) {

View file

@ -138,6 +138,8 @@ class Bus : public MemObject
int busId;
/** the clock speed for the bus */
int clock;
/** cycles of overhead per transaction */
int headerCycles;
/** the width of the bus in bytes */
int width;
/** the next tick at which the bus will be idle */
@ -243,8 +245,13 @@ class Bus : public MemObject
*/
void addressRanges(AddrRangeList &resp, bool &snoop, int id);
/** Occupy the bus with transmitting the packet pkt */
void occupyBus(PacketPtr pkt);
/** Prepare a packet to be sent on the bus. The header finishes at tick
* headerTime
*/
void preparePacket(PacketPtr pkt, Tick & headerTime);
/** Occupy the bus until until */
void occupyBus(Tick until);
/** Ask everyone on the bus what their size is
* @param id id of the busport that made the request
@ -363,17 +370,20 @@ class Bus : public MemObject
unsigned int drain(Event *de);
Bus(const BusParams *p)
: MemObject(p), busId(p->bus_id), clock(p->clock), width(p->width),
tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false),
maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4),
: MemObject(p), busId(p->bus_id), clock(p->clock),
headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
defaultPort(NULL), funcPort(NULL), funcPortId(-4),
responderSet(p->responder_set), defaultBlockSize(p->block_size),
cachedBlockSize(0), cachedBlockSizeValid(false)
{
//Both the width and clock period must be positive
//width, clock period, and header cycles must be positive
if (width <= 0)
fatal("Bus width must be positive\n");
if (clock <= 0)
fatal("Bus clock period must be positive\n");
if (headerCycles <= 0)
fatal("Number of header cycles must be positive\n");
clearBusCache();
clearPortCache();
}