add microPC stuff back in. got deleted on changeset propragation somehow.
[gem5.git] / src / cpu / o3 / lsq_unit_impl.hh
index 3f9db912f455ffa1816d8b6a4b61a6964cb1793a..71b416c9c92141922618e657f870d0698ea48f07 100644 (file)
@@ -29,6 +29,7 @@
  *          Korey Sewell
  */
 
+#include "arch/locked_mem.hh"
 #include "config/use_checker.hh"
 
 #include "cpu/o3/lsq.hh"
@@ -56,6 +57,11 @@ LSQUnit<Impl>::WritebackEvent::process()
     if (!lsqPtr->isSwitchedOut()) {
         lsqPtr->writeback(inst, pkt);
     }
+
+    if (pkt->senderState)
+        delete pkt->senderState;
+
+    delete pkt->req;
     delete pkt;
 }
 
@@ -63,7 +69,7 @@ template<class Impl>
 const char *
 LSQUnit<Impl>::WritebackEvent::description()
 {
-    return "Store writeback event";
+    return "Store writeback";
 }
 
 template<class Impl>
@@ -77,11 +83,10 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
 
     //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
 
+    assert(!pkt->wasNacked());
+
     if (isSwitchedOut() || inst->isSquashed()) {
         iewStage->decrWb(inst->seqNum);
-        delete state;
-        delete pkt;
-        return;
     } else {
         if (!state->noWB) {
             writeback(inst, pkt);
@@ -93,6 +98,7 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
     }
 
     delete state;
+    delete pkt->req;
     delete pkt;
 }
 
@@ -106,9 +112,12 @@ LSQUnit<Impl>::LSQUnit()
 
 template<class Impl>
 void
-LSQUnit<Impl>::init(Params *params, LSQ *lsq_ptr, unsigned maxLQEntries,
-                    unsigned maxSQEntries, unsigned id)
+LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr,
+                    unsigned maxLQEntries, unsigned maxSQEntries, unsigned id)
 {
+    cpu = cpu_ptr;
+    iewStage = iew_ptr;
+
     DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
 
     switchedOut = false;
@@ -131,24 +140,12 @@ LSQUnit<Impl>::init(Params *params, LSQ *lsq_ptr, unsigned maxLQEntries,
     usedPorts = 0;
     cachePorts = params->cachePorts;
 
+    retryPkt = NULL;
     memDepViolator = NULL;
 
     blockedLoadSeqNum = 0;
 }
 
-template<class Impl>
-void
-LSQUnit<Impl>::setCPU(O3CPU *cpu_ptr)
-{
-    cpu = cpu_ptr;
-
-#if USE_CHECKER
-    if (cpu->checker) {
-        cpu->checker->setDcachePort(dcachePort);
-    }
-#endif
-}
-
 template<class Impl>
 std::string
 LSQUnit<Impl>::name() const
@@ -205,6 +202,19 @@ LSQUnit<Impl>::regStats()
         .desc("Number of times an access to memory failed due to the cache being blocked");
 }
 
+template<class Impl>
+void
+LSQUnit<Impl>::setDcachePort(Port *dcache_port)
+{
+    dcachePort = dcache_port;
+
+#if USE_CHECKER
+    if (cpu->checker) {
+        cpu->checker->setDcachePort(dcachePort);
+    }
+#endif
+}
+
 template<class Impl>
 void
 LSQUnit<Impl>::clearLQ()
@@ -401,12 +411,15 @@ template <class Impl>
 Fault
 LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
 {
+    using namespace TheISA;
     // Execute a specific load.
     Fault load_fault = NoFault;
 
     DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
             inst->readPC(),inst->seqNum);
 
+    assert(!inst->isSquashed());
+
     load_fault = inst->initiateAcc();
 
     // If the instruction faulted, then we need to send it along to commit
@@ -416,11 +429,44 @@ LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
         // realizes there is activity.
         // Mark it as executed unless it is an uncached load that
         // needs to hit the head of commit.
