fix partial writes with a functional memory hack
authorAli Saidi <saidi@eecs.umich.edu>
Mon, 7 May 2007 18:42:03 +0000 (14:42 -0400)
committerAli Saidi <saidi@eecs.umich.edu>
Mon, 7 May 2007 18:42:03 +0000 (14:42 -0400)
figure out the block size from devices attached to the bus otherwise use a default block size when no devices that care are attached

configs/common/FSConfig.py:
src/mem/bridge.cc:
src/mem/bridge.hh:
src/python/m5/objects/Bridge.py:
    fix partial writes with a functional memory hack
src/mem/bus.cc:
src/mem/bus.hh:
src/python/m5/objects/Bus.py:
    figure out the block size from devices attached to the bus otherwise use a default block size when no devices that care are attached
src/mem/packet.cc:
    fix WriteInvalidateResp to not be a request that needs a response since it isn't
src/mem/port.hh:
    by default return 0 for deviceBlockSize instead of panicing. This makes finding the block size the bus should use easier

--HG--
extra : convert_revision : 3fcfe95f9f392ef76f324ee8bd1d7f6de95c1a64

configs/common/FSConfig.py
src/mem/bridge.cc
src/mem/bridge.hh
src/mem/bus.cc
src/mem/bus.hh
src/mem/packet.cc
src/mem/port.hh
src/python/m5/objects/Bridge.py
src/python/m5/objects/Bus.py

index be3f5ff79e49084e3676c544eacc9d23ecac6aef..289a7a5f4b391912b8eb8db1e42a0f836f41f203 100644 (file)
@@ -61,7 +61,7 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None):
     self.readfile = mdesc.script()
     self.iobus = Bus(bus_id=0)
     self.membus = Bus(bus_id=1)
-    self.bridge = Bridge()
+    self.bridge = Bridge(fix_partial_write_b=True)
     self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem()))
     self.bridge.side_a = self.iobus.port
     self.bridge.side_b = self.membus.port
index b787f79ca9ae1d4ec6ac1bac90ae941e7384e854..b25d135e214d682180c1fa86eb386912970cd5ae 100644 (file)
 
 Bridge::BridgePort::BridgePort(const std::string &_name,
                                Bridge *_bridge, BridgePort *_otherPort,
-                               int _delay, int _queueLimit)
+                               int _delay, int _queueLimit,
+                               bool fix_partial_write)
     : Port(_name), bridge(_bridge), otherPort(_otherPort),
-      delay(_delay), outstandingResponses(0),
-      queueLimit(_queueLimit), sendEvent(this)
+      delay(_delay), fixPartialWrite(fix_partial_write),
+      outstandingResponses(0), queueLimit(_queueLimit), sendEvent(this)
 {
 }
 
 Bridge::Bridge(const std::string &n, int qsa, int qsb,
-               Tick _delay, int write_ack)
+               Tick _delay, int write_ack, bool fix_partial_write_a,
+               bool fix_partial_write_b)
     : MemObject(n),
-      portA(n + "-portA", this, &portB, _delay, qsa),
-      portB(n + "-portB", this, &portA, _delay, qsa),
+      portA(n + "-portA", this, &portB, _delay, qsa, fix_partial_write_a),
+      portB(n + "-portB", this, &portA, _delay, qsa, fix_partial_write_b),
       ackWrites(write_ack)
 {
+    if (ackWrites)
+        panic("No support for acknowledging writes\n");
 }
 
 Port *
@@ -82,7 +86,10 @@ Bridge::init()
 {
     // Make sure that both sides are connected to.
     if (portA.getPeer() == NULL || portB.getPeer() == NULL)
-        panic("Both ports of bus bridge are not connected to a bus.\n");
+        fatal("Both ports of bus bridge are not connected to a bus.\n");
+
+    if (portA.peerBlockSize() != portB.peerBlockSize())
+        fatal("Busses don't have the same block size... Not supported.\n");
 }
 
 
