diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 328d4e13..078e97db 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -82,7 +82,7 @@ INST(MRS, "MRS", "11010 // System - Flag manipulation instructions INST(CFINV, "CFINV", "11010101000000000100000000011111") // ARMv8.4 -//INST(RMIF, "RMIF", "10111010000iiiiii00001nnnnn0IIII") // ARMv8.4 +INST(RMIF, "RMIF", "10111010000iiiiii00001nnnnn0IIII") // ARMv8.4 //INST(SETF8, "SETF8", "0011101000000000000010nnnnn01101") // ARMv8.4 //INST(SETF16, "SETF16", "0011101000000000010010nnnnn01101") // ARMv8.4 diff --git a/src/frontend/A64/translate/impl/system_flag_manipulation.cpp b/src/frontend/A64/translate/impl/system_flag_manipulation.cpp index 0ce291ff..418caf3f 100644 --- a/src/frontend/A64/translate/impl/system_flag_manipulation.cpp +++ b/src/frontend/A64/translate/impl/system_flag_manipulation.cpp @@ -16,4 +16,48 @@ bool TranslatorVisitor::CFINV() { return true; } +bool TranslatorVisitor::RMIF(Imm<6> lsb, Reg Rn, Imm<4> mask) { + const u32 mask_value = mask.ZeroExtend(); + + // If no bits are to be moved into the NZCV bits, then we + // just preserve the bits and do no extra work. + if (mask_value == 0) { + ir.SetNZCVRaw(ir.GetNZCVRaw()); + return true; + } + + const IR::U64 tmp_reg = ir.GetX(Rn); + const IR::U64 rotated = ir.RotateRight(tmp_reg, ir.Imm8(lsb.ZeroExtend())); + const IR::U32 shifted = ir.LeastSignificantWord(ir.LogicalShiftLeft(rotated, ir.Imm8(28))); + + // On the other hand, if all mask bits are set, then we move all four + // relevant bits in the source register to the NZCV bits. + if (mask_value == 0b1111) { + ir.SetNZCVRaw(shifted); + return true; + } + + // Determine which bits from the PSTATE will be preserved during the operation. + u32 preservation_mask = 0; + if ((mask_value & 0b1000) == 0) { + preservation_mask |= 1U << 31; + } + if ((mask_value & 0b0100) == 0) { + preservation_mask |= 1U << 30; + } + if ((mask_value & 0b0010) == 0) { + preservation_mask |= 1U << 29; + } + if ((mask_value & 0b0001) == 0) { + preservation_mask |= 1U << 28; + } + + const IR::U32 masked = ir.And(shifted, ir.Imm32(~preservation_mask)); + const IR::U32 nzcv = ir.And(ir.GetNZCVRaw(), ir.Imm32(preservation_mask)); + const IR::U32 result = ir.Or(nzcv, masked); + + ir.SetNZCVRaw(result); + return true; +} + } // namespace Dynarmic::A64