X86: Add a .serializing directive that makes a macroop serializing.
[gem5.git] / src / cpu / ozone / front_end_impl.hh
index 467567c1087f9149e039c44e8a0f74c26e47a71d..88413692761484b4dcf82403c931f4a75139530a 100644 (file)
  * Authors: Kevin Lim
  */
 
-#include "arch/faults.hh"
+#include "sim/faults.hh"
 #include "arch/isa_traits.hh"
+#include "arch/utility.hh"
 #include "base/statistics.hh"
+#include "config/the_isa.hh"
+#include "config/use_checker.hh"
 #include "cpu/thread_context.hh"
 #include "cpu/exetrace.hh"
 #include "cpu/ozone/front_end.hh"
-#include "mem/mem_interface.hh"
-#include "sim/byte_swap.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
 
 using namespace TheISA;
 
+template<class Impl>
+Tick
+FrontEnd<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
+{
+    panic("FrontEnd doesn't expect recvAtomic callback!");
+    return curTick;
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
+{
+    warn("FrontEnd doesn't update state from functional calls");
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvStatusChange(Status status)
+{
+    if (status == RangeChange)
+        return;
+
+    panic("FrontEnd doesn't expect recvStatusChange callback!");
+}
+
+template<class Impl>
+bool
+FrontEnd<Impl>::IcachePort::recvTiming(PacketPtr pkt)
+{
+    fe->processCacheCompletion(pkt);
+    return true;
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvRetry()
+{
+    fe->recvRetry();
+}
+
 template <class Impl>
 FrontEnd<Impl>::FrontEnd(Params *params)
     : branchPred(params),
-      icacheInterface(params->icacheInterface),
+      icachePort(this),
+      numInstsReady(params->frontEndLatency, 0),
       instBufferSize(0),
       maxInstBufferSize(params->maxInstBufferSize),
+      latency(params->frontEndLatency),
       width(params->frontEndWidth),
       freeRegs(params->numPhysicalRegs),
       numPhysRegs(params->numPhysicalRegs),
@@ -57,7 +107,7 @@ FrontEnd<Impl>::FrontEnd(Params *params)
 
     memReq = NULL;
     // Size of cache block.
-    cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
+    cacheBlkSize = 64;
 
     assert(isPowerOf2(cacheBlkSize));
 
@@ -69,11 +119,10 @@ FrontEnd<Impl>::FrontEnd(Params *params)
 
     fetchCacheLineNextCycle = true;
 
-    cacheBlkValid = false;
+    cacheBlkValid = cacheBlocked = false;
+
+    retryPkt = NULL;
 
-#if !FULL_SYSTEM
-//    pTable = params->pTable;
-#endif
     fetchFault = NoFault;
 }
 
@@ -84,6 +133,21 @@ FrontEnd<Impl>::name() const
     return cpu->name() + ".frontend";
 }
 
+template <class Impl>
+void
+FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
+{
+    cpu = cpu_ptr;
+
+    icachePort.setName(this->name() + "-iport");
+
+#if USE_CHECKER
+    if (cpu->checker) {
+        cpu->checker->setIcachePort(&icachePort);
+    }
+#endif
+}
+
 template <class Impl>
 void
 FrontEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
@@ -263,6 +327,18 @@ FrontEnd<Impl>::tick()
     if (switchedOut)
         return;
 
+    for (int insts_to_queue = numInstsReady[-latency];
+         !instBuffer.empty() && insts_to_queue;
+         --insts_to_queue)
+    {
+        DPRINTF(FE, "Transferring instruction [sn:%lli] to the feBuffer\n",
+                instBuffer.front()->seqNum);
+        feBuffer.push_back(instBuffer.front());
+        instBuffer.pop_front();
+    }
+
+    numInstsReady.advance();
+
     // @todo: Maybe I want to just have direct communication...
     if (fromCommit->doneSeqNum) {
         branchPred.update(fromCommit->doneSeqNum, 0);
@@ -272,17 +348,17 @@ FrontEnd<Impl>::tick()
     IFQFcount += instBufferSize == maxInstBufferSize;
 
     // Fetch cache line
-    if (status == IcacheMissComplete) {
+    if (status == IcacheAccessComplete) {
         cacheBlkValid = true;
 
         status = Running;
-        if (barrierInst)
-            status = SerializeBlocked;
+//        if (barrierInst)
+//            status = SerializeBlocked;
         if (freeRegs <= 0)
             status = RenameBlocked;
         checkBE();
-    } else if (status == IcacheMissStall) {
-        DPRINTF(FE, "Still in Icache miss stall.\n");
+    } else if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
+        DPRINTF(FE, "Still in Icache wait.\n");
         icacheStallCycles++;
         return;
     }
@@ -303,7 +379,7 @@ FrontEnd<Impl>::tick()
     } else if (status == QuiescePending) {
         DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n");
         return;
-    } else if (status != IcacheMissComplete) {
+    } else if (status != IcacheAccessComplete) {
         if (fetchCacheLineNextCycle) {
             Fault fault = fetchCacheLine();
             if (fault != NoFault) {
@@ -314,7 +390,7 @@ FrontEnd<Impl>::tick()
             fetchCacheLineNextCycle = false;
         }
         // If miss, stall until it returns.
-        if (status == IcacheMissStall) {
+        if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
             // Tell CPU to not tick me for now.
             return;
         }
@@ -351,11 +427,12 @@ FrontEnd<Impl>::tick()
         // latency
         instBuffer.push_back(inst);
         ++instBufferSize;
+        numInstsReady[0]++;
         ++num_inst;
 
 #if FULL_SYSTEM
         if (inst->isQuiesce()) {
-            warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
+//            warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
             status = QuiescePending;
             break;
         }
@@ -385,15 +462,10 @@ Fault
 FrontEnd<Impl>::fetchCacheLine()
 {
     // Read a cache line, based on the current PC.
-#if FULL_SYSTEM
-    // Flag to say whether or not address is physical addr.
-    unsigned flags = cpu->inPalMode(PC) ? PHYSICAL : 0;
-#else
-    unsigned flags = 0;
-#endif // FULL_SYSTEM
     Fault fault = NoFault;
 
-    if (interruptPending && flags == 0) {
+    //AlphaDep
+    if (interruptPending && (PC & 0x3)) {
         return fault;
     }
 
@@ -404,24 +476,18 @@ FrontEnd<Impl>::fetchCacheLine()
 
     // Setup the memReq to do a read of the first isntruction's address.
     // Set the appropriate read size and flags as well.
-    memReq = new MemReq();
-
-    memReq->asid = 0;
-    memReq->thread_num = 0;
-    memReq->data = new uint8_t[64];
-    memReq->tc = tc;
-    memReq->cmd = Read;
-    memReq->reset(fetch_PC, cacheBlkSize, flags);
+    memReq = new Request(0, fetch_PC, cacheBlkSize, 0,
+                         PC, cpu->thread->contextId());
 
     // Translate the instruction request.
-    fault = cpu->translateInstReq(memReq);
+    fault = cpu->itb->translateAtomic(memReq, thread, false, true);
 
     // Now do the timing access to see whether or not the instruction
     // exists within the cache.
-    if (icacheInterface && fault == NoFault) {
-#if FULL_SYSTEM
+    if (fault == NoFault) {
+#if 0
         if (cpu->system->memctrl->badaddr(memReq->paddr) ||
-            memReq->flags & UNCACHEABLE) {
+            memReq->isUncacheable()) {
             DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a "
                     "misspeculating path!",
                     memReq->paddr);
@@ -429,30 +495,21 @@ FrontEnd<Impl>::fetchCacheLine()
         }
 #endif
 
-        memReq->completionEvent = NULL;
-
-        memReq->time = curTick;
-        fault = cpu->mem->read(memReq, cacheData);
-
-        MemAccessResult res = icacheInterface->access(memReq);
-
-        // If the cache missed then schedule an event to wake
-        // up this stage once the cache miss completes.
-        if (icacheInterface->doEvents() && res != MA_HIT) {
-            memReq->completionEvent = new ICacheCompletionEvent(memReq, this);
-
-            status = IcacheMissStall;
-
-            cacheBlkValid = false;
-
-            DPRINTF(FE, "Cache miss.\n");
-        }  else {
-            DPRINTF(FE, "Cache hit.\n");
-
-            cacheBlkValid = true;
-
-//            memcpy(cacheData, memReq->data, memReq->size);
+        // Build packet here.
+        PacketPtr data_pkt = new Packet(memReq,
+                                        Packet::ReadReq, Packet::Broadcast);
+        data_pkt->dataStatic(cacheData);
+
+        if (!icachePort.sendTiming(data_pkt)) {
+            assert(retryPkt == NULL);
+            DPRINTF(Fetch, "Out of MSHRs!\n");
+            status = IcacheWaitRetry;
+            retryPkt = data_pkt;
+            cacheBlocked = true;
+            return NoFault;
         }
+
+        status = IcacheWaitResponse;
     }
 
     // Note that this will set the cache block PC a bit earlier than it should
@@ -524,10 +581,10 @@ FrontEnd<Impl>::processBarriers(DynInstPtr &inst)
 
         // Change status over to SerializeBlocked so that other stages know
         // what this is blocked on.
-        status = SerializeBlocked;
+//        status = SerializeBlocked;
 
-        barrierInst = inst;
-        return true;
+//        barrierInst = inst;
+//        return true;
     } else if ((inst->isStoreConditional() || inst->isSerializeAfter())
                && !inst->isSerializeHandled()) {
         DPRINTF(FE, "Serialize after instruction encountered.\n");
@@ -565,13 +622,14 @@ FrontEnd<Impl>::handleFault(Fault &fault)
 
 //    instruction->setASID(tid);
 
-    instruction->setState(thread);
+    instruction->setThreadState(thread);
 
     instruction->traceData = NULL;
 
     instruction->fault = fault;
     instruction->setCanIssue();
     instBuffer.push_back(instruction);
+    numInstsReady[0]++;
     ++instBufferSize;
 }
 
@@ -601,6 +659,21 @@ FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC,
         freeRegs+= inst->numDestRegs();
     }
 
+    while (!feBuffer.empty() &&
+           feBuffer.back()->seqNum > squash_num) {
+        DynInstPtr inst = feBuffer.back();
+
+        DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n",
+                inst->seqNum, inst->readPC());
+
+        inst->clearDependents();
+
+        feBuffer.pop_back();
+        --instBufferSize;
+
+        freeRegs+= inst->numDestRegs();
+    }
+
     // Copy over rename table from the back end.
     renameTable.copyFrom(backEnd->renameTable);
 
@@ -614,16 +687,16 @@ FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC,
     }
 
     // Clear the icache miss if it's outstanding.
-    if (status == IcacheMissStall && icacheInterface) {
-        DPRINTF(FE, "Squashing outstanding Icache miss.\n");
+    if (status == IcacheWaitResponse) {
+        DPRINTF(FE, "Squashing outstanding Icache access.\n");
         memReq = NULL;
     }
-
+/*
     if (status == SerializeBlocked) {
         assert(barrierInst->seqNum > squash_num);
         barrierInst = NULL;
     }
-
+*/
     // Unless this squash originated from the front end, we're probably
     // in running mode now.
     // Actually might want to make this latency dependent.
@@ -635,13 +708,22 @@ template <class Impl>
 typename Impl::DynInstPtr
 FrontEnd<Impl>::getInst()
 {
-    if (instBufferSize == 0) {
+    if (feBuffer.empty()) {
         return NULL;
     }
 
-    DynInstPtr inst = instBuffer.front();
+    DynInstPtr inst = feBuffer.front();
+
+    if (inst->isSerializeBefore() || inst->isIprAccess()) {
+        DPRINTF(FE, "Back end is getting a serialize before inst\n");
+        if (!backEnd->robEmpty()) {
+            DPRINTF(FE, "Rob is not empty yet, not returning inst\n");
+            return NULL;
+        }
+        inst->clearSerializeBefore();
+    }
 
-    instBuffer.pop_front();
+    feBuffer.pop_front();
 
     --instBufferSize;
 
@@ -652,20 +734,22 @@ FrontEnd<Impl>::getInst()
 
 template <class Impl>
 void
-FrontEnd<Impl>::processCacheCompletion(MemReqPtr &req)
+FrontEnd<Impl>::processCacheCompletion(PacketPtr pkt)
 {
     DPRINTF(FE, "Processing cache completion\n");
 
     // Do something here.
-    if (status != IcacheMissStall ||
-        req != memReq ||
+    if (status != IcacheWaitResponse ||
+        pkt->req != memReq ||
         switchedOut) {
         DPRINTF(FE, "Previous fetch was squashed.\n");
         fetchIcacheSquashes++;
+        delete pkt->req;
+        delete pkt;
         return;
     }
 
-    status = IcacheMissComplete;
+    status = IcacheAccessComplete;
 
 /*    if (checkStall(tid)) {
         fetchStatus[tid] = Blocked;
@@ -677,6 +761,8 @@ FrontEnd<Impl>::processCacheCompletion(MemReqPtr &req)
 
     // Reset the completion event to NULL.
 //    memReq->completionEvent = NULL;
+    delete pkt->req;
+    delete pkt;
     memReq = NULL;
 }
 
@@ -697,6 +783,27 @@ FrontEnd<Impl>::addFreeRegs(int num_freed)
         freeRegs = numPhysRegs;
 }
 
+template <class Impl>
+void
+FrontEnd<Impl>::recvRetry()
+{
+    assert(cacheBlocked);
+    if (retryPkt != NULL) {
+        assert(status == IcacheWaitRetry);
+
+        if (icachePort.sendTiming(retryPkt)) {
+            status = IcacheWaitResponse;
+            retryPkt = NULL;
+            cacheBlocked = false;
+        }
+    } else {
+        // Access has been squashed since it was sent out.  Just clear
+        // the cache being blocked.
+        cacheBlocked = false;
+    }
+
+}
+
 template <class Impl>
 bool
 FrontEnd<Impl>::updateStatus()
@@ -711,11 +818,11 @@ FrontEnd<Impl>::updateStatus()
     }
 
     if (status == BEBlocked && !be_block) {
-        if (barrierInst) {
-            status = SerializeBlocked;
-        } else {
+//        if (barrierInst) {
+//            status = SerializeBlocked;
+//        } else {
             status = Running;
-        }
+//        }
         ret_val = true;
     }
     return ret_val;
@@ -737,6 +844,7 @@ template <class Impl>
 typename Impl::DynInstPtr
 FrontEnd<Impl>::getInstFromCacheline()
 {
+/*
     if (status == SerializeComplete) {
         DynInstPtr inst = barrierInst;
         status = Running;
@@ -744,7 +852,7 @@ FrontEnd<Impl>::getInstFromCacheline()
         inst->clearSerializeBefore();
         return inst;
     }
-
+*/
     InstSeqNum inst_seq;
     MachInst inst;
     // @todo: Fix this magic number used here to handle word offset (and
@@ -769,22 +877,26 @@ FrontEnd<Impl>::getInstFromCacheline()
     // Get the instruction from the array of the cache line.
     inst = htog(*reinterpret_cast<MachInst *>(&cacheData[offset]));
 
+#if THE_ISA == ALPHA_ISA
     ExtMachInst decode_inst = TheISA::makeExtMI(inst, PC);
+#elif THE_ISA == SPARC_ISA
+    ExtMachInst decode_inst = TheISA::makeExtMI(inst, tc);
+#endif
 
     // Create a new DynInst from the instruction fetched.
     DynInstPtr instruction = new DynInst(decode_inst, PC, PC+sizeof(MachInst),
                                          inst_seq, cpu);
 
-    instruction->setState(thread);
+    instruction->setThreadState(thread);
 
     DPRINTF(FE, "Instruction [sn:%lli] created, with PC %#x\n%s\n",
             inst_seq, instruction->readPC(),
             instruction->staticInst->disassemble(PC));
 
     instruction->traceData =
-        Trace::getInstRecord(curTick, tc, cpu,
+        Trace::getInstRecord(curTick, tc,
                              instruction->staticInst,
-                             instruction->readPC(), 0);
+                             instruction->readPC());
 
     // Increment stat of fetched instructions.
     ++fetchedInsts;
@@ -859,6 +971,7 @@ FrontEnd<Impl>::doSwitchOut()
     squash(0, 0);
     instBuffer.clear();
     instBufferSize = 0;
+    feBuffer.clear();
     status = Idle;
 }
 
@@ -899,24 +1012,3 @@ FrontEnd<Impl>::dumpInsts()
         buff_it++;
     }
 }
-
-template <class Impl>
-FrontEnd<Impl>::ICacheCompletionEvent::ICacheCompletionEvent(MemReqPtr &_req, FrontEnd *fe)
-    : Event(&mainEventQueue, Delayed_Writeback_Pri), req(_req), frontEnd(fe)
-{
-    this->setFlags(Event::AutoDelete);
-}
-
-template <class Impl>
-void
-FrontEnd<Impl>::ICacheCompletionEvent::process()
-{
-    frontEnd->processCacheCompletion(req);
-}
-
-template <class Impl>
-const char *
-FrontEnd<Impl>::ICacheCompletionEvent::description()
-{
-    return "ICache completion event";
-}