Merge zizzer.eecs.umich.edu:/z/m5/Bitkeeper/newmem
[gem5.git] / src / cpu / o3 / fetch_impl.hh
index 1256dd2333b9083e613b0963162bc854a3f6cbc8..3ae7bc4020c47bc205de40828d960aa70033d872 100644 (file)
 
 #include <algorithm>
 
+template<class Impl>
+void
+DefaultFetch<Impl>::IcachePort::setPeer(Port *port)
+{
+    Port::setPeer(port);
+
+    fetch->setIcache();
+}
+
 template<class Impl>
 Tick
 DefaultFetch<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
@@ -101,8 +110,9 @@ DefaultFetch<Impl>::IcachePort::recvRetry()
 }
 
 template<class Impl>
-DefaultFetch<Impl>::DefaultFetch(Params *params)
-    : branchPred(params),
+DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
+    : cpu(_cpu),
+      branchPred(params),
       predecoder(NULL),
       decodeToFetchDelay(params->decodeToFetchDelay),
       renameToFetchDelay(params->renameToFetchDelay),
@@ -154,6 +164,17 @@ DefaultFetch<Impl>::DefaultFetch(Params *params)
 
     // Get the size of an instruction.
     instSize = sizeof(TheISA::MachInst);
+
+    // Name is finally available, so create the port.
+    icachePort = new IcachePort(this);
+
+    icachePort->snoopRangeSent = false;
+
+#if USE_CHECKER
+    if (cpu->checker) {
+        cpu->checker->setIcachePort(icachePort);
+    }
+#endif
 }
 
 template <class Impl>
@@ -253,37 +274,10 @@ DefaultFetch<Impl>::regStats()
     branchPred.regStats();
 }
 
-template<class Impl>
-void
-DefaultFetch<Impl>::setCPU(O3CPU *cpu_ptr)
-{
-    DPRINTF(Fetch, "Setting the CPU pointer.\n");
-    cpu = cpu_ptr;
-
-    // Name is finally available, so create the port.
-    icachePort = new IcachePort(this);
-
-    icachePort->snoopRangeSent = false;
-
-#if USE_CHECKER
-    if (cpu->checker) {
-        cpu->checker->setIcachePort(icachePort);
-    }
-#endif
-
-    // Schedule fetch to get the correct PC from the CPU
-    // scheduleFetchStartupEvent(1);
-
-    // Fetch needs to start fetching instructions at the very beginning,
-    // so it must start up in active state.
-    switchToActive();
-}
-
 template<class Impl>
 void
 DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
 {
-    DPRINTF(Fetch, "Setting the time buffer pointer.\n");
     timeBuffer = time_buffer;
 
     // Create wires to get information from proper places in time buffer.
@@ -297,7 +291,6 @@ template<class Impl>
 void
 DefaultFetch<Impl>::setActiveThreads(std::list<unsigned> *at_ptr)
 {
-    DPRINTF(Fetch, "Setting active threads list pointer.\n");
     activeThreads = at_ptr;
 }
 
@@ -305,7 +298,6 @@ template<class Impl>
 void
 DefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
 {
-    DPRINTF(Fetch, "Setting the fetch queue pointer.\n");
     fetchQueue = fq_ptr;
 
     // Create wire to write information to proper place in fetch queue.
@@ -320,15 +312,9 @@ DefaultFetch<Impl>::initStage()
     for (int tid = 0; tid < numThreads; tid++) {
         PC[tid] = cpu->readPC(tid);
         nextPC[tid] = cpu->readNextPC(tid);
-        nextNPC[tid] = cpu->readNextNPC(tid);
+        microPC[tid] = cpu->readMicroPC(tid);
     }
 
-    // Size of cache block.
-    cacheBlkSize = icachePort->peerBlockSize();
-
-    // Create mask to get rid of offset bits.
-    cacheBlkMask = (cacheBlkSize - 1);
-
     for (int tid=0; tid < numThreads; tid++) {
 
         fetchStatus[tid] = Running;
@@ -337,16 +323,36 @@ DefaultFetch<Impl>::initStage()
 
         memReq[tid] = NULL;
 
-        // Create space to store a cache line.
-        cacheData[tid] = new uint8_t[cacheBlkSize];
-        cacheDataPC[tid] = 0;
-        cacheDataValid[tid] = false;
-
         stalls[tid].decode = false;
         stalls[tid].rename = false;
         stalls[tid].iew = false;
         stalls[tid].commit = false;
     }
+
+    // Schedule fetch to get the correct PC from the CPU
+    // scheduleFetchStartupEvent(1);
+
+    // Fetch needs to start fetching instructions at the very beginning,
+    // so it must start up in active state.
+    switchToActive();
+}
+
+template<class Impl>
+void
+DefaultFetch<Impl>::setIcache()
+{
+    // Size of cache block.
+    cacheBlkSize = icachePort->peerBlockSize();
+
+    // Create mask to get rid of offset bits.
+    cacheBlkMask = (cacheBlkSize - 1);
+
+    for (int tid=0; tid < numThreads; tid++) {
+        // Create space to store a cache line.
+        cacheData[tid] = new uint8_t[cacheBlkSize];
+        cacheDataPC[tid] = 0;
+        cacheDataValid[tid] = false;
+    }
 }
 
 template<class Impl>
@@ -433,11 +439,7 @@ DefaultFetch<Impl>::takeOverFrom()
         stalls[i].commit = 0;
         PC[i] = cpu->readPC(i);
         nextPC[i] = cpu->readNextPC(i);
-#if ISA_HAS_DELAY_SLOT
-        nextNPC[i] = cpu->readNextNPC(i);
-#else
-        nextNPC[i] = nextPC[i] + sizeof(TheISA::MachInst);
-#endif
+        microPC[i] = cpu->readMicroPC(i);
         fetchStatus[i] = Running;
     }
     numInst = 0;
