diff --git a/AOpCodeTable.cs b/AOpCodeTable.cs index 71a944c..14ca231 100644 --- a/AOpCodeTable.cs +++ b/AOpCodeTable.cs @@ -11,6 +11,7 @@ namespace ChocolArm64 #region "OpCode Table" //Integer Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs)); + Set("x0111010000xxxxx000000xxxxxxxxxx", AInstEmit.Adcs, typeof(AOpCodeAluRs)); Set("x00100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm)); Set("x0001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs)); Set("x0001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRx)); @@ -90,6 +91,7 @@ namespace ChocolArm64 Set("1101101011000000000011xxxxxxxxxx", AInstEmit.Rev64, typeof(AOpCodeAlu)); Set("x0011010110xxxxx001011xxxxxxxxxx", AInstEmit.Rorv, typeof(AOpCodeAluRs)); Set("x1011010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbc, typeof(AOpCodeAluRs)); + Set("x1111010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbcs, typeof(AOpCodeAluRs)); Set("x00100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sbfm, typeof(AOpCodeBfm)); Set("x0011010110xxxxx000011xxxxxxxxxx", AInstEmit.Sdiv, typeof(AOpCodeAluRs)); Set("10011011001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smaddl, typeof(AOpCodeMul)); @@ -145,6 +147,7 @@ namespace ChocolArm64 Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns)); Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns)); Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg)); + Set("011111101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fabd_S, typeof(AOpCodeSimdReg)); Set("000111100x100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd)); Set("000111100x1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg)); Set("0>0011100<1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg)); diff --git a/ATranslator.cs b/ATranslator.cs index 04cef44..96bbc89 100644 --- a/ATranslator.cs +++ b/ATranslator.cs @@ -6,7 +6,7 @@ using System.Reflection.Emit; namespace ChocolArm64 { - public class ATranslator + class ATranslator { public AThread Thread { get; private set; } @@ -41,7 +41,7 @@ namespace ChocolArm64 while (Position != 0 && KeepRunning); } - internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) + public 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); } - internal bool TryGetCachedSub(long Position, out ATranslatedSub Sub) + public bool TryGetCachedSub(long Position, out ATranslatedSub Sub) { return CachedSubs.TryGetValue(Position, out Sub); } diff --git a/Instruction/AInstEmitAlu.cs b/Instruction/AInstEmitAlu.cs index 72903f5..71d9a66 100644 --- a/Instruction/AInstEmitAlu.cs +++ b/Instruction/AInstEmitAlu.cs @@ -11,7 +11,10 @@ namespace ChocolArm64.Instruction { static partial class AInstEmit { - public static void Adc(AILEmitterCtx Context) + public static void Adc(AILEmitterCtx Context) => EmitAdc(Context, false); + public static void Adcs(AILEmitterCtx Context) => EmitAdc(Context, true); + + private static void EmitAdc(AILEmitterCtx Context, bool SetFlags) { EmitDataLoadOpers(Context); @@ -27,11 +30,19 @@ namespace ChocolArm64.Instruction if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) { - Context.Emit(OpCodes.Conv_I8); + Context.Emit(OpCodes.Conv_U8); } Context.Emit(OpCodes.Add); + if (SetFlags) + { + Context.EmitZNFlagCheck(); + + EmitAddsCCheck(Context); + EmitAddsVCheck(Context); + } + EmitDataStore(Context); } @@ -145,7 +156,10 @@ namespace ChocolArm64.Instruction public static void Lslv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shl); public static void Lsrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr_Un); - public static void Sbc(AILEmitterCtx Context) + public static void Sbc(AILEmitterCtx Context) => EmitSbc(Context, false); + public static void Sbcs(AILEmitterCtx Context) => EmitSbc(Context, true); + + private static void EmitSbc(AILEmitterCtx Context, bool SetFlags) { EmitDataLoadOpers(Context); @@ -165,11 +179,19 @@ namespace ChocolArm64.Instruction if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) { - Context.Emit(OpCodes.Conv_I8); + Context.Emit(OpCodes.Conv_U8); } Context.Emit(OpCodes.Sub); + if (SetFlags) + { + Context.EmitZNFlagCheck(); + + EmitSbcsCCheck(Context); + EmitSubsVCheck(Context); + } + EmitDataStore(Context); } diff --git a/Instruction/AInstEmitAluHelper.cs b/Instruction/AInstEmitAluHelper.cs index e848742..b2ea92a 100644 --- a/Instruction/AInstEmitAluHelper.cs +++ b/Instruction/AInstEmitAluHelper.cs @@ -41,6 +41,25 @@ namespace ChocolArm64.Instruction Context.EmitStflg((int)APState.VBit); } + public static void EmitSbcsCCheck(AILEmitterCtx Context) + { + //C = (Rn == Rm && CIn) || Rn > Rm + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Ceq); + + Context.EmitLdflg((int)APState.CBit); + + Context.Emit(OpCodes.And); + + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Cgt_Un); + Context.Emit(OpCodes.Or); + + Context.EmitStflg((int)APState.CBit); + } + public static void EmitSubsCCheck(AILEmitterCtx Context) { //C = Rn == Rm || Rn > Rm = !(Rn < Rm) diff --git a/Instruction/AInstEmitSimdArithmetic.cs b/Instruction/AInstEmitSimdArithmetic.cs index e1fd56e..e790d67 100644 --- a/Instruction/AInstEmitSimdArithmetic.cs +++ b/Instruction/AInstEmitSimdArithmetic.cs @@ -101,6 +101,16 @@ namespace ChocolArm64.Instruction } } + public static void Fabd_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => + { + Context.Emit(OpCodes.Sub); + + EmitUnaryMathCall(Context, nameof(Math.Abs)); + }); + } + public static void Fabs_S(AILEmitterCtx Context) { EmitScalarUnaryOpF(Context, () => @@ -269,26 +279,25 @@ namespace ChocolArm64.Instruction { 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) + EmitScalarUnaryOpF(Context, () => { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF)); - } - else if (Op.Size == 1) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round)); - } - else - { - throw new InvalidOperationException(); - } + Context.EmitLdarg(ATranslatedSub.StateArgIdx); - EmitScalarSetF(Context, Op.Rd, Op.Size); + 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(); + } + }); } public static void Fsqrt_S(AILEmitterCtx Context) diff --git a/Instruction/AInstEmitSimdHelper.cs b/Instruction/AInstEmitSimdHelper.cs index 20c8be2..68ee3d3 100644 --- a/Instruction/AInstEmitSimdHelper.cs +++ b/Instruction/AInstEmitSimdHelper.cs @@ -36,20 +36,18 @@ namespace ChocolArm64.Instruction { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + int SizeF = Op.Size & 1; + MethodInfo MthdInfo; - if (Op.Size == 0) + if (SizeF == 0) { MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float) }); } - else if (Op.Size == 1) + else /* if (SizeF == 1) */ { MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double) }); } - else - { - throw new InvalidOperationException(); - } Context.EmitCall(MthdInfo); } @@ -58,20 +56,18 @@ namespace ChocolArm64.Instruction { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + int SizeF = Op.Size & 1; + MethodInfo MthdInfo; - if (Op.Size == 0) + if (SizeF == 0) { MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) }); } - else if (Op.Size == 1) + else /* if (SizeF == 1) */ { MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) }); } - else - { - throw new InvalidOperationException(); - } Context.EmitCall(MthdInfo); } @@ -80,28 +76,26 @@ namespace ChocolArm64.Instruction { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + int SizeF = Op.Size & 1; + Context.EmitLdc_I4((int)RoundMode); MethodInfo MthdInfo; Type[] Types = new Type[] { null, typeof(MidpointRounding) }; - Types[0] = Op.Size == 0 + Types[0] = SizeF == 0 ? typeof(float) : typeof(double); - if (Op.Size == 0) + if (SizeF == 0) { MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); } - else if (Op.Size == 1) + else /* if (SizeF == 1) */ { MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); } - else - { - throw new InvalidOperationException(); - } Context.EmitCall(MthdInfo); }