O3: Fix some variable length instruction issues with the O3 CPU and ARM ISA.
authorMatt Horsnell <Matt.Horsnell@arm.com>
Tue, 18 Jan 2011 22:30:05 +0000 (16:30 -0600)
committerMatt Horsnell <Matt.Horsnell@arm.com>
Tue, 18 Jan 2011 22:30:05 +0000 (16:30 -0600)
src/arch/arm/predecoder.cc
src/arch/arm/predecoder.hh
src/cpu/o3/fetch_impl.hh

index 456b9e4c4ea5b6f1535557e1adf1b96cc70fd4c2..71d399e358d6b54fd57fe928e2f4cf6d9411c2f2 100644 (file)
@@ -74,11 +74,15 @@ Predecoder::advanceThumbCond()
 void
 Predecoder::process()
 {
+    // emi is typically ready, with some caveats below...
+    emiReady = true;
+
     if (!emi.thumb) {
         emi.instBits = data;
         emi.sevenAndFour = bits(data, 7) && bits(data, 4);
         emi.isMisc = (bits(data, 24, 23) == 0x2 &&
                       bits(data, 20) == 0);
+        consumeBytes(4);
         DPRINTF(Predecoder, "Arm inst: %#x.\n", (uint64_t)emi);
     } else {
         uint16_t word = (data >> (offset * 8));
@@ -86,7 +90,7 @@ Predecoder::process()
             // A 32 bit thumb inst is half collected.
             emi.instBits = emi.instBits | word;
             bigThumb = false;
-            offset += 2;
+            consumeBytes(2);
             DPRINTF(Predecoder, "Second half of 32 bit Thumb: %#x.\n",
                     emi.instBits);
             if (itstate.mask) {
@@ -105,7 +109,7 @@ Predecoder::process()
                     emi.instBits = (data >> 16) | (data << 16);
                     DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n",
                             emi.instBits);
-                    offset += 4;
+                    consumeBytes(4);
                     if (itstate.mask) {
                         emi.itstate = itstate;
                         advanceThumbCond();
@@ -117,11 +121,13 @@ Predecoder::process()
                             "First half of 32 bit Thumb.\n");
                     emi.instBits = (uint32_t)word << 16;
                     bigThumb = true;
-                    offset += 2;
+                    consumeBytes(2);
+                    // emi not ready yet.
+                    emiReady = false;
                 }
             } else {
                 // A 16 bit thumb inst.
-                offset += 2;
+                consumeBytes(2);
                 emi.instBits = word;
                 // Set the condition code field artificially.
                 emi.condCode = COND_UC;
@@ -159,6 +165,7 @@ Predecoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
     CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
     itstate.top6 = cpsr.it2;
     itstate.bottom2 = cpsr.it1;
+    outOfBytes = false;
     process();
 }
 
index 47242b8fff4aa9338155aaaa2741168d607c9f42..92aab6e304aba7d650f9dfaa58c13b0887a91bd7 100644 (file)
@@ -45,6 +45,8 @@
 #ifndef __ARCH_ARM_PREDECODER_HH__
 #define __ARCH_ARM_PREDECODER_HH__
 
+#include <cassert>
+
 #include "arch/arm/types.hh"
 #include "arch/arm/miscregs.hh"
 #include "base/types.hh"
@@ -61,6 +63,8 @@ namespace ArmISA
         ExtMachInst emi;
         MachInst data;
         bool bigThumb;
+        bool emiReady;
+        bool outOfBytes;
         int offset;
         ITSTATE itstate;
 
@@ -70,6 +74,8 @@ namespace ArmISA
             bigThumb = false;
             offset = 0;
             emi = 0;
+            emiReady = false;
+            outOfBytes = true;
         }
 
         Predecoder(ThreadContext * _tc) :
@@ -103,16 +109,22 @@ namespace ArmISA
             moreBytes(0, 0, machInst);
         }
 
+        inline void consumeBytes(int numBytes)
+        {
+            offset += numBytes;
+            assert(offset <= sizeof(MachInst));
+            if (offset == sizeof(MachInst))
+                outOfBytes = true;
+        }
+
         bool needMoreBytes()
         {
-            return sizeof(MachInst) > offset;
+            return outOfBytes;
         }
 
         bool extMachInstReady()
         {
-            // The only way an instruction wouldn't be ready is if this is a
-            // 32 bit ARM instruction that's not 32 bit aligned.
-            return !bigThumb;
+            return emiReady;
         }
 
         int getInstSize()
@@ -123,9 +135,11 @@ namespace ArmISA
         //This returns a constant reference to the ExtMachInst to avoid a copy
         ExtMachInst getExtMachInst(PCState &pc)
         {
+            assert(emiReady);
             ExtMachInst thisEmi = emi;
             pc.npc(pc.pc() + getInstSize());
             emi = 0;
+            emiReady = false;
             return thisEmi;
         }
     };
index 736a66c64839fa1e445d0acf159198c863bf01fb..927af42c3a938f83fc95548ba5da0899d50c90c3 100644 (file)
@@ -384,7 +384,7 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
 {
     ThreadID tid = pkt->req->threadId();
 
-    DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
+    DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n", tid);
 
     assert(!pkt->wasNacked());
 
@@ -1011,7 +1011,7 @@ DefaultFetch<Impl>::buildInst(ThreadID tid, StaticInstPtr staticInst,
     instruction->setThreadState(cpu->thread[tid]);
 
     DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x (%d) created "
-            "[sn:%lli]\n", tid, thisPC.instAddr(),
+            "[sn:%lli].\n", tid, thisPC.instAddr(),
             thisPC.microPC(), seq);
 
     DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", tid,
@@ -1180,7 +1180,6 @@ DefaultFetch<Impl>::fetch(bool &status_change)
                     ExtMachInst extMachInst;
 
                     extMachInst = predecoder.getExtMachInst(thisPC);
-                    pcOffset = 0;
                     staticInst = StaticInstPtr(extMachInst,
                                                thisPC.instAddr());
 
@@ -1188,7 +1187,12 @@ DefaultFetch<Impl>::fetch(bool &status_change)
                     ++fetchedInsts;
 
                     if (staticInst->isMacroop())
+                    {
                         curMacroop = staticInst;
+                    }
+                    else {
+                        pcOffset = 0;
+                    }
                 } else {
                     // We need more bytes for this instruction.
                     break;
@@ -1196,8 +1200,10 @@ DefaultFetch<Impl>::fetch(bool &status_change)
             }
             if (curMacroop) {
                 staticInst = curMacroop->fetchMicroop(thisPC.microPC());
-                if (staticInst->isLastMicroop())
+                if (staticInst->isLastMicroop()) {
                     curMacroop = NULL;
+                    pcOffset = 0;
+                }
             }
 
             DynInstPtr instruction =