From 814f75142e8e4e81741a859db8189ca60535f3e6 Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Tue, 20 Sep 2022 23:55:13 +0200 Subject: [PATCH] Fpsr and Fpcr freed. (#3701) * Implemented in IR the managed methods of the Saturating region ... ... of the SoftFallback class (the SatQ ones). The need to natively manage the Fpcr and Fpsr system registers is still a fact. Contributes to https://github.com/Ryujinx/Ryujinx/issues/2917 ; I will open another PR to implement in Intrinsics-branchless the methods of the Saturation region as well (the SatXXXToXXX ones). All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq. * Ptc.InternalVersion = 3665 * Addressed PR feedback. * Implemented in IR the managed methods of the ShlReg region of the SoftFallback class. It also includes the last two SatQ ones (following up on https://github.com/Ryujinx/Ryujinx/pull/3665). All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq. * Fpsr and Fpcr freed. Handling/isolation of Fpsr and Fpcr via register for IR and via memory for Tests and Threads, with synchronization to context exchanges (explicit for SoftFloat); without having to call managed methods. Thanks to the inlining work of the previous two PRs and others in this. Tests performed locally in both release and debug modes, in both lowcq and highcq, with FastFP to true and false (explicit FP tests included). Tested with the title Tony Hawk's PS. Depends on shlreg. * Update InstEmitSimdHelper.cs * De-magic Masks. Remove the Stride and Len flags; Fpsr.NZCV are A32 only, then moved to Fpscr: this leads to emitting less IR in reference to Get/Set Fpsr/Fpcr/Fpscr methods in reference to Mrs/Msr (A64) and Vmrs/Vmsr (A32) instructions. * Addressed PR feedback. --- .../Instructions/InstEmitSimdArithmetic.cs | 56 ++-------- ARMeilleure/Instructions/InstEmitSimdCmp32.cs | 30 +----- ARMeilleure/Instructions/InstEmitSimdCvt.cs | 12 +++ ARMeilleure/Instructions/InstEmitSimdCvt32.cs | 39 ++----- .../Instructions/InstEmitSimdHelper.cs | 92 ++++++++++++---- .../Instructions/InstEmitSimdHelper32.cs | 6 +- .../Instructions/InstEmitSimdShift32.cs | 3 +- ARMeilleure/Instructions/InstEmitSystem.cs | 102 +++++++++++++----- ARMeilleure/Instructions/InstEmitSystem32.cs | 75 +++++-------- ARMeilleure/Instructions/NativeInterface.cs | 46 -------- ARMeilleure/Instructions/SoftFallback.cs | 70 ------------ ARMeilleure/Instructions/SoftFloat.cs | 11 +- ARMeilleure/State/ExecutionContext.cs | 19 +++- ARMeilleure/State/FPCR.cs | 19 ++-- ARMeilleure/State/FPSCR.cs | 15 +++ ARMeilleure/State/FPSR.cs | 11 +- ARMeilleure/State/FPState.cs | 23 +++- ARMeilleure/State/NativeContext.cs | 28 +++++ ARMeilleure/Translation/Delegates.cs | 14 --- ARMeilleure/Translation/PTC/Ptc.cs | 2 +- Ryujinx.Tests/Cpu/CpuTest32.cs | 27 +---- 21 files changed, 321 insertions(+), 379 deletions(-) create mode 100644 ARMeilleure/State/FPSCR.cs diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs index 9a632fd63..a35e28a15 100644 --- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs +++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs @@ -726,7 +726,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2); }); } } @@ -774,7 +774,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2); }); } } @@ -900,7 +900,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2); }); } } @@ -948,7 +948,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2); }); } } @@ -1633,37 +1633,17 @@ namespace ARMeilleure.Instructions public static void Frinti_S(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - EmitScalarUnaryOpF(context, (op1) => { - if (op.Size == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (op.Size == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } public static void Frinti_V(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - EmitVectorUnaryOpF(context, (op1) => { - if (sizeF == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (sizeF == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } @@ -1759,37 +1739,17 @@ namespace ARMeilleure.Instructions public static void Frintx_S(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - EmitScalarUnaryOpF(context, (op1) => { - if (op.Size == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (op.Size == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } public static void Frintx_V(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - EmitVectorUnaryOpF(context, (op1) => { - if (sizeF == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (sizeF == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs index 1acc74657..339d32939 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs @@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; using ARMeilleure.Translation; using System; -using System.Reflection; using static ARMeilleure.Instructions.InstEmitHelper; using static ARMeilleure.Instructions.InstEmitSimdHelper; @@ -178,37 +177,20 @@ namespace ARMeilleure.Instructions private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero) { - Operand one = Const(1); if (zero) { EmitVectorUnaryOpF32(context, (m) => { - OperandType type = m.Type; + Operand zeroOp = m.Type == OperandType.FP64 ? ConstF(0.0d) : ConstF(0.0f); - if (type == OperandType.FP64) - { - return context.Call(typeof(SoftFloat64).GetMethod(name), m, ConstF(0.0d), one); - } - else - { - return context.Call(typeof(SoftFloat32).GetMethod(name), m, ConstF(0.0f), one); - } + return EmitSoftFloatCallDefaultFpscr(context, name, m, zeroOp); }); } else { EmitVectorBinaryOpF32(context, (n, m) => { - OperandType type = n.Type; - - if (type == OperandType.FP64) - { - return context.Call(typeof(SoftFloat64).GetMethod(name), n, m, one); - } - else - { - return context.Call(typeof(SoftFloat32).GetMethod(name), n, m, one); - } + return EmitSoftFloatCallDefaultFpscr(context, name, n, m); }); } } @@ -357,11 +339,7 @@ namespace ARMeilleure.Instructions me = ExtractScalar(context, type, op.Vm); } - MethodInfo info = sizeF != 0 - ? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)) - : typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)); - - Operand nzcv = context.Call(info, ne, me, Const(signalNaNs)); + Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs)); EmitSetFpscrNzcv(context, nzcv); } diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs index 6994643ed..c8c427b79 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs @@ -76,7 +76,9 @@ namespace ARMeilleure.Instructions { Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); + context.LoadFromContext(); res = context.ZeroExtend16(OperandType.I64, res); @@ -98,7 +100,9 @@ namespace ARMeilleure.Instructions { Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); + context.LoadFromContext(); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); } @@ -120,7 +124,9 @@ namespace ARMeilleure.Instructions { Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne); + context.LoadFromContext(); res = context.ZeroExtend16(OperandType.I64, res); @@ -143,7 +149,9 @@ namespace ARMeilleure.Instructions { Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne); + context.LoadFromContext(); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); } @@ -224,7 +232,9 @@ namespace ARMeilleure.Instructions { Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1); + context.StoreToContext(); Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); + context.LoadFromContext(); res = context.VectorInsert(res, e, index); } @@ -333,7 +343,9 @@ namespace ARMeilleure.Instructions if (sizeF == 0) { + context.StoreToContext(); Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); + context.LoadFromContext(); e = context.ZeroExtend16(OperandType.I64, e); diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs index b06ddd5e7..69ba42747 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs @@ -161,34 +161,15 @@ namespace ARMeilleure.Instructions { Operand toConvert = ExtractScalar(context, floatSize, op.Vm); - Operand asInteger; - // TODO: Fast Path. if (roundWithFpscr) { - MethodInfo info; - - if (floatSize == OperandType.FP64) - { - info = unsigned - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32)); - } - else - { - info = unsigned - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32)); - } - - asInteger = context.Call(info, toConvert); - } - else - { - // Round towards zero. - asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); + toConvert = EmitRoundByRMode(context, toConvert); } + // Round towards zero. + Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); + InsertScalar(context, op.Vd, asInteger); } } @@ -271,9 +252,7 @@ namespace ARMeilleure.Instructions break; } - Operand asInteger; - - asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); + Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); InsertScalar(context, op.Vd, asInteger); } @@ -399,15 +378,9 @@ namespace ARMeilleure.Instructions // VRINTX (floating-point). public static void Vrintx_S(ArmEmitterContext context) { - OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; - - bool doubleSize = (op.Size & 1) == 1; - string methodName = doubleSize ? nameof(SoftFallback.Round) : nameof(SoftFallback.RoundF); - EmitScalarUnaryOpF32(context, (op1) => { - MethodInfo info = typeof(SoftFallback).GetMethod(methodName); - return context.Call(info, op1); + return EmitRoundByRMode(context, op1); }); } diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs index 80dfc6889..49c9e6879 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs @@ -361,6 +361,54 @@ namespace ARMeilleure.Instructions return context.Call(info, n, Const((int)roundMode)); } + public static Operand EmitGetRoundingMode(ArmEmitterContext context) + { + Operand rMode = context.ShiftLeft(GetFpFlag(FPState.RMode1Flag), Const(1)); + rMode = context.BitwiseOr(rMode, GetFpFlag(FPState.RMode0Flag)); + + return rMode; + } + + public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op) + { + Debug.Assert(op.Type == OperandType.FP32 || op.Type == OperandType.FP64); + + Operand lbl1 = Label(); + Operand lbl2 = Label(); + Operand lbl3 = Label(); + Operand lblEnd = Label(); + + Operand rN = Const((int)FPRoundingMode.ToNearest); + Operand rP = Const((int)FPRoundingMode.TowardsPlusInfinity); + Operand rM = Const((int)FPRoundingMode.TowardsMinusInfinity); + + Operand res = context.AllocateLocal(op.Type); + + Operand rMode = EmitGetRoundingMode(context); + + context.BranchIf(lbl1, rMode, rN, Comparison.NotEqual); + context.Copy(res, EmitRoundMathCall(context, MidpointRounding.ToEven, op)); + context.Branch(lblEnd); + + context.MarkLabel(lbl1); + context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual); + context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op)); + context.Branch(lblEnd); + + context.MarkLabel(lbl2); + context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual); + context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op)); + context.Branch(lblEnd); + + context.MarkLabel(lbl3); + context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op)); + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs) { IOpCodeSimd op = (IOpCodeSimd)context.CurrOp; @@ -369,7 +417,11 @@ namespace ARMeilleure.Instructions ? typeof(SoftFloat32).GetMethod(name) : typeof(SoftFloat64).GetMethod(name); - return context.Call(info, callArgs); + context.StoreToContext(); + Operand res = context.Call(info, callArgs); + context.LoadFromContext(); + + return res; } public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit) @@ -1269,7 +1321,7 @@ namespace ARMeilleure.Instructions public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue) { - isTrue = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz))); + isTrue = GetFpFlag(FPState.FzFlag); Operand lblTrue = Label(); context.BranchIfFalse(lblTrue, isTrue); @@ -1281,9 +1333,7 @@ namespace ARMeilleure.Instructions public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default) { - isTrue = isTrue == default - ? context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz))) - : isTrue; + isTrue = isTrue == default ? GetFpFlag(FPState.FzFlag) : isTrue; Operand lblTrue = Label(); context.BranchIfFalse(lblTrue, isTrue); @@ -1552,13 +1602,13 @@ namespace ARMeilleure.Instructions context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual); context.Copy(res, maxT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl1); context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual); context.Copy(res, minT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1583,7 +1633,7 @@ namespace ARMeilleure.Instructions context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI); context.Copy(res, maxT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1610,13 +1660,13 @@ namespace ARMeilleure.Instructions context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual); context.Copy(res, maxT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl1); context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual); context.Copy(res, minT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1641,7 +1691,7 @@ namespace ARMeilleure.Instructions context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI); context.Copy(res, maxT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1663,7 +1713,7 @@ namespace ARMeilleure.Instructions context.BranchIf(lblEnd, op, minL, Comparison.NotEqual); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1691,7 +1741,7 @@ namespace ARMeilleure.Instructions Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL); context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL)); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1713,7 +1763,7 @@ namespace ARMeilleure.Instructions context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI); context.Copy(res, maxUL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1741,7 +1791,7 @@ namespace ARMeilleure.Instructions Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL); context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL)); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1763,7 +1813,7 @@ namespace ARMeilleure.Instructions context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI); context.Copy(res, zeroL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1790,19 +1840,19 @@ namespace ARMeilleure.Instructions Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add); context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl1); context.BranchIf(lbl2, op2, zeroL, Comparison.Less); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl2); context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1828,14 +1878,14 @@ namespace ARMeilleure.Instructions context.BranchIf(lbl1, op1, zeroL, Comparison.Less); context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI); context.Copy(res, maxUL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl1); context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI); context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual); context.Copy(res, zeroL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs index c530985fa..0620ea332 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs @@ -1181,7 +1181,11 @@ namespace ARMeilleure.Instructions Array.Resize(ref callArgs, callArgs.Length + 1); callArgs[callArgs.Length - 1] = Const(1); - return context.Call(info, callArgs); + context.StoreToContext(); + Operand res = context.Call(info, callArgs); + context.LoadFromContext(); + + return res; } public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size) diff --git a/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs index e0968b7b1..9ac680884 100644 --- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs @@ -1,5 +1,6 @@ using ARMeilleure.Decoders; using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; using ARMeilleure.Translation; using System; using System.Diagnostics; @@ -378,7 +379,7 @@ namespace ARMeilleure.Instructions context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt)); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.MarkLabel(lblNoSat); diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs index cdfaa26ec..cc32228c3 100644 --- a/ARMeilleure/Instructions/InstEmitSystem.cs +++ b/ARMeilleure/Instructions/InstEmitSystem.cs @@ -31,8 +31,8 @@ namespace ARMeilleure.Instructions case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break; case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break; case 0b11_011_0100_0010_000: EmitGetNzcv(context); return; - case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break; - case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break; + case 0b11_011_0100_0100_000: EmitGetFpcr(context); return; + case 0b11_011_0100_0100_001: EmitGetFpsr(context); return; case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break; case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break; case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break; @@ -53,9 +53,9 @@ namespace ARMeilleure.Instructions switch (GetPackedId(op)) { - case 0b11_011_0100_0010_000: EmitSetNzcv(context); return; - case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break; - case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break; + case 0b11_011_0100_0010_000: EmitSetNzcv(context); return; + case 0b11_011_0100_0100_000: EmitSetFpcr(context); return; + case 0b11_011_0100_0100_001: EmitSetFpsr(context); return; case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break; default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); @@ -121,39 +121,91 @@ namespace ARMeilleure.Instructions { OpCodeSystem op = (OpCodeSystem)context.CurrOp; - Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); - Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)); - Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)); - Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)); + Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); + nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag))); + nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag))); + nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag))); - Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); + SetIntOrZR(context, op.Rt, nzcv); + } - SetIntOrZR(context, op.Rt, nzcvSh); + private static void EmitGetFpcr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand fpcr = Const(0); + + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPCR.Mask.HasFlag((FPCR)(1u << flag))) + { + fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); + } + } + + SetIntOrZR(context, op.Rt, fpcr); + } + + private static void EmitGetFpsr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand fpsr = Const(0); + + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSR.Mask.HasFlag((FPSR)(1u << flag))) + { + fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); + } + } + + SetIntOrZR(context, op.Rt, fpsr); } private static void EmitSetNzcv(ArmEmitterContext context) { OpCodeSystem op = (OpCodeSystem)context.CurrOp; - Operand t = GetIntOrZR(context, op.Rt); - t = context.ConvertI64ToI32(t); + Operand nzcv = GetIntOrZR(context, op.Rt); + nzcv = context.ConvertI64ToI32(nzcv); - Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag)); - v = context.BitwiseAnd (v, Const(1)); + SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1))); + SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1))); + SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1))); + SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1))); + } - Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag)); - c = context.BitwiseAnd (c, Const(1)); + private static void EmitSetFpcr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; - Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag)); - z = context.BitwiseAnd (z, Const(1)); + Operand fpcr = GetIntOrZR(context, op.Rt); + fpcr = context.ConvertI64ToI32(fpcr); - Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag)); - n = context.BitwiseAnd (n, Const(1)); + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPCR.Mask.HasFlag((FPCR)(1u << flag))) + { + SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), 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 EmitSetFpsr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand fpsr = GetIntOrZR(context, op.Rt); + fpsr = context.ConvertI64ToI32(fpsr); + + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSR.Mask.HasFlag((FPSR)(1u << flag))) + { + SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1))); + } + } } } } diff --git a/ARMeilleure/Instructions/InstEmitSystem32.cs b/ARMeilleure/Instructions/InstEmitSystem32.cs index acd17045f..e07db4121 100644 --- a/ARMeilleure/Instructions/InstEmitSystem32.cs +++ b/ARMeilleure/Instructions/InstEmitSystem32.cs @@ -169,14 +169,11 @@ namespace ARMeilleure.Instructions } else { - Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); - Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)); - Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)); - Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)); - Operand qSh = context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag)); - - Operand spsr = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); - spsr = context.BitwiseOr(spsr, qSh); + Operand spsr = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag))); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag))); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag))); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag))); // TODO: Remaining flags. @@ -200,8 +197,7 @@ namespace ARMeilleure.Instructions EmitSetNzcv(context, value); - Operand q = context.ShiftRightUI(value, Const((int)PState.QFlag)); - q = context.BitwiseAnd(q, Const(1)); + Operand q = context.BitwiseAnd(context.ShiftRightUI(value, Const((int)PState.QFlag)), Const(1)); SetFlag(context, PState.QFlag, q); } @@ -284,17 +280,10 @@ namespace ARMeilleure.Instructions 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)); + Operand v = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.VFlag)), Const(1)); + Operand c = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.CFlag)), Const(1)); + Operand z = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.ZFlag)), Const(1)); + Operand n = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.NFlag)), Const(1)); SetFlag(context, PState.VFlag, v); SetFlag(context, PState.CFlag, c); @@ -306,42 +295,32 @@ namespace ARMeilleure.Instructions { 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 fpscr = Const(0); - Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag))) + { + fpscr = context.BitwiseOr(fpscr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); + } + } - Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); - - SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr)); + SetIntA32(context, op.Rt, fpscr); } private static void EmitSetFpscr(ArmEmitterContext context) { OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; - Operand t = GetIntA32(context, op.Rt); + Operand fpscr = 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); + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag))) + { + SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpscr, Const(flag)), Const(1))); + } + } } } } diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs index ca4133ada..2ac748a9a 100644 --- a/ARMeilleure/Instructions/NativeInterface.cs +++ b/ARMeilleure/Instructions/NativeInterface.cs @@ -72,29 +72,6 @@ namespace ARMeilleure.Instructions return (ulong)GetContext().DczidEl0; } - public static ulong GetFpcr() - { - return (ulong)GetContext().Fpcr; - } - - public static bool GetFpcrFz() - { - return (GetContext().Fpcr & FPCR.Fz) != 0; - } - - public static ulong GetFpsr() - { - return (ulong)GetContext().Fpsr; - } - - public static uint GetFpscr() - { - ExecutionContext context = GetContext(); - - return (uint)(context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) | - (uint)(context.Fpcr & FPCR.A32Mask); - } - public static ulong GetTpidrEl0() { return (ulong)GetContext().TpidrEl0; @@ -130,29 +107,6 @@ namespace ARMeilleure.Instructions return GetContext().CntvctEl0; } - public static void SetFpcr(ulong value) - { - GetContext().Fpcr = (FPCR)value; - } - - public static void SetFpsr(ulong value) - { - GetContext().Fpsr = (FPSR)value; - } - - public static void SetFpsrQc() - { - GetContext().Fpsr |= FPSR.Qc; - } - - public static void SetFpscr(uint fpscr) - { - ExecutionContext context = GetContext(); - - context.Fpsr = FPSR.A32Mask & (FPSR)fpscr; - context.Fpcr = FPCR.A32Mask & (FPCR)fpscr; - } - public static void SetTpidrEl0(ulong value) { GetContext().TpidrEl0 = (long)value; diff --git a/ARMeilleure/Instructions/SoftFallback.cs b/ARMeilleure/Instructions/SoftFallback.cs index d5e1ab65d..06d76a67c 100644 --- a/ARMeilleure/Instructions/SoftFallback.cs +++ b/ARMeilleure/Instructions/SoftFallback.cs @@ -91,76 +91,6 @@ namespace ARMeilleure.Instructions } #endregion -#region "Rounding" - public static double Round(double value) - { - ExecutionContext context = NativeInterface.GetContext(); - - FPRoundingMode roundMode = context.Fpcr.GetRoundingMode(); - - if (roundMode == FPRoundingMode.ToNearest) - { - return Math.Round(value); // even - } - else if (roundMode == FPRoundingMode.TowardsPlusInfinity) - { - return Math.Ceiling(value); - } - else if (roundMode == FPRoundingMode.TowardsMinusInfinity) - { - return Math.Floor(value); - } - else /* if (roundMode == FPRoundingMode.TowardsZero) */ - { - return Math.Truncate(value); - } - } - - public static float RoundF(float value) - { - ExecutionContext context = NativeInterface.GetContext(); - - FPRoundingMode roundMode = context.Fpcr.GetRoundingMode(); - - if (roundMode == FPRoundingMode.ToNearest) - { - return MathF.Round(value); // even - } - else if (roundMode == FPRoundingMode.TowardsPlusInfinity) - { - return MathF.Ceiling(value); - } - else if (roundMode == FPRoundingMode.TowardsMinusInfinity) - { - return MathF.Floor(value); - } - else /* if (roundMode == FPRoundingMode.TowardsZero) */ - { - return MathF.Truncate(value); - } - } - - public static int FloatToInt32(float value) - { - return SatF32ToS32(RoundF(value)); - } - - public static int DoubleToInt32(double value) - { - return SatF64ToS32(Round(value)); - } - - public static uint FloatToUInt32(float value) - { - return SatF32ToU32(RoundF(value)); - } - - public static uint DoubleToUInt32(double value) - { - return SatF64ToU32(Round(value)); - } -#endregion - #region "Saturation" public static int SatF32ToS32(float value) { diff --git a/ARMeilleure/Instructions/SoftFloat.cs b/ARMeilleure/Instructions/SoftFloat.cs index a138f5df2..9e3db68d9 100644 --- a/ARMeilleure/Instructions/SoftFloat.cs +++ b/ARMeilleure/Instructions/SoftFloat.cs @@ -12,8 +12,8 @@ namespace ARMeilleure.Instructions RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable(); } - internal static readonly byte[] RecipEstimateTable; - internal static readonly byte[] RecipSqrtEstimateTable; + public static readonly byte[] RecipEstimateTable; + public static readonly byte[] RecipSqrtEstimateTable; private static byte[] BuildRecipEstimateTable() { @@ -94,6 +94,13 @@ namespace ARMeilleure.Instructions context.Fpsr |= (FPSR)(1 << (int)exc); } } + + public static FPRoundingMode GetRoundingMode(this FPCR fpcr) + { + const int RModeShift = 22; + + return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u); + } } static class SoftFloat16 diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs index c73ca197d..5d18e6ed8 100644 --- a/ARMeilleure/State/ExecutionContext.cs +++ b/ARMeilleure/State/ExecutionContext.cs @@ -36,10 +36,25 @@ namespace ARMeilleure.State set => _nativeContext.SetPstate(value); } - public FPCR Fpcr { get; set; } - public FPSR Fpsr { get; set; } + public FPSR Fpsr + { + get => (FPSR)_nativeContext.GetFPState((uint)FPSR.Mask); + set => _nativeContext.SetFPState((uint)value, (uint)FPSR.Mask); + } + + public FPCR Fpcr + { + get => (FPCR)_nativeContext.GetFPState((uint)FPCR.Mask); + set => _nativeContext.SetFPState((uint)value, (uint)FPCR.Mask); + } public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz; + public FPSCR Fpscr + { + get => (FPSCR)_nativeContext.GetFPState((uint)FPSCR.Mask); + set => _nativeContext.SetFPState((uint)value, (uint)FPSCR.Mask); + } + public bool IsAarch32 { get; set; } internal ExecutionMode ExecutionMode diff --git a/ARMeilleure/State/FPCR.cs b/ARMeilleure/State/FPCR.cs index 40d560455..6f707de7d 100644 --- a/ARMeilleure/State/FPCR.cs +++ b/ARMeilleure/State/FPCR.cs @@ -5,21 +5,18 @@ namespace ARMeilleure.State [Flags] public enum FPCR : uint { + Ioe = 1u << 8, + Dze = 1u << 9, + Ofe = 1u << 10, Ufe = 1u << 11, + Ixe = 1u << 12, + Ide = 1u << 15, + RMode0 = 1u << 22, + RMode1 = 1u << 23, Fz = 1u << 24, Dn = 1u << 25, Ahp = 1u << 26, - A32Mask = 0x07FF9F00u - } - - public static class FPCRExtensions - { - private const int RModeShift = 22; - - public static FPRoundingMode GetRoundingMode(this FPCR fpcr) - { - return (FPRoundingMode)(((int)fpcr >> RModeShift) & 3); - } + Mask = Ahp | Dn | Fz | RMode1 | RMode0 | Ide | Ixe | Ufe | Ofe | Dze | Ioe // 0x07C09F00u } } diff --git a/ARMeilleure/State/FPSCR.cs b/ARMeilleure/State/FPSCR.cs new file mode 100644 index 000000000..d6d2fc26a --- /dev/null +++ b/ARMeilleure/State/FPSCR.cs @@ -0,0 +1,15 @@ +using System; + +namespace ARMeilleure.State +{ + [Flags] + public enum FPSCR : uint + { + V = 1u << 28, + C = 1u << 29, + Z = 1u << 30, + N = 1u << 31, + + Mask = N | Z | C | V | FPSR.Mask | FPCR.Mask // 0xFFC09F9Fu + } +} diff --git a/ARMeilleure/State/FPSR.cs b/ARMeilleure/State/FPSR.cs index 800dcd10c..5e66d5ce1 100644 --- a/ARMeilleure/State/FPSR.cs +++ b/ARMeilleure/State/FPSR.cs @@ -5,11 +5,14 @@ namespace ARMeilleure.State [Flags] public enum FPSR : uint { + Ioc = 1u << 0, + Dzc = 1u << 1, + Ofc = 1u << 2, Ufc = 1u << 3, - Qc = 1u << 27, + Ixc = 1u << 4, + Idc = 1u << 7, + Qc = 1u << 27, - Nzcv = (1u << 31) | (1u << 30) | (1u << 29) | (1u << 28), - - A32Mask = 0xF800009Fu + Mask = Qc | Idc | Ixc | Ufc | Ofc | Dzc | Ioc // 0x0800009Fu } } diff --git a/ARMeilleure/State/FPState.cs b/ARMeilleure/State/FPState.cs index 60c7126c3..fa6ab9d46 100644 --- a/ARMeilleure/State/FPState.cs +++ b/ARMeilleure/State/FPState.cs @@ -2,9 +2,30 @@ { public enum FPState { + // FPSR Flags. + IocFlag = 0, + DzcFlag = 1, + OfcFlag = 2, + UfcFlag = 3, + IxcFlag = 4, + IdcFlag = 7, + QcFlag = 27, VFlag = 28, CFlag = 29, ZFlag = 30, - NFlag = 31 + NFlag = 31, + + // FPCR Flags. + IoeFlag = 8, + DzeFlag = 9, + OfeFlag = 10, + UfeFlag = 11, + IxeFlag = 12, + IdeFlag = 15, + RMode0Flag = 22, + RMode1Flag = 23, + FzFlag = 24, + DnFlag = 25, + AhpFlag = 26 } } diff --git a/ARMeilleure/State/NativeContext.cs b/ARMeilleure/State/NativeContext.cs index 11ab5ca3a..89e875d12 100644 --- a/ARMeilleure/State/NativeContext.cs +++ b/ARMeilleure/State/NativeContext.cs @@ -140,6 +140,34 @@ namespace ARMeilleure.State GetStorage().FpFlags[(int)flag] = value ? 1u : 0u; } + public unsafe uint GetFPState(uint mask = uint.MaxValue) + { + uint value = 0; + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + uint bit = 1u << flag; + + if ((mask & bit) == bit) + { + value |= GetStorage().FpFlags[flag] != 0 ? bit : 0u; + } + } + return value; + } + + public unsafe void SetFPState(uint value, uint mask = uint.MaxValue) + { + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + uint bit = 1u << flag; + + if ((mask & bit) == bit) + { + GetStorage().FpFlags[flag] = (value & bit) == bit ? 1u : 0u; + } + } + } + public int GetCounter() => GetStorage().Counter; public void SetCounter(int value) => GetStorage().Counter = value; diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs index 0da69ebc3..fef1f4ef7 100644 --- a/ARMeilleure/Translation/Delegates.cs +++ b/ARMeilleure/Translation/Delegates.cs @@ -109,10 +109,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only. - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0))); @@ -124,10 +120,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only. - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only. SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking))); @@ -151,12 +143,8 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only. - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only. SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only. - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only. SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority))); @@ -165,8 +153,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32))); diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 01f089882..f4ae411b7 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 3700; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 3703; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; diff --git a/Ryujinx.Tests/Cpu/CpuTest32.cs b/Ryujinx.Tests/Cpu/CpuTest32.cs index be8df8dfc..aaf0ecfb6 100644 --- a/Ryujinx.Tests/Cpu/CpuTest32.cs +++ b/Ryujinx.Tests/Cpu/CpuTest32.cs @@ -162,7 +162,7 @@ namespace Ryujinx.Tests.Cpu _context.SetPstateFlag(PState.ZFlag, zero); _context.SetPstateFlag(PState.NFlag, negative); - SetFpscr((uint)fpscr); + _context.Fpscr = (FPSCR)fpscr; _context.SetPstateFlag(PState.TFlag, thumb); @@ -467,7 +467,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag), "NFlag"); }); - Assert.That((int)GetFpscr() & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpscr & (int)fpsrMask), "Fpscr"); + Assert.That((int)_context.Fpscr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpscr & (int)fpsrMask), "Fpscr"); if (_usingMemory) { @@ -650,28 +650,5 @@ namespace Ryujinx.Tests.Cpu return rnd & 0x800FFFFFFFFFFFFFul; } - - private uint GetFpscr() - { - uint fpscr = (uint)(_context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) | (uint)(_context.Fpcr & FPCR.A32Mask); - - fpscr |= _context.GetFPstateFlag(FPState.NFlag) ? (1u << (int)FPState.NFlag) : 0; - fpscr |= _context.GetFPstateFlag(FPState.ZFlag) ? (1u << (int)FPState.ZFlag) : 0; - fpscr |= _context.GetFPstateFlag(FPState.CFlag) ? (1u << (int)FPState.CFlag) : 0; - fpscr |= _context.GetFPstateFlag(FPState.VFlag) ? (1u << (int)FPState.VFlag) : 0; - - return fpscr; - } - - private void SetFpscr(uint fpscr) - { - _context.Fpsr = FPSR.A32Mask & (FPSR)fpscr; - _context.Fpcr = FPCR.A32Mask & (FPCR)fpscr; - - _context.SetFPstateFlag(FPState.NFlag, (fpscr & (1u << (int)FPState.NFlag)) != 0); - _context.SetFPstateFlag(FPState.ZFlag, (fpscr & (1u << (int)FPState.ZFlag)) != 0); - _context.SetFPstateFlag(FPState.CFlag, (fpscr & (1u << (int)FPState.CFlag)) != 0); - _context.SetFPstateFlag(FPState.VFlag, (fpscr & (1u << (int)FPState.VFlag)) != 0); - } } } \ No newline at end of file