From 553ba659c40013cde0198c2bdd10b31bdd6f3d97 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 14 Mar 2018 00:12:05 -0300 Subject: [PATCH] Add CRC32 instruction and SLI (vector) --- ChocolArm64/AOpCodeTable.cs | 9 +++ ChocolArm64/Instruction/AInstEmitHash.cs | 74 ++++++++++++++++++ ChocolArm64/Instruction/AInstEmitSimdShift.cs | 54 ++++++++++--- ChocolArm64/Instruction/ASoftFallback.cs | 78 +++++++++++++++++++ 4 files changed, 205 insertions(+), 10 deletions(-) create mode 100644 ChocolArm64/Instruction/AInstEmitHash.cs diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 60646d0e..d32bd9cd 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -42,6 +42,14 @@ namespace ChocolArm64 Set("x1111010010xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ccmp, typeof(AOpCodeCcmpReg)); Set("11010101000000110011xxxx01011111", AInstEmit.Clrex, typeof(AOpCodeSystem)); Set("x101101011000000000100xxxxxxxxxx", AInstEmit.Clz, typeof(AOpCodeAlu)); + Set("x0011010110xxxxx010000xxxxxxxxxx", AInstEmit.Crc32b, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx010001xxxxxxxxxx", AInstEmit.Crc32h, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx010010xxxxxxxxxx", AInstEmit.Crc32w, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx010011xxxxxxxxxx", AInstEmit.Crc32x, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx010100xxxxxxxxxx", AInstEmit.Crc32cb, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx010101xxxxxxxxxx", AInstEmit.Crc32ch, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx010110xxxxxxxxxx", AInstEmit.Crc32cw, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx010111xxxxxxxxxx", AInstEmit.Crc32cx, typeof(AOpCodeAluRs)); Set("x0011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csel, typeof(AOpCodeCsel)); Set("x0011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csinc, typeof(AOpCodeCsel)); Set("x1011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csinv, typeof(AOpCodeCsel)); @@ -243,6 +251,7 @@ namespace ChocolArm64 Set("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm)); Set("0x101110<<100001001110xxxxxxxxxx", AInstEmit.Shll_V, typeof(AOpCodeSimd)); Set("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm)); + Set("0x1011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Sli_V, typeof(AOpCodeSimdShImm)); Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg)); Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg)); Set("0x001110<<1xxxxx100000xxxxxxxxxx", AInstEmit.Smlal_V, typeof(AOpCodeSimdReg)); diff --git a/ChocolArm64/Instruction/AInstEmitHash.cs b/ChocolArm64/Instruction/AInstEmitHash.cs new file mode 100644 index 00000000..fd98f563 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitHash.cs @@ -0,0 +1,74 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + + public static void Crc32b(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32b)); + } + + public static void Crc32h(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32h)); + } + + public static void Crc32w(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32w)); + } + + public static void Crc32x(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32x)); + } + + public static void Crc32cb(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32cb)); + } + + public static void Crc32ch(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32ch)); + } + + public static void Crc32cw(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32cw)); + } + + public static void Crc32cx(AILEmitterCtx Context) + { + EmitCrc32(Context, nameof(ASoftFallback.Crc32cx)); + } + + private static void EmitCrc32(AILEmitterCtx Context, string Name) + { + AOpCodeAluRs Op = (AOpCodeAluRs)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + if (Op.RegisterSize != ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U4); + } + + Context.EmitLdintzr(Op.Rm); + + ASoftFallback.EmitCall(Context, Name); + + if (Op.RegisterSize != ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdShift.cs b/ChocolArm64/Instruction/AInstEmitSimdShift.cs index bb8a8f17..bffed57e 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdShift.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdShift.cs @@ -29,7 +29,7 @@ namespace ChocolArm64.Instruction int Shift = Op.Imm - (8 << Op.Size); - EmitVectorBinaryShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); + EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); } public static void Shll_V(AILEmitterCtx Context) @@ -50,6 +50,40 @@ namespace ChocolArm64.Instruction EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift); } + public static void Sli_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + int Shift = Op.Imm - (8 << Op.Size); + + ulong Mask = ulong.MaxValue >> (64 - Shift); + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); + + Context.EmitLdc_I4(Shift); + + Context.Emit(OpCodes.Shl); + + EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size); + + Context.EmitLdc_I8((long)Mask); + + Context.Emit(OpCodes.And); + Context.Emit(OpCodes.Or); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + public static void Sshl_V(AILEmitterCtx Context) { EmitVectorShl(Context, Signed: true); @@ -83,7 +117,7 @@ namespace ChocolArm64.Instruction int Shift = (8 << (Op.Size + 1)) - Op.Imm; - EmitVectorBinaryShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift); + EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift); } public static void Ssra_V(AILEmitterCtx Context) @@ -98,7 +132,7 @@ namespace ChocolArm64.Instruction Context.Emit(OpCodes.Add); }; - EmitVectorTernaryShImmBinarySx(Context, Emit, Shift); + EmitVectorShImmTernarySx(Context, Emit, Shift); } public static void Ushl_V(AILEmitterCtx Context) @@ -217,22 +251,22 @@ namespace ChocolArm64.Instruction } } - private static void EmitVectorBinaryShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) { - EmitVectorShImmBinaryOp(Context, Emit, Imm, false, true); + EmitVectorShImmOp(Context, Emit, Imm, false, true); } - private static void EmitVectorTernaryShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + private static void EmitVectorShImmTernarySx(AILEmitterCtx Context, Action Emit, int Imm) { - EmitVectorShImmBinaryOp(Context, Emit, Imm, true, true); + EmitVectorShImmOp(Context, Emit, Imm, true, true); } - private static void EmitVectorBinaryShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) { - EmitVectorShImmBinaryOp(Context, Emit, Imm, false, false); + EmitVectorShImmOp(Context, Emit, Imm, false, false); } - private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Ternary, bool Signed) + private static void EmitVectorShImmOp(AILEmitterCtx Context, Action Emit, int Imm, bool Ternary, bool Signed) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs index 797d8157..7e5b3dba 100644 --- a/ChocolArm64/Instruction/ASoftFallback.cs +++ b/ChocolArm64/Instruction/ASoftFallback.cs @@ -38,6 +38,84 @@ namespace ChocolArm64.Instruction return (ulong)Size; } + private const uint Crc32RevPoly = 0xedb88320; + private const uint Crc32cRevPoly = 0x82f63b78; + + public static uint Crc32b(uint Crc, byte Val) => Crc32 (Crc, Crc32RevPoly, Val); + public static uint Crc32h(uint Crc, byte Val) => Crc32h(Crc, Crc32RevPoly, Val); + public static uint Crc32w(uint Crc, byte Val) => Crc32w(Crc, Crc32RevPoly, Val); + public static uint Crc32x(uint Crc, byte Val) => Crc32x(Crc, Crc32RevPoly, Val); + + public static uint Crc32cb(uint Crc, byte Val) => Crc32 (Crc, Crc32cRevPoly, Val); + public static uint Crc32ch(uint Crc, byte Val) => Crc32h(Crc, Crc32cRevPoly, Val); + public static uint Crc32cw(uint Crc, byte Val) => Crc32w(Crc, Crc32cRevPoly, Val); + public static uint Crc32cx(uint Crc, byte Val) => Crc32x(Crc, Crc32cRevPoly, Val); + + private static uint Crc32h(uint Crc, uint Poly, ushort Val) + { + Crc = Crc32(Crc, Poly, (byte)(Val >> 0)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 8)); + + return Crc; + } + + private static uint Crc32w(uint Crc, uint Poly, uint Val) + { + Crc = Crc32(Crc, Poly, (byte)(Val >> 0)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 8)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 16)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 24)); + + return Crc; + } + + private static uint Crc32x(uint Crc, uint Poly, ulong Val) + { + Crc = Crc32(Crc, Poly, (byte)(Val >> 0)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 8)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 16)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 24)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 32)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 40)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 48)); + Crc = Crc32(Crc, Poly, (byte)(Val >> 56)); + + return Crc; + } + + private static uint Crc32(uint Crc, uint Poly, byte Val) + { + Crc ^= Val; + + for (int Bit = 7; Bit >= 0; Bit--) + { + uint Mask = (uint)(-(int)(Crc & 1)); + + Crc = (Crc >> 1) ^ (Poly & Mask); + } + + return Crc; + } + + public static uint ReverseBits8(uint Value) + { + Value = ((Value & 0xaa) >> 1) | ((Value & 0x55) << 1); + Value = ((Value & 0xcc) >> 2) | ((Value & 0x33) << 2); + Value = ((Value & 0xf0) >> 4) | ((Value & 0x0f) << 4); + + return Value; + } + + public static uint ReverseBits16(uint Value) + { + Value = ((Value & 0xaaaa) >> 1) | ((Value & 0x5555) << 1); + Value = ((Value & 0xcccc) >> 2) | ((Value & 0x3333) << 2); + Value = ((Value & 0xf0f0) >> 4) | ((Value & 0x0f0f) << 4); + Value = ((Value & 0xff00) >> 8) | ((Value & 0x00ff) << 8); + + return Value; + } + public static uint ReverseBits32(uint Value) { Value = ((Value & 0xaaaaaaaa) >> 1) | ((Value & 0x55555555) << 1);