CPU: Get rid of the now unnecessary getInst/setInst family of functions.
[gem5.git] / src / cpu / ozone / lw_lsq_impl.hh
index 05db3028ac7dde8364b1a996071f61801385bd30..c714c5d382c32c6caeeeefa9acde40902a510a35 100644 (file)
  * Authors: Kevin Lim
  */
 
-#include "arch/isa_traits.hh"
+#include "arch/faults.hh"
 #include "base/str.hh"
+#include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/ozone/lw_lsq.hh"
 #include "cpu/checker/cpu.hh"
 
-template <class Impl>
-OzoneLWLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(DynInstPtr &_inst,
-                                                             BackEnd *_be,
-                                                             Event *wb_event,
-                                                             OzoneLWLSQ<Impl> *lsq_ptr)
-    : Event(&mainEventQueue),
-      inst(_inst),
-      be(_be),
-      wbEvent(wb_event),
-      miss(false),
-      lsqPtr(lsq_ptr)
+template<class Impl>
+OzoneLWLSQ<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt,
+                                                 OzoneLWLSQ *lsq_ptr)
+    : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
 {
     this->setFlags(Event::AutoDelete);
 }
 
-template <class Impl>
+template<class Impl>
 void
-OzoneLWLSQ<Impl>::StoreCompletionEvent::process()
+OzoneLWLSQ<Impl>::WritebackEvent::process()
 {
-    DPRINTF(OzoneLSQ, "Cache miss complete for store [sn:%lli]\n",
-            inst->seqNum);
+    if (!lsqPtr->isSwitchedOut()) {
+        lsqPtr->writeback(inst, pkt);
+    }
+    delete pkt;
+}
 
-    //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
+template<class Impl>
+const char *
+OzoneLWLSQ<Impl>::WritebackEvent::description() const
+{
+    return "Store writeback";
+}
 
-//    lsqPtr->cpu->wakeCPU();
-    if (lsqPtr->isSwitchedOut()) {
-        if (wbEvent)
-            delete wbEvent;
+template <class Impl>
+Tick
+OzoneLWLSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
+{
+    panic("O3CPU model does not work with atomic mode!");
+    return curTick;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
+{
+    warn("O3CPU doesn't update things on a recvFunctional");
+}
 
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::DcachePort::recvStatusChange(Status status)
+{
+    if (status == RangeChange)
         return;
-    }
 
-    if (wbEvent) {
-        wbEvent->process();
-        delete wbEvent;
-    }
+    panic("O3CPU doesn't expect recvStatusChange callback!");
+}
 
-    lsqPtr->completeStore(inst->sqIdx);
-    if (miss)
-        be->removeDcacheMiss(inst);
+template <class Impl>
+bool
+OzoneLWLSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
+{
+    lsq->completeDataAccess(pkt);
+    return true;
 }
 
 template <class Impl>
-const char *
-OzoneLWLSQ<Impl>::StoreCompletionEvent::description()
+void
+OzoneLWLSQ<Impl>::DcachePort::recvRetry()
+{
+    lsq->recvRetry();
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::completeDataAccess(PacketPtr pkt)
 {
-    return "LSQ store completion event";
+    LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState);
+    DynInstPtr inst = state->inst;
+    DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum);
+    DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum);
+
+    //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
+
+    if (isSwitchedOut() || inst->isSquashed()) {
+        delete state;
+        delete pkt;
+        return;
+    } else {
+        if (!state->noWB) {
+            writeback(inst, pkt);
+        }
+
+        if (inst->isStore()) {
+            completeStore(inst);
+        }
+    }
+
+    delete state;
+    delete pkt;
 }
 
 template <class Impl>
 OzoneLWLSQ<Impl>::OzoneLWLSQ()
-    : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false),
-      loadBlockedHandled(false)
+    : switchedOut(false), dcachePort(this), loads(0), stores(0),
+      storesToWB(0), storesInFlight(0), stalled(false), isStoreBlocked(false),
+      isLoadBlocked(false), loadBlockedHandled(false)
 {
 }
 
