diff --git a/src/binary_translation/ARMFuncs.cpp b/src/binary_translation/ARMFuncs.cpp index 9608fba31..2ce1ae643 100644 --- a/src/binary_translation/ARMFuncs.cpp +++ b/src/binary_translation/ARMFuncs.cpp @@ -165,4 +165,13 @@ ARMFuncs::ResultCarry ARMFuncs::RRX_C(InstructionBlock* instruction, llvm::Value result = ir_builder->CreateOr(result, ir_builder->CreateShl(ir_builder->CreateZExt(carry_in, ir_builder->getInt32Ty()), 31)); auto carry = ir_builder->CreateTrunc(x, ir_builder->getInt1Ty()); return{ result, carry }; +} + +ARMFuncs::ResultCarry ARMFuncs::ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value* carry) +{ + auto ir_builder = instruction->IrBuilder(); + + auto value = ir_builder->getInt32(imm12 & 0xFF); + auto shift = ir_builder->getInt32(2 * (imm12 >> 8)); + return Shift_C(instruction, value, SRType::ROR, shift, carry); } \ No newline at end of file diff --git a/src/binary_translation/ARMFuncs.h b/src/binary_translation/ARMFuncs.h index fc6f55d34..86ba43ab9 100644 --- a/src/binary_translation/ARMFuncs.h +++ b/src/binary_translation/ARMFuncs.h @@ -3,7 +3,8 @@ /* * Functions from the manual, * A8.4.3 Pseudocode details of instruction-specified shifts and rotates - * A2.2.1 Integer arithmetic + * A2.2.1 Integer arithmetic + * A5.2.4 Modified immediate constants in ARM instructions */ class InstructionBlock; @@ -39,4 +40,6 @@ public: static ResultCarry ASR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift); static ResultCarry ROR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift); static ResultCarry RRX_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *carry_in); + + static ResultCarry ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value *carry); }; \ No newline at end of file diff --git a/src/binary_translation/Instructions/MovShift.cpp b/src/binary_translation/Instructions/MovShift.cpp index 114008875..22a7a2f5f 100644 --- a/src/binary_translation/Instructions/MovShift.cpp +++ b/src/binary_translation/Instructions/MovShift.cpp @@ -3,12 +3,12 @@ #include "InstructionBlock.h" #include "ModuleGen.h" #include "ARMFuncs.h" +#include static RegisterInstruction register_instruction; bool MovShift::Decode() { - // Mov and shifts must have zeroes at some operands of different data processing instructions if (ReadFields({ CondDef(), FieldDef<3>(0), FieldDef<4>(13), FieldDef<1>(&s), FieldDef<4>(0), FieldDef<4>(&rd), FieldDef<5>(&imm5), FieldDef<2>(&op2), FieldDef<1>(0), FieldDef<4>(&rm) })) { @@ -17,6 +17,20 @@ bool MovShift::Decode() if (rd == Register::PC && s) return false; // SEE SUBS PC, LR and related instructions; return true; } + if (ReadFields({ CondDef(), FieldDef<7>(0x1d), FieldDef<1>(&s), FieldDef<4>(0), + FieldDef<4>(&rd), FieldDef<12>(&imm12) })) + { + form = Form::ImmediateA1; + return true; + } + if (ReadFields({ CondDef(), FieldDef<8>(0x30), FieldDef<4>(&imm4), + FieldDef<4>(&rd), FieldDef<12>(&imm12) })) + { + s = false; + form = Form::ImmediateA2; + if (rd == Register::PC) return false; // UNPREDICTIBLE + return true; + } return false; } @@ -24,39 +38,51 @@ void MovShift::GenerateInstructionCode(InstructionBlock* instruction_block) { auto ir_builder = instruction_block->IrBuilder(); - auto original_carry = instruction_block->Read(Register::C); - ARMFuncs::ResultCarry result = { instruction_block->Read(rm), original_carry }; + auto carry_in = instruction_block->Read(Register::C); + ARMFuncs::ResultCarry result = {}; - switch (op2) - { - case Op2Type::MoveAndLSL: - if (imm5 != 0) - { - result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSL, - ARMFuncs::DecodeImmShift(instruction_block, 0, imm5).amount, result.carry); - } - break; - case Op2Type::LSR: - result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSR, - ARMFuncs::DecodeImmShift(instruction_block, 1, imm5).amount, result.carry); - break; - case Op2Type::ASR: - result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ASR, - ARMFuncs::DecodeImmShift(instruction_block, 2, imm5).amount, result.carry); - break; - case Op2Type::RRXAndROR: - if (imm5 == 0) - { - result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::RRX, - ir_builder->getInt32(1), result.carry); - } - else - { - result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ROR, - ARMFuncs::DecodeImmShift(instruction_block, 3, imm5).amount, result.carry); - } - break; - } + switch (form) + { + case Form::Register: + result = { instruction_block->Read(rm), carry_in }; + switch (op2) + { + case Op2Type::MoveAndLSL: + if (imm5 != 0) + { + result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSL, + ARMFuncs::DecodeImmShift(instruction_block, 0, imm5).amount, result.carry); + } + break; + case Op2Type::LSR: + result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSR, + ARMFuncs::DecodeImmShift(instruction_block, 1, imm5).amount, result.carry); + break; + case Op2Type::ASR: + result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ASR, + ARMFuncs::DecodeImmShift(instruction_block, 2, imm5).amount, result.carry); + break; + case Op2Type::RRXAndROR: + if (imm5 == 0) + { + result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::RRX, + ir_builder->getInt32(1), result.carry); + } + else + { + result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ROR, + ARMFuncs::DecodeImmShift(instruction_block, 3, imm5).amount, result.carry); + } + break; + } + break; + case Form::ImmediateA1: + result = ARMFuncs::ARMExpandImm_C(instruction_block, imm12, carry_in); + break; + case Form::ImmediateA2: + result.result = ir_builder->getInt32((imm4 << 12) | imm12); + break; + } instruction_block->Write(rd, result.result); @@ -64,7 +90,7 @@ void MovShift::GenerateInstructionCode(InstructionBlock* instruction_block) { instruction_block->Write(Register::N, ir_builder->CreateTrunc(ir_builder->CreateLShr(result.result, 31), ir_builder->getInt1Ty())); instruction_block->Write(Register::Z, ir_builder->CreateICmpEQ(result.result, ir_builder->getInt32(0))); - if (result.carry != original_carry) + if (result.carry != carry_in) instruction_block->Write(Register::C, result.carry); } diff --git a/src/binary_translation/Instructions/MovShift.h b/src/binary_translation/Instructions/MovShift.h index cd892e97b..32f7f45ab 100644 --- a/src/binary_translation/Instructions/MovShift.h +++ b/src/binary_translation/Instructions/MovShift.h @@ -15,7 +15,7 @@ public: }; enum class Form { - Register, RegisterShiftedRegister, Immediate + Register, ImmediateA1, ImmediateA2 }; public: @@ -29,5 +29,6 @@ private: Register rm; u32 imm12; u32 imm5; + u32 imm4; Op2Type op2; }; \ No newline at end of file