From 501c3d5cea6b96f991453cc6f8d395d358d0d4c3 Mon Sep 17 00:00:00 2001 From: Mary Date: Fri, 27 Aug 2021 00:07:44 +0200 Subject: [PATCH] Implement MSR instruction for A32 (#2585) * Implement MSR instruction Fix #1342. Now Pocket Rumble is playable. * Address gdkchan's comments * Address gdkchan's comments * Address gdkchan's comment --- ARMeilleure/Decoders/OpCode32MsrReg.cs | 29 +++++++++++++++ ARMeilleure/Decoders/OpCodeTable.cs | 1 + ARMeilleure/Instructions/InstEmitSystem32.cs | 39 ++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 ARMeilleure/Decoders/OpCode32MsrReg.cs diff --git a/ARMeilleure/Decoders/OpCode32MsrReg.cs b/ARMeilleure/Decoders/OpCode32MsrReg.cs new file mode 100644 index 000000000..d897ffd80 --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32MsrReg.cs @@ -0,0 +1,29 @@ +using ARMeilleure.State; + +namespace ARMeilleure.Decoders +{ + class OpCode32MsrReg : OpCode32 + { + public bool R { get; } + public int Mask { get; } + public int Rd { get; } + public bool Banked { get; } + public int Rn { get; } + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MsrReg(inst, address, opCode); + + public OpCode32MsrReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + R = ((opCode >> 22) & 1) != 0; + Mask = (opCode >> 16) & 0xf; + Rd = (opCode >> 12) & 0xf; + Banked = ((opCode >> 9) & 1) != 0; + Rn = (opCode >> 0) & 0xf; + + if (Rn == RegisterAlias.Aarch32Pc || Mask == 0) + { + Instruction = InstDescriptor.Undefined; + } + } + } +} diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index c1ac83635..12ff051ce 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -702,6 +702,7 @@ namespace ARMeilleure.Decoders SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCode32AluImm16.Create); SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, OpCode32System.Create); SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc, InstEmit32.Mrrc, OpCode32System.Create); + SetA32("<<<<00010x10xxxx111100000000xxxx", InstName.Msr, InstEmit32.Msr, OpCode32MsrReg.Create); SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, OpCode32AluMla.Create); SetA32("<<<<0011111x0000xxxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCode32AluImm.Create); SetA32("<<<<0001111x0000xxxxxxxxxxx0xxxx", InstName.Mvn, InstEmit32.Mvn, OpCode32AluRsImm.Create); diff --git a/ARMeilleure/Instructions/InstEmitSystem32.cs b/ARMeilleure/Instructions/InstEmitSystem32.cs index 9e28a1a16..3e7526597 100644 --- a/ARMeilleure/Instructions/InstEmitSystem32.cs +++ b/ARMeilleure/Instructions/InstEmitSystem32.cs @@ -169,6 +169,45 @@ namespace ARMeilleure.Instructions SetIntA32(context, op.CRn, context.ConvertI64ToI32(context.ShiftRightUI(result, Const(32)))); } + public static void Msr(ArmEmitterContext context) + { + OpCode32MsrReg op = (OpCode32MsrReg)context.CurrOp; + + if (op.R) + { + throw new NotImplementedException("SPSR"); + } + else + { + if ((op.Mask & 8) != 0) + { + Operand value = GetIntA32(context, op.Rn); + + EmitSetNzcv(context, value); + + Operand q = context.ShiftRightUI(value, Const((int)PState.QFlag)); + q = context.BitwiseAnd(q, Const(1)); + + SetFlag(context, PState.QFlag, q); + } + + if ((op.Mask & 4) != 0) + { + throw new NotImplementedException("APSR_g"); + } + + if ((op.Mask & 2) != 0) + { + throw new NotImplementedException("CPSR_x"); + } + + if ((op.Mask & 1) != 0) + { + throw new NotImplementedException("CPSR_c"); + } + } + } + public static void Nop(ArmEmitterContext context) { } public static void Vmrs(ArmEmitterContext context)