@@ -107,8 +114,10 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
 bool
 Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
 {
-    if (queueFull())
+    if (queueFull()) {
+        DPRINTF(BusBridge, "Queue full, returning false\n");
         return false;
+    }
 
    if (pkt->isResponse()) {
         // This is a response for a request we forwarded earlier.  The
@@ -149,6 +158,7 @@ Bridge::BridgePort::trySend()
     assert(!sendQueue.empty());
 
     bool was_full = queueFull();
+    int pbs = peerBlockSize();
 
     PacketBuffer *buf = sendQueue.front();
 
@@ -156,10 +166,18 @@ Bridge::BridgePort::trySend()
 
     PacketPtr pkt = buf->pkt;
 
+    pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
+
+    if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
+            pkt->getOffset(pbs) && pkt->getSize() != pbs) {
+        buf->partialWriteFix(this);
+        pkt = buf->pkt;
+    }
+
     DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
             buf->origSrc, pkt->getDest(), pkt->getAddr());
 
-    pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
+
     if (sendTiming(pkt)) {
         // send successful
         sendQueue.pop_front();
@@ -191,6 +209,7 @@ Bridge::BridgePort::trySend()
 
     } else {
         DPRINTF(BusBridge, "  unsuccessful\n");
+        buf->undoPartialWriteFix();
     }
 }
 
@@ -248,6 +267,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
    Param<int> queue_size_b;
    Param<Tick> delay;
    Param<bool> write_ack;
+   Param<bool> fix_partial_write_a;
+   Param<bool> fix_partial_write_b;
 
 END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
 
@@ -256,14 +277,16 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge)
     INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"),
     INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"),
     INIT_PARAM(delay, "The miminum delay to cross this bridge"),
-    INIT_PARAM(write_ack, "Acknowledge any writes that are received.")
+    INIT_PARAM(write_ack, "Acknowledge any writes that are received."),
+    INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"),
+    INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received")
 
 END_INIT_SIM_OBJECT_PARAMS(Bridge)
 
 CREATE_SIM_OBJECT(Bridge)
 {
     return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay,
-            write_ack);
+            write_ack, fix_partial_write_a, fix_partial_write_b);
 }
 
 REGISTER_SIM_OBJECT("Bridge", Bridge)
index f7d0d12d0dacf296a1ca9506e2883f17463048c4..d1154eda046e23f8bad71e382dfff1ef453ab4cf 100644 (file)
@@ -66,6 +66,8 @@ class Bridge : public MemObject
         /** Minimum delay though this bridge. */
         Tick delay;
 
+        bool fixPartialWrite;
+
         class PacketBuffer : public Packet::SenderState {
 
           public:
@@ -75,10 +77,13 @@ class Bridge : public MemObject
             short origSrc;
             bool expectResponse;
 
+            bool partialWriteFixed;
+            PacketPtr oldPkt;
+
             PacketBuffer(PacketPtr _pkt, Tick t)
                 : ready(t), pkt(_pkt),
                   origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
-                  expectResponse(_pkt->needsResponse())
+                  expectResponse(_pkt->needsResponse()), partialWriteFixed(false)
             {
                 if (!pkt->isResponse())
                     pkt->senderState = this;
@@ -89,7 +94,46 @@ class Bridge : public MemObject
                 assert(pkt->senderState == this);
                 pkt->setDest(origSrc);
                 pkt->senderState = origSenderState;
+                if (partialWriteFixed)
+                    delete oldPkt;
+            }
+
+            void partialWriteFix(Port *port)
+            {
+                assert(!partialWriteFixed);
+                assert(expectResponse);
+
+                int pbs = port->peerBlockSize();
+                partialWriteFixed = true;
+                PacketDataPtr data;
+
+                data = new uint8_t[pbs];
+                PacketPtr funcPkt = new Packet(pkt->req, MemCmd::ReadReq,
+                        Packet::Broadcast, pbs);
+
+                funcPkt->dataStatic(data);
+                port->sendFunctional(funcPkt);
+                assert(funcPkt->result == Packet::Success);
+                delete funcPkt;
+
+                oldPkt = pkt;
+                memcpy(data + oldPkt->getOffset(pbs), pkt->getPtr<uint8_t>(),
+                        pkt->getSize());
+                pkt = new Packet(oldPkt->req, MemCmd::WriteInvalidateReq,
+                        Packet::Broadcast, pbs);
+                pkt->dataDynamicArray(data);
+                pkt->senderState = oldPkt->senderState;
             }
+
+            void undoPartialWriteFix()
+            {
+                if (!partialWriteFixed)
+                    return;
+                delete pkt;
+                pkt = oldPkt;
+                partialWriteFixed = false;
+            }
+
         };
 
         /**
@@ -140,7 +184,7 @@ class Bridge : public MemObject
         /** Constructor for the BusPort.*/
         BridgePort(const std::string &_name,
                    Bridge *_bridge, BridgePort *_otherPort,
-                   int _delay, int _queueLimit);
+                   int _delay, int _queueLimit, bool fix_partial_write);
 
       protected:
 
