aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs')
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs
new file mode 100644
index 00000000..8c7bf91d
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs
@@ -0,0 +1,77 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonSystem
+ {
+ public static void Vmrs(CodeGenContext context, uint rt, uint reg)
+ {
+ if (context.ConsumeSkipNextInstruction())
+ {
+ // This case means that we managed to combine a VCMP and VMRS instruction,
+ // so we have nothing to do here as FCMP/FCMPE already set PSTATE.NZCV.
+ context.SetNzcvModified();
+
+ return;
+ }
+
+ if (reg == 1)
+ {
+ // FPSCR
+
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ if (rt == RegisterUtils.PcRegister)
+ {
+ using ScopedRegister fpsrRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(fpsrRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+ context.Arm64Assembler.Lsr(fpsrRegister.Operand, fpsrRegister.Operand, InstEmitCommon.Const(28));
+
+ InstEmitCommon.RestoreNzcvFlags(context, fpsrRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ else
+ {
+ // FPSCR is a combination of the FPCR and FPSR registers.
+ // We also need to set the FPSR NZCV bits that no longer exist on AArch64.
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+
+ context.Arm64Assembler.MrsFpsr(rtOperand);
+ context.Arm64Assembler.MrsFpcr(tempRegister.Operand);
+ context.Arm64Assembler.Orr(rtOperand, rtOperand, tempRegister.Operand);
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+ context.Arm64Assembler.Bfc(tempRegister.Operand, 0, 28);
+ context.Arm64Assembler.Orr(rtOperand, rtOperand, tempRegister.Operand);
+ }
+ }
+ else
+ {
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+
+ context.Arm64Assembler.Mov(rtOperand, 0u);
+ }
+ }
+
+ public static void Vmsr(CodeGenContext context, uint rt, uint reg)
+ {
+ if (reg == 1)
+ {
+ // FPSCR
+
+ // TODO: Do not set bits related to features that are not supported (like FP16)?
+
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+
+ context.Arm64Assembler.MsrFpcr(rtOperand);
+ context.Arm64Assembler.MsrFpsr(rtOperand);
+ context.Arm64Assembler.StrRiUn(rtOperand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+ }
+ }
+ }
+}