-        if (!(inst->req->isUncacheable()) || inst->isAtCommit()) {
+        if (!(inst->hasRequest() && inst->uncacheable()) ||
+            inst->isAtCommit()) {
             inst->setExecuted();
         }
         iewStage->instToCommit(inst);
         iewStage->activityThisCycle();
+    } else if (!loadBlocked()) {
+        assert(inst->effAddrValid);
+        int load_idx = inst->lqIdx;
+        incrLdIdx(load_idx);
+        while (load_idx != loadTail) {
+            // Really only need to check loads that have actually executed
+
+            // @todo: For now this is extra conservative, detecting a
+            // violation if the addresses match assuming all accesses
+            // are quad word accesses.
+
+            // @todo: Fix this, magic number being used here
+            if (loadQueue[load_idx]->effAddrValid &&
+                (loadQueue[load_idx]->effAddr >> 8) ==
+                (inst->effAddr >> 8)) {
+                // A load incorrectly passed this load.  Squash and refetch.
+                // For now return a fault to show that it was unsuccessful.
+                DynInstPtr violator = loadQueue[load_idx];
+                if (!memDepViolator ||
+                    (violator->seqNum < memDepViolator->seqNum)) {
+                    memDepViolator = violator;
+                } else {
+                    break;
+                }
+
+                ++lsqMemOrderViolation;
+
+                return genMachineCheckFault();
+            }
+
+            incrLdIdx(load_idx);
+        }
     }
 
     return load_fault;
@@ -439,6 +485,8 @@ LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
     DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
             store_inst->readPC(), store_inst->seqNum);
 
+    assert(!store_inst->isSquashed());
+
     // Check the recently completed loads to see if any match this store's
     // address.  If so, then we have a memory ordering violation.
     int load_idx = store_inst->lqIdx;
@@ -462,32 +510,36 @@ LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
         ++storesToWB;
     }
 