@@ -487,7 +489,7 @@ DefaultFetch<Impl>::switchToInactive()
 template <class Impl>
 bool
 DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,
-                                          Addr &next_NPC)
+                                          Addr &next_NPC, Addr &next_MicroPC)
 {
     // Do branch prediction check here.
     // A bit of a misnomer...next_PC is actually the current PC until
@@ -495,13 +497,22 @@ DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,
     bool predict_taken;
 
     if (!inst->isControl()) {
-        next_PC  = next_NPC;
-        next_NPC = next_NPC + instSize;
-        inst->setPredTarg(next_PC, next_NPC);
+        if (inst->isMicroOp() && !inst->isLastMicroOp()) {
+            next_MicroPC++;
+        } else {
+            next_PC  = next_NPC;
+            next_NPC = next_NPC + instSize;
+            next_MicroPC = 0;
+        }
+        inst->setPredTarg(next_PC, next_NPC, next_MicroPC);
         inst->setPredTaken(false);
         return false;
     }
 
+    //Assume for now that all control flow is to a different macroop which
+    //would reset the micro pc to 0.
+    next_MicroPC = 0;
+
     int tid = inst->threadNumber;
     Addr pred_PC = next_PC;
     predict_taken = branchPred.predict(inst, pred_PC, tid);
@@ -528,7 +539,7 @@ DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC,
 #endif
 /*    DPRINTF(Fetch, "[tid:%i]: Branch predicted to go to %#x and then %#x.\n",
             tid, next_PC, next_NPC);*/
-    inst->setPredTarg(next_PC, next_NPC);
+    inst->setPredTarg(next_PC, next_NPC, next_MicroPC);
     inst->setPredTaken(predict_taken);
 
     ++fetchedBranches;
@@ -620,6 +631,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
                 fault = TheISA::genMachineCheckFault();
                 delete mem_req;
                 memReq[tid] = NULL;
+                warn("Bad address!\n");
             }
             assert(retryPkt == NULL);
             assert(retryTid == -1);
@@ -651,14 +663,14 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
 template <class Impl>
 inline void
 DefaultFetch<Impl>::doSquash(const Addr &new_PC,
-        const Addr &new_NPC, unsigned tid)
+        const Addr &new_NPC, const Addr &new_microPC, unsigned tid)
 {
     DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x, NPC to: %#x.\n",
             tid, new_PC, new_NPC);
 
     PC[tid] = new_PC;
     nextPC[tid] = new_NPC;
