# HG changeset patch
# User Gabe Black <[EMAIL PROTECTED]>
# Date 1226044295 28800
# Node ID d562cd16ff32bbdb73a5f571e40496a039092e52
# Parent  2e61b60e6614e026ba055946a45c5f577d8d8ff8
CPU: Make unaligned accesses work in the timing simple CPU.

diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -241,57 +241,130 @@
     _status = Idle;
 }
 
+void
+TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
+{
+    RequestPtr req = pkt->req;
+    if (req->isMmapedIpr()) {
+        Tick delay;
+        delay = TheISA::handleIprRead(thread->getTC(), pkt);
+        new IprEvent(pkt, this, nextCycle(curTick + delay));
+        _status = DcacheWaitResponse;
+        dcache_pkt = NULL;
+    } else if (!dcachePort.sendTiming(pkt)) {
+        _status = DcacheRetry;
+        dcache_pkt = pkt;
+    } else {
+        _status = DcacheWaitResponse;
+        // memory system takes ownership of packet
+        dcache_pkt = NULL;
+    }
+}
 
 template <class T>
 Fault
 TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
 {
-    Request *req =
-        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
-                    _cpuId, /* thread ID */ 0);
+    Fault fault;
+    const int asid = 0;
+    const int threadId = 0;
+    const Addr pc = thread->readPC();
 
-    if (traceData) {
-        traceData->setAddr(req->getVaddr());
+    PacketPtr pkt;
+    RequestPtr req;
+
+    int blockSize = dcachePort.peerBlockSize();
+    int dataSize = sizeof(T);
+
+    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+
+    if (secondAddr > addr) {
+        Addr firstSize = secondAddr - addr;
+        Addr secondSize = dataSize - firstSize;
+        // Make sure we'll only need two accesses.
+        assert(roundDown(secondAddr + secondSize - 1, blockSize) ==
+                secondAddr);
+
+        /*
+         * Do the translations. If something isn't going to work, find out
+         * before we waste time setting up anything else.
+         */
+        req = new Request(asid, addr, firstSize, flags, pc, _cpuId, threadId);
+        fault = thread->translateDataReadReq(req);
+        if (fault != NoFault) {
+            delete req;
+            return fault;
+        }
+        Request *secondReq =
+            new Request(asid, secondAddr, secondSize,
+                        flags, pc, _cpuId, threadId);
+        fault = thread->translateDataReadReq(secondReq);
+        if (fault != NoFault) {
+            delete req;
+            delete secondReq;
+            return fault;
+        }
+
+        // This is the packet we'll process now.
+        pkt = new Packet(req,
+                         (req->isLocked() ?
+                          MemCmd::LoadLockedReq : MemCmd::ReadReq),
+                         Packet::Broadcast);
+        pkt->dataDynamic<uint8_t>(new uint8_t[firstSize]);
+        SplitSenderState *sendState = new SplitSenderState;
+        pkt->senderState = sendState;
+
+        // This is the second half of the access we'll deal with later.
+        PacketPtr secondPkt =
+            new Packet(secondReq,
+                       (secondReq->isLocked() ?
+                        MemCmd::LoadLockedReq : MemCmd::ReadReq),
+                       Packet::Broadcast);
+        secondPkt->dataDynamic<uint8_t>(new uint8_t[secondSize]);
+        sendState->secondPkt = secondPkt;
+
+        /*
+         * This is the big packet that will hold the data we've gotten so far,
+         * if any, and also act as the response we actually give to the
+         * instruction.
+         */
+        Request *origReq =
+            new Request(asid, addr, dataSize, flags, pc, _cpuId, threadId);
+        origReq->setPhys(req->getPaddr(), dataSize, flags);
+        PacketPtr bigPkt =
+            new Packet(origReq, MemCmd::ReadResp, Packet::Broadcast);
+        bigPkt->dataDynamic<T>(new T);
+        sendState->bigPkt = bigPkt;
+    } else {
+        req = new Request(asid, addr, dataSize, flags, pc, _cpuId, threadId);
+
+        // translate to physical address
+        Fault fault = thread->translateDataReadReq(req);
+
+        if (fault != NoFault) {
+            delete req;
+            return fault;
+        }
+
+        pkt = new Packet(req,
+                         (req->isLocked() ?
+                          MemCmd::LoadLockedReq : MemCmd::ReadReq),
+                          Packet::Broadcast);
+        pkt->dataDynamic<T>(new T);
     }
 
-   // translate to physical address
-    Fault fault = thread->translateDataReadReq(req);
-
-    // Now do the access.
-    if (fault == NoFault) {
-        PacketPtr pkt =
-            new Packet(req,
-                       (req->isLocked() ?
-                        MemCmd::LoadLockedReq : MemCmd::ReadReq),
-                       Packet::Broadcast);
-        pkt->dataDynamic<T>(new T);
-
-        if (req->isMmapedIpr()) {
-            Tick delay;
-            delay = TheISA::handleIprRead(thread->getTC(), pkt);
-            new IprEvent(pkt, this, nextCycle(curTick + delay));
-            _status = DcacheWaitResponse;
-            dcache_pkt = NULL;
-        } else if (!dcachePort.sendTiming(pkt)) {
-            _status = DcacheRetry;
-            dcache_pkt = pkt;
-        } else {
-            _status = DcacheWaitResponse;
-            // memory system takes ownership of packet
-            dcache_pkt = NULL;
-        }
-
-        // This will need a new way to tell if it has a dcache attached.
-        if (req->isUncacheable())
-            recordEvent("Uncached Read");
-    } else {
-        delete req;
-    }
+    handleReadPacket(pkt);
 
     if (traceData) {
         traceData->setData(data);
+        traceData->setAddr(addr);
     }
-    return fault;
+
+    // This will need a new way to tell if it has a dcache attached.
+    if (req->isUncacheable())
+        recordEvent("Uncached Read");
+
+    return NoFault;
 }
 
 Fault
