Add code to emulate RFE Arm instruction.

Add new instruction context for RFE instruction.

Add several new helper functions to help emulate RFE instruction
(including CurrentModeIsPrivileged, BadMode, and CPSRWriteByInstr).

llvm-svn: 126965
This commit is contained in:
Caroline Tice 2011-03-03 22:37:46 +00:00
parent d8a555bb3b
commit 94f87e37c8
3 changed files with 243 additions and 3 deletions

View File

@ -171,7 +171,8 @@ public:
eContextWriteMemoryRandomBits,
eContextMultiplication,
eContextAddition
eContextAddition,
eContextReturnFromException
};
enum InfoType {

View File

@ -7748,6 +7748,156 @@ EmulateInstructionARM::EmulateUXTH (ARMEncoding encoding)
}
return true;
}
// RFE (Return From Exception) loads the PC and the CPSR from the word at the specified address and the following
// word respectively.
bool
EmulateInstructionARM::EmulateRFE (ARMEncoding encoding)
{
#if 0
if ConditionPassed() then
EncodingSpecificOperations();
if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then
UNPREDICTABLE;
else
address = if increment then R[n] else R[n]-8;
if wordhigher then address = address+4;
CPSRWriteByInstr(MemA[address+4,4], 1111, TRUE);
BranchWritePC(MemA[address,4]);
if wback then R[n] = if increment then R[n]+8 else R[n]-8;
#endif
bool success = false;
const uint32_t opcode = OpcodeAsUnsigned (&success);
if (!success)
return false;
if (ConditionPassed())
{
uint32_t n;
bool wback;
bool increment;
bool wordhigher;
// EncodingSpecificOperations();
switch (encoding)
{
case eEncodingT1:
// n = UInt(Rn); wback = (W == 1); increment = FALSE; wordhigher = FALSE;
n = Bits32 (opcode, 19, 16);
wback = BitIsSet (opcode, 21);
increment = false;
wordhigher = false;
// if n == 15 then UNPREDICTABLE;
if (n == 15)
return false;
// if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
if (InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingT2:
// n = UInt(Rn); wback = (W == 1); increment = TRUE; wordhigher = FALSE;
n = Bits32 (opcode, 19, 16);
wback = BitIsSet (opcode, 21);
increment = true;
wordhigher = false;
// if n == 15 then UNPREDICTABLE;
if (n == 15)
return false;
// if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
if (InITBlock() && !LastInITBlock())
return false;
break;
case eEncodingA1:
// n = UInt(Rn);
n = Bits32 (opcode, 19, 16);
// wback = (W == 1); inc = (U == 1); wordhigher = (P == U);
wback = BitIsSet (opcode, 21);
increment = BitIsSet (opcode, 23);
wordhigher = (Bit32 (opcode, 24) == Bit32 (opcode, 23));
// if n == 15 then UNPREDICTABLE;
if (n == 15)
return false;
break;
default:
return false;
}
// if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then
if (!CurrentModeIsPrivileged ())
// UNPREDICTABLE;
return false;
else
{
uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
if (!success)
return false;
addr_t address;
// address = if increment then R[n] else R[n]-8;
if (increment)
address = Rn;
else
address = Rn - 8;
// if wordhigher then address = address+4;
if (wordhigher)
address = address + 4;
// CPSRWriteByInstr(MemA[address+4,4], 1111, TRUE);
Register base_reg;
base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n);
EmulateInstruction::Context context;
context.type = eContextReturnFromException;
context.SetRegisterPlusOffset (base_reg, address - Rn);
uint64_t data = MemARead (context, address + 4, 4, 0, &success);
if (!success)
return false;
CPSRWriteByInstr (data, 15, true);
// BranchWritePC(MemA[address,4]);
uint64_t data2 = MemARead (context, address, 4, 0, &success);
if (!success)
return false;
BranchWritePC (context, data2);
// if wback then R[n] = if increment then R[n]+8 else R[n]-8;
if (wback)
{
context.type = eContextAdjustBaseRegister;
if (increment)
{
context.SetOffset (8);
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + 8))
return false;
}
else
{
context.SetOffset (-8);
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn - 8))
return false;
}
} // if wback
}
} // if ConditionPassed()
return true;
}
// Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a register value and an immediate value,
// and writes the result to the destination register. It can optionally update the condition flags based on
@ -9147,7 +9297,8 @@ EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode)
{ 0x0fff00f0, 0x06af00f0, ARMV6_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>{,<rotation>}" },
{ 0x0fff00f0, 0x06bf0070, ARMV6_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>{,<rotation>}" },
{ 0x0fff00f0, 0x06ef0070, ARMV6_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>{,<rotation>}" },
{ 0x0fff00f0, 0x06ff0070, ARMV6_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>{,<rotation>}" }
{ 0x0fff00f0, 0x06ff0070, ARMV6_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>{,<rotation>}" },
{ 0xfe500000, 0xf8100000, ARMV6_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}" }
};
static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
@ -9428,7 +9579,9 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode)
{ 0xffffffc0, 0x0000b2c0, ARMV6_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>" },
{ 0xfffff080, 0xfa5ff080, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c>.w <Rd>,<Rm>{,<rotation>}" },
{ 0xffffffc0, 0x0000b280, ARMV6_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>" },
{ 0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}" }
{ 0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}" },
{ 0xffd00000, 0xe8100000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateRFE, "rfedb<c> <Rn>{!}" },
{ 0xffd00000, 0xe9900000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{ia}<c> <Rn>{!}" }
};
@ -9608,6 +9761,83 @@ EmulateInstructionARM::LastInITBlock()
return CurrentInstrSet() == eModeThumb && m_it_session.LastInITBlock();
}
bool
EmulateInstructionARM::BadMode (uint32_t mode)
{
switch (mode)
{
case 16: return false; // '10000'
case 17: return false; // '10001'
case 18: return false; // '10010'
case 19: return false; // '10011'
case 22: return false; // '10110'
case 23: return false; // '10111'
case 27: return false; // '11011'
case 31: return false; // '11111'
default: return true;
}
return true;
}
bool
EmulateInstructionARM::CurrentModeIsPrivileged ()
{
uint32_t mode = Bits32 (m_inst_cpsr, 4, 0);
if (BadMode (mode))
return false;
if (mode == 16)
return false;
return true;
}
void
EmulateInstructionARM::CPSRWriteByInstr (uint32_t value, uint32_t bytemask, bool affect_execstate)
{
bool privileged = CurrentModeIsPrivileged();
uint32_t tmp_cpsr = 0;
tmp_cpsr = tmp_cpsr | (Bits32 (m_inst_cpsr, 23, 20) << 20);
if (BitIsSet (bytemask, 3))
{
tmp_cpsr = tmp_cpsr | (Bits32 (value, 31, 27) << 27);
if (affect_execstate)
tmp_cpsr = tmp_cpsr | (Bits32 (value, 26, 24) << 24);
}
if (BitIsSet (bytemask, 2))
{
tmp_cpsr = tmp_cpsr | (Bits32 (value, 19, 16) << 16);
}
if (BitIsSet (bytemask, 1))
{
if (affect_execstate)
tmp_cpsr = tmp_cpsr | (Bits32 (value, 15, 10) << 10);
tmp_cpsr = tmp_cpsr | (Bit32 (value, 9) << 9);
if (privileged)
tmp_cpsr = tmp_cpsr | (Bit32 (value, 8) << 8);
}
if (BitIsSet (bytemask, 0))
{
if (privileged)
tmp_cpsr = tmp_cpsr | (Bits32 (value, 7, 6) << 6);
if (affect_execstate)
tmp_cpsr = tmp_cpsr | (Bit32 (value, 5) << 5);
if (privileged)
tmp_cpsr = tmp_cpsr | Bits32 (value, 4, 0);
}
m_inst_cpsr = tmp_cpsr;
}
bool
EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr)
{

View File

@ -155,6 +155,15 @@ public:
// LastInITBlock - Returns true if we're in Thumb mode and the last instruction inside an IT Block.
bool LastInITBlock();
bool
BadMode (uint32_t mode);
bool
CurrentModeIsPrivileged ();
void
CPSRWriteByInstr (uint32_t value, uint32_t bytemask, bool affect_execstate);
bool
BranchWritePC(const Context &context, uint32_t addr);