@@ -182,7 +226,8 @@ class Bridge : public MemObject
 
     virtual void init();
 
-    Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack);
+    Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack,
+            bool fix_partial_write_a, bool fix_partial_write_b);
 };
 
 #endif //__MEM_BUS_HH__
index b0636ecc2c3f105165a72e7d810178c08a60840e..6682ade5585a79f72c9347847c7bdc3f276c74bd 100644 (file)
@@ -48,6 +48,7 @@ Bus::getPort(const std::string &if_name, int idx)
         if (defaultPort == NULL) {
             defaultPort = new BusPort(csprintf("%s-default",name()), this,
                                       defaultId);
+            cachedBlockSizeValid = false;
             return defaultPort;
         } else
             fatal("Default port already set\n");
@@ -68,6 +69,7 @@ Bus::getPort(const std::string &if_name, int idx)
     assert(maxId < std::numeric_limits<typeof(maxId)>::max());
     BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
     interfaces[id] = bp;
+    cachedBlockSizeValid = false;
     return bp;
 }
 
@@ -182,6 +184,7 @@ Bus::recvTiming(PacketPtr pkt)
     if (tickNextIdle > curTick ||
             (retryList.size() && (!inRetry || pktPort != retryList.front()))) {
         addToRetryList(pktPort);
+        DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n");
         return false;
     }
 
@@ -207,11 +210,12 @@ Bus::recvTiming(PacketPtr pkt)
                     inRetry = false;
                 }
                 occupyBus(pkt);
+                DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n");
                 return true;
             }
         } else {
             //Snoop didn't succeed
-            DPRINTF(Bus, "Adding a retry to RETRY list %d\n",
+            DPRINTF(Bus, "Adding1 a retry to RETRY list %d\n",
                     pktPort->getId());
             addToRetryList(pktPort);
             return false;
@@ -239,13 +243,14 @@ Bus::recvTiming(PacketPtr pkt)
         }
 
         // Packet not successfully sent. Leave or put it on the retry list.
-        DPRINTF(Bus, "Adding a retry to RETRY list %d\n",
+        DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n",
                 pktPort->getId());
         addToRetryList(pktPort);
         return false;
     }
     else {
         //Forwarding up from responder, just return true;
+        DPRINTF(Bus, "recvTiming: can we be here?\n");
         return true;
     }
 }
