-# 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
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.")
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
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 {
}
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: 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();
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) {
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 */
*/
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
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();
}