diff --git a/src/mem/Bus.py b/src/mem/Bus.py index 247a1fe31..f4ea9a73b 100644 --- a/src/mem/Bus.py +++ b/src/mem/Bus.py @@ -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.") diff --git a/src/mem/bus.cc b/src/mem/bus.cc index f47d48d0b..ff4512aca 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -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) { diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 0c23175f1..274c02de4 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -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(); }