O3: Fix some variable length instruction issues with the O3 CPU and ARM ISA.

This commit is contained in:
Matt Horsnell 2011-01-18 16:30:05 -06:00
parent c98df6f8c2
commit b13a79ee71
3 changed files with 39 additions and 12 deletions

View file

@ -74,11 +74,15 @@ Predecoder::advanceThumbCond()
void void
Predecoder::process() Predecoder::process()
{ {
// emi is typically ready, with some caveats below...
emiReady = true;
if (!emi.thumb) { if (!emi.thumb) {
emi.instBits = data; emi.instBits = data;
emi.sevenAndFour = bits(data, 7) && bits(data, 4); emi.sevenAndFour = bits(data, 7) && bits(data, 4);
emi.isMisc = (bits(data, 24, 23) == 0x2 && emi.isMisc = (bits(data, 24, 23) == 0x2 &&
bits(data, 20) == 0); bits(data, 20) == 0);
consumeBytes(4);
DPRINTF(Predecoder, "Arm inst: %#x.\n", (uint64_t)emi); DPRINTF(Predecoder, "Arm inst: %#x.\n", (uint64_t)emi);
} else { } else {
uint16_t word = (data >> (offset * 8)); uint16_t word = (data >> (offset * 8));
@ -86,7 +90,7 @@ Predecoder::process()
// A 32 bit thumb inst is half collected. // A 32 bit thumb inst is half collected.
emi.instBits = emi.instBits | word; emi.instBits = emi.instBits | word;
bigThumb = false; bigThumb = false;
offset += 2; consumeBytes(2);
DPRINTF(Predecoder, "Second half of 32 bit Thumb: %#x.\n", DPRINTF(Predecoder, "Second half of 32 bit Thumb: %#x.\n",
emi.instBits); emi.instBits);
if (itstate.mask) { if (itstate.mask) {
@ -105,7 +109,7 @@ Predecoder::process()
emi.instBits = (data >> 16) | (data << 16); emi.instBits = (data >> 16) | (data << 16);
DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n", DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n",
emi.instBits); emi.instBits);
offset += 4; consumeBytes(4);
if (itstate.mask) { if (itstate.mask) {
emi.itstate = itstate; emi.itstate = itstate;
advanceThumbCond(); advanceThumbCond();
@ -117,11 +121,13 @@ Predecoder::process()
"First half of 32 bit Thumb.\n"); "First half of 32 bit Thumb.\n");
emi.instBits = (uint32_t)word << 16; emi.instBits = (uint32_t)word << 16;
bigThumb = true; bigThumb = true;
offset += 2; consumeBytes(2);
// emi not ready yet.
emiReady = false;
} }
} else { } else {
// A 16 bit thumb inst. // A 16 bit thumb inst.
offset += 2; consumeBytes(2);
emi.instBits = word; emi.instBits = word;
// Set the condition code field artificially. // Set the condition code field artificially.
emi.condCode = COND_UC; emi.condCode = COND_UC;
@ -159,6 +165,7 @@ Predecoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
itstate.top6 = cpsr.it2; itstate.top6 = cpsr.it2;
itstate.bottom2 = cpsr.it1; itstate.bottom2 = cpsr.it1;
outOfBytes = false;
process(); process();
} }

View file

