Bus: Fix the bus timing to be more realistic.
authorGabe Black <gblack@eecs.umich.edu>
Tue, 26 Feb 2008 07:20:08 +0000 (02:20 -0500)
committerGabe Black <gblack@eecs.umich.edu>
Tue, 26 Feb 2008 07:20:08 +0000 (02:20 -0500)
--HG--
extra : convert_revision : acd70dc98ab840e55b114706fbb6afb2a95e54bc

src/mem/Bus.py
src/mem/bus.cc
src/mem/bus.hh

index 247a1fe310d832df74207f6fed84d4b33baa3584..f4ea9a73bf7a6994e2c8830736fd5078476448f3 100644 (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.")
index f47d48d0b6a55b2596f6c08dfaa500b084bab95b..ff4512aca1b79aa9a9ae7466976343aae87a3154 100644 (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) {
index 0c23175f135cf54df0370092ca7a7d6169c8bbaf..274c02de417d39dbf7a1aa4947f57dc74c3908e3 100644 (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();
     }