-    nextNPC[tid] = new_NPC + instSize;
+    microPC[tid] = new_microPC;
 
     // Clear the icache miss if it's outstanding.
     if (fetchStatus[tid] == IcacheWaitResponse) {
@@ -670,11 +682,12 @@ DefaultFetch<Impl>::doSquash(const Addr &new_PC,
     // Get rid of the retrying packet if it was from this thread.
     if (retryTid == tid) {
         assert(cacheBlocked);
-        cacheBlocked = false;
-        retryTid = -1;
-        delete retryPkt->req;
-        delete retryPkt;
+        if (retryPkt) {
+            delete retryPkt->req;
+            delete retryPkt;
+        }
         retryPkt = NULL;
+        retryTid = -1;
     }
 
     fetchStatus[tid] = Squashing;
@@ -685,12 +698,12 @@ DefaultFetch<Impl>::doSquash(const Addr &new_PC,
 template<class Impl>
 void
 DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, const Addr &new_NPC,
-                                     const InstSeqNum &seq_num,
-                                     unsigned tid)
+                                     const Addr &new_MicroPC,
+                                     const InstSeqNum &seq_num, unsigned tid)
 {
     DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);
 
-    doSquash(new_PC, new_NPC, tid);
+    doSquash(new_PC, new_NPC, new_MicroPC, tid);
 
     // Tell the CPU to remove any instructions that are in flight between
     // fetch and decode.
@@ -766,20 +779,15 @@ DefaultFetch<Impl>::updateFetchStatus()
 template <class Impl>
 void
 DefaultFetch<Impl>::squash(const Addr &new_PC, const Addr &new_NPC,
-                           const InstSeqNum &seq_num,
-                           bool squash_delay_slot, unsigned tid)
+                           const Addr &new_MicroPC,
+                           const InstSeqNum &seq_num, unsigned tid)
 {
     DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);
 
-    doSquash(new_PC, new_NPC, tid);
+    doSquash(new_PC, new_NPC, new_MicroPC, tid);
 
-#if ISA_HAS_DELAY_SLOT
     // Tell the CPU to remove any instructions that are not in the ROB.
-    cpu->removeInstsNotInROB(tid, squash_delay_slot, seq_num);
-#else
-    // Tell the CPU to remove any instructions that are not in the ROB.
-    cpu->removeInstsNotInROB(tid, true, 0);
-#endif
+    cpu->removeInstsNotInROB(tid);
 }
 
 template <class Impl>
@@ -888,17 +896,11 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
 
         DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
                 "from commit.\n",tid);
-
-#if ISA_HAS_DELAY_SLOT
-    InstSeqNum doneSeqNum = fromCommit->commitInfo[tid].bdelayDoneSeqNum;
-#else
-    InstSeqNum doneSeqNum = fromCommit->commitInfo[tid].doneSeqNum;
-#endif
         // In any case, squash.
         squash(fromCommit->commitInfo[tid].nextPC,
                fromCommit->commitInfo[tid].nextNPC,
-               doneSeqNum,
-               fromCommit->commitInfo[tid].squashDelaySlot,
+               fromCommit->commitInfo[tid].nextMicroPC,
+               fromCommit->commitInfo[tid].doneSeqNum,
                tid);
 
         // Also check if there's a mispredict that happened.
@@ -947,18 +949,14 @@ DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
 
         if (fetchStatus[tid] != Squashing) {
 
-#if ISA_HAS_DELAY_SLOT
-            InstSeqNum doneSeqNum = fromDecode->decodeInfo[tid].bdelayDoneSeqNum;
-#else
-            InstSeqNum doneSeqNum = fromDecode->decodeInfo[tid].doneSeqNum;
-#endif
             DPRINTF(Fetch, "Squashing from decode with PC = %#x, NPC = %#x\n",
                     fromDecode->decodeInfo[tid].nextPC,
                     fromDecode->decodeInfo[tid].nextNPC);
             // Squash unless we're already squashing
             squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
                              fromDecode->decodeInfo[tid].nextNPC,
-                             doneSeqNum,
+                             fromDecode->decodeInfo[tid].nextMicroPC,
+                             fromDecode->decodeInfo[tid].doneSeqNum,
                              tid);
 
             return true;
@@ -1012,9 +1010,9 @@ DefaultFetch<Impl>::fetch(bool &status_change)
     DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);
 
     // The current PC.
-    Addr &fetch_PC = PC[tid];
-
-    Addr &fetch_NPC = nextPC[tid];
+    Addr fetch_PC = PC[tid];
+    Addr fetch_NPC = nextPC[tid];
+    Addr fetch_MicroPC = microPC[tid];
 
     // Fault code for memory access.
     Fault fault = NoFault;
@@ -1073,6 +1071,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
 
     Addr next_PC = fetch_PC;
     Addr next_NPC = fetch_NPC;
