CPU: Refactor read/write in the simple timing CPU.
authorGabe Black <gblack@eecs.umich.edu>
Fri, 14 Nov 2008 07:30:37 +0000 (23:30 -0800)
committerGabe Black <gblack@eecs.umich.edu>
Fri, 14 Nov 2008 07:30:37 +0000 (23:30 -0800)
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh
src/mem/request.hh

index 5d37fa620d8d9652f16628ce027045232d935eb9..5da08db47cb406c0bb4e39e972c3395a48427240 100644 (file)
@@ -262,6 +262,72 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
     return dcache_pkt == NULL;
 }
 
+Fault
+TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
+        RequestPtr &req, Addr split_addr, uint8_t *data, bool read)
+{
+    Fault fault;
+    RequestPtr req1, req2;
+    assert(!req->isLocked() && !req->isSwap());
+    req->splitOnVaddr(split_addr, req1, req2);
+
+    pkt1 = pkt2 = NULL;
+    if ((fault = buildPacket(pkt1, req1, read)) != NoFault ||
+            (fault = buildPacket(pkt2, req2, read)) != NoFault) {
+        delete req;
+        delete pkt1;
+        req = NULL;
+        pkt1 = NULL;
+        return fault;
+    }
+
+    assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
+
+    req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
+    PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
+                               Packet::Broadcast);
+
+    pkt->dataDynamic<uint8_t>(data);
+    pkt1->dataStatic<uint8_t>(data);
+    pkt2->dataStatic<uint8_t>(data + req1->getSize());
+
+    SplitMainSenderState * main_send_state = new SplitMainSenderState;
+    pkt->senderState = main_send_state;
+    main_send_state->fragments[0] = pkt1;
+    main_send_state->fragments[1] = pkt2;
+    main_send_state->outstanding = 2;
+    pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
+    pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
+    return fault;
+}
+
+Fault
+TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read)
+{
+    Fault fault = read ? thread->translateDataReadReq(req) :
+                         thread->translateDataWriteReq(req);
+    MemCmd cmd;
+    if (fault != NoFault) {
+        delete req;
+        req = NULL;
+        pkt = NULL;
+        return fault;
+    } else if (read) {
+        cmd = MemCmd::ReadReq;
+        if (req->isLocked())
+            cmd = MemCmd::LoadLockedReq;
+    } else {
+        cmd = MemCmd::WriteReq;
+        if (req->isLocked()) {
+            cmd = MemCmd::StoreCondReq;
+        } else if (req->isSwap()) {
+            cmd = MemCmd::SwapReq;
+        }
+    }
+    pkt = new Packet(req, cmd, Packet::Broadcast);
+    return NoFault;
+}
+
 template <class T>
 Fault
 TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
@@ -270,91 +336,35 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
     const int asid = 0;
     const int thread_id = 0;
     const Addr pc = thread->readPC();
-
-    PacketPtr pkt;
-    RequestPtr req;
-
     int block_size = dcachePort.peerBlockSize();
     int data_size = sizeof(T);
 
