diff options
| -rw-r--r-- | lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp | 108 | ||||
| -rw-r--r-- | lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h | 4 |
2 files changed, 109 insertions, 3 deletions
diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 1797bc15294..15c4df3434a 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -2132,9 +2132,9 @@ EmulateInstructionARM::EmulateASRImm (ARMEncoding encoding) if (ConditionPassed()) { - uint32_t Rd; // the destination register - uint32_t Rm; // the first operand register - uint32_t imm5; // encoding for the shift amount + uint32_t Rd; // the destination register + uint32_t Rm; // the first operand register + uint32_t imm5; // encoding for the shift amount uint32_t carry; // the carry bit after the shift operation bool setflags; switch (encoding) { @@ -2203,6 +2203,103 @@ EmulateInstructionARM::EmulateASRImm (ARMEncoding encoding) return true; } +// Arithmetic Shift Right (register) shifts a register value right by a variable number of bits, +// shifting in copies of its sign bit, and writes the result to the destination register. +// The variable number of bits is read from the bottom byte of a register. It can optionally update +// the condition flags based on the result. +bool +EmulateInstructionARM::EmulateASRReg (ARMEncoding encoding) +{ +#if 0 + // ARM pseudo code... + if ConditionPassed() then + EncodingSpecificOperations(); + shift_n = UInt(R[m]<7:0>); + (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); + R[d] = result; + if setflags then + APSR.N = result<31>; + APSR.Z = IsZeroBit(result); + APSR.C = carry; + // APSR.V unchanged +#endif + + bool success = false; + const uint32_t opcode = OpcodeAsUnsigned (&success); + if (!success) + return false; + + if (ConditionPassed()) + { + uint32_t Rd; // the destination register + uint32_t Rn; // the first operand register + uint32_t Rm; // the register whose bottom byte contains the amount to shift by + uint32_t carry; // the carry bit after the shift operation + bool setflags; + switch (encoding) { + case eEncodingT1: + Rd = Bits32(opcode, 2, 0); + Rn = Rd; + Rm = Bits32(opcode, 5, 3); + setflags = !InITBlock(); + break; + case eEncodingT2: + Rd = Bits32(opcode, 11, 8); + Rn = Bits32(opcode, 19, 16); + Rm = Bits32(opcode, 3, 0); + setflags = BitIsSet(opcode, 20); + if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) + return false; + break; + case eEncodingA1: + Rd = Bits32(opcode, 15, 12); + Rn = Bits32(opcode, 3, 0); + Rm = Bits32(opcode, 11, 8); + setflags = BitIsSet(opcode, 20); + if (Rd == 15 || Rn == 15 || Rm == 15) + return false; + break; + default: + return false; + } + + // Get the first operand. + uint32_t value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); + if (!success) + return false; + // Get the Rm register content. + uint32_t val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); + if (!success) + return false; + + // Get the shift amount. + uint32_t amt = Bits32(val, 7, 0); + + uint32_t result = Shift_C(value, SRType_ASR, amt, Bit32(m_inst_cpsr, CPSR_C), carry); + + // The context specifies that an immediate is to be moved into Rd. + EmulateInstruction::Context context; + context.type = EmulateInstruction::eContextImmediate; + context.SetNoArgs (); + + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, result)) + return false; + if (setflags) + { + m_new_inst_cpsr = m_inst_cpsr; + SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(result, CPSR_N)); + SetBit32(m_new_inst_cpsr, CPSR_Z, result == 0 ? 1 : 0); + SetBit32(m_new_inst_cpsr, CPSR_C, carry); + if (m_new_inst_cpsr != m_inst_cpsr) + { + if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) + return false; + } + } + } + return true; +} + // LDM loads multiple registers from consecutive memory locations, using an // address from a base register. Optionally the address just above the highest of those locations // can be written back to the base register. @@ -3625,6 +3722,8 @@ EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode) { 0x0fef0000, 0x03e00000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMvnRdImm, "mvn{s} <Rd>, #<const>"}, // asr (immediate) { 0x0fef0070, 0x01a00040, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c> <Rd>, <Rm>, #imm"}, + // asr (immediate) + { 0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c> <Rd>, <Rn>, <Rm>"}, //---------------------------------------------------------------------- // Load instructions @@ -3753,6 +3852,9 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode) // asr (immediate) { 0xfffff800, 0x00001000, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"}, { 0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"}, + // asr (register) + { 0xffffffc0, 0x00004100, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateASRReg, "asrs|asr<c> <Rdn>, <Rm>"}, + { 0xffe0f0f0, 0xfa40f000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c>.w <Rd>, <Rn>, <Rm>"}, //---------------------------------------------------------------------- // Load instructions diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index 7ea87252c64..08ce5297353 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -308,6 +308,10 @@ protected: bool EmulateASRImm (ARMEncoding encoding); + // A8.6.15 ASR (register) + bool + EmulateASRReg (ARMEncoding encoding); + bool EmulateLDM (ARMEncoding encoding); |