+    Addr next_MicroPC = fetch_MicroPC;
 
     InstSeqNum inst_seq;
     MachInst inst;
@@ -1080,6 +1079,9 @@ DefaultFetch<Impl>::fetch(bool &status_change)
     // @todo: Fix this hack.
     unsigned offset = (fetch_PC & cacheBlkMask) & ~3;
 
+    StaticInstPtr staticInst = NULL;
+    StaticInstPtr macroop = NULL;
+
     if (fault == NoFault) {
         // If the read of the first instruction was successful, then grab the
         // instructions from the rest of the cache line and put them into the
@@ -1092,11 +1094,9 @@ DefaultFetch<Impl>::fetch(bool &status_change)
         // ended this fetch block.
         bool predicted_branch = false;
 
-        for (;
-             offset < cacheBlkSize &&
-                 numInst < fetchWidth &&
-                 !predicted_branch;
-             ++numInst) {
+        while (offset < cacheBlkSize &&
+               numInst < fetchWidth &&
+               !predicted_branch) {
 
             // If we're branching after this instruction, quite fetching
             // from the same block then.
@@ -1107,91 +1107,103 @@ DefaultFetch<Impl>::fetch(bool &status_change)
                         fetch_PC, fetch_NPC);
             }
 
-
-            // Get a sequence number.
-            inst_seq = cpu->getAndIncrementInstSeq();
-
             // Make sure this is a valid index.
             assert(offset <= cacheBlkSize - instSize);
 
-            // Get the instruction from the array of the cache line.
-            inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
-                        (&cacheData[tid][offset]));
+            if (!macroop) {
+                // Get the instruction from the array of the cache line.
+                inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
+                            (&cacheData[tid][offset]));
 
-            predecoder.setTC(cpu->thread[tid]->getTC());
-            predecoder.moreBytes(fetch_PC, 0, inst);
+                predecoder.setTC(cpu->thread[tid]->getTC());
+                predecoder.moreBytes(fetch_PC, 0, inst);
 
-            ext_inst = predecoder.getExtMachInst();
+                ext_inst = predecoder.getExtMachInst();
+                staticInst = StaticInstPtr(ext_inst);
+                if (staticInst->isMacroOp())
+                    macroop = staticInst;
+            }
+            do {
+                if (macroop) {
+                    staticInst = macroop->fetchMicroOp(fetch_MicroPC);
+                    if (staticInst->isLastMicroOp())
+                        macroop = NULL;
+                }
 
-            // Create a new DynInst from the instruction fetched.
-            DynInstPtr instruction = new DynInst(ext_inst,
-                                                 fetch_PC, fetch_NPC,
-                                                 next_PC, next_NPC,
-                                                 inst_seq, cpu);
-            instruction->setTid(tid);
+                // Get a sequence number.
+                inst_seq = cpu->getAndIncrementInstSeq();
 
-            instruction->setASID(tid);
+                // Create a new DynInst from the instruction fetched.
+                DynInstPtr instruction = new DynInst(staticInst,
+                                                     fetch_PC, fetch_NPC, fetch_MicroPC,
+                                                     next_PC, next_NPC, next_MicroPC,
+                                                     inst_seq, cpu);
+                instruction->setTid(tid);
 
-            instruction->setThreadState(cpu->thread[tid]);
+                instruction->setASID(tid);
 
-            DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created "
-                    "[sn:%lli]\n",
-                    tid, instruction->readPC(), inst_seq);
+                instruction->setThreadState(cpu->thread[tid]);
 
-            //DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst);
+                DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created "
+                        "[sn:%lli]\n",
+                        tid, instruction->readPC(), inst_seq);
 
-            DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
-                    tid, instruction->staticInst->disassemble(fetch_PC));
+                //DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst);
 
-            instruction->traceData =
-                Trace::getInstRecord(curTick, cpu->tcBase(tid),
-                                     instruction->staticInst,
-                                     instruction->readPC());
+                DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
+                        tid, instruction->staticInst->disassemble(fetch_PC));
 
-            ///FIXME This needs to be more robust in dealing with delay slots
-#if !ISA_HAS_DELAY_SLOT
-            predicted_branch |=
-#endif
-            lookupAndUpdateNextPC(instruction, next_PC, next_NPC);
-            predicted_branch |= (next_PC != fetch_NPC);
+                instruction->traceData =
+                    Trace::getInstRecord(curTick, cpu->tcBase(tid),
+                                         instruction->staticInst,
+                                         instruction->readPC());
 
