Ryujinx/ARMeilleure/Instructions/InstEmitSystem32.cs
Mary 501c3d5cea
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
2021-08-27 00:07:44 +02:00

332 lines
12 KiB
C#

using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
static partial class InstEmit32
{
public static void Mcr(ArmEmitterContext context)
{
OpCode32System op = (OpCode32System)context.CurrOp;
if (op.Coproc != 15)
{
InstEmit.Und(context);
return;
}
if (op.Opc1 != 0)
{
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
}
MethodInfo info;
switch (op.CRn)
{
case 13: // Process and Thread Info.
if (op.CRm != 0)
{
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
switch (op.Opc2)
{
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032)); break;
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
break;
case 7:
switch (op.CRm) // Cache and Memory barrier.
{
case 10:
switch (op.Opc2)
{
case 5: // Data Memory Barrier Register.
return; // No-op.
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
default:
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
default:
throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
context.Call(info, GetIntA32(context, op.Rt));
}
public static void Mrc(ArmEmitterContext context)
{
OpCode32System op = (OpCode32System)context.CurrOp;
if (op.Coproc != 15)
{
InstEmit.Und(context);
return;
}
if (op.Opc1 != 0)
{
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
}
MethodInfo info;
switch (op.CRn)
{
case 13: // Process and Thread Info.
if (op.CRm != 0)
{
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
switch (op.Opc2)
{
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032)); break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32)); break;
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
break;
default:
throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
if (op.Rt == RegisterAlias.Aarch32Pc)
{
// Special behavior: copy NZCV flags into APSR.
EmitSetNzcv(context, context.Call(info));
return;
}
else
{
SetIntA32(context, op.Rt, context.Call(info));
}
}
public static void Mrrc(ArmEmitterContext context)
{
OpCode32System op = (OpCode32System)context.CurrOp;
if (op.Coproc != 15)
{
InstEmit.Und(context);
return;
}
int opc = op.MrrcOp;
MethodInfo info;
switch (op.CRm)
{
case 14: // Timer.
switch (opc)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
default:
throw new NotImplementedException($"Unknown MRRC Opc1 0x{opc:X16} at 0x{op.Address:X16}.");
}
break;
default:
throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
Operand result = context.Call(info);
SetIntA32(context, op.Rt, context.ConvertI64ToI32(result));
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)
{
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
if (op.Rt == RegisterAlias.Aarch32Pc && op.Sreg == 0b0001)
{
// Special behavior: copy NZCV flags into APSR.
SetFlag(context, PState.VFlag, GetFpFlag(FPState.VFlag));
SetFlag(context, PState.CFlag, GetFpFlag(FPState.CFlag));
SetFlag(context, PState.ZFlag, GetFpFlag(FPState.ZFlag));
SetFlag(context, PState.NFlag, GetFpFlag(FPState.NFlag));
return;
}
switch (op.Sreg)
{
case 0b0000: // FPSID
throw new NotImplementedException("Supervisor Only");
case 0b0001: // FPSCR
EmitGetFpscr(context); return;
case 0b0101: // MVFR2
throw new NotImplementedException("MVFR2");
case 0b0110: // MVFR1
throw new NotImplementedException("MVFR1");
case 0b0111: // MVFR0
throw new NotImplementedException("MVFR0");
case 0b1000: // FPEXC
throw new NotImplementedException("Supervisor Only");
default:
throw new NotImplementedException($"Unknown VMRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
}
public static void Vmsr(ArmEmitterContext context)
{
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
switch (op.Sreg)
{
case 0b0000: // FPSID
throw new NotImplementedException("Supervisor Only");
case 0b0001: // FPSCR
EmitSetFpscr(context); return;
case 0b0101: // MVFR2
throw new NotImplementedException("MVFR2");
case 0b0110: // MVFR1
throw new NotImplementedException("MVFR1");
case 0b0111: // MVFR0
throw new NotImplementedException("MVFR0");
case 0b1000: // FPEXC
throw new NotImplementedException("Supervisor Only");
default:
throw new NotImplementedException($"Unknown VMSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
}
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
{
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
v = context.BitwiseAnd(v, Const(1));
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
c = context.BitwiseAnd(c, Const(1));
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
z = context.BitwiseAnd(z, Const(1));
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
n = context.BitwiseAnd(n, Const(1));
SetFlag(context, PState.VFlag, v);
SetFlag(context, PState.CFlag, c);
SetFlag(context, PState.ZFlag, z);
SetFlag(context, PState.NFlag, n);
}
private static void EmitGetFpscr(ArmEmitterContext context)
{
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
Operand vSh = context.ShiftLeft(GetFpFlag(FPState.VFlag), Const((int)FPState.VFlag));
Operand cSh = context.ShiftLeft(GetFpFlag(FPState.CFlag), Const((int)FPState.CFlag));
Operand zSh = context.ShiftLeft(GetFpFlag(FPState.ZFlag), Const((int)FPState.ZFlag));
Operand nSh = context.ShiftLeft(GetFpFlag(FPState.NFlag), Const((int)FPState.NFlag));
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr)));
SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr));
}
private static void EmitSetFpscr(ArmEmitterContext context)
{
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
Operand t = GetIntA32(context, op.Rt);
Operand v = context.ShiftRightUI(t, Const((int)FPState.VFlag));
v = context.BitwiseAnd(v, Const(1));
Operand c = context.ShiftRightUI(t, Const((int)FPState.CFlag));
c = context.BitwiseAnd(c, Const(1));
Operand z = context.ShiftRightUI(t, Const((int)FPState.ZFlag));
z = context.BitwiseAnd(z, Const(1));
Operand n = context.ShiftRightUI(t, Const((int)FPState.NFlag));
n = context.BitwiseAnd(n, Const(1));
SetFpFlag(context, FPState.VFlag, v);
SetFpFlag(context, FPState.CFlag, c);
SetFpFlag(context, FPState.ZFlag, z);
SetFpFlag(context, FPState.NFlag, n);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr)), t);
}
}
}