@@ -253,12 +258,12 @@ Bus::recvTiming(PacketPtr pkt)
 void
 Bus::recvRetry(int id)
 {
-    DPRINTF(Bus, "Received a retry\n");
+    DPRINTF(Bus, "Received a retry from %s\n", id == -1 ? "self" : interfaces[id]->getPeer()->name());
     // If there's anything waiting, and the bus isn't busy...
     if (retryList.size() && curTick >= tickNextIdle) {
         //retryingPort = retryList.front();
         inRetry = true;
-        DPRINTF(Bus, "Sending a retry\n");
+        DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
         retryList.front()->sendRetry();
         // If inRetry is still true, sendTiming wasn't called
         if (inRetry)
@@ -267,18 +272,20 @@ Bus::recvRetry(int id)
             retryList.pop_front();
             inRetry = false;
 
-            //Bring tickNextIdle up to the present
-            while (tickNextIdle < curTick)
-                tickNextIdle += clock;
+            if (id != -1) {
+                //Bring tickNextIdle up to the present
+                while (tickNextIdle < curTick)
+                    tickNextIdle += clock;
 
-            //Burn a cycle for the missed grant.
-            tickNextIdle += clock;
+                //Burn a cycle for the missed grant.
+                tickNextIdle += clock;
 
-            if (!busIdle.scheduled()) {
-                busIdle.schedule(tickNextIdle);
-            } else {
-                busIdle.reschedule(tickNextIdle);
-            }
+                if (!busIdle.scheduled()) {
+                    busIdle.schedule(tickNextIdle);
+                } else {
+                    busIdle.reschedule(tickNextIdle);
+                }
+            } // id != -1
         }
     }
     //If we weren't able to drain before, we might be able to now.
@@ -598,6 +605,37 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
     }
 }
 
+int
+Bus::findBlockSize(int id)
+{
+    if (cachedBlockSizeValid)
+        return cachedBlockSize;
+
+    int max_bs = -1, tmp_bs;
+    range_map<Addr,int>::iterator portIter;
+    std::vector<DevMap>::iterator snoopIter;
+    for (portIter = portMap.begin(); portIter != portMap.end(); portIter++) {
+        tmp_bs = interfaces[portIter->second]->peerBlockSize();
+        if (tmp_bs > max_bs)
+            max_bs = tmp_bs;
+    }
+    for (snoopIter = portSnoopList.begin();
+         snoopIter != portSnoopList.end(); snoopIter++) {
+        tmp_bs = interfaces[snoopIter->portId]->peerBlockSize();
+        if (tmp_bs > max_bs)
+            max_bs = tmp_bs;
+    }
+    if (max_bs <= 0)
+        max_bs = defaultBlockSize;
+
+    if (max_bs != 64)
+        warn_once("Blocksize found to not be 64... hmm... probably not.\n");
+    cachedBlockSize = max_bs;
+    cachedBlockSizeValid = true;
+    return max_bs;
+}
+
+
 unsigned int
 Bus::drain(Event * de)
 {
@@ -618,6 +656,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
     Param<int> clock;
     Param<int> width;
     Param<bool> responder_set;
+    Param<int> block_size;
 
 END_DECLARE_SIM_OBJECT_PARAMS(Bus)
 
@@ -625,12 +664,14 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
     INIT_PARAM(bus_id, "a globally unique bus id"),
     INIT_PARAM(clock, "bus clock speed"),
     INIT_PARAM(width, "width of the bus (bits)"),
-    INIT_PARAM(responder_set, "Is a default responder set by the user")
+    INIT_PARAM(responder_set, "Is a default responder set by the user"),
+    INIT_PARAM(block_size, "Default blocksize if no device has one")
 END_INIT_SIM_OBJECT_PARAMS(Bus)
 
 CREATE_SIM_OBJECT(Bus)
 {
-    return new Bus(getInstanceName(), bus_id, clock, width, responder_set);
+    return new Bus(getInstanceName(), bus_id, clock, width, responder_set,
+            block_size);
 }
 
 REGISTER_SIM_OBJECT("Bus", Bus)
index 0dd7547c523291924aca6a7fc24afb74abfa0bde..f0dc67b1232b5cc507f7cc588fca67fb55c6d32f 100644 (file)
@@ -133,6 +133,12 @@ class Bus : public MemObject
     /** Occupy the bus with transmitting the packet pkt */
     void occupyBus(PacketPtr pkt);
 
+    /** Ask everyone on the bus what their size is
+     * @param id id of the busport that made the request
+     * @return the max of all the sizes
+     */
+    int findBlockSize(int id);
+
     /** Declaration of the buses port type, one will be instantiated for each
         of the interfaces connecting to the bus. */
     class BusPort : public Port
@@ -195,8 +201,11 @@ class Bus : public MemObject
                                             AddrRangeList &snoop)
         { bus->addressRanges(resp, snoop, id); }
 
