diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index 8a6e8606d5..748a70a006 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -599,7 +599,14 @@ namespace ARMeilleure.CodeGen.X86 X86MemoryOperand memOp = new X86MemoryOperand(dest.Type, Register(X86Register.Rsp), null, Scale.x1, offs); - context.Assembler.Mov(dest, memOp); + if (dest.GetRegister().Type == RegisterType.Integer) + { + context.Assembler.Mov(dest, memOp); + } + else + { + context.Assembler.Movdqu(dest, memOp); + } } private static void GenerateLoad(CodeGenContext context, Operation operation) diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index c52ebdb0ab..2d7985c591 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -80,7 +80,7 @@ namespace ARMeilleure.Decoders SetA64("x0111010010xxxxxxxxx00xxxxx0xxxx", InstName.Ccmn, InstEmit.Ccmn, typeof(OpCodeCcmpReg)); SetA64("x1111010010xxxxxxxxx10xxxxx0xxxx", InstName.Ccmp, InstEmit.Ccmp, typeof(OpCodeCcmpImm)); SetA64("x1111010010xxxxxxxxx00xxxxx0xxxx", InstName.Ccmp, InstEmit.Ccmp, typeof(OpCodeCcmpReg)); - SetA64("11010101000000110011xxxx01011111", InstName.Clrex, null, typeof(OpCodeSystem)); + SetA64("11010101000000110011xxxx01011111", InstName.Clrex, InstEmit.Clrex, typeof(OpCodeSystem)); SetA64("x101101011000000000101xxxxxxxxxx", InstName.Cls, InstEmit.Cls, typeof(OpCodeAlu)); SetA64("x101101011000000000100xxxxxxxxxx", InstName.Clz, InstEmit.Clz, typeof(OpCodeAlu)); SetA64("00011010110xxxxx010000xxxxxxxxxx", InstName.Crc32b, InstEmit.Crc32b, typeof(OpCodeAluBinary)); @@ -95,8 +95,8 @@ namespace ARMeilleure.Decoders SetA64("x0011010100xxxxxxxxx01xxxxxxxxxx", InstName.Csinc, InstEmit.Csinc, typeof(OpCodeCsel)); SetA64("x1011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csinv, InstEmit.Csinv, typeof(OpCodeCsel)); SetA64("x1011010100xxxxxxxxx01xxxxxxxxxx", InstName.Csneg, InstEmit.Csneg, typeof(OpCodeCsel)); - SetA64("11010101000000110011xxxx10111111", InstName.Dmb, null, typeof(OpCodeSystem)); - SetA64("11010101000000110011xxxx10011111", InstName.Dsb, null, typeof(OpCodeSystem)); + SetA64("11010101000000110011xxxx10111111", InstName.Dmb, InstEmit.Dmb, typeof(OpCodeSystem)); + SetA64("11010101000000110011xxxx10011111", InstName.Dsb, InstEmit.Dsb, typeof(OpCodeSystem)); SetA64("01001010xx1xxxxx0xxxxxxxxxxxxxxx", InstName.Eon, InstEmit.Eon, typeof(OpCodeAluRs)); SetA64("11001010xx1xxxxxxxxxxxxxxxxxxxxx", InstName.Eon, InstEmit.Eon, typeof(OpCodeAluRs)); SetA64("0101001000xxxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, typeof(OpCodeAluImm)); @@ -105,11 +105,11 @@ namespace ARMeilleure.Decoders SetA64("11001010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, typeof(OpCodeAluRs)); SetA64("00010011100xxxxx0xxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, typeof(OpCodeAluRs)); SetA64("10010011110xxxxxxxxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, typeof(OpCodeAluRs)); - SetA64("11010101000000110010xxxxxxx11111", InstName.Hint, null, typeof(OpCodeSystem)); - SetA64("11010101000000110011xxxx11011111", InstName.Isb, null, typeof(OpCodeSystem)); - SetA64("xx001000110xxxxx1xxxxxxxxxxxxxxx", InstName.Ldar, null, typeof(OpCodeMemEx)); - SetA64("1x001000011xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxp, null, typeof(OpCodeMemEx)); - SetA64("xx001000010xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxr, null, typeof(OpCodeMemEx)); + SetA64("11010101000000110010xxxxxxx11111", InstName.Hint, InstEmit.Hint, typeof(OpCodeSystem)); + SetA64("11010101000000110011xxxx11011111", InstName.Isb, InstEmit.Isb, typeof(OpCodeSystem)); + SetA64("xx001000110xxxxx1xxxxxxxxxxxxxxx", InstName.Ldar, InstEmit.Ldar, typeof(OpCodeMemEx)); + SetA64("1x001000011xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxp, InstEmit.Ldaxp, typeof(OpCodeMemEx)); + SetA64("xx001000010xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxr, InstEmit.Ldaxr, typeof(OpCodeMemEx)); SetA64("<<10100xx1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldp, InstEmit.Ldp, typeof(OpCodeMemPair)); SetA64("xx111000010xxxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeMemImm)); SetA64("xx11100101xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeMemImm)); @@ -121,8 +121,8 @@ namespace ARMeilleure.Decoders SetA64("1011100110xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemImm)); SetA64("0x1110001x1xxxxxxxxx10xxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemReg)); SetA64("10111000101xxxxxxxxx10xxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemReg)); - SetA64("xx001000010xxxxx0xxxxxxxxxxxxxxx", InstName.Ldxr, null, typeof(OpCodeMemEx)); - SetA64("1x001000011xxxxx0xxxxxxxxxxxxxxx", InstName.Ldxp, null, typeof(OpCodeMemEx)); + SetA64("xx001000010xxxxx0xxxxxxxxxxxxxxx", InstName.Ldxr, InstEmit.Ldxr, typeof(OpCodeMemEx)); + SetA64("1x001000011xxxxx0xxxxxxxxxxxxxxx", InstName.Ldxp, InstEmit.Ldxp, typeof(OpCodeMemEx)); SetA64("x0011010110xxxxx001000xxxxxxxxxx", InstName.Lslv, InstEmit.Lslv, typeof(OpCodeAluRs)); SetA64("x0011010110xxxxx001001xxxxxxxxxx", InstName.Lsrv, InstEmit.Lsrv, typeof(OpCodeAluRs)); SetA64("x0011011000xxxxx0xxxxxxxxxxxxxxx", InstName.Madd, InstEmit.Madd, typeof(OpCodeMul)); @@ -132,19 +132,19 @@ namespace ARMeilleure.Decoders SetA64("100100101xxxxxxxxxxxxxxxxxxxxxxx", InstName.Movn, InstEmit.Movn, typeof(OpCodeMov)); SetA64("0101001010xxxxxxxxxxxxxxxxxxxxxx", InstName.Movz, InstEmit.Movz, typeof(OpCodeMov)); SetA64("110100101xxxxxxxxxxxxxxxxxxxxxxx", InstName.Movz, InstEmit.Movz, typeof(OpCodeMov)); - SetA64("110101010011xxxxxxxxxxxxxxxxxxxx", InstName.Mrs, null, typeof(OpCodeSystem)); - SetA64("110101010001xxxxxxxxxxxxxxxxxxxx", InstName.Msr, null, typeof(OpCodeSystem)); + SetA64("110101010011xxxxxxxxxxxxxxxxxxxx", InstName.Mrs, InstEmit.Mrs, typeof(OpCodeSystem)); + SetA64("110101010001xxxxxxxxxxxxxxxxxxxx", InstName.Msr, InstEmit.Msr, typeof(OpCodeSystem)); SetA64("x0011011000xxxxx1xxxxxxxxxxxxxxx", InstName.Msub, InstEmit.Msub, typeof(OpCodeMul)); - SetA64("11010101000000110010000000011111", InstName.Nop, null, typeof(OpCodeSystem)); + SetA64("11010101000000110010000000011111", InstName.Nop, InstEmit.Nop, typeof(OpCodeSystem)); SetA64("00101010xx1xxxxx0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit.Orn, typeof(OpCodeAluRs)); SetA64("10101010xx1xxxxxxxxxxxxxxxxxxxxx", InstName.Orn, InstEmit.Orn, typeof(OpCodeAluRs)); SetA64("0011001000xxxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluImm)); SetA64("101100100xxxxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluImm)); SetA64("00101010xx0xxxxx0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluRs)); SetA64("10101010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluRs)); - SetA64("1111100110xxxxxxxxxxxxxxxxxxxxxx", InstName.Pfrm, null, typeof(OpCodeMemImm)); - SetA64("11111000100xxxxxxxxx00xxxxxxxxxx", InstName.Pfrm, null, typeof(OpCodeMemImm)); - SetA64("11011000xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pfrm, null, typeof(OpCodeMemLit)); + SetA64("1111100110xxxxxxxxxxxxxxxxxxxxxx", InstName.Pfrm, InstEmit.Pfrm, typeof(OpCodeMemImm)); + SetA64("11111000100xxxxxxxxx00xxxxxxxxxx", InstName.Pfrm, InstEmit.Pfrm, typeof(OpCodeMemImm)); + SetA64("11011000xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pfrm, InstEmit.Pfrm, typeof(OpCodeMemLit)); SetA64("x101101011000000000000xxxxxxxxxx", InstName.Rbit, InstEmit.Rbit, typeof(OpCodeAlu)); SetA64("1101011001011111000000xxxxx00000", InstName.Ret, InstEmit.Ret, typeof(OpCodeBReg)); SetA64("x101101011000000000001xxxxxxxxxx", InstName.Rev16, InstEmit.Rev16, typeof(OpCodeAlu)); @@ -159,15 +159,15 @@ namespace ARMeilleure.Decoders SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, typeof(OpCodeMul)); SetA64("10011011001xxxxx1xxxxxxxxxxxxxxx", InstName.Smsubl, InstEmit.Smsubl, typeof(OpCodeMul)); SetA64("10011011010xxxxx0xxxxxxxxxxxxxxx", InstName.Smulh, InstEmit.Smulh, typeof(OpCodeMul)); - SetA64("xx001000100xxxxx1xxxxxxxxxxxxxxx", InstName.Stlr, null, typeof(OpCodeMemEx)); - SetA64("1x001000001xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxp, null, typeof(OpCodeMemEx)); - SetA64("xx001000000xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxr, null, typeof(OpCodeMemEx)); + SetA64("xx001000100xxxxx1xxxxxxxxxxxxxxx", InstName.Stlr, InstEmit.Stlr, typeof(OpCodeMemEx)); + SetA64("1x001000001xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxp, InstEmit.Stlxp, typeof(OpCodeMemEx)); + SetA64("xx001000000xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxr, InstEmit.Stlxr, typeof(OpCodeMemEx)); SetA64("x010100xx0xxxxxxxxxxxxxxxxxxxxxx", InstName.Stp, InstEmit.Stp, typeof(OpCodeMemPair)); SetA64("xx111000000xxxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeMemImm)); SetA64("xx11100100xxxxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeMemImm)); SetA64("xx111000001xxxxxxxxx10xxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeMemReg)); - SetA64("1x001000001xxxxx0xxxxxxxxxxxxxxx", InstName.Stxp, null, typeof(OpCodeMemEx)); - SetA64("xx001000000xxxxx0xxxxxxxxxxxxxxx", InstName.Stxr, null, typeof(OpCodeMemEx)); + SetA64("1x001000001xxxxx0xxxxxxxxxxxxxxx", InstName.Stxp, InstEmit.Stxp, typeof(OpCodeMemEx)); + SetA64("xx001000000xxxxx0xxxxxxxxxxxxxxx", InstName.Stxr, InstEmit.Stxr, typeof(OpCodeMemEx)); SetA64("x10100010xxxxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluImm)); SetA64("01001011<<0xxxxx0xxxxxxxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluRs)); SetA64("11001011<<0xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluRs)); @@ -179,7 +179,7 @@ namespace ARMeilleure.Decoders SetA64("x1101011001xxxxxxxx0xxxxxxxxxxxx", InstName.Subs, InstEmit.Subs, typeof(OpCodeAluRx)); SetA64("x1101011001xxxxxxxx100xxxxxxxxxx", InstName.Subs, InstEmit.Subs, typeof(OpCodeAluRx)); SetA64("11010100000xxxxxxxxxxxxxxxx00001", InstName.Svc, InstEmit.Svc, typeof(OpCodeException)); - SetA64("1101010100001xxxxxxxxxxxxxxxxxxx", InstName.Sys, null, typeof(OpCodeSystem)); + SetA64("1101010100001xxxxxxxxxxxxxxxxxxx", InstName.Sys, InstEmit.Sys, typeof(OpCodeSystem)); SetA64("x0110111xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tbnz, InstEmit.Tbnz, typeof(OpCodeBImmTest)); SetA64("x0110110xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tbz, InstEmit.Tbz, typeof(OpCodeBImmTest)); SetA64("01010011000xxxxx0xxxxxxxxxxxxxxx", InstName.Ubfm, InstEmit.Ubfm, typeof(OpCodeBfm)); @@ -362,17 +362,17 @@ namespace ARMeilleure.Decoders SetA64("0>0011101<1xxxxx110101xxxxxxxxxx", InstName.Fsub_V, InstEmit.Fsub_V, typeof(OpCodeSimdReg)); SetA64("01001110000xxxxx000111xxxxxxxxxx", InstName.Ins_Gp, InstEmit.Ins_Gp, typeof(OpCodeSimdIns)); SetA64("01101110000xxxxx0xxxx1xxxxxxxxxx", InstName.Ins_V, InstEmit.Ins_V, typeof(OpCodeSimdIns)); - SetA64("0x00110001000000xxxxxxxxxxxxxxxx", InstName.Ld__Vms, null, typeof(OpCodeSimdMemMs)); - SetA64("0x001100110xxxxxxxxxxxxxxxxxxxxx", InstName.Ld__Vms, null, typeof(OpCodeSimdMemMs)); - SetA64("0x00110101x00000xxxxxxxxxxxxxxxx", InstName.Ld__Vss, null, typeof(OpCodeSimdMemSs)); - SetA64("0x00110111xxxxxxxxxxxxxxxxxxxxxx", InstName.Ld__Vss, null, typeof(OpCodeSimdMemSs)); - SetA64("xx10110xx1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldp, null, typeof(OpCodeSimdMemPair)); - SetA64("xx111100x10xxxxxxxxx00xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111100x10xxxxxxxxx01xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111100x10xxxxxxxxx11xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111101x1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111100x11xxxxxxxxx10xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemReg)); - SetA64("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr_Literal, null, typeof(OpCodeSimdMemLit)); + SetA64("0x00110001000000xxxxxxxxxxxxxxxx", InstName.Ld__Vms, InstEmit.Ld__Vms, typeof(OpCodeSimdMemMs)); + SetA64("0x001100110xxxxxxxxxxxxxxxxxxxxx", InstName.Ld__Vms, InstEmit.Ld__Vms, typeof(OpCodeSimdMemMs)); + SetA64("0x00110101x00000xxxxxxxxxxxxxxxx", InstName.Ld__Vss, InstEmit.Ld__Vss, typeof(OpCodeSimdMemSs)); + SetA64("0x00110111xxxxxxxxxxxxxxxxxxxxxx", InstName.Ld__Vss, InstEmit.Ld__Vss, typeof(OpCodeSimdMemSs)); + SetA64("xx10110xx1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldp, InstEmit.Ldp, typeof(OpCodeSimdMemPair)); + SetA64("xx111100x10xxxxxxxxx00xxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x10xxxxxxxxx01xxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x10xxxxxxxxx11xxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeSimdMemImm)); + SetA64("xx111101x1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x11xxxxxxxxx10xxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeSimdMemReg)); + SetA64("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr_Literal, InstEmit.Ldr_Literal, typeof(OpCodeSimdMemLit)); SetA64("0x001110<<1xxxxx100101xxxxxxxxxx", InstName.Mla_V, InstEmit.Mla_V, typeof(OpCodeSimdReg)); SetA64("0x101111xxxxxxxx0000x0xxxxxxxxxx", InstName.Mla_Ve, InstEmit.Mla_Ve, typeof(OpCodeSimdRegElem)); SetA64("0x101110<<1xxxxx100101xxxxxxxxxx", InstName.Mls_V, InstEmit.Mls_V, typeof(OpCodeSimdReg)); @@ -496,16 +496,16 @@ namespace ARMeilleure.Decoders SetA64("0100111101xxxxxx000101xxxxxxxxxx", InstName.Ssra_V, InstEmit.Ssra_V, typeof(OpCodeSimdShImm)); SetA64("0x001110<<1xxxxx001000xxxxxxxxxx", InstName.Ssubl_V, InstEmit.Ssubl_V, typeof(OpCodeSimdReg)); SetA64("0x001110<<1xxxxx001100xxxxxxxxxx", InstName.Ssubw_V, InstEmit.Ssubw_V, typeof(OpCodeSimdReg)); - SetA64("0x00110000000000xxxxxxxxxxxxxxxx", InstName.St__Vms, null, typeof(OpCodeSimdMemMs)); - SetA64("0x001100100xxxxxxxxxxxxxxxxxxxxx", InstName.St__Vms, null, typeof(OpCodeSimdMemMs)); - SetA64("0x00110100x00000xxxxxxxxxxxxxxxx", InstName.St__Vss, null, typeof(OpCodeSimdMemSs)); - SetA64("0x00110110xxxxxxxxxxxxxxxxxxxxxx", InstName.St__Vss, null, typeof(OpCodeSimdMemSs)); - SetA64("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", InstName.Stp, null, typeof(OpCodeSimdMemPair)); - SetA64("xx111100x00xxxxxxxxx00xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111100x00xxxxxxxxx01xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111100x00xxxxxxxxx11xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111101x0xxxxxxxxxxxxxxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); - SetA64("xx111100x01xxxxxxxxx10xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemReg)); + SetA64("0x00110000000000xxxxxxxxxxxxxxxx", InstName.St__Vms, InstEmit.St__Vms, typeof(OpCodeSimdMemMs)); + SetA64("0x001100100xxxxxxxxxxxxxxxxxxxxx", InstName.St__Vms, InstEmit.St__Vms, typeof(OpCodeSimdMemMs)); + SetA64("0x00110100x00000xxxxxxxxxxxxxxxx", InstName.St__Vss, InstEmit.St__Vss, typeof(OpCodeSimdMemSs)); + SetA64("0x00110110xxxxxxxxxxxxxxxxxxxxxx", InstName.St__Vss, InstEmit.St__Vss, typeof(OpCodeSimdMemSs)); + SetA64("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", InstName.Stp, InstEmit.Stp, typeof(OpCodeSimdMemPair)); + SetA64("xx111100x00xxxxxxxxx00xxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x00xxxxxxxxx01xxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x00xxxxxxxxx11xxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeSimdMemImm)); + SetA64("xx111101x0xxxxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x01xxxxxxxxx10xxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeSimdMemReg)); SetA64("01111110111xxxxx100001xxxxxxxxxx", InstName.Sub_S, InstEmit.Sub_S, typeof(OpCodeSimdReg)); SetA64("0>101110<<1xxxxx100001xxxxxxxxxx", InstName.Sub_V, InstEmit.Sub_V, typeof(OpCodeSimdReg)); SetA64("0x001110<<1xxxxx011000xxxxxxxxxx", InstName.Subhn_V, InstEmit.Subhn_V, typeof(OpCodeSimdReg)); diff --git a/ARMeilleure/Instructions/InstEmitMemory.cs b/ARMeilleure/Instructions/InstEmitMemory.cs index 7fc4f0ef90..6bdcc5a800 100644 --- a/ARMeilleure/Instructions/InstEmitMemory.cs +++ b/ARMeilleure/Instructions/InstEmitMemory.cs @@ -102,7 +102,7 @@ namespace ARMeilleure.Instructions Operand address = GetAddress(context); - EmitStore(context, address, op.Rt, op.Size); + InstEmitMemoryHelper.EmitStore(context, address, op.Rt, op.Size); EmitWBackIfNeeded(context, address); } @@ -115,8 +115,8 @@ namespace ARMeilleure.Instructions Operand address2 = context.Add(address, Const(1L << op.Size)); - EmitStore(context, address, op.Rt, op.Size); - EmitStore(context, address2, op.Rt2, op.Size); + InstEmitMemoryHelper.EmitStore(context, address, op.Rt, op.Size); + InstEmitMemoryHelper.EmitStore(context, address2, op.Rt2, op.Size); EmitWBackIfNeeded(context, address); } @@ -129,7 +129,7 @@ namespace ARMeilleure.Instructions { case OpCodeMemImm op: { - address = GetIntOrSP(op, op.Rn); + address = context.Copy(GetIntOrSP(op, op.Rn)); //Pre-indexing. if (!op.PostIdx) diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx.cs b/ARMeilleure/Instructions/InstEmitMemoryEx.cs new file mode 100644 index 0000000000..2be90efd14 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitMemoryEx.cs @@ -0,0 +1,268 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; +using System; +using System.Diagnostics; +using System.Reflection; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + [Flags] + private enum AccessType + { + None = 0, + Ordered = 1, + Exclusive = 2, + OrderedEx = Ordered | Exclusive + } + + public static void Clrex(EmitterContext context) + { + MethodInfo info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ClearExclusive)); + + context.Call(info); + } + + public static void Dmb(EmitterContext context) => EmitBarrier(context); + public static void Dsb(EmitterContext context) => EmitBarrier(context); + + public static void Ldar(EmitterContext context) => EmitLdr(context, AccessType.Ordered); + public static void Ldaxr(EmitterContext context) => EmitLdr(context, AccessType.OrderedEx); + public static void Ldxr(EmitterContext context) => EmitLdr(context, AccessType.Exclusive); + public static void Ldxp(EmitterContext context) => EmitLdp(context, AccessType.Exclusive); + public static void Ldaxp(EmitterContext context) => EmitLdp(context, AccessType.OrderedEx); + + private static void EmitLdr(EmitterContext context, AccessType accType) + { + EmitLoadEx(context, accType, pair: false); + } + + private static void EmitLdp(EmitterContext context, AccessType accType) + { + EmitLoadEx(context, accType, pair: true); + } + + private static void EmitLoadEx(EmitterContext context, AccessType accType, bool pair) + { + OpCodeMemEx op = (OpCodeMemEx)context.CurrOp; + + bool ordered = (accType & AccessType.Ordered) != 0; + bool exclusive = (accType & AccessType.Exclusive) != 0; + + if (ordered) + { + EmitBarrier(context); + } + + Operand address = context.Copy(GetIntOrSP(op, op.Rn)); + + if (pair) + { + //Exclusive loads should be atomic. For pairwise loads, we need to + //read all the data at once. For a 32-bits pairwise load, we do a + //simple 64-bits load, for a 128-bits load, we need to call a special + //method to read 128-bits atomically. + if (op.Size == 2) + { + Operand value = EmitLoad(context, address, exclusive, 3); + + Operand valueLow = context.Copy(Local(OperandType.I32), value); + + valueLow = context.Copy(Local(OperandType.I64), valueLow); + + Operand valueHigh = context.ShiftRightUI(value, Const(32)); + + SetIntOrZR(context, op.Rt, valueLow); + SetIntOrZR(context, op.Rt2, valueHigh); + } + else if (op.Size == 3) + { + Operand value = EmitLoad(context, address, exclusive, 4); + + Operand valueLow = context.VectorExtract(value, Local(OperandType.I64), 0); + Operand valueHigh = context.VectorExtract(value, Local(OperandType.I64), 1); + + SetIntOrZR(context, op.Rt, valueLow); + SetIntOrZR(context, op.Rt2, valueHigh); + } + else + { + throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes."); + } + } + else + { + //8, 16, 32 or 64-bits (non-pairwise) load. + Operand value = EmitLoad(context, address, exclusive, op.Size); + + SetIntOrZR(context, op.Rt, value); + } + } + + private static Operand EmitLoad( + EmitterContext context, + Operand address, + bool exclusive, + int size) + { + string fallbackMethodName = null; + + if (exclusive) + { + switch (size) + { + case 0: fallbackMethodName = nameof(NativeInterface.ReadByteExclusive); break; + case 1: fallbackMethodName = nameof(NativeInterface.ReadUInt16Exclusive); break; + case 2: fallbackMethodName = nameof(NativeInterface.ReadUInt32Exclusive); break; + case 3: fallbackMethodName = nameof(NativeInterface.ReadUInt64Exclusive); break; + case 4: fallbackMethodName = nameof(NativeInterface.ReadVector128Exclusive); break; + } + } + else + { + switch (size) + { + case 0: fallbackMethodName = nameof(NativeInterface.ReadByte); break; + case 1: fallbackMethodName = nameof(NativeInterface.ReadUInt16); break; + case 2: fallbackMethodName = nameof(NativeInterface.ReadUInt32); break; + case 3: fallbackMethodName = nameof(NativeInterface.ReadUInt64); break; + case 4: fallbackMethodName = nameof(NativeInterface.ReadVector128); break; + } + } + + MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName); + + return context.Call(info, address); + } + + public static void Pfrm(EmitterContext context) + { + //Memory Prefetch, execute as no-op. + } + + public static void Stlr(EmitterContext context) => EmitStr(context, AccessType.Ordered); + public static void Stlxr(EmitterContext context) => EmitStr(context, AccessType.OrderedEx); + public static void Stxr(EmitterContext context) => EmitStr(context, AccessType.Exclusive); + public static void Stxp(EmitterContext context) => EmitStp(context, AccessType.Exclusive); + public static void Stlxp(EmitterContext context) => EmitStp(context, AccessType.OrderedEx); + + private static void EmitStr(EmitterContext context, AccessType accType) + { + EmitStoreEx(context, accType, pair: false); + } + + private static void EmitStp(EmitterContext context, AccessType accType) + { + EmitStoreEx(context, accType, pair: true); + } + + private static void EmitStoreEx(EmitterContext context, AccessType accType, bool pair) + { + OpCodeMemEx op = (OpCodeMemEx)context.CurrOp; + + bool ordered = (accType & AccessType.Ordered) != 0; + bool exclusive = (accType & AccessType.Exclusive) != 0; + + if (ordered) + { + EmitBarrier(context); + } + + Operand address = context.Copy(GetIntOrSP(op, op.Rn)); + + Operand t = GetIntOrZR(op, op.Rt); + + Operand s = null; + + if (pair) + { + Debug.Assert(op.Size == 2 || op.Size == 3, "Invalid size for pairwise store."); + + Operand t2 = GetIntOrZR(op, op.Rt2); + + Operand value; + + if (op.Size == 2) + { + value = context.BitwiseOr(t, context.ShiftLeft(t2, Const(32))); + } + else /* if (op.Size == 3) */ + { + value = context.VectorInsert(context.VectorZero(), t, 0); + value = context.VectorInsert(value, t2, 1); + } + + s = EmitStore(context, address, value, exclusive, op.Size + 1); + } + else + { + s = EmitStore(context, address, t, exclusive, op.Size); + } + + if (s != null) + { + //This is only needed for exclusive stores. The function returns 0 + //when the store is successful, and 1 otherwise. + SetIntOrZR(context, op.Rs, s); + } + } + + private static Operand EmitStore( + EmitterContext context, + Operand address, + Operand value, + bool exclusive, + int size) + { + if (size < 3) + { + value = context.Copy(Local(OperandType.I32), value); + } + + string fallbackMethodName = null; + + if (exclusive) + { + switch (size) + { + case 0: fallbackMethodName = nameof(NativeInterface.WriteByteExclusive); break; + case 1: fallbackMethodName = nameof(NativeInterface.WriteUInt16Exclusive); break; + case 2: fallbackMethodName = nameof(NativeInterface.WriteUInt32Exclusive); break; + case 3: fallbackMethodName = nameof(NativeInterface.WriteUInt64Exclusive); break; + case 4: fallbackMethodName = nameof(NativeInterface.WriteVector128Exclusive); break; + } + + MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName); + + return context.Call(info, address, value); + } + else + { + switch (size) + { + case 0: fallbackMethodName = nameof(NativeInterface.WriteByte); break; + case 1: fallbackMethodName = nameof(NativeInterface.WriteUInt16); break; + case 2: fallbackMethodName = nameof(NativeInterface.WriteUInt32); break; + case 3: fallbackMethodName = nameof(NativeInterface.WriteUInt64); break; + case 4: fallbackMethodName = nameof(NativeInterface.WriteVector128); break; + } + + MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName); + + return null; + } + } + + private static void EmitBarrier(EmitterContext context) + { + //Note: This barrier is most likely not necessary, and probably + //doesn't make any difference since we need to do a ton of stuff + //(software MMU emulation) to read or write anything anyway. + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs index 9981278c20..f76710a98f 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs @@ -50,11 +50,11 @@ namespace ARMeilleure.Instructions { if (ForceFallback || !Optimizations.UseSse2 || size < 2) { - EmitReadVectorFallback(context, address, rt, size); + EmitReadVectorFallback(context, address, context.VectorZero(), rt, 0, size); } else { - EmitReadVector(context, address, rt, size); + EmitReadVector(context, address, context.VectorZero(), rt, 0, size); } } else @@ -92,6 +92,24 @@ namespace ARMeilleure.Instructions } } + public static void EmitLoadSimd( + EmitterContext context, + Operand address, + Operand vector, + int rt, + int elem, + int size) + { + if (ForceFallback || !Optimizations.UseSse2 || size < 2) + { + EmitReadVectorFallback(context, address, vector, rt, elem, size); + } + else + { + EmitReadVector(context, address, vector, rt, elem, size); + } + } + public static void EmitStore(EmitterContext context, Operand address, int rt, int size) { bool isSimd = IsSimd(context); @@ -105,11 +123,11 @@ namespace ARMeilleure.Instructions { if (ForceFallback || !Optimizations.UseSse2 || size < 2) { - EmitWriteVectorFallback(context, address, rt, size); + EmitWriteVectorFallback(context, address, rt, 0, size); } else { - EmitWriteVector(context, address, rt, size); + EmitWriteVector(context, address, rt, 0, size); } } else @@ -125,6 +143,23 @@ namespace ARMeilleure.Instructions } } + public static void EmitStoreSimd( + EmitterContext context, + Operand address, + int rt, + int elem, + int size) + { + if (ForceFallback || !Optimizations.UseSse2 || size < 2) + { + EmitWriteVectorFallback(context, address, rt, elem, size); + } + else + { + EmitWriteVector(context, address, rt, elem, size); + } + } + private static bool IsSimd(EmitterContext context) { return context.CurrOp is IOpCodeSimd && @@ -167,7 +202,13 @@ namespace ARMeilleure.Instructions context.MarkLabel(lblEnd); } - private static void EmitReadVector(EmitterContext context, Operand address, int rt, int size) + private static void EmitReadVector( + EmitterContext context, + Operand address, + Operand vector, + int rt, + int elem, + int size) { Operand isUnalignedAddr = EmitAddressCheck(context, address, size); @@ -179,7 +220,7 @@ namespace ARMeilleure.Instructions context.MarkLabel(lblSlowPath); - EmitReadVectorFallback(context, address, rt, size); + EmitReadVectorFallback(context, address, vector, rt, elem, size); context.Branch(lblEnd); @@ -250,7 +291,12 @@ namespace ARMeilleure.Instructions context.MarkLabel(lblEnd); } - private static void EmitWriteVector(EmitterContext context, Operand address, int rt, int size) + private static void EmitWriteVector( + EmitterContext context, + Operand address, + int rt, + int elem, + int size) { Operand isUnalignedAddr = EmitAddressCheck(context, address, size); @@ -262,7 +308,7 @@ namespace ARMeilleure.Instructions context.MarkLabel(lblSlowPath); - EmitWriteVectorFallback(context, address, rt, size); + EmitWriteVectorFallback(context, address, rt, elem, size); context.Branch(lblEnd); @@ -346,35 +392,46 @@ namespace ARMeilleure.Instructions MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName); - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - address = context.Copy(Local(OperandType.I64), address); - } - context.Copy(GetT(context, rt), context.Call(info, address)); } - private static void EmitReadVectorFallback(EmitterContext context, Operand address, int rt, int size) + private static void EmitReadVectorFallback( + EmitterContext context, + Operand address, + Operand vector, + int rt, + int elem, + int size) { string fallbackMethodName = null; switch (size) { - case 0: fallbackMethodName = nameof(NativeInterface.ReadVector8); break; - case 1: fallbackMethodName = nameof(NativeInterface.ReadVector16); break; - case 2: fallbackMethodName = nameof(NativeInterface.ReadVector32); break; - case 3: fallbackMethodName = nameof(NativeInterface.ReadVector64); break; + case 0: fallbackMethodName = nameof(NativeInterface.ReadByte); break; + case 1: fallbackMethodName = nameof(NativeInterface.ReadUInt16); break; + case 2: fallbackMethodName = nameof(NativeInterface.ReadUInt32); break; + case 3: fallbackMethodName = nameof(NativeInterface.ReadUInt64); break; case 4: fallbackMethodName = nameof(NativeInterface.ReadVector128); break; } MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName); - if (context.CurrOp.RegisterSize == RegisterSize.Int32) + Operand value = context.Call(info, address); + + if (size < 3) { - address = context.Copy(Local(OperandType.I64), address); + value = context.Copy(Local(OperandType.I32), value); } - context.Copy(GetVec(rt), context.Call(info, address)); + switch (size) + { + case 0: value = context.VectorInsert8 (vector, value, elem); break; + case 1: value = context.VectorInsert16(vector, value, elem); break; + case 2: value = context.VectorInsert (vector, value, elem); break; + case 3: value = context.VectorInsert (vector, value, elem); break; + } + + context.Copy(GetVec(rt), value); } private static void EmitWriteIntFallback(EmitterContext context, Operand address, int rt, int size) @@ -391,11 +448,6 @@ namespace ARMeilleure.Instructions MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName); - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - address = context.Copy(Local(OperandType.I64), address); - } - Operand value = GetT(context, rt); if (size < 3) @@ -406,27 +458,44 @@ namespace ARMeilleure.Instructions context.Call(info, address, value); } - private static void EmitWriteVectorFallback(EmitterContext context, Operand address, int rt, int size) + private static void EmitWriteVectorFallback( + EmitterContext context, + Operand address, + int rt, + int elem, + int size) { string fallbackMethodName = null; switch (size) { - case 0: fallbackMethodName = nameof(NativeInterface.WriteVector8); break; - case 1: fallbackMethodName = nameof(NativeInterface.WriteVector16); break; - case 2: fallbackMethodName = nameof(NativeInterface.WriteVector32); break; - case 3: fallbackMethodName = nameof(NativeInterface.WriteVector64); break; + case 0: fallbackMethodName = nameof(NativeInterface.WriteByte); break; + case 1: fallbackMethodName = nameof(NativeInterface.WriteUInt16); break; + case 2: fallbackMethodName = nameof(NativeInterface.WriteUInt32); break; + case 3: fallbackMethodName = nameof(NativeInterface.WriteUInt64); break; case 4: fallbackMethodName = nameof(NativeInterface.WriteVector128); break; } MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName); - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - address = context.Copy(Local(OperandType.I64), address); - } + Operand value; - Operand value = GetVec(rt); + if (size < 4) + { + value = Local(size == 3 ? OperandType.I64 : OperandType.I32); + + switch (size) + { + case 0: context.VectorExtract8 (GetVec(rt), value, elem); break; + case 1: context.VectorExtract16(GetVec(rt), value, elem); break; + case 2: context.VectorExtract (GetVec(rt), value, elem); break; + case 3: context.VectorExtract (GetVec(rt), value, elem); break; + } + } + else + { + value = GetVec(rt); + } context.Call(info, address, value); } diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs index 694330fdec..0a2869ef92 100644 --- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs +++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs @@ -160,7 +160,7 @@ namespace ARMeilleure.Instructions if (Optimizations.UsePopCnt) { - de = context.AddIntrinsic(Instruction.X86Popcnt, ne); + de = context.AddIntrinsicLong(Instruction.X86Popcnt, ne); } else { diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs index a0478bfbf0..b6ee6f6ec8 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs @@ -1440,8 +1440,7 @@ namespace ARMeilleure.Instructions { ThrowIfInvalid(index, size); - Operand res = Local(size == 3 ? OperandType.I64 - : OperandType.I32); + Operand res = Local(size == 3 ? OperandType.I64 : OperandType.I32); switch (size) { diff --git a/ARMeilleure/Instructions/InstEmitSimdMemory.cs b/ARMeilleure/Instructions/InstEmitSimdMemory.cs new file mode 100644 index 0000000000..32afb5bebf --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitSimdMemory.cs @@ -0,0 +1,160 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System.Diagnostics; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.Instructions.InstEmitMemoryHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void Ld__Vms(EmitterContext context) + { + EmitSimdMemMs(context, isLoad: true); + } + + public static void Ld__Vss(EmitterContext context) + { + EmitSimdMemSs(context, isLoad: true); + } + + public static void St__Vms(EmitterContext context) + { + EmitSimdMemMs(context, isLoad: false); + } + + public static void St__Vss(EmitterContext context) + { + EmitSimdMemSs(context, isLoad: false); + } + + private static void EmitSimdMemMs(EmitterContext context, bool isLoad) + { + OpCodeSimdMemMs op = (OpCodeSimdMemMs)context.CurrOp; + + Operand n = GetIntOrSP(op, op.Rn); + + long offset = 0; + + for (int rep = 0; rep < op.Reps; rep++) + for (int elem = 0; elem < op.Elems; elem++) + for (int sElem = 0; sElem < op.SElems; sElem++) + { + int rtt = (op.Rt + rep + sElem) & 0x1f; + + Operand tt = GetVec(rtt); + + Operand address = context.Add(n, Const(offset)); + + if (isLoad) + { + EmitLoadSimd(context, address, tt, rtt, elem, op.Size); + + if (op.RegisterSize == RegisterSize.Simd64 && elem == op.Elems - 1) + { + context.Copy(tt, context.VectorZeroUpper64(tt)); + } + } + else + { + EmitStoreSimd(context, address, rtt, elem, op.Size); + } + + offset += 1 << op.Size; + } + + if (op.WBack) + { + EmitSimdMemWBack(context, offset); + } + } + + private static void EmitSimdMemSs(EmitterContext context, bool isLoad) + { + OpCodeSimdMemSs op = (OpCodeSimdMemSs)context.CurrOp; + + Operand n = GetIntOrSP(op, op.Rn); + + long offset = 0; + + if (op.Replicate) + { + //Only loads uses the replicate mode. + Debug.Assert(isLoad, "Replicate mode is not valid for stores."); + + int elems = op.GetBytesCount() >> op.Size; + + for (int sElem = 0; sElem < op.SElems; sElem++) + { + int rt = (op.Rt + sElem) & 0x1f; + + Operand t = GetVec(rt); + + Operand address = context.Add(n, Const(offset)); + + for (int index = 0; index < elems; index++) + { + EmitLoadSimd(context, address, t, rt, index, op.Size); + } + + if (op.RegisterSize == RegisterSize.Simd64) + { + context.Copy(t, context.VectorZeroUpper64(t)); + } + + offset += 1 << op.Size; + } + } + else + { + for (int sElem = 0; sElem < op.SElems; sElem++) + { + int rt = (op.Rt + sElem) & 0x1f; + + Operand t = GetVec(rt); + + Operand address = context.Add(n, Const(offset)); + + if (isLoad) + { + EmitLoadSimd(context, address, t, rt, op.Index, op.Size); + } + else + { + EmitStoreSimd(context, address, rt, op.Index, op.Size); + } + + offset += 1 << op.Size; + } + } + + if (op.WBack) + { + EmitSimdMemWBack(context, offset); + } + } + + private static void EmitSimdMemWBack(EmitterContext context, long offset) + { + OpCodeMemReg op = (OpCodeMemReg)context.CurrOp; + + Operand n = GetIntOrSP(op, op.Rn); + Operand m; + + if (op.Rm != RegisterAlias.Zr) + { + m = GetIntOrZR(op, op.Rm); + } + else + { + m = Const(offset); + } + + context.Copy(n, context.Add(n, m)); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs new file mode 100644 index 0000000000..5e86274ef7 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitSystem.cs @@ -0,0 +1,121 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; +using System; +using System.Reflection; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + private const int DczSizeLog2 = 4; + + public static void Hint(EmitterContext context) + { + //Execute as no-op. + } + + public static void Isb(EmitterContext context) + { + //Execute as no-op. + } + + public static void Mrs(EmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + string name; + + switch (GetPackedId(op)) + { + case 0b11_011_0000_0000_001: name = nameof(NativeInterface.GetCtrEl0); break; + case 0b11_011_0000_0000_111: name = nameof(NativeInterface.GetDczidEl0); break; + case 0b11_011_0100_0100_000: name = nameof(NativeInterface.GetFpcr); break; + case 0b11_011_0100_0100_001: name = nameof(NativeInterface.GetFpsr); break; + case 0b11_011_1101_0000_010: name = nameof(NativeInterface.GetTpidrEl0); break; + case 0b11_011_1101_0000_011: name = nameof(NativeInterface.GetTpidr); break; + case 0b11_011_1110_0000_000: name = nameof(NativeInterface.GetCntfrqEl0); break; + case 0b11_011_1110_0000_001: name = nameof(NativeInterface.GetCntpctEl0); break; + + default: throw new NotImplementedException($"Unknown MRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); + } + + MethodInfo info = typeof(NativeInterface).GetMethod(name); + + SetIntOrZR(context, op.Rt, context.Call(info)); + } + + public static void Msr(EmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + string name; + + switch (GetPackedId(op)) + { + case 0b11_011_0100_0100_000: name = nameof(NativeInterface.SetFpcr); break; + case 0b11_011_0100_0100_001: name = nameof(NativeInterface.SetFpsr); break; + case 0b11_011_1101_0000_010: name = nameof(NativeInterface.SetTpidrEl0); break; + + default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); + } + + MethodInfo info = typeof(NativeInterface).GetMethod(name); + + context.Call(info, GetIntOrZR(op, op.Rt)); + } + + public static void Nop(EmitterContext context) + { + //Do nothing. + } + + public static void Sys(EmitterContext context) + { + //This instruction is used to do some operations on the CPU like cache invalidation, + //address translation and the like. + //We treat it as no-op here since we don't have any cache being emulated anyway. + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + switch (GetPackedId(op)) + { + case 0b11_011_0111_0100_001: + { + //DC ZVA + Operand t = GetIntOrZR(op, op.Rt); + + MethodInfo info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); + + for (long offset = 0; offset < (4 << DczSizeLog2); offset += 8) + { + Operand address = context.Add(t, Const(offset)); + + context.Call(info, address, Const(0L)); + } + + break; + } + + //No-op + case 0b11_011_0111_1110_001: //DC CIVAC + break; + } + } + + private static int GetPackedId(OpCodeSystem op) + { + int id; + + id = op.Op2 << 0; + id |= op.CRm << 3; + id |= op.CRn << 7; + id |= op.Op1 << 11; + id |= op.Op0 << 14; + + return id; + } + } +} diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs index db83696835..46f2e1b08f 100644 --- a/ARMeilleure/Instructions/NativeInterface.cs +++ b/ARMeilleure/Instructions/NativeInterface.cs @@ -8,15 +8,23 @@ namespace ARMeilleure.Instructions { static class NativeInterface { - private struct ThreadContext + private const int ErgSizeLog2 = 4; + + private class ThreadContext { public ExecutionContext Context { get; } public MemoryManager Memory { get; } + public ulong ExclusiveAddress { get; set; } + public ulong ExclusiveValueLow { get; set; } + public ulong ExclusiveValueHigh { get; set; } + public ThreadContext(ExecutionContext context, MemoryManager memory) { Context = context; Memory = memory; + + ExclusiveAddress = ulong.MaxValue; } } @@ -52,6 +60,64 @@ namespace ARMeilleure.Instructions GetContext().OnUndefined(address, opCode); } +#region "System registers" + public static ulong GetCtrEl0() + { + return (ulong)GetContext().CtrEl0; + } + + public static ulong GetDczidEl0() + { + return (ulong)GetContext().DczidEl0; + } + + public static ulong GetFpcr() + { + return (ulong)GetContext().Fpcr; + } + + public static ulong GetFpsr() + { + return (ulong)GetContext().Fpsr; + } + + public static ulong GetTpidrEl0() + { + return (ulong)GetContext().TpidrEl0; + } + + public static ulong GetTpidr() + { + return (ulong)GetContext().Tpidr; + } + + public static ulong GetCntfrqEl0() + { + return GetContext().CntfrqEl0; + } + + public static ulong GetCntpctEl0() + { + return GetContext().CntpctEl0; + } + + public static void SetFpcr(ulong value) + { + GetContext().Fpcr = (FPCR)value; + } + + public static void SetFpsr(ulong value) + { + GetContext().Fpsr = (FPSR)value; + } + + public static void SetTpidrEl0(ulong value) + { + GetContext().TpidrEl0 = (long)value; + } +#endregion + +#region "Read" public static byte ReadByte(ulong address) { return GetMemoryManager().ReadByte((long)address); @@ -72,31 +138,80 @@ namespace ARMeilleure.Instructions return GetMemoryManager().ReadUInt64((long)address); } - public static V128 ReadVector8(ulong address) - { - return new V128(0); //TODO - } - - public static V128 ReadVector16(ulong address) - { - return new V128(0); //TODO - } - - public static V128 ReadVector32(ulong address) - { - return new V128(0); //TODO - } - - public static V128 ReadVector64(ulong address) - { - return new V128(0); //TODO - } - public static V128 ReadVector128(ulong address) { - return new V128(0); //TODO + return GetMemoryManager().ReadVector128((long)address); + } +#endregion + +#region "Read exclusive" + public static byte ReadByteExclusive(ulong address) + { + ThreadContext context = GetCurrentContext(); + + byte value = context.Memory.ReadByte((long)address); + + context.ExclusiveAddress = GetMaskedExclusiveAddress(address); + context.ExclusiveValueLow = value; + context.ExclusiveValueHigh = 0; + + return value; } + public static ushort ReadUInt16Exclusive(ulong address) + { + ThreadContext context = GetCurrentContext(); + + ushort value = context.Memory.ReadUInt16((long)address); + + context.ExclusiveAddress = GetMaskedExclusiveAddress(address); + context.ExclusiveValueLow = value; + context.ExclusiveValueHigh = 0; + + return value; + } + + public static uint ReadUInt32Exclusive(ulong address) + { + ThreadContext context = GetCurrentContext(); + + uint value = context.Memory.ReadUInt32((long)address); + + context.ExclusiveAddress = GetMaskedExclusiveAddress(address); + context.ExclusiveValueLow = value; + context.ExclusiveValueHigh = 0; + + return value; + } + + public static ulong ReadUInt64Exclusive(ulong address) + { + ThreadContext context = GetCurrentContext(); + + ulong value = context.Memory.ReadUInt64((long)address); + + context.ExclusiveAddress = GetMaskedExclusiveAddress(address); + context.ExclusiveValueLow = value; + context.ExclusiveValueHigh = 0; + + return value; + } + + public static V128 ReadVector128Exclusive(ulong address) + { + ThreadContext context = GetCurrentContext(); + + V128 value = context.Memory.ReadVector128((long)address); + + context.ExclusiveAddress = GetMaskedExclusiveAddress(address); + context.ExclusiveValueLow = value.GetUInt64(0); + context.ExclusiveValueHigh = value.GetUInt64(1); + + return value; + } +#endregion + +#region "Write" public static void WriteByte(ulong address, byte value) { GetMemoryManager().WriteByte((long)address, value); @@ -117,29 +232,139 @@ namespace ARMeilleure.Instructions GetMemoryManager().WriteUInt64((long)address, value); } - public static void WriteVector8(ulong address, V128 value) - { - //TODO - } - - public static void WriteVector16(ulong address, V128 value) - { - //TODO - } - - public static void WriteVector32(ulong address, V128 value) - { - //TODO - } - - public static void WriteVector64(ulong address, V128 value) - { - //TODO - } - public static void WriteVector128(ulong address, V128 value) { - //TODO + GetMemoryManager().WriteVector128((long)address, value); + } +#endregion + +#region "Write exclusive" + public static int WriteByteExclusive(ulong address, byte value) + { + ThreadContext context = GetCurrentContext(); + + bool success = context.ExclusiveAddress == GetMaskedExclusiveAddress(address); + + if (success) + { + success = context.Memory.AtomicCompareExchangeByte( + (long)address, + (byte)value, + (byte)context.ExclusiveValueLow); + + if (success) + { + ClearExclusive(); + } + } + + return success ? 0 : 1; + } + + public static int WriteUInt16Exclusive(ulong address, ushort value) + { + ThreadContext context = GetCurrentContext(); + + bool success = context.ExclusiveAddress == GetMaskedExclusiveAddress(address); + + if (success) + { + success = context.Memory.AtomicCompareExchangeInt16( + (long)address, + (short)value, + (short)context.ExclusiveValueLow); + + if (success) + { + ClearExclusive(); + } + } + + return success ? 0 : 1; + } + + public static int WriteUInt32Exclusive(ulong address, uint value) + { + ThreadContext context = GetCurrentContext(); + + bool success = context.ExclusiveAddress == GetMaskedExclusiveAddress(address); + + if (success) + { + success = context.Memory.AtomicCompareExchangeInt32( + (long)address, + (int)value, + (int)context.ExclusiveValueLow); + + if (success) + { + ClearExclusive(); + } + } + + return success ? 0 : 1; + } + + public static int WriteUInt64Exclusive(ulong address, ulong value) + { + ThreadContext context = GetCurrentContext(); + + bool success = context.ExclusiveAddress == GetMaskedExclusiveAddress(address); + + if (success) + { + success = context.Memory.AtomicCompareExchangeInt64( + (long)address, + (long)value, + (long)context.ExclusiveValueLow); + + if (success) + { + ClearExclusive(); + } + } + + return success ? 0 : 1; + } + + public static int WriteVector128Exclusive(ulong address, V128 value) + { + ThreadContext context = GetCurrentContext(); + + bool success = context.ExclusiveAddress == GetMaskedExclusiveAddress(address); + + if (success) + { + success = context.Memory.AtomicCompareExchangeInt128( + (long)address, + value.GetUInt64(0), + value.GetUInt64(1), + context.ExclusiveValueLow, + context.ExclusiveValueHigh); + + if (success) + { + ClearExclusive(); + } + } + + return success ? 0 : 1; + } +#endregion + + private static ulong GetMaskedExclusiveAddress(ulong address) + { + return address & ~((4UL << ErgSizeLog2) - 1); + } + + public static void ClearExclusive() + { + GetCurrentContext().ExclusiveAddress = ulong.MaxValue; + } + + private static ThreadContext GetCurrentContext() + { + return _contexts[Thread.CurrentThread]; } public static ExecutionContext GetContext() diff --git a/ARMeilleure/Memory/MemoryManager.cs b/ARMeilleure/Memory/MemoryManager.cs index 9d451a1116..98390ab063 100644 --- a/ARMeilleure/Memory/MemoryManager.cs +++ b/ARMeilleure/Memory/MemoryManager.cs @@ -1,3 +1,4 @@ +using ARMeilleure.State; using System; using System.Runtime.InteropServices; using System.Threading; @@ -466,6 +467,23 @@ namespace ARMeilleure.Memory return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; } + internal bool AtomicCompareExchangeInt128( + long position, + ulong expectedLow, + ulong expectedHigh, + ulong desiredLow, + ulong desiredHigh) + { + if ((position & 0xf) != 0) + { + AbortWithAlignmentFault(position); + } + + IntPtr ptr = TranslateWrite(position); + + throw new NotImplementedException(); + } + public int AtomicIncrementInt32(long position) { if ((position & 3) != 0) @@ -560,6 +578,11 @@ namespace ARMeilleure.Memory } } + public V128 ReadVector128(long position) + { + return new V128(ReadUInt64(position), ReadUInt64(position + 8)); + } + public byte[] ReadBytes(long position, long size) { long endAddr = position + size; @@ -697,6 +720,12 @@ namespace ARMeilleure.Memory } } + public void WriteVector128(long position, V128 value) + { + WriteUInt64(position + 0, value.GetUInt64(0)); + WriteUInt64(position + 8, value.GetUInt64(1)); + } + public void WriteBytes(long position, byte[] data) { long endAddr = position + data.Length; diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs index 5a618d1237..2c1dbd73b7 100644 --- a/ARMeilleure/State/ExecutionContext.cs +++ b/ARMeilleure/State/ExecutionContext.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; namespace ARMeilleure.State { @@ -8,6 +9,27 @@ namespace ARMeilleure.State internal IntPtr NativeContextPtr => _nativeContext.BasePtr; + private static Stopwatch _tickCounter; + + private static double _hostTickFreq; + + public uint CtrEl0 => 0x8444c004; + public uint DczidEl0 => 0x00000004; + + public ulong CntfrqEl0 { get; set; } + public ulong CntpctEl0 + { + get + { + double ticks = _tickCounter.ElapsedTicks * _hostTickFreq; + + return (ulong)(ticks * CntfrqEl0); + } + } + + public long TpidrEl0 { get; set; } + public long Tpidr { get; set; } + public FPCR Fpcr { get; set; } public FPSR Fpsr { get; set; } @@ -15,6 +37,15 @@ namespace ARMeilleure.State public event EventHandler SupervisorCall; public event EventHandler Undefined; + static ExecutionContext() + { + _hostTickFreq = 1.0 / Stopwatch.Frequency; + + _tickCounter = new Stopwatch(); + + _tickCounter.Start(); + } + public ExecutionContext() { _nativeContext = new NativeContext();