-    Addr second_addr = roundDown(addr + data_size - 1, block_size);
-
-    if (second_addr > addr) {
-        Addr first_size = second_addr - addr;
-        Addr second_size = data_size - first_size;
-        // Make sure we'll only need two accesses.
-        assert(roundDown(second_addr + second_size - 1, block_size) ==
-                second_addr);
-
-        /*
-         * 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, first_size,
-                          flags, pc, _cpuId, thread_id);
-        fault = thread->translateDataReadReq(req);
-        if (fault != NoFault) {
-            delete req;
-            return fault;
-        }
-        Request *second_req =
-            new Request(asid, second_addr, second_size,
-                        flags, pc, _cpuId, thread_id);
-        fault = thread->translateDataReadReq(second_req);
-        if (fault != NoFault) {
-            delete req;
-            delete second_req;
-            return fault;
-        }
-
-        T * data_ptr = new T;
-
-        /*
-         * 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 *orig_req =
-            new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id);
-        orig_req->setPhys(req->getPaddr(), data_size, flags);
-        PacketPtr big_pkt =
-            new Packet(orig_req, MemCmd::ReadResp, Packet::Broadcast);
-        big_pkt->dataDynamic<T>(data_ptr);
-        SplitMainSenderState * main_send_state = new SplitMainSenderState;
-        big_pkt->senderState = main_send_state;
-        main_send_state->outstanding = 2;
-
-        // This is the packet we'll process now.
-        pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
-        pkt->dataStatic<uint8_t>((uint8_t *)data_ptr);
-        pkt->senderState = new SplitFragmentSenderState(big_pkt, 0);
-
-        // This is the second half of the access we'll deal with later.
-        PacketPtr second_pkt =
-            new Packet(second_req, MemCmd::ReadReq, Packet::Broadcast);
-        second_pkt->dataStatic<uint8_t>((uint8_t *)data_ptr + first_size);
-        second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1);
-        if (!handleReadPacket(pkt)) {
-            main_send_state->fragments[1] = second_pkt;
-        } else {
-            handleReadPacket(second_pkt);
+    PacketPtr pkt;
+    RequestPtr req  = new Request(asid, addr, data_size,
+                                  flags, pc, _cpuId, thread_id);
+
+    Addr split_addr = roundDown(addr + data_size - 1, block_size);
+    assert(split_addr <= addr || split_addr - addr < block_size);
+
+    if (split_addr > addr) {
+        PacketPtr pkt1, pkt2;
+        this->buildSplitPacket(pkt1, pkt2, req,
+                split_addr, (uint8_t *)(new T), true);
+        if (handleReadPacket(pkt1)) {
+            SplitFragmentSenderState * send_state =
+                dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+            send_state->clearFromParent();
+            if (handleReadPacket(pkt2)) {
+                send_state =
+                    dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+                send_state->clearFromParent();
+            }
         }
     } else {
-        req = new Request(asid, addr, data_size,
-                          flags, pc, _cpuId, thread_id);
-
-        // translate to physical address
-        Fault fault = thread->translateDataReadReq(req);
-
+        Fault fault = buildPacket(pkt, req, true);
         if (fault != NoFault) {
-            delete req;
             return fault;
         }
-
-        pkt = new Packet(req,
-                         (req->isLocked() ?
-                          MemCmd::LoadLockedReq : MemCmd::ReadReq),
-                          Packet::Broadcast);
         pkt->dataDynamic<T>(new T);
 
         handleReadPacket(pkt);
@@ -468,107 +478,50 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
 {
     const int asid = 0;
     const int thread_id = 0;
-    bool do_access = true;  // flag to suppress cache access
     const Addr pc = thread->readPC();
-
-    RequestPtr req;
-
     int block_size = dcachePort.peerBlockSize();
     int data_size = sizeof(T);
 
-    Addr second_addr = roundDown(addr + data_size - 1, block_size);
+    RequestPtr req = new Request(asid, addr, data_size,
+                                 flags, pc, _cpuId, thread_id);
 
-    if (second_addr > addr) {
-        Fault fault;
-        Addr first_size = second_addr - addr;
-        Addr second_size = data_size - first_size;
-        // Make sure we'll only need two accesses.
-        assert(roundDown(second_addr + second_size - 1, block_size) == 
-                second_addr);
+    Addr split_addr = roundDown(addr + data_size - 1, block_size);
+    assert(split_addr <= addr || split_addr - addr < block_size);
 
-        req = new Request(asid, addr, first_size,
-                          flags, pc, _cpuId, thread_id);
-        fault = thread->translateDataWriteReq(req);
-        if (fault != NoFault) {
-            delete req;
-            return fault;
-        }
-        RequestPtr second_req = new Request(asid, second_addr, second_size,
-                                            flags, pc, _cpuId, thread_id);
-        fault = thread->translateDataWriteReq(second_req);
-        if (fault != NoFault) {
-            delete req;
-            delete second_req;
+    if (split_addr > addr) {
+        PacketPtr pkt1, pkt2;
+        T *dataP = new T;
+        *dataP = data;
+        Fault fault = this->buildSplitPacket(pkt1, pkt2, req, split_addr,
+                                             (uint8_t *)dataP, false);
+        if (fault != NoFault)
             return fault;
-        }
-
-        if (req->isLocked() || req->isSwap() || 
-                second_req->isLocked() || second_req->isSwap()) {
-            panic("LL/SCs and swaps can't be split.");
-        }
-
-        T * data_ptr = new T;
-
-        /*
-         * 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 orig_req = 
-            new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id);
-        orig_req->setPhys(req->getPaddr(), data_size, flags);
-        PacketPtr big_pkt =
-            new Packet(orig_req, MemCmd::WriteResp, Packet::Broadcast);
-        big_pkt->dataDynamic<T>(data_ptr);
-        big_pkt->set(data);
-        SplitMainSenderState * main_send_state = new SplitMainSenderState;
-        big_pkt->senderState = main_send_state;
-        main_send_state->outstanding = 2;
-
-        assert(dcache_pkt == NULL);
-        // This is the packet we'll process now.
-        dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
-        dcache_pkt->dataStatic<uint8_t>((uint8_t *)data_ptr);
-        dcache_pkt->senderState = new SplitFragmentSenderState(big_pkt, 0);
-
-        // This is the second half of the access we'll deal with later.
-        PacketPtr second_pkt =
-            new Packet(second_req, MemCmd::WriteReq, Packet::Broadcast);
-        second_pkt->dataStatic<uint8_t>((uint8_t *)data_ptr + first_size);
-        second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1);
-        if (!handleWritePacket()) {
-            main_send_state->fragments[1] = second_pkt;
-        } else {
-            dcache_pkt = second_pkt;
-            handleWritePacket();
+        dcache_pkt = pkt1;
+        if (handleWritePacket()) {
+            SplitFragmentSenderState * send_state =
+                dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+            send_state->clearFromParent();
+            dcache_pkt = pkt2;
+            if (handleReadPacket(pkt2)) {
+                send_state =
+                    dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+                send_state->clearFromParent();
+            }
         }
     } else {
-        req = new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id);
+        bool do_access = true;  // flag to suppress cache access
 
-        // translate to physical address
-        Fault fault = thread->translateDataWriteReq(req);
-        if (fault != NoFault) {
-            delete req;
+        Fault fault = buildPacket(dcache_pkt, req, false);
+        if (fault != NoFault)
             return fault;
-        }
-
-        MemCmd cmd = MemCmd::WriteReq; // default
 
         if (req->isLocked()) {
-            cmd = MemCmd::StoreCondReq;
             do_access = TheISA::handleLockedWrite(thread, req);
-        } else if (req->isSwap()) {
-            cmd = MemCmd::SwapReq;
-            if (req->isCondSwap()) {
-                assert(res);
-                req->setExtraData(*res);
-            }
+        } else if (req->isCondSwap()) {
+            assert(res);
+            req->setExtraData(*res);
         }
 
-        // Note: need to allocate dcache_pkt even if do_access is
-        // false, as it's used unconditionally to call completeAcc().
-        assert(dcache_pkt == NULL);
-        dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
         dcache_pkt->allocate();
         if (req->isMmapedIpr())
             dcache_pkt->set(htog(data));
index b641b13028eb1bdf338f7904134c378b03f80d89..c305d03612cdcd85599b75e1bb4268c68f848df3 100644 (file)
@@ -65,12 +65,6 @@ class TimingSimpleCPU : public BaseSimpleCPU
         int outstanding;
         PacketPtr fragments[2];
 
-        SplitMainSenderState()
-        {
-            fragments[0] = NULL;
-            fragments[1] = NULL;
-        }
-
         int
         getPendingFragment()
         {
@@ -102,6 +96,10 @@ class TimingSimpleCPU : public BaseSimpleCPU
         }
     };
 
+    Fault buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, RequestPtr &req,
+            Addr split_addr, uint8_t *data, bool read);
+    Fault buildPacket(PacketPtr &pkt, RequestPtr &req, bool read);
+
     bool handleReadPacket(PacketPtr pkt);
     // This function always implicitly uses dcache_pkt.
     bool handleWritePacket();
index c3a523d9b8a25f6330623ef30adc1c7014c7d949..007c33acfeceaf4720fbb0d742e6d000bcd73aa7 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "base/fast_alloc.hh"
 #include "base/flags.hh"
+#include "base/misc.hh"
 #include "sim/host.hh"
 #include "sim/core.hh"
 
@@ -232,6 +233,24 @@ class Request : public FastAlloc
         flags.set(VALID_PADDR);
     }
 
+    /**
+     * Generate two requests as if this request had been split into two
+     * pieces. The original request can't have been translated already.
+     */
+    void splitOnVaddr(Addr split_addr, RequestPtr &req1, RequestPtr &req2)
+    {
+        assert(flags.any(VALID_VADDR));
+        assert(flags.none(VALID_PADDR));
+        assert(split_addr > vaddr && split_addr < vaddr + size);
+        req1 = new Request;
+        *req1 = *this;
+        req2 = new Request;
+        *req2 = *this;
+        req1->size = split_addr - vaddr;
+        req2->vaddr = split_addr;
+        req2->size = size - req1->size;
+    }
+
     /**
      * Accessor for paddr.
      */