@@ -109,8 +157,6 @@ OzoneLWLSQ<Impl>::init(Params *params, unsigned maxLQEntries,
     usedPorts = 0;
     cachePorts = params->cachePorts;
 
-    dcacheInterface = params->dcacheInterface;
-
     loadFaultInst = storeFaultInst = memDepViolator = NULL;
 
     blockedLoadSeqNum = 0;
@@ -123,6 +169,29 @@ OzoneLWLSQ<Impl>::name() const
     return "lsqunit";
 }
 
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::regStats()
+{
+    lsqMemOrderViolation
+        .name(name() + ".memOrderViolation")
+        .desc("Number of memory ordering violations");
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::setCPU(OzoneCPU *cpu_ptr)
+{
+    cpu = cpu_ptr;
+    dcachePort.setName(this->name() + "-dport");
+
+#if USE_CHECKER
+    if (cpu->checker) {
+        cpu->checker->setDcachePort(&dcachePort);
+    }
+#endif
+}
+
 template<class Impl>
 void
 OzoneLWLSQ<Impl>::clearLQ()
@@ -259,7 +328,7 @@ unsigned
 OzoneLWLSQ<Impl>::numFreeEntries()
 {
     unsigned free_lq_entries = LQEntries - loads;
-    unsigned free_sq_entries = SQEntries - stores;
+    unsigned free_sq_entries = SQEntries - (stores + storesInFlight);
 
     // Both the LQ and SQ entries have an extra dummy entry to differentiate
     // empty/full conditions.  Subtract 1 from the free entries.
@@ -323,6 +392,9 @@ OzoneLWLSQ<Impl>::executeLoad(DynInstPtr &inst)
     // Actually probably want the oldest faulting load
     if (load_fault != NoFault) {
         DPRINTF(OzoneLSQ, "Load [sn:%lli] has a fault\n", inst->seqNum);
+        if (!(inst->req->isUncacheable() && !inst->isAtCommit())) {
+            inst->setExecuted();
+        }
         // Maybe just set it as can commit here, although that might cause
         // some other problems with sending traps to the ROB too quickly.
         be->instToCommit(inst);
@@ -399,6 +471,7 @@ OzoneLWLSQ<Impl>::executeStore(DynInstPtr &store_inst)
                 // A load incorrectly passed this store.  Squash and refetch.
                 // For now return a fault to show that it was unsuccessful.
                 memDepViolator = (*lq_it);
+                ++lsqMemOrderViolation;
 
                 return TheISA::genMachineCheckFault();
             }
@@ -481,12 +554,18 @@ OzoneLWLSQ<Impl>::writebackStores()
            (*sq_it).canWB &&
            usedPorts < cachePorts) {
 
+        if (isStoreBlocked) {
+            DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache"
+                    " is blocked!\n");
+            break;
+        }
+
         DynInstPtr inst = (*sq_it).inst;
 
         if ((*sq_it).size == 0 && !(*sq_it).completed) {
             sq_it--;
-            completeStore(inst->sqIdx);
-
+            removeStore(inst->sqIdx);
+            completeStore(inst);
             continue;
         }
 
@@ -495,53 +574,74 @@ OzoneLWLSQ<Impl>::writebackStores()
             continue;
         }
 
-        if (dcacheInterface && dcacheInterface->isBlocked()) {
-            DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache"
-                    " is blocked!\n");
-            break;
-        }
-
         ++usedPorts;
 
         assert((*sq_it).req);
         assert(!(*sq_it).committed);
 
+        Request *req = (*sq_it).req;
         (*sq_it).committed = true;
 
-        MemReqPtr req = (*sq_it).req;
+        assert(!inst->memData);
+        inst->memData = new uint8_t[64];
+        memcpy(inst->memData, (uint8_t *)&(*sq_it).data,
+               req->getSize());
 
-        req->cmd = Write;
-        req->completionEvent = NULL;
-        req->time = curTick;
+        MemCmd command =
+            req->isSwap() ? MemCmd::SwapReq :
+            (req->isLLSC() ? MemCmd::WriteReq : MemCmd::StoreCondReq);
+        PacketPtr data_pkt = new Packet(req, command, Packet::Broadcast);
+        data_pkt->dataStatic(inst->memData);
 
