diff options
Diffstat (limited to 'src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs')
| -rw-r--r-- | src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs | 77 |
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); + } + } + } +} |
