From e164ede4dca052dc3dfae1e8151e943a062cc0f8 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 14 Aug 2016 19:39:16 +0100 Subject: [PATCH] TranslateArm: Implement MRS, MSR (imm), MSR (reg) --- src/backend_x64/emit_x64.cpp | 10 ++++ src/frontend/decoder/arm.h | 5 +- .../disassembler/disassembler_arm.cpp | 15 +++++- src/frontend/ir/ir_emitter.cpp | 8 +++ src/frontend/ir/ir_emitter.h | 2 + src/frontend/ir/opcodes.inc | 2 + .../translate_arm/status_register_access.cpp | 50 +++++++++++++++++-- .../translate/translate_arm/translate_arm.h | 5 +- src/ir_opt/get_set_elimination_pass.cpp | 8 +++ 9 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 08b51183..4dec3115 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -209,6 +209,16 @@ void EmitX64::EmitSetZFlag(IR::Block&, IR::Inst* inst) { } } +void EmitX64::EmitGetCpsr(IR::Block&, IR::Inst* inst) { + X64Reg result = reg_alloc.DefRegister(inst, any_gpr); + code->MOV(32, R(result), MJitStateCpsr()); +} + +void EmitX64::EmitSetCpsr(IR::Block&, IR::Inst* inst) { + X64Reg arg = reg_alloc.UseRegister(inst->GetArg(0), any_gpr); + code->MOV(32, MJitStateCpsr(), R(arg)); +} + void EmitX64::EmitGetCFlag(IR::Block&, IR::Inst* inst) { X64Reg result = reg_alloc.DefRegister(inst, any_gpr); code->MOV(32, R(result), MJitStateCpsr()); diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index ad955408..6e5d3eb4 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -343,8 +343,9 @@ std::vector> GetArmDecodeTable() { // Status Register Access instructions INST(&V::arm_CPS, "CPS", "111100010000---00000000---0-----"), // v6 INST(&V::arm_SETEND, "SETEND", "1111000100000001000000e000000000"), // v6 - INST(&V::arm_MRS, "MRS", "----00010-00--------00--00000000"), // v3 - INST(&V::arm_MSR, "MSR", "----00-10-10----1111------------"), // v3 + INST(&V::arm_MRS, "MRS", "cccc000100001111dddd000000000000"), // v3 + INST(&V::arm_MSR_imm, "MSR (imm)", "cccc00110010mm001111rrrrvvvvvvvv"), // v3 + INST(&V::arm_MSR_reg, "MSR (reg)", "cccc00010010mm00111100000000nnnn"), // v3 INST(&V::arm_RFE, "RFE", "----0001101-0000---------110----"), // v6 INST(&V::arm_SRS, "SRS", "0000011--0-00000000000000001----"), // v6 diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index f5f74895..7ee9b042 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -749,8 +749,19 @@ public: // Status register access instructions std::string arm_CPS() { return "ice"; } - std::string arm_MRS() { return "ice"; } - std::string arm_MSR() { return "ice"; } + std::string arm_MRS(Cond cond, Reg d) { + return Common::StringFromFormat("mrs%s %s, apsr", CondToString(cond), RegToString(d)); + } + std::string arm_MSR_imm(Cond cond, int mask, int rotate, Imm8 imm8) { + bool write_nzcvq = Common::Bit<1>(mask); + bool write_g = Common::Bit<0>(mask); + return Common::StringFromFormat("msr%s apsr_%s%s, #%u", CondToString(cond), write_nzcvq ? "nzcvq" : "", write_g ? "g" : "", ArmExpandImm(rotate, imm8)); + } + std::string arm_MSR_reg(Cond cond, int mask, Reg n) { + bool write_nzcvq = Common::Bit<1>(mask); + bool write_g = Common::Bit<0>(mask); + return Common::StringFromFormat("msr%s apsr_%s%s, %s", CondToString(cond), write_nzcvq ? "nzcvq" : "", write_g ? "g" : "", RegToString(n)); + } std::string arm_RFE() { return "ice"; } std::string arm_SETEND(bool E) { return E ? "setend be" : "setend le"; diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 8fbba46a..a4381db6 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -102,6 +102,14 @@ void IREmitter::PushRSB(const LocationDescriptor& return_location) { Inst(IR::Opcode::PushRSB, {IR::Value(return_location.UniqueHash())}); } +IR::Value IREmitter::GetCpsr() { + return Inst(IR::Opcode::GetCpsr, {}); +} + +void IREmitter::SetCpsr(const IR::Value& value) { + Inst(IR::Opcode::SetCpsr, {value}); +} + IR::Value IREmitter::GetCFlag() { return Inst(IR::Opcode::GetCFlag, {}); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 58ac6f75..e559c18c 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -56,6 +56,8 @@ public: void CallSupervisor(const IR::Value& value); void PushRSB(const LocationDescriptor& return_location); + IR::Value GetCpsr(); + void SetCpsr(const IR::Value& value); IR::Value GetCFlag(); void SetNFlag(const IR::Value& value); void SetZFlag(const IR::Value& value); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index c81be50e..df01681e 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -10,6 +10,8 @@ OPCODE(GetExtendedRegister64, T::F64, T::ExtRegRef OPCODE(SetRegister, T::Void, T::RegRef, T::U32 ) OPCODE(SetExtendedRegister32, T::Void, T::ExtRegRef, T::F32 ) OPCODE(SetExtendedRegister64, T::Void, T::ExtRegRef, T::F64 ) +OPCODE(GetCpsr, T::U32, ) +OPCODE(SetCpsr, T::Void, T::U32 ) OPCODE(GetNFlag, T::U1, ) OPCODE(SetNFlag, T::Void, T::U1 ) OPCODE(GetZFlag, T::U1, ) diff --git a/src/frontend/translate/translate_arm/status_register_access.cpp b/src/frontend/translate/translate_arm/status_register_access.cpp index 563cad55..ba5f4a93 100644 --- a/src/frontend/translate/translate_arm/status_register_access.cpp +++ b/src/frontend/translate/translate_arm/status_register_access.cpp @@ -13,12 +13,54 @@ bool ArmTranslatorVisitor::arm_CPS() { return InterpretThisInstruction(); } -bool ArmTranslatorVisitor::arm_MRS() { - return InterpretThisInstruction(); +bool ArmTranslatorVisitor::arm_MRS(Cond cond, Reg d) { + if (d == Reg::PC) + return UnpredictableInstruction(); + // MRS , APSR + if (ConditionPassed(cond)) { + ir.SetRegister(d, ir.GetCpsr()); + } + return true; } -bool ArmTranslatorVisitor::arm_MSR() { - return InterpretThisInstruction(); +bool ArmTranslatorVisitor::arm_MSR_imm(Cond cond, int mask, int rotate, Imm8 imm8) { + bool write_nzcvq = Common::Bit<1>(mask); + bool write_g = Common::Bit<0>(mask); + u32 imm32 = ArmExpandImm(rotate, imm8); + ASSERT_MSG(write_nzcvq || write_g, "Decode error"); + // MSR , # + if (ConditionPassed(cond)) { + u32 cpsr_mask = 0; + if (write_nzcvq) + cpsr_mask |= 0xF8000000; + if (write_g) + cpsr_mask |= 0x000F0000; + auto old_cpsr = ir.And(ir.GetCpsr(), ir.Imm32(~cpsr_mask)); + auto new_cpsr = ir.Imm32(imm32 & cpsr_mask); + ir.SetCpsr(ir.Or(old_cpsr, new_cpsr)); + } + return true; +} + +bool ArmTranslatorVisitor::arm_MSR_reg(Cond cond, int mask, Reg n) { + bool write_nzcvq = Common::Bit<1>(mask); + bool write_g = Common::Bit<0>(mask); + if (!write_nzcvq && !write_g) + return UnpredictableInstruction(); + if (n == Reg::PC) + return UnpredictableInstruction(); + // MSR , # + if (ConditionPassed(cond)) { + u32 cpsr_mask = 0; + if (write_nzcvq) + cpsr_mask |= 0xF8000000; + if (write_g) + cpsr_mask |= 0x000F0000; + auto old_cpsr = ir.And(ir.GetCpsr(), ir.Imm32(~cpsr_mask)); + auto new_cpsr = ir.And(ir.GetRegister(n), ir.Imm32(cpsr_mask)); + ir.SetCpsr(ir.Or(old_cpsr, new_cpsr)); + } + return true; } bool ArmTranslatorVisitor::arm_RFE() { diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index 8a816e5a..a7532c0f 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -318,8 +318,9 @@ struct ArmTranslatorVisitor final { // Status register access instructions bool arm_CPS(); - bool arm_MRS(); - bool arm_MSR(); + bool arm_MRS(Cond cond, Reg d); + bool arm_MSR_imm(Cond cond, int mask, int rotate, Imm8 imm8); + bool arm_MSR_reg(Cond cond, int mask, Reg n); bool arm_RFE(); bool arm_SETEND(bool E); bool arm_SRS(); diff --git a/src/ir_opt/get_set_elimination_pass.cpp b/src/ir_opt/get_set_elimination_pass.cpp index 3ac3943b..1d7d7f2a 100644 --- a/src/ir_opt/get_set_elimination_pass.cpp +++ b/src/ir_opt/get_set_elimination_pass.cpp @@ -92,6 +92,14 @@ void GetSetElimination(IR::Block& block) { do_get(v_info, inst); break; } + case IR::Opcode::SetCpsr: + case IR::Opcode::GetCpsr: { + n_info = {}; + z_info = {}; + c_info = {}; + v_info = {}; + break; + } default: break; }