diff --git a/src/frontend/A32/decoder/arm.inc b/src/frontend/A32/decoder/arm.inc index 77a8023b..dfd7a519 100644 --- a/src/frontend/A32/decoder/arm.inc +++ b/src/frontend/A32/decoder/arm.inc @@ -91,6 +91,7 @@ INST(arm_WFE, "WFE", "----0011001000001111000000000010 INST(arm_WFI, "WFI", "----0011001000001111000000000011") // v6K INST(arm_YIELD, "YIELD", "----0011001000001111000000000001") // v6K INST(arm_NOP, "Reserved Hint", "----0011001000001111------------") +INST(arm_NOP, "Reserved Hint", "----001100100000111100000000----") // Synchronization Primitive instructions INST(arm_CLREX, "CLREX", "11110101011111111111000000011111") // v6K @@ -271,7 +272,7 @@ INST(arm_QDSUB, "QDSUB", "cccc00010110nnnndddd00000101mmmm INST(arm_CPS, "CPS", "111100010000---00000000---0-----") // v6 INST(arm_SETEND, "SETEND", "1111000100000001000000e000000000") // v6 INST(arm_MRS, "MRS", "cccc000100001111dddd000000000000") // v3 -INST(arm_MSR_imm, "MSR (imm)", "cccc00110010mm001111rrrrvvvvvvvv") // v3 -INST(arm_MSR_reg, "MSR (reg)", "cccc00010010mm00111100000000nnnn") // v3 +INST(arm_MSR_imm, "MSR (imm)", "cccc00110010mmmm1111rrrrvvvvvvvv") // v3 +INST(arm_MSR_reg, "MSR (reg)", "cccc00010010mmmm111100000000nnnn") // v3 INST(arm_RFE, "RFE", "1111100--0-1----0000101000000000") // v6 INST(arm_SRS, "SRS", "1111100--1-0110100000101000-----") // v6 diff --git a/src/frontend/A32/translate/translate_arm/status_register_access.cpp b/src/frontend/A32/translate/translate_arm/status_register_access.cpp index da6f4456..e642e584 100644 --- a/src/frontend/A32/translate/translate_arm/status_register_access.cpp +++ b/src/frontend/A32/translate/translate_arm/status_register_access.cpp @@ -25,10 +25,11 @@ bool ArmTranslatorVisitor::arm_MRS(Cond cond, Reg d) { } 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"); + const bool write_nzcvq = Common::Bit<3>(mask); + const bool write_g = Common::Bit<2>(mask); + const bool write_e = Common::Bit<1>(mask); + const u32 imm32 = ArmExpandImm(rotate, imm8); + ASSERT_MSG(mask != 0, "Decode error"); // MSR , # if (ConditionPassed(cond)) { if (write_nzcvq) { @@ -37,25 +38,44 @@ bool ArmTranslatorVisitor::arm_MSR_imm(Cond cond, int mask, int rotate, Imm8 imm if (write_g) { ir.SetGEFlagsCompressed(ir.Imm32(imm32 & 0x000F0000)); } + if (write_e) { + const bool E = (imm32 & 0x00000200) != 0; + if (E != ir.current_location.EFlag()) { + ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(4).SetEFlag(E)}); + return false; + } + } } 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) + const bool write_nzcvq = Common::Bit<3>(mask); + const bool write_g = Common::Bit<2>(mask); + const bool write_e = Common::Bit<1>(mask); + if (mask == 0) return UnpredictableInstruction(); if (n == Reg::PC) return UnpredictableInstruction(); // MSR , # if (ConditionPassed(cond)) { - auto value = ir.GetRegister(n); - if (write_nzcvq){ - ir.SetCpsrNZCVQ(ir.And(value, ir.Imm32(0xF8000000))); - } - if (write_g){ - ir.SetGEFlagsCompressed(ir.And(value, ir.Imm32(0x000F0000))); + const auto value = ir.GetRegister(n); + if (!write_e) { + if (write_nzcvq) { + ir.SetCpsrNZCVQ(ir.And(value, ir.Imm32(0xF8000000))); + } + if (write_g) { + ir.SetGEFlagsCompressed(ir.And(value, ir.Imm32(0x000F0000))); + } + } else { + const u32 cpsr_mask = (write_nzcvq ? 0xF8000000 : 0) | (write_g ? 0x000F0000 : 0) | 0x00000200; + const auto old_cpsr = ir.And(ir.GetCpsr(), ir.Imm32(~cpsr_mask)); + const auto new_cpsr = ir.And(value, ir.Imm32(cpsr_mask)); + ir.SetCpsr(ir.Or(old_cpsr, new_cpsr)); + ir.PushRSB(ir.current_location.AdvancePC(4)); + ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + 4)); + ir.SetTerm(IR::Term::CheckHalt{IR::Term::PopRSBHint{}}); + return false; } } return true;