ARM: Implement support for the IT instruction and the ITSTATE bits of CPSR.

This commit is contained in:
Gabe Black 2010-06-02 12:58:16 -05:00
parent b93ceef538
commit 05bd3eb4ec
12 changed files with 384 additions and 150 deletions

View file

@ -159,121 +159,133 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
npc = npc | (ULL(1) << PcTBitShift); npc = npc | (ULL(1) << PcTBitShift);
tc->setNextPC(npc); tc->setNextPC(npc);
} } else if (misc_reg >= MISCREG_CP15_UNIMP_START &&
if (misc_reg >= MISCREG_CP15_UNIMP_START &&
misc_reg < MISCREG_CP15_END) { misc_reg < MISCREG_CP15_END) {
panic("Unimplemented CP15 register %s wrote with %#x.\n", panic("Unimplemented CP15 register %s wrote with %#x.\n",
miscRegName[misc_reg], val); miscRegName[misc_reg], val);
} } else {
switch (misc_reg) { switch (misc_reg) {
case MISCREG_CPACR: case MISCREG_ITSTATE:
{ {
CPACR newCpacr = 0; ITSTATE itstate = newVal;
CPACR valCpacr = val; CPSR cpsr = miscRegs[MISCREG_CPSR];
newCpacr.cp10 = valCpacr.cp10; cpsr.it1 = itstate.bottom2;
newCpacr.cp11 = valCpacr.cp11; cpsr.it2 = itstate.top6;
if (newCpacr.cp10 != 0x3 || newCpacr.cp11 != 3) { miscRegs[MISCREG_CPSR] = cpsr;
panic("Disabling coprocessors isn't implemented.\n"); DPRINTF(MiscRegs,
"Updating ITSTATE -> %#x in CPSR -> %#x.\n",
(uint8_t)itstate, (uint32_t)cpsr);
} }
newVal = newCpacr; break;
} case MISCREG_CPACR:
break; {
case MISCREG_CSSELR: CPACR newCpacr = 0;
warn("The csselr register isn't implemented.\n"); CPACR valCpacr = val;
break; newCpacr.cp10 = valCpacr.cp10;
case MISCREG_FPSCR: newCpacr.cp11 = valCpacr.cp11;
{ if (newCpacr.cp10 != 0x3 || newCpacr.cp11 != 3) {
const uint32_t ones = (uint32_t)(-1); panic("Disabling coprocessors isn't implemented.\n");
FPSCR fpscrMask = 0; }
fpscrMask.ioc = ones; newVal = newCpacr;
fpscrMask.dzc = ones; }
fpscrMask.ofc = ones; break;
fpscrMask.ufc = ones; case MISCREG_CSSELR:
fpscrMask.ixc = ones; warn("The csselr register isn't implemented.\n");
fpscrMask.idc = ones; break;
fpscrMask.len = ones; case MISCREG_FPSCR:
fpscrMask.stride = ones; {
fpscrMask.rMode = ones; const uint32_t ones = (uint32_t)(-1);
fpscrMask.fz = ones; FPSCR fpscrMask = 0;
fpscrMask.dn = ones; fpscrMask.ioc = ones;
fpscrMask.ahp = ones; fpscrMask.dzc = ones;
fpscrMask.qc = ones; fpscrMask.ofc = ones;
fpscrMask.v = ones; fpscrMask.ufc = ones;
fpscrMask.c = ones; fpscrMask.ixc = ones;
fpscrMask.z = ones; fpscrMask.idc = ones;
fpscrMask.n = ones; fpscrMask.len = ones;
newVal = (newVal & (uint32_t)fpscrMask) | fpscrMask.stride = ones;
(miscRegs[MISCREG_FPSCR] & ~(uint32_t)fpscrMask); fpscrMask.rMode = ones;
} fpscrMask.fz = ones;
break; fpscrMask.dn = ones;
case MISCREG_FPEXC: fpscrMask.ahp = ones;
{ fpscrMask.qc = ones;
const uint32_t fpexcMask = 0x60000000; fpscrMask.v = ones;
newVal = (newVal & fpexcMask) | fpscrMask.c = ones;
(miscRegs[MISCREG_FPEXC] & ~fpexcMask); fpscrMask.z = ones;
} fpscrMask.n = ones;
break; newVal = (newVal & (uint32_t)fpscrMask) |
case MISCREG_SCTLR: (miscRegs[MISCREG_FPSCR] & ~(uint32_t)fpscrMask);
{ }
DPRINTF(MiscRegs, "Writing SCTLR: %#x\n", newVal); break;
SCTLR sctlr = miscRegs[MISCREG_SCTLR]; case MISCREG_FPEXC:
SCTLR new_sctlr = newVal; {
new_sctlr.nmfi = (bool)sctlr.nmfi; const uint32_t fpexcMask = 0x60000000;
miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr; newVal = (newVal & fpexcMask) |
(miscRegs[MISCREG_FPEXC] & ~fpexcMask);
}
break;
case MISCREG_SCTLR:
{
DPRINTF(MiscRegs, "Writing SCTLR: %#x\n", newVal);
SCTLR sctlr = miscRegs[MISCREG_SCTLR];
SCTLR new_sctlr = newVal;
new_sctlr.nmfi = (bool)sctlr.nmfi;
miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr;
return;
}
case MISCREG_TLBTR:
case MISCREG_MVFR0:
case MISCREG_MVFR1:
case MISCREG_MPIDR:
case MISCREG_FPSID:
return;
case MISCREG_TLBIALLIS:
case MISCREG_TLBIALL:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushAll();
tc->getDTBPtr()->flushAll();
return;
case MISCREG_ITLBIALL:
tc->getITBPtr()->flushAll();
return;
case MISCREG_DTLBIALL:
tc->getDTBPtr()->flushAll();
return;
case MISCREG_TLBIMVAIS:
case MISCREG_TLBIMVA:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_TLBIASIDIS:
case MISCREG_TLBIASID:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
return;
case MISCREG_TLBIMVAAIS:
case MISCREG_TLBIMVAA:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushMva(mbits(newVal, 31,12));
tc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
return;
case MISCREG_ITLBIMVA:
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_DTLBIMVA:
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_ITLBIASID:
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
return;
case MISCREG_DTLBIASID:
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
return; return;
} }
case MISCREG_TLBTR:
case MISCREG_MVFR0:
case MISCREG_MVFR1:
case MISCREG_MPIDR:
case MISCREG_FPSID:
return;
case MISCREG_TLBIALLIS:
case MISCREG_TLBIALL:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushAll();
tc->getDTBPtr()->flushAll();
return;
case MISCREG_ITLBIALL:
tc->getITBPtr()->flushAll();
return;
case MISCREG_DTLBIALL:
tc->getDTBPtr()->flushAll();
return;
case MISCREG_TLBIMVAIS:
case MISCREG_TLBIMVA:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_TLBIASIDIS:
case MISCREG_TLBIASID:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
return;
case MISCREG_TLBIMVAAIS:
case MISCREG_TLBIMVAA:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushMva(mbits(newVal, 31,12));
tc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
return;
case MISCREG_ITLBIMVA:
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_DTLBIMVA:
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_ITLBIASID:
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
return;
case MISCREG_DTLBIASID:
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
return;
} }
setMiscRegNoEffect(misc_reg, newVal); setMiscRegNoEffect(misc_reg, newVal);
} }

