ARM: Cleanup implementation of ITSTATE and put important code in PCState.

Consolidate all code to handle ITSTATE in the PCState object rather than
touching a variety of structures/objects.
This commit is contained in:
Ali Saidi 2011-04-04 11:42:28 -05:00
parent ac650199ee
commit a679cd917a
21 changed files with 81 additions and 277 deletions

View file

@ -76,12 +76,6 @@ class Predecoder
emiIsReady = false; emiIsReady = false;
} }
void
reset(const ExtMachInst &old_emi)
{
reset();
}
// Use this to give data to the predecoder. This should be used // Use this to give data to the predecoder. This should be used
// when there is control flow. // when there is control flow.
void void

View file

@ -108,7 +108,9 @@ ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
CPSR saved_cpsr = tc->readMiscReg(MISCREG_CPSR) | CPSR saved_cpsr = tc->readMiscReg(MISCREG_CPSR) |
tc->readIntReg(INTREG_CONDCODES); tc->readIntReg(INTREG_CONDCODES);
Addr curPc M5_VAR_USED = tc->pcState().pc(); Addr curPc M5_VAR_USED = tc->pcState().pc();
ITSTATE it = tc->pcState().itstate();
saved_cpsr.it2 = it.top6;
saved_cpsr.it1 = it.bottom2;
cpsr.mode = nextMode(); cpsr.mode = nextMode();
cpsr.it1 = cpsr.it2 = 0; cpsr.it1 = cpsr.it2 = 0;
@ -159,7 +161,7 @@ Reset::invoke(ThreadContext *tc, StaticInstPtr inst)
{ {
tc->getCpuPtr()->clearInterrupts(); tc->getCpuPtr()->clearInterrupts();
tc->clearArchRegs(); tc->clearArchRegs();
ArmFault::invoke(tc); ArmFault::invoke(tc, inst);
} }
#else #else
@ -203,7 +205,7 @@ template<class T>
void void
AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst) AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst)
{ {
ArmFaultVals<T>::invoke(tc); ArmFaultVals<T>::invoke(tc, inst);
FSR fsr = 0; FSR fsr = 0;
fsr.fsLow = bits(status, 3, 0); fsr.fsLow = bits(status, 3, 0);
fsr.fsHigh = bits(status, 4); fsr.fsHigh = bits(status, 4);
@ -223,7 +225,6 @@ FlushPipe::invoke(ThreadContext *tc, StaticInstPtr inst) {
// start refetching from the next instruction. // start refetching from the next instruction.
PCState pc = tc->pcState(); PCState pc = tc->pcState();
assert(inst); assert(inst);
pc.forcedItState(inst->machInst.newItstate);
inst->advancePC(pc); inst->advancePC(pc);
tc->pcState(pc); tc->pcState(pc);
} }

View file

@ -266,18 +266,6 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
miscRegName[misc_reg], val); miscRegName[misc_reg], val);
} else { } else {
switch (misc_reg) { switch (misc_reg) {
case MISCREG_ITSTATE:
{
ITSTATE itstate = newVal;
CPSR cpsr = miscRegs[MISCREG_CPSR];
cpsr.it1 = itstate.bottom2;
cpsr.it2 = itstate.top6;
miscRegs[MISCREG_CPSR] = cpsr;
DPRINTF(MiscRegs,
"Updating ITSTATE -> %#x in CPSR -> %#x.\n",
(uint8_t)itstate, (uint32_t)cpsr);
}
break;
case MISCREG_CPACR: case MISCREG_CPACR:
{ {
CPACR newCpacr = 0; CPACR newCpacr = 0;

View file

@ -245,7 +245,7 @@ let {{
CondCodes = CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr;
NextThumb = ((CPSR)newCpsr).t; NextThumb = ((CPSR)newCpsr).t;
NextJazelle = ((CPSR)newCpsr).j; NextJazelle = ((CPSR)newCpsr).j;
ForcedItState = ((((CPSR)newCpsr).it2 << 2) & 0xFC) NextItState = ((((CPSR)newCpsr).it2 << 2) & 0xFC)
| (((CPSR)newCpsr).it1 & 0x3); | (((CPSR)newCpsr).it1 & 0x3);
''' '''
buildImmDataInst(mnem + 's', code, flagType, buildImmDataInst(mnem + 's', code, flagType,

View file

@ -94,7 +94,7 @@ let {{
Cpsr = ~CondCodesMask & newCpsr; Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr;
IWNPC = cSwap(%s, cpsr.e) | ((Spsr & 0x20) ? 1 : 0); IWNPC = cSwap(%s, cpsr.e) | ((Spsr & 0x20) ? 1 : 0);
ForcedItState = ((((CPSR)Spsr).it2 << 2) & 0xFC) NextItState = ((((CPSR)Spsr).it2 << 2) & 0xFC)
| (((CPSR)Spsr).it1 & 0x3); | (((CPSR)Spsr).it1 & 0x3);
''' '''
@ -628,7 +628,7 @@ let {{
Cpsr = ~CondCodesMask & newCpsr; Cpsr = ~CondCodesMask & newCpsr;
NextThumb = ((CPSR)newCpsr).t; NextThumb = ((CPSR)newCpsr).t;
NextJazelle = ((CPSR)newCpsr).j; NextJazelle = ((CPSR)newCpsr).j;
ForcedItState = ((((CPSR)URb).it2 << 2) & 0xFC) NextItState = ((((CPSR)URb).it2 << 2) & 0xFC)
| (((CPSR)URb).it1 & 0x3); | (((CPSR)URb).it1 & 0x3);
CondCodes = CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr;
''' '''

View file

@ -83,10 +83,6 @@ let {{
uint32_t newCpsr = uint32_t newCpsr =
cpsrWriteByInstr(Cpsr | CondCodes, Op1, byteMask, false, sctlr.nmfi); cpsrWriteByInstr(Cpsr | CondCodes, Op1, byteMask, false, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr; Cpsr = ~CondCodesMask & newCpsr;
NextThumb = ((CPSR)newCpsr).t;
NextJazelle = ((CPSR)newCpsr).j;
ForcedItState = ((((CPSR)Op1).it2 << 2) & 0xFC)
| (((CPSR)Op1).it1 & 0x3);
CondCodes = CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr;
''' '''
msrCpsrRegIop = InstObjParams("msr", "MsrCpsrReg", "MsrRegOp", msrCpsrRegIop = InstObjParams("msr", "MsrCpsrReg", "MsrRegOp",
@ -111,10 +107,6 @@ let {{
uint32_t newCpsr = uint32_t newCpsr =
cpsrWriteByInstr(Cpsr | CondCodes, imm, byteMask, false, sctlr.nmfi); cpsrWriteByInstr(Cpsr | CondCodes, imm, byteMask, false, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr; Cpsr = ~CondCodesMask & newCpsr;
NextThumb = ((CPSR)newCpsr).t;
NextJazelle = ((CPSR)newCpsr).j;
ForcedItState = ((((CPSR)imm).it2 << 2) & 0xFC)
| (((CPSR)imm).it1 & 0x3);
CondCodes = CondCodesMask & newCpsr; CondCodes = CondCodesMask & newCpsr;
''' '''
msrCpsrImmIop = InstObjParams("msr", "MsrCpsrImm", "MsrImmOp", msrCpsrImmIop = InstObjParams("msr", "MsrCpsrImm", "MsrImmOp",
@ -538,7 +530,7 @@ let {{
exec_output += PredOpExecute.subst(sevIop) exec_output += PredOpExecute.subst(sevIop)
itIop = InstObjParams("it", "ItInst", "PredOp", \ itIop = InstObjParams("it", "ItInst", "PredOp", \
{ "code" : "Itstate = machInst.newItstate;", { "code" : ";",
"predicate_test" : predicateTest }, "predicate_test" : predicateTest },
["IsNonSpeculative", "IsSerializeAfter"]) ["IsNonSpeculative", "IsSerializeAfter"])
header_output += BasicDeclare.subst(itIop) header_output += BasicDeclare.subst(itIop)

View file

@ -217,7 +217,6 @@ def operands {{
#Fixed index control regs #Fixed index control regs
'Cpsr': cntrlReg('MISCREG_CPSR', srtCpsr), 'Cpsr': cntrlReg('MISCREG_CPSR', srtCpsr),
'Itstate': cntrlRegNC('MISCREG_ITSTATE', type = 'ub'),
'Spsr': cntrlRegNC('MISCREG_SPSR'), 'Spsr': cntrlRegNC('MISCREG_SPSR'),
'Fpsr': cntrlRegNC('MISCREG_FPSR'), 'Fpsr': cntrlRegNC('MISCREG_FPSR'),
'Fpsid': cntrlRegNC('MISCREG_FPSID'), 'Fpsid': cntrlRegNC('MISCREG_FPSID'),
@ -247,7 +246,8 @@ def operands {{
'Thumb': pcStateReg('thumb', srtPC), 'Thumb': pcStateReg('thumb', srtPC),
'NextThumb': pcStateReg('nextThumb', srtMode), 'NextThumb': pcStateReg('nextThumb', srtMode),
'NextJazelle': pcStateReg('nextJazelle', srtMode), 'NextJazelle': pcStateReg('nextJazelle', srtMode),
'ForcedItState': pcStateReg('forcedItState', srtMode), 'NextItState': pcStateReg('nextItstate', srtMode),
'Itstate': pcStateReg('itstate', srtMode),
#Register operands depending on a field in the instruction encoding. These #Register operands depending on a field in the instruction encoding. These
#should be avoided since they may not be portable across different #should be avoided since they may not be portable across different

View file

@ -241,10 +241,6 @@ def template MicroNeonMixExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};

View file

@ -102,11 +102,6 @@ def template SwapExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -135,11 +130,6 @@ def template SwapInitiateAcc {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -166,10 +156,6 @@ def template SwapCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -199,11 +185,6 @@ def template LoadExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -238,11 +219,6 @@ def template NeonLoadExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -276,11 +252,6 @@ def template StoreExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -319,11 +290,6 @@ def template NeonStoreExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -363,11 +329,6 @@ def template StoreExExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -396,10 +357,6 @@ def template StoreExInitiateAcc {{
} else { } else {
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
@ -430,11 +387,6 @@ def template StoreInitiateAcc {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -467,11 +419,6 @@ def template NeonStoreInitiateAcc {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -494,10 +441,6 @@ def template LoadInitiateAcc {{
} }
} else { } else {
xc->setPredicate(false); xc->setPredicate(false);
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
} }
return fault; return fault;
@ -523,10 +466,6 @@ def template NeonLoadInitiateAcc {{
} }
} else { } else {
xc->setPredicate(false); xc->setPredicate(false);
if (fault == NoFault && machInst.itstateMask != 0 &&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
} }
return fault; return fault;
@ -557,10 +496,6 @@ def template LoadCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -591,10 +526,6 @@ def template NeonLoadCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -604,10 +535,6 @@ def template StoreCompleteAcc {{
%(CPU_exec_context)s *xc, %(CPU_exec_context)s *xc,
Trace::InstRecord *traceData) const Trace::InstRecord *traceData) const
{ {
if (machInst.itstateMask != 0) {
warn_once("Complete acc isn't called on normal stores in O3.");
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return NoFault; return NoFault;
} }
}}; }};
@ -618,10 +545,6 @@ def template NeonStoreCompleteAcc {{
PacketPtr pkt, %(CPU_exec_context)s *xc, PacketPtr pkt, %(CPU_exec_context)s *xc,
Trace::InstRecord *traceData) const Trace::InstRecord *traceData) const
{ {
if (machInst.itstateMask != 0) {
warn_once("Complete acc isn't called on normal stores in O3.");
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return NoFault; return NoFault;
} }
}}; }};
@ -646,10 +569,6 @@ def template StoreExCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};

View file

@ -438,9 +438,6 @@ def template ClrexInitiateAcc {{
} }
} else { } else {
xc->setPredicate(false); xc->setPredicate(false);
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
} }
return fault; return fault;
@ -452,10 +449,6 @@ def template ClrexCompleteAcc {{
%(CPU_exec_context)s *xc, %(CPU_exec_context)s *xc,
Trace::InstRecord *traceData) const Trace::InstRecord *traceData) const
{ {
if (machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return NoFault; return NoFault;
} }
}}; }};

View file

@ -229,10 +229,6 @@ def template NeonEqualRegExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -281,10 +277,6 @@ def template NeonUnequalRegExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};

View file

@ -174,11 +174,6 @@ def template PredOpExecute {{
xc->setPredicate(false); xc->setPredicate(false);
} }
if (fault == NoFault && machInst.itstateMask != 0&&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -206,11 +201,6 @@ def template QuiescePredOpExecute {{
#endif #endif
} }
if (fault == NoFault && machInst.itstateMask != 0&&
(!isMicroop() || isLastMicroop())) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};

View file

@ -67,7 +67,6 @@ namespace ArmISA
enum MiscRegIndex { enum MiscRegIndex {
MISCREG_CPSR = 0, MISCREG_CPSR = 0,
MISCREG_ITSTATE,
MISCREG_SPSR, MISCREG_SPSR,
MISCREG_SPSR_FIQ, MISCREG_SPSR_FIQ,
MISCREG_SPSR_IRQ, MISCREG_SPSR_IRQ,
@ -207,7 +206,7 @@ namespace ArmISA
unsigned crm, unsigned opc2); unsigned crm, unsigned opc2);
const char * const miscRegName[NUM_MISCREGS] = { const char * const miscRegName[NUM_MISCREGS] = {
"cpsr", "itstate", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc", "cpsr", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc",
"spsr_mon", "spsr_und", "spsr_abt", "spsr_mon", "spsr_und", "spsr_abt",
"fpsr", "fpsid", "fpscr", "fpscr_qc", "fpscr_exc", "fpexc", "fpsr", "fpsid", "fpscr", "fpscr_qc", "fpscr_exc", "fpexc",
"mvfr0", "mvfr1", "mvfr0", "mvfr1",
@ -264,20 +263,6 @@ namespace ArmISA
Bitfield<4, 0> mode; Bitfield<4, 0> mode;
EndBitUnion(CPSR) EndBitUnion(CPSR)
BitUnion8(ITSTATE)
/* Note that the split (cond, mask) below is not as in ARM ARM.
* But it is more convenient for simulation. The condition
* is always the concatenation of the top 3 bits and the next bit,
* which applies when one of the bottom 4 bits is set.
* Refer to predecoder.cc for the use case.
*/
Bitfield<7, 4> cond;
Bitfield<3, 0> mask;
// Bitfields for moving to/from CPSR
Bitfield<7, 2> top6;
Bitfield<1, 0> bottom2;
EndBitUnion(ITSTATE)
// This mask selects bits of the CPSR that actually go in the CondCodes // This mask selects bits of the CPSR that actually go in the CondCodes
// integer register to allow renaming. // integer register to allow renaming.
static const uint32_t CondCodesMask = 0xF80F0000; static const uint32_t CondCodesMask = 0xF80F0000;

View file

@ -50,27 +50,6 @@
namespace ArmISA namespace ArmISA
{ {
void
Predecoder::advanceThumbCond()
{
uint8_t condMask = itstate.mask;
uint8_t thumbCond = itstate.cond;
DPRINTF(Predecoder, "Advancing ITSTATE from %#x, %#x.\n",
thumbCond, condMask);
condMask = condMask << 1;
uint8_t newBit = bits(condMask, 4);
condMask &= mask(4);
if (condMask == 0) {
thumbCond = 0;
} else {
replaceBits(thumbCond, 0, newBit);
}
DPRINTF(Predecoder, "Advancing ITSTATE to %#x, %#x.\n",
thumbCond, condMask);
itstate.mask = condMask;
itstate.cond = thumbCond;
}
void void
Predecoder::process() Predecoder::process()
{ {
@ -93,11 +72,6 @@ Predecoder::process()
consumeBytes(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) {
emi.itstate = itstate;
advanceThumbCond();
emi.newItstate = itstate;
}
} else { } else {
uint16_t highBits = word & 0xF800; uint16_t highBits = word & 0xF800;
if (highBits == 0xE800 || highBits == 0xF000 || if (highBits == 0xE800 || highBits == 0xF000 ||
@ -110,11 +84,6 @@ Predecoder::process()
DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n", DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n",
emi.instBits); emi.instBits);
consumeBytes(4); consumeBytes(4);
if (itstate.mask) {
emi.itstate = itstate;
advanceThumbCond();
emi.newItstate = itstate;
}
} else { } else {
// We only have the first half word. // We only have the first half word.
DPRINTF(Predecoder, DPRINTF(Predecoder,
@ -135,16 +104,11 @@ Predecoder::process()
emi.instBits); emi.instBits);
if (bits(word, 15, 8) == 0xbf && if (bits(word, 15, 8) == 0xbf &&
bits(word, 3, 0) != 0x0) { bits(word, 3, 0) != 0x0) {
emi.itstate = itstate; foundIt = true;
itstate = bits(word, 7, 0); itBits = bits(word, 7, 0);
emi.newItstate = itstate;
DPRINTF(Predecoder, DPRINTF(Predecoder,
"IT detected, cond = %#x, mask = %#x\n", "IT detected, cond = %#x, mask = %#x\n",
itstate.cond, itstate.mask); itBits.cond, itBits.mask);
} else if (itstate.mask) {
emi.itstate = itstate;
advanceThumbCond();
emi.newItstate = itstate;
} }
} }
} }
@ -163,16 +127,6 @@ Predecoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
emi.fpscrLen = fpscr.len; emi.fpscrLen = fpscr.len;
emi.fpscrStride = fpscr.stride; emi.fpscrStride = fpscr.stride;
if (pc.forcedItStateIsValid()) {
// returns from exceptions/interrupts force the it state.
itstate = pc.forcedItState();
DPRINTF(Predecoder, "Predecoder, itstate forced = %08x.\n", pc.forcedItState());
} else if (predAddrValid && (pc.instAddr() != predAddr)) {
// Control flow changes necessitate a 0 itstate.
itstate.top6 = 0;
itstate.bottom2 = 0;
}
outOfBytes = false; outOfBytes = false;
process(); process();
} }

View file

@ -66,9 +66,8 @@ namespace ArmISA
bool emiReady; bool emiReady;
bool outOfBytes; bool outOfBytes;
int offset; int offset;
ITSTATE itstate; bool foundIt;
Addr predAddr; ITSTATE itBits;
bool predAddrValid;
public: public:
void reset() void reset()
@ -78,15 +77,7 @@ namespace ArmISA
emi = 0; emi = 0;
emiReady = false; emiReady = false;
outOfBytes = true; outOfBytes = true;
itstate = 0; foundIt = false;
predAddr = 0;
predAddrValid = false;
}
void reset(const ExtMachInst &old_emi)
{
reset();
itstate = old_emi.newItstate;
} }
Predecoder(ThreadContext * _tc) : Predecoder(ThreadContext * _tc) :
@ -106,7 +97,6 @@ namespace ArmISA
tc = _tc; tc = _tc;
} }
void advanceThumbCond();
void process(); void process();
//Use this to give data to the predecoder. This should be used //Use this to give data to the predecoder. This should be used
@ -149,11 +139,13 @@ namespace ArmISA
assert(emiReady); assert(emiReady);
ExtMachInst thisEmi = emi; ExtMachInst thisEmi = emi;
pc.npc(pc.pc() + getInstSize()); pc.npc(pc.pc() + getInstSize());
predAddrValid = true; if (foundIt)
predAddr = pc.pc() + getInstSize(); pc.nextItstate(itBits);
thisEmi.itstate = pc.itstate();
pc.size(getInstSize()); pc.size(getInstSize());
emi = 0; emi = 0;
emiReady = false; emiReady = false;
foundIt = false;
return thisEmi; return thisEmi;
} }
}; };

View file

@ -53,8 +53,22 @@ namespace ArmISA
{ {
typedef uint32_t MachInst; typedef uint32_t MachInst;
BitUnion8(ITSTATE)
/* Note that the split (cond, mask) below is not as in ARM ARM.
* But it is more convenient for simulation. The condition
* is always the concatenation of the top 3 bits and the next bit,
* which applies when one of the bottom 4 bits is set.
* Refer to predecoder.cc for the use case.
*/
Bitfield<7, 4> cond;
Bitfield<3, 0> mask;
// Bitfields for moving to/from CPSR
Bitfield<7, 2> top6;
Bitfield<1, 0> bottom2;
EndBitUnion(ITSTATE)
BitUnion64(ExtMachInst) BitUnion64(ExtMachInst)
Bitfield<63, 56> newItstate;
// ITSTATE bits // ITSTATE bits
Bitfield<55, 48> itstate; Bitfield<55, 48> itstate;
Bitfield<55, 52> itstateCond; Bitfield<55, 52> itstateCond;
@ -202,11 +216,11 @@ namespace ArmISA
}; };
uint8_t flags; uint8_t flags;
uint8_t nextFlags; uint8_t nextFlags;
uint8_t forcedItStateValue; uint8_t _itstate;
uint8_t _nextItstate;
uint8_t _size; uint8_t _size;
bool forcedItStateValid;
public: public:
PCState() : flags(0), nextFlags(0), forcedItStateValue(0), forcedItStateValid(false) PCState() : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
{} {}
void void
@ -216,7 +230,7 @@ namespace ArmISA
npc(val + (thumb() ? 2 : 4)); npc(val + (thumb() ? 2 : 4));
} }
PCState(Addr val) : flags(0), nextFlags(0), forcedItStateValue(0), forcedItStateValid(false) PCState(Addr val) : flags(0), nextFlags(0), _itstate(0), _nextItstate(0)
{ set(val); } { set(val); }
bool bool
@ -290,23 +304,27 @@ namespace ArmISA
} }
uint8_t uint8_t
forcedItState() const itstate() const
{ {
return forcedItStateValue; return _itstate;
} }
void void
forcedItState(uint8_t value) itstate(uint8_t value)
{ {
forcedItStateValue = value; _itstate = value;
// Not valid unless the advance is called.
forcedItStateValid = false;
} }
bool uint8_t
forcedItStateIsValid() const nextItstate() const
{ {
return forcedItStateValid; return _nextItstate;
}
void
nextItstate(uint8_t value)
{
_nextItstate = value;
} }
void void
@ -316,12 +334,27 @@ namespace ArmISA
npc(pc() + (thumb() ? 2 : 4)); npc(pc() + (thumb() ? 2 : 4));
flags = nextFlags; flags = nextFlags;
// Validate the itState if (_nextItstate) {
if (forcedItStateValue != 0 && !forcedItStateValid) { _itstate = _nextItstate;
forcedItStateValid = true; _nextItstate = 0;
} else { } else if (_itstate) {
forcedItStateValid = false; ITSTATE it = _itstate;
forcedItStateValue = 0; uint8_t cond_mask = it.mask;
uint8_t thumb_cond = it.cond;
DPRINTF(Predecoder, "Advancing ITSTATE from %#x,%#x.\n",
thumb_cond, cond_mask);
cond_mask <<= 1;
uint8_t new_bit = bits(cond_mask, 4);
cond_mask &= mask(4);
if (cond_mask == 0)
thumb_cond = 0;
else
replaceBits(thumb_cond, 0, new_bit);
DPRINTF(Predecoder, "Advancing ITSTATE to %#x,%#x.\n",
thumb_cond, cond_mask);
it.mask = cond_mask;
it.cond = thumb_cond;
_itstate = it;
} }
} }
@ -395,7 +428,8 @@ namespace ArmISA
operator == (const PCState &opc) const operator == (const PCState &opc) const
{ {
return Base::operator == (opc) && return Base::operator == (opc) &&
flags == opc.flags && nextFlags == opc.nextFlags; flags == opc.flags && nextFlags == opc.nextFlags &&
_itstate == opc._itstate && _nextItstate == opc._nextItstate;
} }
void void
@ -405,8 +439,8 @@ namespace ArmISA
SERIALIZE_SCALAR(flags); SERIALIZE_SCALAR(flags);
SERIALIZE_SCALAR(_size); SERIALIZE_SCALAR(_size);
SERIALIZE_SCALAR(nextFlags); SERIALIZE_SCALAR(nextFlags);
SERIALIZE_SCALAR(forcedItStateValue); SERIALIZE_SCALAR(_itstate);
SERIALIZE_SCALAR(forcedItStateValid); SERIALIZE_SCALAR(_nextItstate);
} }
void void
@ -416,8 +450,8 @@ namespace ArmISA
UNSERIALIZE_SCALAR(flags); UNSERIALIZE_SCALAR(flags);
UNSERIALIZE_SCALAR(_size); UNSERIALIZE_SCALAR(_size);
UNSERIALIZE_SCALAR(nextFlags); UNSERIALIZE_SCALAR(nextFlags);
UNSERIALIZE_SCALAR(forcedItStateValue); UNSERIALIZE_SCALAR(_itstate);
UNSERIALIZE_SCALAR(forcedItStateValid); UNSERIALIZE_SCALAR(_nextItstate);
} }
}; };