-    if (!memDepViolator) {
-        while (load_idx != loadTail) {
-            // Really only need to check loads that have actually executed
-            // It's safe to check all loads because effAddr is set to
-            // InvalAddr when the dyn inst is created.
-
-            // @todo: For now this is extra conservative, detecting a
-            // violation if the addresses match assuming all accesses
-            // are quad word accesses.
-
-            // @todo: Fix this, magic number being used here
-            if ((loadQueue[load_idx]->effAddr >> 8) ==
-                (store_inst->effAddr >> 8)) {
-                // A load incorrectly passed this store.  Squash and refetch.
-                // For now return a fault to show that it was unsuccessful.
-                memDepViolator = loadQueue[load_idx];
-                ++lsqMemOrderViolation;
-
-                return genMachineCheckFault();
+    assert(store_inst->effAddrValid);
+    while (load_idx != loadTail) {
+        // Really only need to check loads that have actually executed
+        // It's safe to check all loads because effAddr is set to
+        // InvalAddr when the dyn inst is created.
+
+        // @todo: For now this is extra conservative, detecting a
+        // violation if the addresses match assuming all accesses
+        // are quad word accesses.
+
+        // @todo: Fix this, magic number being used here
+        if (loadQueue[load_idx]->effAddrValid &&
+            (loadQueue[load_idx]->effAddr >> 8) ==
+            (store_inst->effAddr >> 8)) {
+            // A load incorrectly passed this store.  Squash and refetch.
+            // For now return a fault to show that it was unsuccessful.
+            DynInstPtr violator = loadQueue[load_idx];
+            if (!memDepViolator ||
+                (violator->seqNum < memDepViolator->seqNum)) {
+                memDepViolator = violator;
+            } else {
+                break;
             }
 
-            incrLdIdx(load_idx);
+            ++lsqMemOrderViolation;
+
+            return genMachineCheckFault();
         }
 
-        // If we've reached this point, there was no violation.
-        memDepViolator = NULL;
+        incrLdIdx(load_idx);
     }
 
     return store_fault;
@@ -594,10 +646,14 @@ LSQUnit<Impl>::writebackStores()
 
         assert(!inst->memData);
         inst->memData = new uint8_t[64];
-        memcpy(inst->memData, (uint8_t *)&storeQueue[storeWBIdx].data,
-               req->getSize());
 
-        PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
+        memcpy(inst->memData, storeQueue[storeWBIdx].data, req->getSize());
+
+        MemCmd command =
+            req->isSwap() ? MemCmd::SwapReq :
+            (req->isLocked() ? MemCmd::StoreCondReq : MemCmd::WriteReq);
+        PacketPtr data_pkt = new Packet(req, command,
+                                        Packet::Broadcast);
         data_pkt->dataStatic(inst->memData);
 
         LSQSenderState *state = new LSQSenderState;
@@ -609,32 +665,28 @@ LSQUnit<Impl>::writebackStores()
         DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
                 "to Addr:%#x, data:%#x [sn:%lli]\n",
                 storeWBIdx, inst->readPC(),
-                req->getPaddr(), *(inst->memData),
+                req->getPaddr(), (int)*(inst->memData),
                 inst->seqNum);
 
         // @todo: Remove this SC hack once the memory system handles it.
-        if (req->isLocked()) {
-            if (req->isUncacheable()) {
-                req->setScResult(2);
-            } else {
-                if (cpu->lockFlag) {
-                    req->setScResult(1);
-                    DPRINTF(LSQUnit, "Store conditional [sn:%lli] succeeded.",
-                            inst->seqNum);
-                } else {
-                    req->setScResult(0);
-                    // Hack: Instantly complete this store.
-//                    completeDataAccess(data_pkt);
-                    DPRINTF(LSQUnit, "Store conditional [sn:%lli] failed.  "
-                            "Instantly completing it.\n",
-                            inst->seqNum);
-                    WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
-                    wb->schedule(curTick + 1);
-                    delete state;
-                    completeStore(storeWBIdx);
-                    incrStIdx(storeWBIdx);
-                    continue;
-                }
+        if (inst->isStoreConditional()) {
+            // Disable recording the result temporarily.  Writing to
+            // misc regs normally updates the result, but this is not
+            // the desired behavior when handling store conditionals.
+            inst->recordResult = false;
+            bool success = TheISA::handleLockedWrite(inst.get(), req);
+            inst->recordResult = true;
+
+            if (!success) {
+                // Instantly complete this store.
+                DPRINTF(LSQUnit, "Store conditional [sn:%lli] failed.  "
+                        "Instantly completing it.\n",
+                        inst->seqNum);
+                WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
+                wb->schedule(curTick + 1);
+                completeStore(storeWBIdx);
+                incrStIdx(storeWBIdx);
+                continue;
             }
         } else {
             // Non-store conditionals do not need a writeback.
@@ -642,11 +694,8 @@ LSQUnit<Impl>::writebackStores()
         }
 
         if (!dcachePort->sendTiming(data_pkt)) {
-            if (data_pkt->result == Packet::BadAddress) {
-                panic("LSQ sent out a bad address for a completed store!");
-            }
             // Need to handle becoming blocked on a store.
-            DPRINTF(IEW, "D-Cache became blcoked when writing [sn:%lli], will"
+            DPRINTF(IEW, "D-Cache became blocked when writing [sn:%lli], will"
                     "retry later\n",
                     inst->seqNum);
             isStoreBlocked = true;
@@ -721,6 +770,10 @@ LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
         }
     }
 
+    if (memDepViolator && squashed_num < memDepViolator->seqNum) {
+        memDepViolator = NULL;
+    }
+
     int store_idx = storeTail;
     decrStIdx(store_idx);
 
@@ -750,6 +803,11 @@ LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
         storeQueue[store_idx].inst = NULL;
         storeQueue[store_idx].canWB = 0;
 
+        // Must delete request now that it wasn't handed off to
+        // memory.  This is quite ugly.  @todo: Figure out the proper
+        // place to really handle request deletes.
+        delete storeQueue[store_idx].req;
+
         storeQueue[store_idx].req = NULL;
         --stores;
 
@@ -763,7 +821,7 @@ LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
 
 template <class Impl>
 void
-LSQUnit<Impl>::storePostSend(Packet *pkt)
+LSQUnit<Impl>::storePostSend(PacketPtr pkt)
 {
     if (isStalled() &&
         storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
@@ -787,26 +845,6 @@ LSQUnit<Impl>::storePostSend(Packet *pkt)
 #endif
     }
 
-    if (pkt->result != Packet::Success) {
-        DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n",
-                storeWBIdx);
-
-        DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
-                storeQueue[storeWBIdx].inst->seqNum);
-
-        //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
-
-        //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size());
-
-        // @todo: Increment stat here.
-    } else {
-        DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n",
-                storeWBIdx);
-
-        DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
-                storeQueue[storeWBIdx].inst->seqNum);
-    }
-
     incrStIdx(storeWBIdx);
 }
 
@@ -892,12 +930,10 @@ void
 LSQUnit<Impl>::recvRetry()
 {
     if (isStoreBlocked) {
+        DPRINTF(LSQUnit, "Receiving retry: store blocked\n");
         assert(retryPkt != NULL);
 
         if (dcachePort->sendTiming(retryPkt)) {
-            if (retryPkt->result == Packet::BadAddress) {
-                panic("LSQ sent out a bad address for a completed store!");
-            }
             storePostSend(retryPkt);
             retryPkt = NULL;
             isStoreBlocked = false;