-        switch((*sq_it).size) {
-          case 1:
-            cpu->write(req, (uint8_t &)(*sq_it).data);
-            break;
-          case 2:
-            cpu->write(req, (uint16_t &)(*sq_it).data);
-            break;
-          case 4:
-            cpu->write(req, (uint32_t &)(*sq_it).data);
-            break;
-          case 8:
-            cpu->write(req, (uint64_t &)(*sq_it).data);
-            break;
-          default:
-            panic("Unexpected store size!\n");
-        }
-        if (!(req->flags & LOCKED)) {
-            (*sq_it).inst->setCompleted();
-            if (cpu->checker) {
-                cpu->checker->tick((*sq_it).inst);
+        LSQSenderState *state = new LSQSenderState;
+        state->isLoad = false;
+        state->idx = inst->sqIdx;
+        state->inst = inst;
+        data_pkt->senderState = state;
+
+        DPRINTF(OzoneLSQ, "D-Cache: Writing back store PC:%#x "
+                "to Addr:%#x, data:%#x [sn:%lli]\n",
+                (*sq_it).inst->readPC(),
+                req->getPaddr(), *(inst->memData),
+                inst->seqNum);
+
+        // @todo: Remove this SC hack once the memory system handles it.
+        if (req->isLLSC()) {
+            if (req->isUncacheable()) {
+                req->setExtraData(2);
+            } else {
+                if (cpu->lockFlag) {
+                    req->setExtraData(1);
+                } else {
+                    req->setExtraData(0);
+                    // Hack: Instantly complete this store.
+                    completeDataAccess(data_pkt);
+                    --sq_it;
+                    continue;
+                }
             }
+        } else {
+            // Non-store conditionals do not need a writeback.
+            state->noWB = true;
         }
 
+        if (!dcachePort.sendTiming(data_pkt)) {
+            // Need to handle becoming blocked on a store.
+            isStoreBlocked = true;
+            assert(retryPkt == NULL);
+            retryPkt = data_pkt;
+        } else {
+            storePostSend(data_pkt, inst);
+            --sq_it;
+        }
+/*
         DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x "
                 "to Addr:%#x, data:%#x [sn:%lli]\n",
                 inst->sqIdx,inst->readPC(),
                 req->paddr, *(req->data),
                 inst->seqNum);
+        DPRINTF(OzoneLSQ, "StoresInFlight: %i\n",
+                storesInFlight + 1);
 
         if (dcacheInterface) {
             assert(!req->completionEvent);
@@ -564,7 +664,7 @@ OzoneLWLSQ<Impl>::writebackStores()
             if (result != MA_HIT && dcacheInterface->doEvents()) {
                 store_event->miss = true;
                 typename BackEnd::LdWritebackEvent *wb = NULL;
-                if (req->flags & LOCKED) {
+                if (req->isLLSC()) {
                     wb = new typename BackEnd::LdWritebackEvent(inst,
                                                             be);
                     store_event->wbEvent = wb;
@@ -591,7 +691,7 @@ OzoneLWLSQ<Impl>::writebackStores()
 //                DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
 //                        inst->seqNum);
 
-                if (req->flags & LOCKED) {
+                if (req->isLLSC()) {
                     // Stx_C does not generate a system port
                     // transaction in the 21264, but that might be
                     // hard to accomplish in this model.
@@ -603,9 +703,12 @@ OzoneLWLSQ<Impl>::writebackStores()
                 }
                 sq_it--;
             }
+            ++storesInFlight;
+//            removeStore(inst->sqIdx);
         } else {
             panic("Must HAVE DCACHE!!!!!\n");
         }
+*/
     }
 
     // Not sure this should set it to 0.
@@ -619,7 +722,7 @@ void
 OzoneLWLSQ<Impl>::squash(const InstSeqNum &squashed_num)
 {
     DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!"
-            "(Loads:%i Stores:%i)\n",squashed_num,loads,stores);
+            "(Loads:%i Stores:%i)\n",squashed_num,loads,stores+storesInFlight);
 
 
     LQIt lq_it = loadQueue.begin();
@@ -685,10 +788,6 @@ OzoneLWLSQ<Impl>::squash(const InstSeqNum &squashed_num)
         SQIndices.push((*sq_it).inst->sqIdx);
         (*sq_it).inst = NULL;
         (*sq_it).canWB = 0;
-
-        if ((*sq_it).req) {
-            assert(!(*sq_it).req->completionEvent);
-        }
         (*sq_it).req = NULL;
         --stores;
         storeQueue.erase(sq_it++);
@@ -734,7 +833,55 @@ OzoneLWLSQ<Impl>::dumpInsts()
 
 template <class Impl>
 void