View file

@ -75,12 +75,6 @@ class Predecoder
emiIsReady = false; emiIsReady = false;
} }
void
reset(const ExtMachInst &old_emi)
{
reset();
}
//Use this to give data to the predecoder. This should be used //Use this to give data to the predecoder. This should be used
//when there is control flow. //when there is control flow.
void void

View file

@ -82,12 +82,6 @@ class Predecoder
emiIsReady = false; emiIsReady = false;
} }
void
reset(const ExtMachInst &old_emi)
{
reset();
}
// Use this to give data to the predecoder. This should be used // Use this to give data to the predecoder. This should be used
// when there is control flow. // when there is control flow.
void void

View file

@ -75,12 +75,6 @@ class Predecoder
emiIsReady = false; emiIsReady = false;
} }
void
reset(const ExtMachInst &old_emi)
{
reset();
}
// Use this to give data to the predecoder. This should be used // Use this to give data to the predecoder. This should be used
// when there is control flow. // when there is control flow.
void void

View file

@ -174,12 +174,6 @@ namespace X86ISA
state = ResetState; state = ResetState;
} }
void
reset(const ExtMachInst &old_emi)
{
reset();
}
ThreadContext * getTC() ThreadContext * getTC()
{ {
return tc; return tc;

View file

@ -821,8 +821,6 @@ DefaultFetch<Impl>::squash(const TheISA::PCState &newPC,
DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n", tid); DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n", tid);
doSquash(newPC, tid); doSquash(newPC, tid);
if (squashInst)
predecoder.reset(squashInst->staticInst->machInst);
// Tell the CPU to remove any instructions that are not in the ROB. // Tell the CPU to remove any instructions that are not in the ROB.
cpu->removeInstsNotInROB(tid); cpu->removeInstsNotInROB(tid);