-            // Add instruction to the CPU's list of instructions.
-            instruction->setInstListIt(cpu->addInst(instruction));
+                ///FIXME This needs to be more robust in dealing with delay slots
+                predicted_branch |=
+                    lookupAndUpdateNextPC(instruction, next_PC, next_NPC, next_MicroPC);
 
-            // Write the instruction to the first slot in the queue
-            // that heads to decode.
-            toDecode->insts[numInst] = instruction;
+                // Add instruction to the CPU's list of instructions.
+                instruction->setInstListIt(cpu->addInst(instruction));
 
-            toDecode->size++;
+                // Write the instruction to the first slot in the queue
+                // that heads to decode.
+                toDecode->insts[numInst] = instruction;
 
-            // Increment stat of fetched instructions.
-            ++fetchedInsts;
+                toDecode->size++;
 
-            // Move to the next instruction, unless we have a branch.
-            fetch_PC = next_PC;
-            fetch_NPC = next_NPC;
+                // Increment stat of fetched instructions.
+                ++fetchedInsts;
 
-            if (instruction->isQuiesce()) {
-                DPRINTF(Fetch, "Quiesce instruction encountered, halting fetch!",
-                        curTick);
-                fetchStatus[tid] = QuiescePending;
-                ++numInst;
-                status_change = true;
-                break;
-            }
+                // Move to the next instruction, unless we have a branch.
+                fetch_PC = next_PC;
+                fetch_NPC = next_NPC;
+                fetch_MicroPC = next_MicroPC;
 
+                if (instruction->isQuiesce()) {
+                    DPRINTF(Fetch, "Quiesce instruction encountered, halting fetch!",
+                            curTick);
+                    fetchStatus[tid] = QuiescePending;
+                    ++numInst;
+                    status_change = true;
+                    break;
+                }
+
+                ++numInst;
+            } while (staticInst->isMicroOp() &&
+                     !staticInst->isLastMicroOp() &&
+                     numInst < fetchWidth);
             offset += instSize;
         }
 
-        if (offset >= cacheBlkSize) {
-            DPRINTF(Fetch, "[tid:%i]: Done fetching, reached the end of cache "
-                    "block.\n", tid);
+        if (predicted_branch) {
+            DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "
+                    "instruction encountered.\n", tid);
         } else if (numInst >= fetchWidth) {
             DPRINTF(Fetch, "[tid:%i]: Done fetching, reached fetch bandwidth "
                     "for this cycle.\n", tid);
-        } else if (predicted_branch) {
-            DPRINTF(Fetch, "[tid:%i]: Done fetching, predicted branch "
-                    "instruction encountered.\n", tid);
+        } else if (offset >= cacheBlkSize) {
+            DPRINTF(Fetch, "[tid:%i]: Done fetching, reached the end of cache "
+                    "block.\n", tid);
         }
     }
 
@@ -1204,12 +1216,8 @@ DefaultFetch<Impl>::fetch(bool &status_change)
     if (fault == NoFault) {
         PC[tid] = next_PC;
         nextPC[tid] = next_NPC;
-        nextNPC[tid] = next_NPC + instSize;
-#if ISA_HAS_DELAY_SLOT
-        DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n", tid, PC[tid]);
-#else
+        microPC[tid] = next_MicroPC;
         DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n", tid, next_PC);
-#endif
     } else {
         // We shouldn't be in an icache miss and also have a fault (an ITB
         // miss)
@@ -1221,14 +1229,15 @@ DefaultFetch<Impl>::fetch(bool &status_change)
         // until commit handles the fault.  The only other way it can
         // wake up is if a squash comes along and changes the PC.
 #if FULL_SYSTEM
-        assert(numInst != fetchWidth);
+        assert(numInst < fetchWidth);
         // Get a sequence number.
         inst_seq = cpu->getAndIncrementInstSeq();
         // We will use a nop in order to carry the fault.
         ext_inst = TheISA::NoopMachInst;
 
+        StaticInstPtr staticInst = new StaticInst(ext_inst);
         // Create a new DynInst from the dummy nop.
-        DynInstPtr instruction = new DynInst(ext_inst,
+        DynInstPtr instruction = new DynInst(staticInst,
                                              fetch_PC, fetch_NPC,
                                              next_PC, next_NPC,
                                              inst_seq, cpu);