-OzoneLWLSQ<Impl>::completeStore(int store_idx)
+OzoneLWLSQ<Impl>::storePostSend(PacketPtr pkt, DynInstPtr &inst)
+{
+    if (isStalled() &&
+        inst->seqNum == stallingStoreIsn) {
+        DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
+                "load [sn:%lli]\n",
+                stallingStoreIsn, (*stallingLoad)->seqNum);
+        stalled = false;
+        stallingStoreIsn = 0;
+        be->replayMemInst((*stallingLoad));
+    }
+
+    if (!inst->isStoreConditional()) {
+        // The store is basically completed at this time. This
+        // only works so long as the checker doesn't try to
+        // verify the value in memory for stores.
+        inst->setCompleted();
+#if USE_CHECKER
+        if (cpu->checker) {
+            cpu->checker->verify(inst);
+        }
+#endif
+    }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt)
+{
+    // Squashed instructions do not need to complete their access.
+    if (inst->isSquashed()) {
+        assert(!inst->isStore());
+        return;
+    }
+
+    if (!inst->isExecuted()) {
+        inst->setExecuted();
+
+        // Complete access to copy data to proper place.
+        inst->completeAcc(pkt);
+    }
+
+    // Need to insert instruction into queue to commit
+    be->instToCommit(inst);
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::removeStore(int store_idx)
 {
     SQHashIt sq_hash_it = SQItHash.find(store_idx);
     assert(sq_hash_it != SQItHash.end());
@@ -744,8 +891,6 @@ OzoneLWLSQ<Impl>::completeStore(int store_idx)
     (*sq_it).completed = true;
     DynInstPtr inst = (*sq_it).inst;
 
-    --storesToWB;
-
     if (isStalled() &&
         inst->seqNum == stallingStoreIsn) {
         DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
@@ -763,12 +908,28 @@ OzoneLWLSQ<Impl>::completeStore(int store_idx)
     SQItHash.erase(sq_hash_it);
     SQIndices.push(inst->sqIdx);
     storeQueue.erase(sq_it);
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::completeStore(DynInstPtr &inst)
+{
+    --storesToWB;
     --stores;
 
     inst->setCompleted();
+#if USE_CHECKER
     if (cpu->checker) {
-        cpu->checker->tick(inst);
+        cpu->checker->verify(inst);
     }
+#endif
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::recvRetry()
+{
+    panic("Unimplemented!");
 }
 
 template <class Impl>
@@ -777,73 +938,16 @@ OzoneLWLSQ<Impl>::switchOut()
 {
     assert(storesToWB == 0);
     switchedOut = true;
-    SQIt sq_it = --(storeQueue.end());
-    while (storesToWB > 0 &&
-           sq_it != storeQueue.end() &&
-           (*sq_it).inst &&
-           (*sq_it).canWB) {
-
-        DynInstPtr inst = (*sq_it).inst;
-
-        if ((*sq_it).size == 0 && !(*sq_it).completed) {
-            sq_it--;
-            continue;
-        }
-
-        // Store conditionals don't complete until *after* they have written
-        // back.  If it's here and not yet sent to memory, then don't bother
-        // as it's not part of committed state.
-        if (inst->isDataPrefetch() || (*sq_it).committed) {
-            sq_it--;
-            continue;
-        } else if ((*sq_it).req->flags & LOCKED) {
-            sq_it--;
-            assert(!(*sq_it).canWB ||
-                   ((*sq_it).canWB && (*sq_it).req->flags & LOCKED));
-            continue;
-        }
-
-        assert((*sq_it).req);
-        assert(!(*sq_it).committed);
-
-        MemReqPtr req = (*sq_it).req;
-        (*sq_it).committed = true;
-
-        req->cmd = Write;
-        req->completionEvent = NULL;
-        req->time = curTick;
-        assert(!req->data);
-        req->data = new uint8_t[64];
-        memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size);
-
-        DPRINTF(OzoneLSQ, "Switching out : Writing back store idx:%i PC:%#x "
-                "to Addr:%#x, data:%#x directly to memory [sn:%lli]\n",
-                inst->sqIdx,inst->readPC(),
-                req->paddr, *(req->data),
-                inst->seqNum);
-
-        switch((*sq_it).size) {
-          case 1:
-            cpu->write(req, (uint8_t &)(*sq_it).data);
-            break;
-          case 2:
-            cpu->write(req, (uint16_t &)(*sq_it).data);
-            break;
-          case 4:
-            cpu->write(req, (uint32_t &)(*sq_it).data);
-            break;
-          case 8:
-            cpu->write(req, (uint64_t &)(*sq_it).data);
-            break;
-          default:
-            panic("Unexpected store size!\n");
-        }
-    }
 
     // Clear the queue to free up resources
+    assert(stores == 0);
+    assert(storeQueue.empty());
+    assert(loads == 0);
+    assert(loadQueue.empty());
+    assert(storesInFlight == 0);
     storeQueue.clear();
     loadQueue.clear();
-    loads = stores = storesToWB = 0;
+    loads = stores = storesToWB = storesInFlight = 0;
 }
 
 template <class Impl>