diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index b8fe278dd..71a944cf8 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -51,6 +51,7 @@ namespace ChocolArm64 Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm)); Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs)); Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs)); + Set("11010101000000110010xxxxxxx11111", AInstEmit.Hint, typeof(AOpCodeSystem)); Set("xx001000110xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldar, typeof(AOpCodeMemEx)); Set("1x001000011xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxp, typeof(AOpCodeMemEx)); Set("xx001000010xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxr, typeof(AOpCodeMemEx)); @@ -193,6 +194,7 @@ namespace ChocolArm64 Set("000111100x100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd)); Set("000111100x100101010000xxxxxxxxxx", AInstEmit.Frintm_S, typeof(AOpCodeSimd)); Set("000111100x100100110000xxxxxxxxxx", AInstEmit.Frintp_S, typeof(AOpCodeSimd)); + Set("000111100x100111010000xxxxxxxxxx", AInstEmit.Frintx_S, typeof(AOpCodeSimd)); Set("000111100x100001110000xxxxxxxxxx", AInstEmit.Fsqrt_S, typeof(AOpCodeSimd)); Set("000111100x1xxxxx001110xxxxxxxxxx", AInstEmit.Fsub_S, typeof(AOpCodeSimdReg)); Set("0>0011101<1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg)); diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 96bbc89ea..04cef44f1 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -6,7 +6,7 @@ using System.Reflection.Emit; namespace ChocolArm64 { - class ATranslator + public class ATranslator { public AThread Thread { get; private set; } @@ -41,7 +41,7 @@ namespace ChocolArm64 while (Position != 0 && KeepRunning); } - public bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) + internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) { if (OpCode.Emitter != AInstEmit.Bl) { @@ -53,7 +53,7 @@ namespace ChocolArm64 return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub); } - public bool TryGetCachedSub(long Position, out ATranslatedSub Sub) + internal bool TryGetCachedSub(long Position, out ATranslatedSub Sub) { return CachedSubs.TryGetValue(Position, out Sub); } diff --git a/ChocolArm64/Decoder/AOpCodeSimd.cs b/ChocolArm64/Decoder/AOpCodeSimd.cs index 5f940b220..417085172 100644 --- a/ChocolArm64/Decoder/AOpCodeSimd.cs +++ b/ChocolArm64/Decoder/AOpCodeSimd.cs @@ -10,8 +10,6 @@ namespace ChocolArm64.Decoder public int Opc { get; private set; } public int Size { get; protected set; } - public int SizeF => Size & 1; - public AOpCodeSimd(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { Rd = (OpCode >> 0) & 0x1f; diff --git a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs index 6665f219e..e1fd56e00 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs @@ -265,6 +265,32 @@ namespace ChocolArm64.Instruction }); } + public static void Frintx_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + Context.EmitLdarg(ATranslatedSub.StateArgIdx); + + Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr)); + + if (Op.Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF)); + } + else if (Op.Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round)); + } + else + { + throw new InvalidOperationException(); + } + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + public static void Fsqrt_S(AILEmitterCtx Context) { EmitScalarUnaryOpF(Context, () => diff --git a/ChocolArm64/Instruction/AInstEmitSystem.cs b/ChocolArm64/Instruction/AInstEmitSystem.cs index 6754be7a8..f9d186020 100644 --- a/ChocolArm64/Instruction/AInstEmitSystem.cs +++ b/ChocolArm64/Instruction/AInstEmitSystem.cs @@ -9,6 +9,11 @@ namespace ChocolArm64.Instruction { static partial class AInstEmit { + public static void Hint(AILEmitterCtx Context) + { + //Execute as no-op. + } + public static void Mrs(AILEmitterCtx Context) { AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs index a57966baf..5127182dd 100644 --- a/ChocolArm64/Instruction/ASoftFallback.cs +++ b/ChocolArm64/Instruction/ASoftFallback.cs @@ -189,6 +189,32 @@ namespace ChocolArm64.Instruction (Value >> 6) & 1 + (Value >> 7); } + public static float RoundF(float Value, int Fpcr) + { + switch ((ARoundMode)((Fpcr >> 22) & 3)) + { + case ARoundMode.ToNearest: return MathF.Round (Value); + case ARoundMode.TowardsPlusInfinity: return MathF.Ceiling (Value); + case ARoundMode.TowardsMinusInfinity: return MathF.Floor (Value); + case ARoundMode.TowardsZero: return MathF.Truncate(Value); + } + + throw new InvalidOperationException(); + } + + public static double Round(double Value, int Fpcr) + { + switch ((ARoundMode)((Fpcr >> 22) & 3)) + { + case ARoundMode.ToNearest: return Math.Round (Value); + case ARoundMode.TowardsPlusInfinity: return Math.Ceiling (Value); + case ARoundMode.TowardsMinusInfinity: return Math.Floor (Value); + case ARoundMode.TowardsZero: return Math.Truncate(Value); + } + + throw new InvalidOperationException(); + } + public static AVec Tbl1_V64(AVec Vector, AVec Tb0) { return Tbl(Vector, 8, Tb0); diff --git a/ChocolArm64/State/ARoundMode.cs b/ChocolArm64/State/ARoundMode.cs new file mode 100644 index 000000000..9896f3075 --- /dev/null +++ b/ChocolArm64/State/ARoundMode.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.State +{ + public enum ARoundMode + { + ToNearest = 0, + TowardsPlusInfinity = 1, + TowardsMinusInfinity = 2, + TowardsZero = 3 + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILEmitterCtx.cs b/ChocolArm64/Translation/AILEmitterCtx.cs index cf6445401..9199eddc6 100644 --- a/ChocolArm64/Translation/AILEmitterCtx.cs +++ b/ChocolArm64/Translation/AILEmitterCtx.cs @@ -18,8 +18,8 @@ namespace ChocolArm64.Translation private AILBlock ILBlock; - private AOpCode LastCmpOp; - private AOpCode LastFlagOp; + private AOpCode OptOpLastCompare; + private AOpCode OptOpLastFlagSet; private int BlkIndex; private int OpcIndex; @@ -75,6 +75,9 @@ namespace ChocolArm64.Translation BlkIndex++; OpcIndex = -1; + OptOpLastFlagSet = null; + OptOpLastCompare = null; + ILBlock = Emitter.GetILBlock(BlkIndex); } @@ -120,7 +123,7 @@ namespace ChocolArm64.Translation public void TryOptMarkCondWithoutCmp() { - LastCmpOp = CurrOp; + OptOpLastCompare = CurrOp; AInstEmitAluHelper.EmitDataLoadOpers(this); @@ -146,14 +149,15 @@ namespace ChocolArm64.Translation { OpCode ILOp; - int IntCond = (int)Cond; + int IntCond = (int)Cond; - if (LastCmpOp != null && LastFlagOp == LastCmpOp && BranchOps.ContainsKey(Cond)) + if (OptOpLastCompare != null && + OptOpLastCompare == OptOpLastFlagSet && BranchOps.ContainsKey(Cond)) { - Ldloc(Tmp3Index, AIoType.Int, LastCmpOp.RegisterSize); - Ldloc(Tmp4Index, AIoType.Int, LastCmpOp.RegisterSize); + Ldloc(Tmp3Index, AIoType.Int, OptOpLastCompare.RegisterSize); + Ldloc(Tmp4Index, AIoType.Int, OptOpLastCompare.RegisterSize); - if (LastCmpOp.Emitter == AInstEmit.Adds) + if (OptOpLastCompare.Emitter == AInstEmit.Adds) { Emit(OpCodes.Neg); } @@ -356,7 +360,7 @@ namespace ChocolArm64.Translation public void EmitLdflg(int Index) => Ldloc(Index, AIoType.Flag); public void EmitStflg(int Index) { - LastFlagOp = CurrOp; + OptOpLastFlagSet = CurrOp; Stloc(Index, AIoType.Flag); } diff --git a/Ryujinx.Core/OsHle/MemoryRegions.cs b/Ryujinx.Core/OsHle/MemoryRegions.cs index e8ededc8f..86d266f60 100644 --- a/Ryujinx.Core/OsHle/MemoryRegions.cs +++ b/Ryujinx.Core/OsHle/MemoryRegions.cs @@ -1,5 +1,3 @@ -using ChocolArm64.Memory; - namespace Ryujinx.Core.OsHle { static class MemoryRegions diff --git a/Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs b/Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs index 545883836..11069cb22 100644 --- a/Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs @@ -291,7 +291,10 @@ namespace Ryujinx.Core.OsHle.Objects.Android BufferQueue[Slot].State = BufferState.Free; - WaitBufferFree.Set(); + lock (WaitBufferFree) + { + WaitBufferFree.Set(); + } }); } @@ -317,15 +320,15 @@ namespace Ryujinx.Core.OsHle.Objects.Android do { - if ((Slot = GetFreeSlot(Width, Height)) != -1) - { - break; - } - - Logging.Debug("Waiting for a free BufferQueue slot..."); - lock (WaitBufferFree) { + if ((Slot = GetFreeSlot(Width, Height)) != -1) + { + break; + } + + Logging.Debug("Waiting for a free BufferQueue slot..."); + if (!KeepRunning) { break;