@@ -364,26 +437,129 @@
     return read(addr, (uint32_t&)data, flags);
 }
 
+void
+TimingSimpleCPU::handleWritePacket()
+{
+    RequestPtr req = dcache_pkt->req;
+    if (req->isMmapedIpr()) {
+        Tick delay;
+        delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
+        new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
+        _status = DcacheWaitResponse;
+        dcache_pkt = NULL;
+    } else if (!dcachePort.sendTiming(dcache_pkt)) {
+        _status = DcacheRetry;
+    } else {
+        _status = DcacheWaitResponse;
+        // memory system takes ownership of packet
+        dcache_pkt = NULL;
+    }
+}
 
 template <class T>
 Fault
 TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
 {
-    Request *req =
-        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
-                    _cpuId, /* thread ID */ 0);
+    const int asid = 0;
+    const int threadId = 0;
+    bool do_access = true;  // flag to suppress cache access
+    const Addr pc = thread->readPC();
 
-    if (traceData) {
-        traceData->setAddr(req->getVaddr());
-    }
+    RequestPtr req;
 
-    // translate to physical address
-    Fault fault = thread->translateDataWriteReq(req);
+    int blockSize = dcachePort.peerBlockSize();
+    int dataSize = sizeof(T);
 
-    // Now do the access.
-    if (fault == NoFault) {
+    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+
+    if (secondAddr > addr) {
+        Fault fault;
+        Addr firstSize = secondAddr - addr;
+        Addr secondSize = dataSize - firstSize;
+        // Make sure we'll only need two accesses.
+        assert(roundDown(secondAddr + secondSize - 1, blockSize) == 
+                secondAddr);
+
+        req = new Request(asid, addr, firstSize, flags, pc, _cpuId, threadId);
+        fault = thread->translateDataWriteReq(req);
+        if (fault != NoFault) {
+            delete req;
+            return fault;
+        }
+        RequestPtr secondReq = new Request(asid, secondAddr, secondSize,
+                                           flags, pc, _cpuId, threadId);
+        fault = thread->translateDataWriteReq(secondReq);
+        if (fault != NoFault) {
+            delete req;
+            delete secondReq;
+            return fault;
+        }
+
         MemCmd cmd = MemCmd::WriteReq; // default
-        bool do_access = true;  // flag to suppress cache access
+        if (req->isLocked()) {
+            cmd = MemCmd::StoreCondReq;
+            do_access = TheISA::handleLockedWrite(thread, req);
+        } else if (req->isSwap()) {
+            panic("Conditional swaps can't be split.");
+        }
+
+        MemCmd secondCmd = MemCmd::WriteReq; // default
+        bool secondDoAccess = do_access;
+        if (secondReq->isLocked()) {
+            secondCmd = MemCmd::StoreCondReq;
+            secondDoAccess = TheISA::handleLockedWrite(thread, secondReq);
+        } else if (req->isSwap()) {
+            panic("Conditional swaps can't be split.");
+        }
+
+        if (do_access != secondDoAccess) {
+            panic("Both parts of a split store conditional"
+                  " must succeed or fail.\n");
+        }
+
+        uint8_t *dataPtr;
+
+        assert(dcache_pkt == NULL);
+        // This is the packet we'll process now.
+        dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
+        dataPtr = new uint8_t[firstSize];
+        memcpy(dataPtr, &data, firstSize);
+        dcache_pkt->dataDynamic(dataPtr);
+        SplitSenderState *sendState = new SplitSenderState;
+        dcache_pkt->senderState = sendState;
+
+        // This is the second half of the access we'll deal with later.
+        PacketPtr secondPkt =
+            new Packet(secondReq, secondCmd, Packet::Broadcast);
+        dataPtr = new uint8_t[secondSize];
+        memcpy(dataPtr, ((uint8_t *)&data) + firstSize, secondSize);
+        secondPkt->dataDynamic<uint8_t>(dataPtr);
+        sendState->secondPkt = secondPkt;
+
+        /*
+         * This is the big packet that will hold the data we've gotten so far,
+         * if any, and also act as the response we actually give to the
+         * instruction.
+         */
+        RequestPtr origReq = 
+            new Request(asid, addr, dataSize, flags, pc, _cpuId, threadId);
+        origReq->setPhys(req->getPaddr(), dataSize, flags);
+        PacketPtr bigPkt =
+            new Packet(origReq, MemCmd::WriteResp, Packet::Broadcast);
+        sendState->bigPkt = bigPkt;
+        bigPkt->allocate();
+        bigPkt->set(data);
+    } else {
+        req = new Request(asid, addr, dataSize, flags, pc, _cpuId, threadId);
+
+        // translate to physical address
+        Fault fault = thread->translateDataWriteReq(req);
+        if (fault != NoFault) {
+            delete req;
+            return fault;
+        }
+
+        MemCmd cmd = MemCmd::WriteReq; // default
 
         if (req->isLocked()) {
             cmd = MemCmd::StoreCondReq;
@@ -401,38 +577,27 @@
         assert(dcache_pkt == NULL);
         dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
         dcache_pkt->allocate();
-        dcache_pkt->set(data);
-
-        if (do_access) {
-            if (req->isMmapedIpr()) {
-                Tick delay;
-                dcache_pkt->set(htog(data));
-                delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
-                new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
-                _status = DcacheWaitResponse;
-                dcache_pkt = NULL;
-            } else if (!dcachePort.sendTiming(dcache_pkt)) {
-                _status = DcacheRetry;
-            } else {
-                _status = DcacheWaitResponse;
-                // memory system takes ownership of packet
-                dcache_pkt = NULL;
-            }
-        }
-        // This will need a new way to tell if it's hooked up to a cache or 
not.
-        if (req->isUncacheable())
-            recordEvent("Uncached Write");
-    } else {
-        delete req;
+        if (req->isMmapedIpr())
+            dcache_pkt->set(htog(data));
+        else
+            dcache_pkt->set(data);
     }
 
+    if (do_access)
+        handleWritePacket();
+
     if (traceData) {
+        traceData->setAddr(req->getVaddr());
         traceData->setData(data);
     }
 
+    // This will need a new way to tell if it's hooked up to a cache or not.
+    if (req->isUncacheable())
+        recordEvent("Uncached Write");
+
     // If the write needs to have a fault on the access, consider calling
     // changeStatus() and changing it to "bad addr write" or something.
-    return fault;
+    return NoFault;
 }
 
 Fault
@@ -721,11 +886,52 @@
     // received a response from the dcache: complete the load or store
     // instruction
     assert(!pkt->isError());
-    assert(_status == DcacheWaitResponse);
-    _status = Running;
 
     numCycles += tickToCycles(curTick - previousTick);
     previousTick = curTick;
+
+    if (pkt->senderState) {
+        SplitSenderState * sendState =
+            dynamic_cast<SplitSenderState *>(pkt->senderState);
+        assert(sendState);
+        pkt->senderState = NULL;
+        PacketPtr secondPkt = sendState->secondPkt;
+        PacketPtr bigPkt = sendState->bigPkt;
+        if (secondPkt) {
+            // There's more data to get.
+            secondPkt->senderState = sendState;
+            sendState->secondPkt = NULL;
+            assert(pkt->getSize() < bigPkt->getSize());
+            if (bigPkt->isRead()) {
+                memcpy(bigPkt->getPtr<uint8_t>(),
+                       pkt->getPtr<uint8_t>(),
+                       pkt->getSize());
+                delete pkt->req;
+                delete pkt;
+                handleReadPacket(secondPkt);
+            } else {
+                dcache_pkt = secondPkt;
+                handleWritePacket();
+            }
+            return;
+        } else {
+            // This is it. Lets finish this up.
+            assert(bigPkt->getSize() > pkt->getSize());
+            Addr offset = bigPkt->getSize() - pkt->getSize();
+            if (bigPkt->isRead()) {
+                memcpy(bigPkt->getPtr<uint8_t>() + offset,
+                       pkt->getPtr<uint8_t>(),
+                       pkt->getSize());
+            }
+            delete pkt->req;
+            delete pkt;
+            delete sendState;
+            pkt = bigPkt;
+        }
+    }
+
+    assert(_status == DcacheWaitResponse);
+    _status = Running;
 
     Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
 
@@ -787,10 +993,11 @@
         // delay processing of returned data until next CPU clock edge
         Tick next_tick = cpu->nextCycle(curTick);
 
-        if (next_tick == curTick)
+        if (next_tick == curTick) {
             cpu->completeDataAccess(pkt);
-        else
+        } else {
             tickEvent.schedule(pkt, next_tick);
+        }
 
         return true;
     }
diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh
--- a/src/cpu/simple/timing.hh
+++ b/src/cpu/simple/timing.hh
@@ -48,6 +48,17 @@
     Event *drainEvent;
 
   private:
+
+    class SplitSenderState : public Packet::SenderState
+    {
+      public:
+        PacketPtr bigPkt;
+        PacketPtr secondPkt;
+    };
+
+    void handleReadPacket(PacketPtr pkt);
+    // This function always implicitly uses dcache_pkt.
+    void handleWritePacket();
 
     class CpuPort : public Port
     {
_______________________________________________
m5-dev mailing list
m5-dev@m5sim.org
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to