View file

@ -852,30 +852,70 @@ def format Thumb16ShiftAddSubMoveCmp() {{
const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 8, 6); const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 8, 6);
switch (bits(machInst, 13, 11)) { switch (bits(machInst, 13, 11)) {
case 0x0: // lsl case 0x0: // lsl
return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSL); if (machInst.itstateMask) {
return new MovReg(machInst, rd, INTREG_ZERO, rn, imm5, LSL);
} else {
return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSL);
}
case 0x1: // lsr case 0x1: // lsr
return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSR); if (machInst.itstateMask) {
return new MovReg(machInst, rd, INTREG_ZERO, rn, imm5, LSR);
} else {
return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, LSR);
}
case 0x2: // asr case 0x2: // asr
return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, ASR); if (machInst.itstateMask) {
return new MovReg(machInst, rd, INTREG_ZERO, rn, imm5, ASR);
} else {
return new MovRegCc(machInst, rd, INTREG_ZERO, rn, imm5, ASR);
}
case 0x3: case 0x3:
switch (bits(machInst, 10, 9)) { switch (bits(machInst, 10, 9)) {
case 0x0: case 0x0:
return new AddRegCc(machInst, rd, rn, rm, 0, LSL); if (machInst.itstateMask) {
return new AddReg(machInst, rd, rn, rm, 0, LSL);
} else {
return new AddRegCc(machInst, rd, rn, rm, 0, LSL);
}
case 0x1: case 0x1:
return new SubRegCc(machInst, rd, rn, rm, 0, LSL); if (machInst.itstateMask) {
return new SubReg(machInst, rd, rn, rm, 0, LSL);
} else {
return new SubRegCc(machInst, rd, rn, rm, 0, LSL);
}
case 0x2: case 0x2:
return new AddImmCc(machInst, rd, rn, imm3, true); if (machInst.itstateMask) {
return new AddImm(machInst, rd, rn, imm3, true);
} else {
return new AddImmCc(machInst, rd, rn, imm3, true);
}
case 0x3: case 0x3:
return new SubImmCc(machInst, rd, rn, imm3, true); if (machInst.itstateMask) {
return new SubImm(machInst, rd, rn, imm3, true);
} else {
return new SubImmCc(machInst, rd, rn, imm3, true);
}
} }
case 0x4: case 0x4:
return new MovImmCc(machInst, rd8, INTREG_ZERO, imm8, false); if (machInst.itstateMask) {
return new MovImm(machInst, rd8, INTREG_ZERO, imm8, false);
} else {
return new MovImmCc(machInst, rd8, INTREG_ZERO, imm8, false);
}
case 0x5: case 0x5:
return new CmpImmCc(machInst, INTREG_ZERO, rd8, imm8, true); return new CmpImmCc(machInst, INTREG_ZERO, rd8, imm8, true);
case 0x6: case 0x6:
return new AddImmCc(machInst, rd8, rd8, imm8, true); if (machInst.itstateMask) {
return new AddImm(machInst, rd8, rd8, imm8, true);
} else {
return new AddImmCc(machInst, rd8, rd8, imm8, true);
}
case 0x7: case 0x7:
return new SubImmCc(machInst, rd8, rd8, imm8, true); if (machInst.itstateMask) {
return new SubImm(machInst, rd8, rd8, imm8, true);
} else {
return new SubImmCc(machInst, rd8, rd8, imm8, true);
}
} }
} }
''' '''
@ -888,37 +928,97 @@ def format Thumb16DataProcessing() {{
const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 5, 3); const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 5, 3);
switch (bits(machInst, 9, 6)) { switch (bits(machInst, 9, 6)) {
case 0x0: case 0x0:
return new AndRegCc(machInst, rdn, rdn, rm, 0, LSL); if (machInst.itstateMask) {
return new AndReg(machInst, rdn, rdn, rm, 0, LSL);
} else {
return new AndRegCc(machInst, rdn, rdn, rm, 0, LSL);
}
case 0x1: case 0x1:
return new EorRegCc(machInst, rdn, rdn, rm, 0, LSL); if (machInst.itstateMask) {
return new EorReg(machInst, rdn, rdn, rm, 0, LSL);
} else {
return new EorRegCc(machInst, rdn, rdn, rm, 0, LSL);
}
case 0x2: //lsl case 0x2: //lsl
return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, LSL); if (machInst.itstateMask) {
return new MovRegReg(machInst, rdn,
INTREG_ZERO, rdn, rm, LSL);
} else {
return new MovRegRegCc(machInst, rdn,
INTREG_ZERO, rdn, rm, LSL);
}
case 0x3: //lsr case 0x3: //lsr
return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, LSR); if (machInst.itstateMask) {
return new MovRegReg(machInst, rdn,
INTREG_ZERO, rdn, rm, LSR);
} else {
return new MovRegRegCc(machInst, rdn,
INTREG_ZERO, rdn, rm, LSR);
}
case 0x4: //asr case 0x4: //asr
return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, ASR); if (machInst.itstateMask) {
return new MovRegReg(machInst, rdn,
INTREG_ZERO, rdn, rm, ASR);
} else {
return new MovRegRegCc(machInst, rdn,
INTREG_ZERO, rdn, rm, ASR);
}
case 0x5: case 0x5:
return new AdcRegCc(machInst, rdn, rdn, rm, 0, LSL); if (machInst.itstateMask) {
return new AdcReg(machInst, rdn, rdn, rm, 0, LSL);
} else {
return new AdcRegCc(machInst, rdn, rdn, rm, 0, LSL);
}
case 0x6: case 0x6:
return new SbcRegCc(machInst, rdn, rdn, rm, 0, LSL); if (machInst.itstateMask) {
return new SbcReg(machInst, rdn, rdn, rm, 0, LSL);
} else {
return new SbcRegCc(machInst, rdn, rdn, rm, 0, LSL);
}
case 0x7: // ror case 0x7: // ror
return new MovRegRegCc(machInst, rdn, INTREG_ZERO, rdn, rm, ROR); if (machInst.itstateMask) {
return new MovRegReg(machInst, rdn,
INTREG_ZERO, rdn, rm, ROR);
} else {
return new MovRegRegCc(machInst, rdn,
INTREG_ZERO, rdn, rm, ROR);
}
case 0x8: case 0x8:
return new TstRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); return new TstRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL);
case 0x9: case 0x9:
return new RsbImmCc(machInst, rdn, rm, 0, true); if (machInst.itstateMask) {
return new RsbImm(machInst, rdn, rm, 0, true);
} else {
return new RsbImmCc(machInst, rdn, rm, 0, true);
}
case 0xa: case 0xa:
return new CmpRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); return new CmpRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL);
case 0xb: case 0xb:
return new CmnRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL); return new CmnRegCc(machInst, INTREG_ZERO, rdn, rm, 0, LSL);
case 0xc: case 0xc:
return new OrrRegCc(machInst, rdn, rdn, rm, 0, LSL); if (machInst.itstateMask) {
return new OrrReg(machInst, rdn, rdn, rm, 0, LSL);
} else {
return new OrrRegCc(machInst, rdn, rdn, rm, 0, LSL);
}
case 0xd: case 0xd:
return new MulCc(machInst, rdn, rm, rdn); if (machInst.itstateMask) {
return new Mul(machInst, rdn, rm, rdn);
} else {
return new MulCc(machInst, rdn, rm, rdn);
}
case 0xe: case 0xe:
return new BicRegCc(machInst, rdn, rdn, rm, 0, LSL); if (machInst.itstateMask) {
return new BicReg(machInst, rdn, rdn, rm, 0, LSL);
} else {
return new BicRegCc(machInst, rdn, rdn, rm, 0, LSL);
}
case 0xf: case 0xf:
return new MvnRegCc(machInst, rdn, INTREG_ZERO, rm, 0, LSL); if (machInst.itstateMask) {
return new MvnReg(machInst, rdn, INTREG_ZERO, rm, 0, LSL);
} else {
return new MvnRegCc(machInst, rdn, INTREG_ZERO, rm, 0, LSL);
}
} }
} }
''' '''
@ -1070,7 +1170,7 @@ def format Thumb16Misc() {{
return new WarnUnimplemented("bkpt", machInst); return new WarnUnimplemented("bkpt", machInst);
case 0xf: case 0xf:
if (bits(machInst, 3, 0) != 0) if (bits(machInst, 3, 0) != 0)
return new WarnUnimplemented("it", machInst); return new ItInst(machInst);
switch (bits(machInst, 7, 4)) { switch (bits(machInst, 7, 4)) {
case 0x0: case 0x0:
return new NopInst(machInst); return new NopInst(machInst);

View file

@ -46,10 +46,6 @@
// Load/store microops // Load/store microops
// //
let {{
predicateTest = 'testPredicate(CondCodes, condCode)'
}};
let {{ let {{
microLdrUopCode = "IWRa = cSwap(Mem.uw, ((CPSR)Cpsr).e);" microLdrUopCode = "IWRa = cSwap(Mem.uw, ((CPSR)Cpsr).e);"
microLdrUopIop = InstObjParams('ldr_uop', 'MicroLdrUop', microLdrUopIop = InstObjParams('ldr_uop', 'MicroLdrUop',

View file

@ -456,10 +456,18 @@ let {{
decoder_output += RegRegRegRegOpConstructor.subst(usada8Iop) decoder_output += RegRegRegRegOpConstructor.subst(usada8Iop)
exec_output += PredOpExecute.subst(usada8Iop) exec_output += PredOpExecute.subst(usada8Iop)
nopIop = InstObjParams("nop", "NopInst", "ArmStaticInst", "", []) nopIop = InstObjParams("nop", "NopInst", "PredOp", \
{ "code" : "", "predicate_test" : predicateTest })
header_output += BasicDeclare.subst(nopIop) header_output += BasicDeclare.subst(nopIop)
decoder_output += BasicConstructor.subst(nopIop) decoder_output += BasicConstructor.subst(nopIop)
exec_output += BasicExecute.subst(nopIop) exec_output += PredOpExecute.subst(nopIop)
itIop = InstObjParams("it", "ItInst", "PredOp", \
{ "code" : "Itstate = machInst.newItstate;",
"predicate_test" : predicateTest })
header_output += BasicDeclare.subst(itIop)
decoder_output += BasicConstructor.subst(itIop)
exec_output += PredOpExecute.subst(itIop)
ubfxCode = ''' ubfxCode = '''
Dest = bits(Op1, imm2, imm1); Dest = bits(Op1, imm2, imm1);

View file

@ -171,6 +171,7 @@ def operands {{
'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 2), 'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 2),
'Cpsr': ('ControlReg', 'uw', 'MISCREG_CPSR', (None, None, 'IsControl'), 1), 'Cpsr': ('ControlReg', 'uw', 'MISCREG_CPSR', (None, None, 'IsControl'), 1),
'Itstate': ('ControlReg', 'ub', 'MISCREG_ITSTATE', None, 2),
'Spsr': ('ControlReg', 'uw', 'MISCREG_SPSR', None, 2), 'Spsr': ('ControlReg', 'uw', 'MISCREG_SPSR', None, 2),
'Fpsr': ('ControlReg', 'uw', 'MISCREG_FPSR', None, 2), 'Fpsr': ('ControlReg', 'uw', 'MISCREG_FPSR', None, 2),
'Fpsid': ('ControlReg', 'uw', 'MISCREG_FPSID', None, 2), 'Fpsid': ('ControlReg', 'uw', 'MISCREG_FPSID', None, 2),

View file

@ -71,6 +71,10 @@ def template SwapExecute {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -101,6 +105,10 @@ def template SwapInitiateAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -127,6 +135,10 @@ def template SwapCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -154,6 +166,10 @@ def template LoadExecute {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -186,6 +202,10 @@ def template StoreExecute {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -224,6 +244,10 @@ def template StoreExExecute {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -257,6 +281,10 @@ def template StoreExInitiateAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -290,6 +318,10 @@ def template StoreInitiateAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -340,6 +372,10 @@ def template LoadCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -361,6 +397,10 @@ def template StoreCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};
@ -385,6 +425,10 @@ def template StoreExCompleteAcc {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};

View file

@ -46,7 +46,11 @@
// //
let {{ let {{
predicateTest = 'testPredicate(CondCodes, condCode)' predicateTest = '''
testPredicate(CondCodes, machInst.itstateMask ?
(ConditionCode)(uint8_t)machInst.itstateCond :
condCode)
'''
}}; }};
def template DataImmDeclare {{ def template DataImmDeclare {{
@ -143,6 +147,10 @@ def template PredOpExecute {{
} }
} }
if (fault == NoFault && machInst.itstateMask != 0) {
xc->setMiscReg(MISCREG_ITSTATE, machInst.newItstate);
}
return fault; return fault;
} }
}}; }};

View file

@ -67,6 +67,7 @@ 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,
@ -189,7 +190,7 @@ namespace ArmISA
unsigned crm, unsigned opc2); unsigned crm, unsigned opc2);
const char * const miscRegName[NUM_MISCREGS] = { const char * const miscRegName[NUM_MISCREGS] = {
"cpsr", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc", "cpsr", "itstate", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc",
"spsr_mon", "spsr_und", "spsr_abt", "spsr_mon", "spsr_und", "spsr_abt",
"fpsr", "fpsid", "fpscr", "fpexc", "mvfr0", "mvfr1", "fpsr", "fpsid", "fpscr", "fpexc", "mvfr0", "mvfr1",
"sctlr_rst", "sev_mailbox", "sctlr_rst", "sev_mailbox",
@ -241,6 +242,14 @@ namespace ArmISA
Bitfield<4, 0> mode; Bitfield<4, 0> mode;
EndBitUnion(CPSR) EndBitUnion(CPSR)
BitUnion8(ITSTATE)
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

@ -62,11 +62,21 @@ namespace ArmISA
MachInst data; MachInst data;
bool bigThumb; bool bigThumb;
int offset; int offset;
ITSTATE itstate;
public: public:
void reset()
{
bigThumb = false;
offset = 0;
emi = 0;
}
Predecoder(ThreadContext * _tc) : Predecoder(ThreadContext * _tc) :
tc(_tc), data(0), bigThumb(false), offset(0) tc(_tc), data(0)
{} {
reset();
}
ThreadContext * getTC() ThreadContext * getTC()
{ {
@ -78,11 +88,24 @@ namespace ArmISA
tc = _tc; tc = _tc;
} }
void reset() void advanceThumbCond()
{ {
bigThumb = false; uint8_t condMask = itstate.mask;
offset = 0; uint8_t thumbCond = itstate.cond;
emi = 0; 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 process() void process()
@ -92,7 +115,7 @@ namespace ArmISA
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);
DPRINTF(Predecoder, "Arm inst.\n"); DPRINTF(Predecoder, "Arm inst: %#x.\n", (uint64_t)emi);
} else { } else {
uint16_t word = (data >> (offset * 8)); uint16_t word = (data >> (offset * 8));
if (bigThumb) { if (bigThumb) {
@ -102,6 +125,11 @@ namespace ArmISA
offset += 2; offset += 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 ||
@ -114,6 +142,11 @@ namespace ArmISA
DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n", DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n",
emi.instBits); emi.instBits);
offset += 4; offset += 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,
@ -130,6 +163,19 @@ namespace ArmISA
emi.condCode = COND_UC; emi.condCode = COND_UC;
DPRINTF(Predecoder, "16 bit Thumb: %#x.\n", DPRINTF(Predecoder, "16 bit Thumb: %#x.\n",
emi.instBits); emi.instBits);
if (bits(word, 15, 8) == 0xbf &&
bits(word, 3, 0) != 0x0) {
emi.itstate = itstate;
itstate = bits(word, 7, 0);
emi.newItstate = itstate;
DPRINTF(Predecoder,
"IT detected, cond = %#x, mask = %#x\n",
itstate.cond, itstate.mask);
} else if (itstate.mask) {
emi.itstate = itstate;
advanceThumbCond();
emi.newItstate = itstate;
}
} }
} }
} }
@ -145,6 +191,9 @@ namespace ArmISA
FPSCR fpscr = tc->readMiscReg(MISCREG_FPSCR); FPSCR fpscr = tc->readMiscReg(MISCREG_FPSCR);
emi.fpscrLen = fpscr.len; emi.fpscrLen = fpscr.len;
emi.fpscrStride = fpscr.stride; emi.fpscrStride = fpscr.stride;
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
itstate.top6 = cpsr.it2;
itstate.bottom2 = cpsr.it1;
process(); process();
} }

View file

@ -51,6 +51,12 @@ namespace ArmISA
typedef uint32_t MachInst; typedef uint32_t MachInst;
BitUnion64(ExtMachInst) BitUnion64(ExtMachInst)
Bitfield<63, 56> newItstate;
// ITSTATE bits
Bitfield<55, 48> itstate;
Bitfield<55, 52> itstateCond;
Bitfield<51, 48> itstateMask;
// FPSCR fields // FPSCR fields
Bitfield<41, 40> fpscrStride; Bitfield<41, 40> fpscrStride;
Bitfield<39, 37> fpscrLen; Bitfield<39, 37> fpscrLen;

View file

@ -48,6 +48,7 @@
#include "arch/arm/miscregs.hh" #include "arch/arm/miscregs.hh"
#include "arch/arm/types.hh" #include "arch/arm/types.hh"
#include "base/hashmap.hh" #include "base/hashmap.hh"
#include "base/trace.hh"
#include "base/types.hh" #include "base/types.hh"
#include "cpu/thread_context.hh" #include "cpu/thread_context.hh"

View file

@ -357,10 +357,10 @@ BaseSimpleCPU::checkForInterrupts()
Fault interrupt = interrupts->getInterrupt(tc); Fault interrupt = interrupts->getInterrupt(tc);
if (interrupt != NoFault) { if (interrupt != NoFault) {
predecoder.reset();
fetchOffset = 0; fetchOffset = 0;
interrupts->updateIntrInfo(tc); interrupts->updateIntrInfo(tc);
interrupt->invoke(tc); interrupt->invoke(tc);
predecoder.reset();
} }
} }
#endif #endif
@ -508,8 +508,8 @@ BaseSimpleCPU::advancePC(Fault fault)
fetchOffset = 0; fetchOffset = 0;
if (fault != NoFault) { if (fault != NoFault) {
curMacroStaticInst = StaticInst::nullStaticInstPtr; curMacroStaticInst = StaticInst::nullStaticInstPtr;
predecoder.reset();
fault->invoke(tc); fault->invoke(tc);
predecoder.reset();
} else { } else {
//If we're at the last micro op for this instruction //If we're at the last micro op for this instruction
if (curStaticInst && curStaticInst->isLastMicroop()) { if (curStaticInst && curStaticInst->isLastMicroop()) {