-        // Hack to make translating port work without changes
-        virtual int deviceBlockSize() { return 32; }
+        // Ask the bus to ask everyone on the bus what their block size is and
+        // take the max of it. This might need to be changed a bit if we ever
+        // support multiple block sizes.
+        virtual int deviceBlockSize()
+        { return bus->findBlockSize(id); }
 
     };
 
@@ -256,6 +265,10 @@ class Bus : public MemObject
     /** Has the user specified their own default responder? */
     bool responderSet;
 
+    int defaultBlockSize;
+    int cachedBlockSize;
+    bool cachedBlockSizeValid;
+
   public:
 
     /** A function used to return the port associated with this bus object. */
@@ -267,11 +280,12 @@ class Bus : public MemObject
     unsigned int drain(Event *de);
 
     Bus(const std::string &n, int bus_id, int _clock, int _width,
-        bool responder_set)
+        bool responder_set, int dflt_blk_size)
         : MemObject(n), busId(bus_id), clock(_clock), width(_width),
           tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false),
           maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4),
-          responderSet(responder_set)
+          responderSet(responder_set), defaultBlockSize(dflt_blk_size),
+          cachedBlockSize(0), cachedBlockSizeValid(false)
     {
         //Both the width and clock period must be positive
         if (width <= 0)
index 14d08db1b2eb37dde24b7925e9a4afa77088cce4..2463a19ba892d78029c185055b771bfbc999f262 100644 (file)
@@ -85,7 +85,7 @@ MemCmd::commandInfo[] =
     { SET5(IsWrite, IsInvalidate, IsRequest, HasData, NeedsResponse),
             WriteInvalidateResp, "WriteInvalidateReq" },
     /* WriteInvalidateResp */
-    { SET5(IsWrite, IsInvalidate, IsRequest, NeedsResponse, IsResponse),
+    { SET3(IsWrite, IsInvalidate, IsResponse),
             InvalidCmd, "WriteInvalidateResp" },
     /* UpgradeReq */
     { SET3(IsInvalidate, IsRequest, IsUpgrade), InvalidCmd, "UpgradeReq" },
index 6296b42ca96b979a4877750800a791577a12992b..877e0029396e62e27a071a6e275ec78ca3432195 100644 (file)
@@ -161,10 +161,10 @@ class Port
 
     /** Called by a peer port in order to determine the block size of the
         device connected to this port.  It sometimes doesn't make sense for
-        this function to be called, a DMA interface doesn't really have a
-        block size, so it is defaulted to a panic.
+        this function to be called, so it just returns 0. Anytthing that is
+        concerned with the size should just ignore that.
     */
-    virtual int deviceBlockSize() { panic("??"); M5_DUMMY_RETURN }
+    virtual int deviceBlockSize() { return 0; }
 
     /** The peer port is requesting us to reply with a list of the ranges we
         are responsible for.
index ee8e76bff77efca8fd77a3301eaadbf096f81fbe..e123c2891fb1aa5e1ae9d586c197727b4dbfbee1 100644 (file)
@@ -9,3 +9,5 @@ class Bridge(MemObject):
     queue_size_b = Param.Int(16, "The number of requests to buffer")
     delay = Param.Latency('0ns', "The latency of this bridge")
     write_ack = Param.Bool(False, "Should this bridge ack writes")
+    fix_partial_write_a = Param.Bool(False, "Should this bridge fixup partial block writes")
+    fix_partial_write_b = Param.Bool(False, "Should this bridge fixup partial block writes")
index 8226fe8d2619ab8914b2f51ff9e86c37119d26df..48dbbe3077c5ee16ebd1b7d126622de8b1ebf92f 100644 (file)
@@ -11,6 +11,7 @@ class Bus(MemObject):
     clock = Param.Clock("1GHz", "bus clock speed")
     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.")
     if build_env['FULL_SYSTEM']:
         responder = BadAddr(pio_addr=0x0, pio_latency="1ps")
         default = Port(Self.responder.pio, "Default port for requests that aren't handled by a device.")