@ -45,6 +45,8 @@
#ifndef __ARCH_ARM_PREDECODER_HH__ #ifndef __ARCH_ARM_PREDECODER_HH__
#define __ARCH_ARM_PREDECODER_HH__ #define __ARCH_ARM_PREDECODER_HH__
#include <cassert>
#include "arch/arm/types.hh" #include "arch/arm/types.hh"
#include "arch/arm/miscregs.hh" #include "arch/arm/miscregs.hh"
#include "base/types.hh" #include "base/types.hh"
@ -61,6 +63,8 @@ namespace ArmISA
ExtMachInst emi; ExtMachInst emi;
MachInst data; MachInst data;
bool bigThumb; bool bigThumb;
bool emiReady;
bool outOfBytes;
int offset; int offset;
ITSTATE itstate; ITSTATE itstate;
@ -70,6 +74,8 @@ namespace ArmISA
bigThumb = false; bigThumb = false;
offset = 0; offset = 0;
emi = 0; emi = 0;
emiReady = false;
outOfBytes = true;
} }
Predecoder(ThreadContext * _tc) : Predecoder(ThreadContext * _tc) :
@ -103,16 +109,22 @@ namespace ArmISA
moreBytes(0, 0, machInst); moreBytes(0, 0, machInst);
} }
inline void consumeBytes(int numBytes)
{
offset += numBytes;
assert(offset <= sizeof(MachInst));
if (offset == sizeof(MachInst))
outOfBytes = true;
}
bool needMoreBytes() bool needMoreBytes()
{ {
return sizeof(MachInst) > offset; return outOfBytes;
} }
bool extMachInstReady() bool extMachInstReady()
{ {
// The only way an instruction wouldn't be ready is if this is a return emiReady;
// 32 bit ARM instruction that's not 32 bit aligned.
return !bigThumb;
} }
int getInstSize() int getInstSize()
@ -123,9 +135,11 @@ namespace ArmISA
//This returns a constant reference to the ExtMachInst to avoid a copy //This returns a constant reference to the ExtMachInst to avoid a copy
ExtMachInst getExtMachInst(PCState &pc) ExtMachInst getExtMachInst(PCState &pc)
{ {
assert(emiReady);
ExtMachInst thisEmi = emi; ExtMachInst thisEmi = emi;
pc.npc(pc.pc() + getInstSize()); pc.npc(pc.pc() + getInstSize());
emi = 0; emi = 0;
emiReady = false;
return thisEmi; return thisEmi;
} }
}; };

View file

@ -384,7 +384,7 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
{ {
ThreadID tid = pkt->req->threadId(); 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()); assert(!pkt->wasNacked());
@ -1011,7 +1011,7 @@ DefaultFetch<Impl>::buildInst(ThreadID tid, StaticInstPtr staticInst,
instruction->setThreadState(cpu->thread[tid]); instruction->setThreadState(cpu->thread[tid]);
DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x (%d) created " DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x (%d) created "
"[sn:%lli]\n", tid, thisPC.instAddr(), "[sn:%lli].\n", tid, thisPC.instAddr(),
thisPC.microPC(), seq); thisPC.microPC(), seq);
DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", tid, DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", tid,
@ -1180,7 +1180,6 @@ DefaultFetch<Impl>::fetch(bool &status_change)
ExtMachInst extMachInst; ExtMachInst extMachInst;
extMachInst = predecoder.getExtMachInst(thisPC); extMachInst = predecoder.getExtMachInst(thisPC);
pcOffset = 0;
staticInst = StaticInstPtr(extMachInst, staticInst = StaticInstPtr(extMachInst,
thisPC.instAddr()); thisPC.instAddr());
@ -1188,7 +1187,12 @@ DefaultFetch<Impl>::fetch(bool &status_change)
++fetchedInsts; ++fetchedInsts;
if (staticInst->isMacroop()) if (staticInst->isMacroop())
{
curMacroop = staticInst; curMacroop = staticInst;
}
else {
pcOffset = 0;
}
} else { } else {
// We need more bytes for this instruction. // We need more bytes for this instruction.
break; break;
@ -1196,8 +1200,10 @@ DefaultFetch<Impl>::fetch(bool &status_change)
} }
if (curMacroop) { if (curMacroop) {
staticInst = curMacroop->fetchMicroop(thisPC.microPC()); staticInst = curMacroop->fetchMicroop(thisPC.microPC());
if (staticInst->isLastMicroop()) if (staticInst->isLastMicroop()) {
curMacroop = NULL; curMacroop = NULL;
pcOffset = 0;
}
} }
DynInstPtr instruction = DynInstPtr instruction =