Bus: Fix the bus timing to be more realistic.
--HG-- extra : convert_revision : acd70dc98ab840e55b114706fbb6afb2a95e54bc
This commit is contained in:
parent
2e079ce038
commit
ec1a4cbbc7
3 changed files with 43 additions and 30 deletions
|
@ -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.")
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue