diff --git a/ARMeilleure/Decoders/Decoder.cs b/ARMeilleure/Decoders/Decoder.cs index 4dd8742c..426465aa 100644 --- a/ARMeilleure/Decoders/Decoder.cs +++ b/ARMeilleure/Decoders/Decoder.cs @@ -251,6 +251,13 @@ namespace ARMeilleure.Decoders return false; } + // Compare and branch instructions are always conditional. + if (opCode.Instruction.Name == InstName.Cbz || + opCode.Instruction.Name == InstName.Cbnz) + { + return false; + } + // Note: On ARM32, most instructions have conditional execution, // so there's no "Always" (unconditional) branch like on ARM64. // We need to check if the condition is "Always" instead. diff --git a/ARMeilleure/Decoders/DecoderHelper.cs b/ARMeilleure/Decoders/DecoderHelper.cs index 6fe4678f..38f98c39 100644 --- a/ARMeilleure/Decoders/DecoderHelper.cs +++ b/ARMeilleure/Decoders/DecoderHelper.cs @@ -151,7 +151,7 @@ namespace ARMeilleure.Decoders public static bool VectorArgumentsInvalid(bool q, params int[] args) { - if (q) + if (q) { for (int i = 0; i < args.Length; i++) { diff --git a/ARMeilleure/Decoders/IOpCode32Mem.cs b/ARMeilleure/Decoders/IOpCode32Mem.cs index 145bc618..6664ddff 100644 --- a/ARMeilleure/Decoders/IOpCode32Mem.cs +++ b/ARMeilleure/Decoders/IOpCode32Mem.cs @@ -3,6 +3,7 @@ namespace ARMeilleure.Decoders interface IOpCode32Mem : IOpCode32 { int Rt { get; } + int Rt2 => Rt | 1; int Rn { get; } bool WBack { get; } diff --git a/ARMeilleure/Decoders/OpCodeT16Adr.cs b/ARMeilleure/Decoders/OpCodeT16Adr.cs index ef14791d..03abd499 100644 --- a/ARMeilleure/Decoders/OpCodeT16Adr.cs +++ b/ARMeilleure/Decoders/OpCodeT16Adr.cs @@ -4,14 +4,13 @@ namespace ARMeilleure.Decoders { public int Rd { get; } - public bool Add => true; public int Immediate { get; } public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode); public OpCodeT16Adr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { - Rd = (opCode >> 8) & 7; + Rd = (opCode >> 8) & 7; int imm = (opCode & 0xff) << 2; Immediate = (int)(GetPc() & 0xfffffffc) + imm; diff --git a/ARMeilleure/Decoders/OpCodeT32AluImm12.cs b/ARMeilleure/Decoders/OpCodeT32AluImm12.cs new file mode 100644 index 00000000..31de63dd --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT32AluImm12.cs @@ -0,0 +1,16 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeT32AluImm12 : OpCodeT32Alu, IOpCode32AluImm + { + public int Immediate { get; } + + public bool IsRotated => false; + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluImm12(inst, address, opCode); + + public OpCodeT32AluImm12(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT32AluReg.cs b/ARMeilleure/Decoders/OpCodeT32AluReg.cs new file mode 100644 index 00000000..a487f55a --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT32AluReg.cs @@ -0,0 +1,14 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeT32AluReg : OpCodeT32Alu, IOpCode32AluReg + { + public int Rm { get; } + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluReg(inst, address, opCode); + + public OpCodeT32AluReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rm = (opCode >> 0) & 0xf; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT32MemImm8D.cs b/ARMeilleure/Decoders/OpCodeT32MemImm8D.cs index 18eeffa4..7a078c48 100644 --- a/ARMeilleure/Decoders/OpCodeT32MemImm8D.cs +++ b/ARMeilleure/Decoders/OpCodeT32MemImm8D.cs @@ -23,7 +23,7 @@ namespace ARMeilleure.Decoders Add = ((opCode >> 23) & 1) != 0; WBack = ((opCode >> 21) & 1) != 0; - Immediate = opCode & 0xff; + Immediate = (opCode & 0xff) << 2; IsLoad = ((opCode >> 20) & 1) != 0; } diff --git a/ARMeilleure/Decoders/OpCodeT32MovImm16.cs b/ARMeilleure/Decoders/OpCodeT32MovImm16.cs new file mode 100644 index 00000000..55db012c --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT32MovImm16.cs @@ -0,0 +1,19 @@ +using ARMeilleure.Common; +using System.Runtime.Intrinsics; + +namespace ARMeilleure.Decoders +{ + class OpCodeT32MovImm16 : OpCodeT32Alu, IOpCode32AluImm + { + public int Immediate { get; } + + public bool IsRotated => false; + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MovImm16(inst, address, opCode); + + public OpCodeT32MovImm16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800) | ((opCode >> 4) & 0xf000); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT32ShiftReg.cs b/ARMeilleure/Decoders/OpCodeT32ShiftReg.cs new file mode 100644 index 00000000..36055975 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT32ShiftReg.cs @@ -0,0 +1,19 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeT32ShiftReg : OpCodeT32Alu, IOpCode32AluRsReg + { + public int Rm => Rn; + public int Rs { get; } + + public ShiftType ShiftType { get; } + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32ShiftReg(inst, address, opCode); + + public OpCodeT32ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rs = (opCode >> 0) & 0xf; + + ShiftType = (ShiftType)((opCode >> 21) & 3); + } + } +} diff --git a/ARMeilleure/Decoders/OpCodeT32Tb.cs b/ARMeilleure/Decoders/OpCodeT32Tb.cs new file mode 100644 index 00000000..527754b1 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT32Tb.cs @@ -0,0 +1,16 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeT32Tb : OpCodeT32, IOpCode32BReg + { + public int Rm { get; } + public int Rn { get; } + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32Tb(inst, address, opCode); + + public OpCodeT32Tb(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rm = (opCode >> 0) & 0xf; + Rn = (opCode >> 16) & 0xf; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index ed77b99c..a7793681 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -1021,7 +1021,7 @@ namespace ARMeilleure.Decoders SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create); SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create); SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create); - SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blx, OpCodeT16BReg.Create); + SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blxr, OpCodeT16BReg.Create); SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create); SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create); SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create); @@ -1069,6 +1069,7 @@ namespace ARMeilleure.Decoders SetT32("11110x01010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluImm.Create); SetT32("11101011000x1>1<<<xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create); SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create); - SetT32("1110100>x1>0<<<xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create); SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create); SetT32("11101011101 EmitTb(context, halfword: false); + public static void Tbh(ArmEmitterContext context) => EmitTb(context, halfword: true); + + private static void EmitTb(ArmEmitterContext context, bool halfword) + { + OpCodeT32Tb op = (OpCodeT32Tb)context.CurrOp; + + Operand halfwords; + + if (halfword) + { + Operand address = context.Add(GetIntA32(context, op.Rn), context.ShiftLeft(GetIntA32(context, op.Rm), Const(1))); + halfwords = InstEmitMemoryHelper.EmitReadInt(context, address, 1); + } + else + { + Operand address = context.Add(GetIntA32(context, op.Rn), GetIntA32(context, op.Rm)); + halfwords = InstEmitMemoryHelper.EmitReadIntAligned(context, address, 0); + } + + Operand targetAddress = context.Add(Const((int)op.GetPc()), context.ShiftLeft(halfwords, Const(1))); + + EmitVirtualJump(context, targetAddress, isReturn: false); + } } } \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitMemory32.cs b/ARMeilleure/Instructions/InstEmitMemory32.cs index e15f6a5b..17ec97aa 100644 --- a/ARMeilleure/Instructions/InstEmitMemory32.cs +++ b/ARMeilleure/Instructions/InstEmitMemory32.cs @@ -204,15 +204,15 @@ namespace ARMeilleure.Instructions context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); - Load(op.Rt, 0, WordSizeLog2); - Load(op.Rt | 1, 4, WordSizeLog2); + Load(op.Rt, 0, WordSizeLog2); + Load(op.Rt2, 4, WordSizeLog2); context.Branch(lblEnd); context.MarkLabel(lblBigEndian); - Load(op.Rt | 1, 0, WordSizeLog2); - Load(op.Rt, 4, WordSizeLog2); + Load(op.Rt2, 0, WordSizeLog2); + Load(op.Rt, 4, WordSizeLog2); context.MarkLabel(lblEnd); } @@ -237,15 +237,15 @@ namespace ARMeilleure.Instructions context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); - Store(op.Rt, 0, WordSizeLog2); - Store(op.Rt | 1, 4, WordSizeLog2); + Store(op.Rt, 0, WordSizeLog2); + Store(op.Rt2, 4, WordSizeLog2); context.Branch(lblEnd); context.MarkLabel(lblBigEndian); - Store(op.Rt | 1, 0, WordSizeLog2); - Store(op.Rt, 4, WordSizeLog2); + Store(op.Rt2, 0, WordSizeLog2); + Store(op.Rt, 4, WordSizeLog2); context.MarkLabel(lblEnd); } diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs index 2877d53e..f97e395c 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs @@ -123,6 +123,41 @@ namespace ARMeilleure.Instructions context.CurrOp is OpCodeSimdMemSs); } + public static Operand EmitReadInt(ArmEmitterContext context, Operand address, int size) + { + Operand temp = context.AllocateLocal(size == 3 ? OperandType.I64 : OperandType.I32); + + Operand lblSlowPath = Label(); + Operand lblEnd = Label(); + + Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size); + + Operand value = default; + + switch (size) + { + case 0: value = context.Load8 (physAddr); break; + case 1: value = context.Load16(physAddr); break; + case 2: value = context.Load (OperandType.I32, physAddr); break; + case 3: value = context.Load (OperandType.I64, physAddr); break; + } + + context.Copy(temp, value); + + if (!context.Memory.Type.IsHostMapped()) + { + context.Branch(lblEnd); + + context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); + + context.Copy(temp, EmitReadIntFallback(context, address, size)); + + context.MarkLabel(lblEnd); + } + + return temp; + } + private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size) { Operand lblSlowPath = Label(); @@ -419,6 +454,11 @@ namespace ARMeilleure.Instructions } private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size) + { + SetInt(context, rt, EmitReadIntFallback(context, address, size)); + } + + private static Operand EmitReadIntFallback(ArmEmitterContext context, Operand address, int size) { MethodInfo info = null; @@ -430,7 +470,7 @@ namespace ARMeilleure.Instructions case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break; } - SetInt(context, rt, context.Call(info, address)); + return context.Call(info, address); } private static void EmitReadVectorFallback( diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs index 0d63820b..f2c95ae9 100644 --- a/ARMeilleure/Instructions/InstName.cs +++ b/ARMeilleure/Instructions/InstName.cs @@ -545,6 +545,8 @@ namespace ARMeilleure.Instructions Strexh, Strh, Sxtb16, + Tbb, + Tbh, Teq, Trap, Tst, diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index dd24e373..3a950354 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 = 3677; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 3683; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1";