summaryrefslogtreecommitdiff
path: root/src/arch/arm
diff options
context:
space:
mode:
authorMatt Horsnell <Matt.Horsnell@arm.com>2011-01-18 16:30:05 -0600
committerMatt Horsnell <Matt.Horsnell@arm.com>2011-01-18 16:30:05 -0600
commitb13a79ee717b876e4bc837ba95985abd4d18162f (patch)
treecc11aa8c68e1a22854f2201bf6073e69db88e84e /src/arch/arm
parentc98df6f8c2f3a3685fd9210ccaee2fac07e4f604 (diff)
downloadgem5-b13a79ee717b876e4bc837ba95985abd4d18162f.tar.xz
O3: Fix some variable length instruction issues with the O3 CPU and ARM ISA.
Diffstat (limited to 'src/arch/arm')
-rw-r--r--src/arch/arm/predecoder.cc15
-rw-r--r--src/arch/arm/predecoder.hh22
2 files changed, 29 insertions, 8 deletions
diff --git a/src/arch/arm/predecoder.cc b/src/arch/arm/predecoder.cc
index 456b9e4c4..71d399e35 100644
--- a/src/arch/arm/predecoder.cc
+++ b/src/arch/arm/predecoder.cc
@@ -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();
}
diff --git a/src/arch/arm/predecoder.hh b/src/arch/arm/predecoder.hh
index 47242b8ff..92aab6e30 100644
--- a/src/arch/arm/predecoder.hh
+++ b/src/arch/arm/predecoder.hh
@@ -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;
}
};