diff --git a/ARMeilleure/Decoders/IOpCode32MemEx.cs b/ARMeilleure/Decoders/IOpCode32MemEx.cs index 12ac572f1a..aca7200a5c 100644 --- a/ARMeilleure/Decoders/IOpCode32MemEx.cs +++ b/ARMeilleure/Decoders/IOpCode32MemEx.cs @@ -2,6 +2,6 @@ { interface IOpCode32MemEx : IOpCode32Mem { - public int Rd { get; } + int Rd { get; } } } diff --git a/ARMeilleure/Decoders/OpCode32AluBf.cs b/ARMeilleure/Decoders/OpCode32AluBf.cs index 556c1074d5..7ee0ee34eb 100644 --- a/ARMeilleure/Decoders/OpCode32AluBf.cs +++ b/ARMeilleure/Decoders/OpCode32AluBf.cs @@ -17,8 +17,8 @@ Rd = (opCode >> 12) & 0xf; Rn = (opCode >> 0) & 0xf; - Msb = ((opCode >> 16) & 31); - Lsb = ((opCode >> 7) & 31); + Msb = (opCode >> 16) & 0x1f; + Lsb = (opCode >> 7) & 0x1f; } } } diff --git a/ARMeilleure/Decoders/OpCode32AluUmull.cs b/ARMeilleure/Decoders/OpCode32AluUmull.cs index 9b14bf5e61..c98d9305b4 100644 --- a/ARMeilleure/Decoders/OpCode32AluUmull.cs +++ b/ARMeilleure/Decoders/OpCode32AluUmull.cs @@ -20,10 +20,10 @@ Rm = (opCode >> 8) & 0xf; Rn = (opCode >> 0) & 0xf; - NHigh = ((opCode >> 5) * 0x1) == 1; - MHigh = ((opCode >> 6) * 0x1) == 1; + NHigh = ((opCode >> 5) & 0x1) == 1; + MHigh = ((opCode >> 6) & 0x1) == 1; - SetFlags = ((opCode >> 20) & 1) != 0; + SetFlags = ((opCode >> 20) & 0x1) != 0; DataOp = DataOp.Arithmetic; } } diff --git a/ARMeilleure/Decoders/OpCode32MemLdEx.cs b/ARMeilleure/Decoders/OpCode32MemLdEx.cs index 3d3a6772ef..42d1a33a02 100644 --- a/ARMeilleure/Decoders/OpCode32MemLdEx.cs +++ b/ARMeilleure/Decoders/OpCode32MemLdEx.cs @@ -3,6 +3,7 @@ class OpCode32MemLdEx : OpCode32Mem, IOpCode32MemEx { public int Rd { get; private set; } + public OpCode32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { Rd = opCode & 0xf; diff --git a/ARMeilleure/Decoders/OpCode32MemReg.cs b/ARMeilleure/Decoders/OpCode32MemReg.cs index dea42823de..ccc05a875e 100644 --- a/ARMeilleure/Decoders/OpCode32MemReg.cs +++ b/ARMeilleure/Decoders/OpCode32MemReg.cs @@ -3,6 +3,7 @@ class OpCode32MemReg : OpCode32Mem { public int Rm { get; private set; } + public OpCode32MemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { Rm = (opCode >> 0) & 0xf; diff --git a/ARMeilleure/Decoders/OpCode32MemRsImm.cs b/ARMeilleure/Decoders/OpCode32MemRsImm.cs index 33f51145d4..299e83e2c5 100644 --- a/ARMeilleure/Decoders/OpCode32MemRsImm.cs +++ b/ARMeilleure/Decoders/OpCode32MemRsImm.cs @@ -4,6 +4,7 @@ { public int Rm { get; private set; } public ShiftType ShiftType { get; private set; } + public OpCode32MemRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { Rm = (opCode >> 0) & 0xf; diff --git a/ARMeilleure/Decoders/OpCode32MemStEx.cs b/ARMeilleure/Decoders/OpCode32MemStEx.cs index 1d9b199852..b9c6d4f4ff 100644 --- a/ARMeilleure/Decoders/OpCode32MemStEx.cs +++ b/ARMeilleure/Decoders/OpCode32MemStEx.cs @@ -2,7 +2,8 @@ { class OpCode32MemStEx : OpCode32Mem, IOpCode32MemEx { - public int Rd { get; internal set; } + public int Rd { get; private set; } + public OpCode32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { Rd = (opCode >> 12) & 0xf; diff --git a/ARMeilleure/Decoders/OpCode32Simd.cs b/ARMeilleure/Decoders/OpCode32Simd.cs index 6e168d4bc6..cda10c3c8f 100644 --- a/ARMeilleure/Decoders/OpCode32Simd.cs +++ b/ARMeilleure/Decoders/OpCode32Simd.cs @@ -13,14 +13,15 @@ Q = ((opCode >> 6) & 0x1) != 0; F = ((opCode >> 10) & 0x1) != 0; U = ((opCode >> 24) & 0x1) != 0; - Opc = ((opCode >> 7) & 0x3); + Opc = (opCode >> 7) & 0x3; RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64; Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf); Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf); - if (this.GetType() == typeof(OpCode32Simd) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm)) // Subclasses have their own handling of Vx to account for before checking. + // Subclasses have their own handling of Vx to account for before checking. + if (GetType() == typeof(OpCode32Simd) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm)) { Instruction = InstDescriptor.Undefined; } diff --git a/ARMeilleure/Decoders/OpCode32SimdBase.cs b/ARMeilleure/Decoders/OpCode32SimdBase.cs index 3e767c304e..10b5465978 100644 --- a/ARMeilleure/Decoders/OpCode32SimdBase.cs +++ b/ARMeilleure/Decoders/OpCode32SimdBase.cs @@ -16,7 +16,7 @@ namespace ARMeilleure.Decoders // Fx: The starting index of the target vector within the quadword, with size treated as floating point. (16 or 32) public int Qd => GetQuadwordIndex(Vd); public int Id => GetQuadwordSubindex(Vd) << (3 - Size); - public int Fd => GetQuadwordSubindex(Vd) << (1 - (Size & 1)); // When the top bit is truncated, 1 SHOULD be fp16, but switch does not support it so we always assume 64. + public int Fd => GetQuadwordSubindex(Vd) << (1 - (Size & 1)); // When the top bit is truncated, 1 is fp16 which is an optional extension in ARMv8.2. We always assume 64. public int Qm => GetQuadwordIndex(Vm); public int Im => GetQuadwordSubindex(Vm) << (3 - Size); diff --git a/ARMeilleure/Decoders/OpCode32SimdDupGP.cs b/ARMeilleure/Decoders/OpCode32SimdDupGP.cs index 62e4e9bb16..58a8a7fe32 100644 --- a/ARMeilleure/Decoders/OpCode32SimdDupGP.cs +++ b/ARMeilleure/Decoders/OpCode32SimdDupGP.cs @@ -13,6 +13,7 @@ if (Size == -1) { Instruction = InstDescriptor.Undefined; + return; } Q = ((opCode >> 21) & 0x1) != 0; diff --git a/ARMeilleure/Decoders/OpCode32SimdImm44.cs b/ARMeilleure/Decoders/OpCode32SimdImm44.cs index 0334595492..f8f73bbba1 100644 --- a/ARMeilleure/Decoders/OpCode32SimdImm44.cs +++ b/ARMeilleure/Decoders/OpCode32SimdImm44.cs @@ -11,7 +11,7 @@ { Size = (opCode >> 8) & 0x3; - var single = Size != 3; + bool single = Size != 3; if (single) { diff --git a/ARMeilleure/Decoders/OpCode32SimdMemImm.cs b/ARMeilleure/Decoders/OpCode32SimdMemImm.cs index 5063b5bce2..630566cc3f 100644 --- a/ARMeilleure/Decoders/OpCode32SimdMemImm.cs +++ b/ARMeilleure/Decoders/OpCode32SimdMemImm.cs @@ -20,7 +20,7 @@ bool u = (opCode & (1 << 23)) != 0; Add = u; - var single = Size != 0b11; + bool single = Size != 3; if (single) { diff --git a/ARMeilleure/Decoders/OpCode32SimdMemMult.cs b/ARMeilleure/Decoders/OpCode32SimdMemMult.cs index b855010557..9d43a71eb2 100644 --- a/ARMeilleure/Decoders/OpCode32SimdMemMult.cs +++ b/ARMeilleure/Decoders/OpCode32SimdMemMult.cs @@ -24,6 +24,7 @@ if (p == u && w) { Instruction = InstDescriptor.Undefined; + return; } DoubleWidth = (opCode & (1 << 8)) != 0; diff --git a/ARMeilleure/Decoders/OpCode32SimdMemPair.cs b/ARMeilleure/Decoders/OpCode32SimdMemPair.cs index 0fd307cfff..93320e7f95 100644 --- a/ARMeilleure/Decoders/OpCode32SimdMemPair.cs +++ b/ARMeilleure/Decoders/OpCode32SimdMemPair.cs @@ -1,4 +1,5 @@ -using System; +using ARMeilleure.State; +using System; namespace ARMeilleure.Decoders { @@ -34,8 +35,8 @@ namespace ARMeilleure.Decoders Rm = (opCode >> 0) & 0xf; Rn = (opCode >> 16) & 0xf; - WBack = Rm != 15; - RegisterIndex = (Rm != 15 && Rm != 13); + WBack = Rm != RegisterAlias.Aarch32Pc; + RegisterIndex = Rm != RegisterAlias.Aarch32Pc && Rm != RegisterAlias.Aarch32Sp; Regs = RegsMap[(opCode >> 8) & 0xf]; diff --git a/ARMeilleure/Decoders/OpCode32SimdMemSingle.cs b/ARMeilleure/Decoders/OpCode32SimdMemSingle.cs index 0f8979a90a..8cdd374366 100644 --- a/ARMeilleure/Decoders/OpCode32SimdMemSingle.cs +++ b/ARMeilleure/Decoders/OpCode32SimdMemSingle.cs @@ -40,7 +40,7 @@ namespace ARMeilleure.Decoders Rn = (opCode >> 16) & 0xf; WBack = Rm != RegisterAlias.Aarch32Pc; - RegisterIndex = (Rm != RegisterAlias.Aarch32Pc && Rm != RegisterAlias.Aarch32Sp); + RegisterIndex = Rm != RegisterAlias.Aarch32Pc && Rm != RegisterAlias.Aarch32Sp; } } } diff --git a/ARMeilleure/Decoders/OpCode32SimdMovGp.cs b/ARMeilleure/Decoders/OpCode32SimdMovGp.cs index aa608c1e0b..918291a174 100644 --- a/ARMeilleure/Decoders/OpCode32SimdMovGp.cs +++ b/ARMeilleure/Decoders/OpCode32SimdMovGp.cs @@ -14,10 +14,10 @@ public OpCode32SimdMovGp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { // Which one is used is instruction dependant. - Op = ((opCode >> 20) & 0x1); + Op = (opCode >> 20) & 0x1; - Opc1 = ((opCode >> 21) & 0x3); - Opc2 = ((opCode >> 5) & 0x3); + Opc1 = (opCode >> 21) & 0x3; + Opc2 = (opCode >> 5) & 0x3; Vn = ((opCode >> 7) & 0x1) | ((opCode >> 15) & 0x1e); Rt = (opCode >> 12) & 0xf; diff --git a/ARMeilleure/Decoders/OpCode32SimdMovGpDouble.cs b/ARMeilleure/Decoders/OpCode32SimdMovGpDouble.cs index 81ed623d3e..5f2725e15e 100644 --- a/ARMeilleure/Decoders/OpCode32SimdMovGpDouble.cs +++ b/ARMeilleure/Decoders/OpCode32SimdMovGpDouble.cs @@ -12,7 +12,7 @@ public OpCode32SimdMovGpDouble(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { // Which one is used is instruction dependant. - Op = ((opCode >> 20) & 0x1); + Op = (opCode >> 20) & 0x1; Rt = (opCode >> 12) & 0xf; Rt2 = (opCode >> 16) & 0xf; diff --git a/ARMeilleure/Decoders/OpCode32SimdMovGpElem.cs b/ARMeilleure/Decoders/OpCode32SimdMovGpElem.cs index c05d250a35..350d5c8467 100644 --- a/ARMeilleure/Decoders/OpCode32SimdMovGpElem.cs +++ b/ARMeilleure/Decoders/OpCode32SimdMovGpElem.cs @@ -13,7 +13,7 @@ public OpCode32SimdMovGpElem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { - Op = ((opCode >> 20) & 0x1); + Op = (opCode >> 20) & 0x1; U = ((opCode >> 23) & 1) != 0; var opc = (((opCode >> 23) & 1) << 4) | (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3); @@ -36,6 +36,7 @@ else { Instruction = InstDescriptor.Undefined; + return; } Vd = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf); diff --git a/ARMeilleure/Decoders/OpCode32SimdReg.cs b/ARMeilleure/Decoders/OpCode32SimdReg.cs index cb32b6c9bb..da1d2e363f 100644 --- a/ARMeilleure/Decoders/OpCode32SimdReg.cs +++ b/ARMeilleure/Decoders/OpCode32SimdReg.cs @@ -13,7 +13,7 @@ Vn = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf); // Subclasses have their own handling of Vx to account for before checking. - if (this.GetType() == typeof(OpCode32SimdReg) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm, Vn)) + if (GetType() == typeof(OpCode32SimdReg) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm, Vn)) { Instruction = InstDescriptor.Undefined; } diff --git a/ARMeilleure/Decoders/OpCode32SimdRegElem.cs b/ARMeilleure/Decoders/OpCode32SimdRegElem.cs index 7ac9b5b485..4bf15cca55 100644 --- a/ARMeilleure/Decoders/OpCode32SimdRegElem.cs +++ b/ARMeilleure/Decoders/OpCode32SimdRegElem.cs @@ -12,7 +12,7 @@ Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e); - if (DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vn) || (Size == 0 || (Size == 1 && F))) + if (DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vn) || Size == 0 || (Size == 1 && F)) { Instruction = InstDescriptor.Undefined; } diff --git a/ARMeilleure/Decoders/OpCode32SimdRegS.cs b/ARMeilleure/Decoders/OpCode32SimdRegS.cs index 893ecff6dc..b4ffad80a2 100644 --- a/ARMeilleure/Decoders/OpCode32SimdRegS.cs +++ b/ARMeilleure/Decoders/OpCode32SimdRegS.cs @@ -6,7 +6,7 @@ public OpCode32SimdRegS(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { - var single = Size != 0b11; + bool single = Size != 3; if (single) { Vn = ((opCode >> 7) & 0x1) | ((opCode >> 15) & 0x1e); diff --git a/ARMeilleure/Decoders/OpCode32SimdS.cs b/ARMeilleure/Decoders/OpCode32SimdS.cs index fc11269f3a..2e860d9c87 100644 --- a/ARMeilleure/Decoders/OpCode32SimdS.cs +++ b/ARMeilleure/Decoders/OpCode32SimdS.cs @@ -12,7 +12,7 @@ Opc = (opCode >> 15) & 0x3; Size = (opCode >> 8) & 0x3; - var single = Size != 0b11; + bool single = Size != 3; RegisterSize = single ? RegisterSize.Int32 : RegisterSize.Int64; diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index 9505179f8b..621c732eaf 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -774,7 +774,7 @@ namespace ARMeilleure.Decoders SetA32("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, typeof(OpCode32SimdS)); SetA32("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, typeof(OpCode32SimdS)); - SetA32("111100111x11xx11xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, typeof(OpCode32SimdCmpZ)); // FP and integer, vector. + SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, typeof(OpCode32SimdCmpZ)); // FP and integer, vector. SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, typeof(OpCode32SimdS)); // FP 32 and 64, scalar. SetA32("<<<<11101x11110xxxxx10xx11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI)); // FP32 to int. SetA32("<<<<11101x111000xxxx10xxx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI)); // Int to FP32. diff --git a/ARMeilleure/Instructions/InstEmitAlu32.cs b/ARMeilleure/Instructions/InstEmitAlu32.cs index 660d850c51..4d03f5c24a 100644 --- a/ARMeilleure/Instructions/InstEmitAlu32.cs +++ b/ARMeilleure/Instructions/InstEmitAlu32.cs @@ -72,6 +72,35 @@ namespace ARMeilleure.Instructions EmitAluStore(context, res); } + public static void Bfc(ArmEmitterContext context) + { + OpCode32AluBf op = (OpCode32AluBf)context.CurrOp; + + Operand d = GetIntA32(context, op.Rd); + Operand res = context.BitwiseAnd(d, Const(~op.DestMask)); + + SetIntA32(context, op.Rd, res); + } + + public static void Bfi(ArmEmitterContext context) + { + OpCode32AluBf op = (OpCode32AluBf)context.CurrOp; + + Operand n = GetIntA32(context, op.Rn); + Operand d = GetIntA32(context, op.Rd); + Operand part = context.BitwiseAnd(n, Const(op.SourceMask)); + + if (op.Lsb != 0) + { + part = context.ShiftLeft(part, Const(op.Lsb)); + } + + Operand res = context.BitwiseAnd(d, Const(~op.DestMask)); + res = context.BitwiseOr(res, context.BitwiseAnd(part, Const(op.DestMask))); + + SetIntA32(context, op.Rd, res); + } + public static void Bic(ArmEmitterContext context) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; @@ -156,311 +185,6 @@ namespace ARMeilleure.Instructions EmitAluStore(context, m); } - public static void Orr(ArmEmitterContext context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - Operand n = GetAluN(context); - Operand m = GetAluM(context); - - Operand res = context.BitwiseOr(n, m); - - if (op.SetFlags) - { - EmitNZFlagsCheck(context, res); - } - - EmitAluStore(context, res); - } - - public static void Rsc(ArmEmitterContext context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - Operand n = GetAluN(context); - Operand m = GetAluM(context, setCarry: false); - - Operand res = context.Subtract(m, n); - - Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); - - res = context.Subtract(res, borrow); - - if (op.SetFlags) - { - EmitNZFlagsCheck(context, res); - - EmitSbcsCCheck(context, m, n); - EmitSubsVCheck(context, m, n, res); - } - - EmitAluStore(context, res); - } - - public static void Rsb(ArmEmitterContext context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - Operand n = GetAluN(context); - Operand m = GetAluM(context, setCarry: false); - - Operand res = context.Subtract(m, n); - - if (op.SetFlags) - { - EmitNZFlagsCheck(context, res); - - EmitSubsCCheck(context, m, res); - EmitSubsVCheck(context, m, n, res); - } - - EmitAluStore(context, res); - } - - public static void Sub(ArmEmitterContext context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - Operand n = GetAluN(context); - Operand m = GetAluM(context, setCarry: false); - - Operand res = context.Subtract(n, m); - - if (op.SetFlags) - { - EmitNZFlagsCheck(context, res); - - EmitSubsCCheck(context, n, res); - EmitSubsVCheck(context, n, m, res); - } - - EmitAluStore(context, res); - } - - public static void Sbc(ArmEmitterContext context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - Operand n = GetAluN(context); - Operand m = GetAluM(context, setCarry: false); - - Operand res = context.Subtract(n, m); - - Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); - - res = context.Subtract(res, borrow); - - if (op.SetFlags) - { - EmitNZFlagsCheck(context, res); - - EmitSbcsCCheck(context, n, m); - EmitSubsVCheck(context, n, m, res); - } - - EmitAluStore(context, res); - } - - public static void Tst(ArmEmitterContext context) - { - Operand n = GetAluN(context); - Operand m = GetAluM(context); - - Operand res = context.BitwiseAnd(n, m); - EmitNZFlagsCheck(context, res); - } - - public static void Teq(ArmEmitterContext context) - { - Operand n = GetAluN(context); - Operand m = GetAluM(context); - - Operand res = context.BitwiseExclusiveOr(n, m); - - EmitNZFlagsCheck(context, res); - } - - private static void EmitSignExtend(ArmEmitterContext context, bool signed, int bits) - { - IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp; - - Operand m = GetAluM(context); - Operand res; - - if (op.RotateBits == 0) - { - res = m; - } - else - { - Operand rotate = Const(op.RotateBits); - res = context.RotateRight(m, rotate); - } - - switch (bits) - { - case 8: - res = (signed) ? context.SignExtend8(OperandType.I32, res) : context.ZeroExtend8(OperandType.I32, res); - break; - case 16: - res = (signed) ? context.SignExtend16(OperandType.I32, res) : context.ZeroExtend16(OperandType.I32, res); - break; - } - - - if (op.Add) - { - res = context.Add(res, GetAluN(context)); - } - - EmitAluStore(context, res); - } - - private static void EmitExtend16(ArmEmitterContext context, bool signed) - { - IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp; - - Operand m = GetAluM(context); - Operand res; - - if (op.RotateBits == 0) - { - res = m; - } - else - { - Operand rotate = Const(op.RotateBits); - res = context.RotateRight(m, rotate); - } - - Operand low16, high16; - if (signed) - { - low16 = context.SignExtend8(OperandType.I32, res); - high16 = context.SignExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); - } - else - { - low16 = context.ZeroExtend8(OperandType.I32, res); - high16 = context.ZeroExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); - } - - if (op.Add) - { - Operand n = GetAluN(context); - Operand lowAdd, highAdd; - if (signed) - { - lowAdd = context.SignExtend16(OperandType.I32, n); - highAdd = context.SignExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); - } - else - { - lowAdd = context.ZeroExtend16(OperandType.I32, n); - highAdd = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); - } - - low16 = context.Add(low16, lowAdd); - high16 = context.Add(high16, highAdd); - } - - res = context.BitwiseOr( - context.ZeroExtend16(OperandType.I32, low16), - context.ShiftLeft(context.ZeroExtend16(OperandType.I32, high16), Const(16))); - - EmitAluStore(context, res); - } - - public static void Uxtb(ArmEmitterContext context) - { - EmitSignExtend(context, false, 8); - } - - public static void Uxtb16(ArmEmitterContext context) - { - EmitExtend16(context, false); - } - - public static void Uxth(ArmEmitterContext context) - { - EmitSignExtend(context, false, 16); - } - - public static void Sxtb(ArmEmitterContext context) - { - EmitSignExtend(context, true, 8); - } - - public static void Sxtb16(ArmEmitterContext context) - { - EmitExtend16(context, true); - } - - public static void Sxth(ArmEmitterContext context) - { - EmitSignExtend(context, true, 16); - } - - public static void Udiv(ArmEmitterContext context) - { - EmitDiv(context, true); - } - - public static void Sdiv(ArmEmitterContext context) - { - EmitDiv(context, false); - } - - public static void EmitDiv(ArmEmitterContext context, bool unsigned) - { - Operand n = GetAluN(context); - Operand m = GetAluM(context); - Operand zero = Const(m.Type, 0); - - Operand divisorIsZero = context.ICompareEqual(m, zero); - - Operand lblBadDiv = Label(); - Operand lblEnd = Label(); - - context.BranchIfTrue(lblBadDiv, divisorIsZero); - - if (!unsigned) - { - // ARM64 behaviour: If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). - // TODO: tests to ensure A32 works the same - - Operand intMin = Const(int.MinValue); - Operand minus1 = Const(-1); - - Operand nIsIntMin = context.ICompareEqual(n, intMin); - Operand mIsMinus1 = context.ICompareEqual(m, minus1); - - Operand lblGoodDiv = Label(); - - context.BranchIfFalse(lblGoodDiv, context.BitwiseAnd(nIsIntMin, mIsMinus1)); - - EmitAluStore(context, intMin); - - context.Branch(lblEnd); - - context.MarkLabel(lblGoodDiv); - } - - Operand res = unsigned - ? context.DivideUI(n, m) - : context.Divide(n, m); - - EmitAluStore(context, res); - - context.Branch(lblEnd); - - context.MarkLabel(lblBadDiv); - - EmitAluStore(context, zero); - - context.MarkLabel(lblEnd); - } - public static void Movt(ArmEmitterContext context) { OpCode32AluImm16 op = (OpCode32AluImm16)context.CurrOp; @@ -473,6 +197,23 @@ namespace ARMeilleure.Instructions EmitAluStore(context, res); } + public static void Mul(ArmEmitterContext context) + { + IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; + + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand res = context.Multiply(n, m); + + if (op.SetFlags) + { + EmitNZFlagsCheck(context, res); + } + + EmitAluStore(context, res); + } + public static void Mvn(ArmEmitterContext context) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; @@ -488,14 +229,14 @@ namespace ARMeilleure.Instructions EmitAluStore(context, res); } - public static void Mul(ArmEmitterContext context) + public static void Orr(ArmEmitterContext context) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; Operand n = GetAluN(context); Operand m = GetAluM(context); - Operand res = context.Multiply(n, m); + Operand res = context.BitwiseOr(n, m); if (op.SetFlags) { @@ -563,45 +304,72 @@ namespace ARMeilleure.Instructions EmitAluStore(context, context.SignExtend16(OperandType.I32, res)); } - public static void Bfc(ArmEmitterContext context) + public static void Rsc(ArmEmitterContext context) { - OpCode32AluBf op = (OpCode32AluBf)context.CurrOp; + IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - Operand d = GetIntA32(context, op.Rd); - Operand res = context.BitwiseAnd(d, Const(~op.DestMask)); + Operand n = GetAluN(context); + Operand m = GetAluM(context, setCarry: false); - SetIntA32(context, op.Rd, res); - } + Operand res = context.Subtract(m, n); - public static void Bfi(ArmEmitterContext context) - { - OpCode32AluBf op = (OpCode32AluBf)context.CurrOp; + Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); - Operand n = GetIntA32(context, op.Rn); - Operand d = GetIntA32(context, op.Rd); - Operand part = context.BitwiseAnd(n, Const(op.SourceMask)); + res = context.Subtract(res, borrow); - if (op.Lsb != 0) + if (op.SetFlags) { - part = context.ShiftLeft(part, Const(op.Lsb)); + EmitNZFlagsCheck(context, res); + + EmitSbcsCCheck(context, m, n); + EmitSubsVCheck(context, m, n, res); } - Operand res = context.BitwiseAnd(d, Const(~op.DestMask)); - res = context.BitwiseOr(res, context.BitwiseAnd(part, Const(op.DestMask))); - - SetIntA32(context, op.Rd, res); + EmitAluStore(context, res); } - public static void Ubfx(ArmEmitterContext context) + public static void Rsb(ArmEmitterContext context) { - OpCode32AluBf op = (OpCode32AluBf)context.CurrOp; + IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width. + Operand n = GetAluN(context); + Operand m = GetAluM(context, setCarry: false); - Operand n = GetIntA32(context, op.Rn); - Operand res = context.ShiftRightUI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb)); + Operand res = context.Subtract(m, n); - SetIntA32(context, op.Rd, res); + if (op.SetFlags) + { + EmitNZFlagsCheck(context, res); + + EmitSubsCCheck(context, m, res); + EmitSubsVCheck(context, m, n, res); + } + + EmitAluStore(context, res); + } + + public static void Sbc(ArmEmitterContext context) + { + IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; + + Operand n = GetAluN(context); + Operand m = GetAluM(context, setCarry: false); + + Operand res = context.Subtract(n, m); + + Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); + + res = context.Subtract(res, borrow); + + if (op.SetFlags) + { + EmitNZFlagsCheck(context, res); + + EmitSbcsCCheck(context, n, m); + EmitSubsVCheck(context, n, m, res); + } + + EmitAluStore(context, res); } public static void Sbfx(ArmEmitterContext context) @@ -616,6 +384,237 @@ namespace ARMeilleure.Instructions SetIntA32(context, op.Rd, res); } + public static void Sdiv(ArmEmitterContext context) + { + EmitDiv(context, false); + } + + public static void Sub(ArmEmitterContext context) + { + IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; + + Operand n = GetAluN(context); + Operand m = GetAluM(context, setCarry: false); + + Operand res = context.Subtract(n, m); + + if (op.SetFlags) + { + EmitNZFlagsCheck(context, res); + + EmitSubsCCheck(context, n, res); + EmitSubsVCheck(context, n, m, res); + } + + EmitAluStore(context, res); + } + + public static void Sxtb(ArmEmitterContext context) + { + EmitSignExtend(context, true, 8); + } + + public static void Sxtb16(ArmEmitterContext context) + { + EmitExtend16(context, true); + } + + public static void Sxth(ArmEmitterContext context) + { + EmitSignExtend(context, true, 16); + } + + public static void Teq(ArmEmitterContext context) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand res = context.BitwiseExclusiveOr(n, m); + + EmitNZFlagsCheck(context, res); + } + + public static void Tst(ArmEmitterContext context) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand res = context.BitwiseAnd(n, m); + EmitNZFlagsCheck(context, res); + } + + public static void Ubfx(ArmEmitterContext context) + { + OpCode32AluBf op = (OpCode32AluBf)context.CurrOp; + + var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width. + + Operand n = GetIntA32(context, op.Rn); + Operand res = context.ShiftRightUI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb)); + + SetIntA32(context, op.Rd, res); + } + + public static void Udiv(ArmEmitterContext context) + { + EmitDiv(context, true); + } + + public static void Uxtb(ArmEmitterContext context) + { + EmitSignExtend(context, false, 8); + } + + public static void Uxtb16(ArmEmitterContext context) + { + EmitExtend16(context, false); + } + + public static void Uxth(ArmEmitterContext context) + { + EmitSignExtend(context, false, 16); + } + + private static void EmitSignExtend(ArmEmitterContext context, bool signed, int bits) + { + IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp; + + Operand m = GetAluM(context); + Operand res; + + if (op.RotateBits == 0) + { + res = m; + } + else + { + Operand rotate = Const(op.RotateBits); + res = context.RotateRight(m, rotate); + } + + switch (bits) + { + case 8: + res = (signed) ? context.SignExtend8(OperandType.I32, res) : context.ZeroExtend8(OperandType.I32, res); + break; + case 16: + res = (signed) ? context.SignExtend16(OperandType.I32, res) : context.ZeroExtend16(OperandType.I32, res); + break; + } + + if (op.Add) + { + res = context.Add(res, GetAluN(context)); + } + + EmitAluStore(context, res); + } + + private static void EmitExtend16(ArmEmitterContext context, bool signed) + { + IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp; + + Operand m = GetAluM(context); + Operand res; + + if (op.RotateBits == 0) + { + res = m; + } + else + { + Operand rotate = Const(op.RotateBits); + res = context.RotateRight(m, rotate); + } + + Operand low16, high16; + if (signed) + { + low16 = context.SignExtend8(OperandType.I32, res); + high16 = context.SignExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); + } + else + { + low16 = context.ZeroExtend8(OperandType.I32, res); + high16 = context.ZeroExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); + } + + if (op.Add) + { + Operand n = GetAluN(context); + Operand lowAdd, highAdd; + if (signed) + { + lowAdd = context.SignExtend16(OperandType.I32, n); + highAdd = context.SignExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); + } + else + { + lowAdd = context.ZeroExtend16(OperandType.I32, n); + highAdd = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); + } + + low16 = context.Add(low16, lowAdd); + high16 = context.Add(high16, highAdd); + } + + res = context.BitwiseOr( + context.ZeroExtend16(OperandType.I32, low16), + context.ShiftLeft(context.ZeroExtend16(OperandType.I32, high16), Const(16))); + + EmitAluStore(context, res); + } + + public static void EmitDiv(ArmEmitterContext context, bool unsigned) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + Operand zero = Const(m.Type, 0); + + Operand divisorIsZero = context.ICompareEqual(m, zero); + + Operand lblBadDiv = Label(); + Operand lblEnd = Label(); + + context.BranchIfTrue(lblBadDiv, divisorIsZero); + + if (!unsigned) + { + // ARM64 behaviour: If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). + // TODO: tests to ensure A32 works the same + + Operand intMin = Const(int.MinValue); + Operand minus1 = Const(-1); + + Operand nIsIntMin = context.ICompareEqual(n, intMin); + Operand mIsMinus1 = context.ICompareEqual(m, minus1); + + Operand lblGoodDiv = Label(); + + context.BranchIfFalse(lblGoodDiv, context.BitwiseAnd(nIsIntMin, mIsMinus1)); + + EmitAluStore(context, intMin); + + context.Branch(lblEnd); + + context.MarkLabel(lblGoodDiv); + } + + Operand res = unsigned + ? context.DivideUI(n, m) + : context.Divide(n, m); + + EmitAluStore(context, res); + + context.Branch(lblEnd); + + context.MarkLabel(lblBadDiv); + + EmitAluStore(context, zero); + + context.MarkLabel(lblEnd); + } + private static void EmitAluStore(ArmEmitterContext context, Operand value) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; diff --git a/ARMeilleure/Instructions/InstEmitAluHelper.cs b/ARMeilleure/Instructions/InstEmitAluHelper.cs index 19794c4e91..745a119e8d 100644 --- a/ARMeilleure/Instructions/InstEmitAluHelper.cs +++ b/ARMeilleure/Instructions/InstEmitAluHelper.cs @@ -4,6 +4,7 @@ using ARMeilleure.State; using ARMeilleure.Translation; using System; using System.Diagnostics; + using static ARMeilleure.Instructions.InstEmitHelper; using static ARMeilleure.IntermediateRepresentation.OperandHelper; diff --git a/ARMeilleure/Instructions/InstEmitFlow32.cs b/ARMeilleure/Instructions/InstEmitFlow32.cs index f3239498a4..058631b149 100644 --- a/ARMeilleure/Instructions/InstEmitFlow32.cs +++ b/ARMeilleure/Instructions/InstEmitFlow32.cs @@ -35,15 +35,6 @@ namespace ARMeilleure.Instructions Blx(context, x: true); } - public static void Bx(ArmEmitterContext context) - { - IOpCode32BReg op = (IOpCode32BReg)context.CurrOp; - - context.StoreToContext(); - - EmitBxWritePc(context, GetIntA32(context, op.Rm)); - } - private static void Blx(ArmEmitterContext context, bool x) { IOpCode32BImm op = (IOpCode32BImm)context.CurrOp; @@ -53,8 +44,8 @@ namespace ARMeilleure.Instructions bool isThumb = IsThumb(context.CurrOp); uint currentPc = isThumb - ? op.GetPc() | 1 - : op.GetPc() - 4; + ? pc | 1 + : pc - 4; SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc)); @@ -90,5 +81,14 @@ namespace ARMeilleure.Instructions context.Return(addr); // Call. } + + public static void Bx(ArmEmitterContext context) + { + IOpCode32BReg op = (IOpCode32BReg)context.CurrOp; + + context.StoreToContext(); + + EmitBxWritePc(context, GetIntA32(context, op.Rm)); + } } } \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitMemory32.cs b/ARMeilleure/Instructions/InstEmitMemory32.cs index 27c37d8cde..ffd816b299 100644 --- a/ARMeilleure/Instructions/InstEmitMemory32.cs +++ b/ARMeilleure/Instructions/InstEmitMemory32.cs @@ -16,7 +16,6 @@ namespace ARMeilleure.Instructions private const int HWordSizeLog2 = 1; private const int WordSizeLog2 = 2; private const int DWordSizeLog2 = 3; - private const int QWordSizeLog2 = 4; [Flags] enum AccessType diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs index 517454d471..004c06f093 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs @@ -16,6 +16,10 @@ namespace ARMeilleure.Instructions context.Call(new _Void(NativeInterface.ClearExclusive)); } + public static void Dmb(ArmEmitterContext context) => EmitBarrier(context); + + public static void Dsb(ArmEmitterContext context) => EmitBarrier(context); + public static void Ldrex(ArmEmitterContext context) { EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Exclusive); @@ -128,9 +132,6 @@ namespace ARMeilleure.Instructions EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Ordered); } - public static void Dmb(ArmEmitterContext context) => EmitBarrier(context); - public static void Dsb(ArmEmitterContext context) => EmitBarrier(context); - private static void EmitExLoadOrStore(ArmEmitterContext context, int size, AccessType accType) { IOpCode32MemEx op = (IOpCode32MemEx)context.CurrOp; diff --git a/ARMeilleure/Instructions/InstEmitMul32.cs b/ARMeilleure/Instructions/InstEmitMul32.cs index bbe1459446..e64f3568ee 100644 --- a/ARMeilleure/Instructions/InstEmitMul32.cs +++ b/ARMeilleure/Instructions/InstEmitMul32.cs @@ -53,27 +53,6 @@ namespace ARMeilleure.Instructions EmitAluStore(context, res); } - public static void Umull(ArmEmitterContext context) - { - OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp; - - Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn)); - Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm)); - - Operand res = context.Multiply(n, m); - - Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); - Operand lo = context.ConvertI64ToI32(res); - - if (op.SetFlags) - { - EmitNZFlagsCheck(context, res); - } - - EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi); - EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo); - } - public static void Smull(ArmEmitterContext context) { OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp; @@ -178,47 +157,6 @@ namespace ARMeilleure.Instructions EmitMlal(context, true); } - public static void Umlal(ArmEmitterContext context) - { - EmitMlal(context, false); - } - - public static void EmitMlal(ArmEmitterContext context, bool signed) - { - OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp; - - Operand n = GetIntA32(context, op.Rn); - Operand m = GetIntA32(context, op.Rm); - - if (signed) - { - n = context.SignExtend32(OperandType.I64, n); - m = context.SignExtend32(OperandType.I64, m); - } - else - { - n = context.ZeroExtend32(OperandType.I64, n); - m = context.ZeroExtend32(OperandType.I64, m); - } - - Operand res = context.Multiply(n, m); - - Operand toAdd = context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi)), Const(32)); - toAdd = context.BitwiseOr(toAdd, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo))); - res = context.Add(res, toAdd); - - Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); - Operand lo = context.ConvertI64ToI32(res); - - if (op.SetFlags) - { - EmitNZFlagsCheck(context, res); - } - - EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi); - EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo); - } - public static void Smlalh(ArmEmitterContext context) { OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp; @@ -286,5 +224,67 @@ namespace ARMeilleure.Instructions EmitGenericAluStoreA32(context, op.Rd, false, res); } + + public static void Umlal(ArmEmitterContext context) + { + EmitMlal(context, false); + } + + public static void Umull(ArmEmitterContext context) + { + OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp; + + Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn)); + Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm)); + + Operand res = context.Multiply(n, m); + + Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); + Operand lo = context.ConvertI64ToI32(res); + + if (op.SetFlags) + { + EmitNZFlagsCheck(context, res); + } + + EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi); + EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo); + } + + public static void EmitMlal(ArmEmitterContext context, bool signed) + { + OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp; + + Operand n = GetIntA32(context, op.Rn); + Operand m = GetIntA32(context, op.Rm); + + if (signed) + { + n = context.SignExtend32(OperandType.I64, n); + m = context.SignExtend32(OperandType.I64, m); + } + else + { + n = context.ZeroExtend32(OperandType.I64, n); + m = context.ZeroExtend32(OperandType.I64, m); + } + + Operand res = context.Multiply(n, m); + + Operand toAdd = context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi)), Const(32)); + toAdd = context.BitwiseOr(toAdd, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo))); + res = context.Add(res, toAdd); + + Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); + Operand lo = context.ConvertI64ToI32(res); + + if (op.SetFlags) + { + EmitNZFlagsCheck(context, res); + } + + EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi); + EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo); + } } } diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs index 9b09543c15..8fe2479ccb 100644 --- a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs @@ -87,7 +87,7 @@ namespace ARMeilleure.Instructions insert = context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u)); break; default: - throw new ArgumentOutOfRangeException("Unknown Vdup Size!"); + throw new InvalidOperationException("Unknown Vdup Size."); } InsertScalar(context, op.Vd, insert); @@ -116,7 +116,7 @@ namespace ARMeilleure.Instructions insert = context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u)); break; default: - throw new ArgumentOutOfRangeException("Unknown Vdup Size!"); + throw new InvalidOperationException("Unknown Vdup Size."); } InsertScalar(context, op.Vd, insert); @@ -483,6 +483,7 @@ namespace ARMeilleure.Instructions public static void Vpadd_I(ArmEmitterContext context) { OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; + EmitVectorPairwiseOpI32(context, (op1, op2) => context.Add(op1, op2), !op.U); } @@ -515,17 +516,15 @@ namespace ARMeilleure.Instructions context.ShiftLeft(context.BitwiseAnd(op1, Const(0x0000ffff)), Const(16))); case 3: return context.BitwiseOr( - context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff000000000000ul)), Const(48)), - context.ShiftLeft(context.BitwiseAnd(op1, Const(0x000000000000fffful)), Const(48))), - context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0x0000ffff00000000ul)), Const(16)), - context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000ffff0000ul)), Const(16))) - ); + context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff000000000000ul)), Const(48)), + context.ShiftLeft(context.BitwiseAnd(op1, Const(0x000000000000fffful)), Const(48))), + context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0x0000ffff00000000ul)), Const(16)), + context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000ffff0000ul)), Const(16)))); } case 2: // Swap upper and lower halves. return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffffffff00000000ul)), Const(32)), - context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000fffffffful)), Const(32))); - + context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000fffffffful)), Const(32))); } return op1; diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs index b39964c4f1..6ab089cb22 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs @@ -61,11 +61,6 @@ namespace ARMeilleure.Instructions bool toInteger = (op.Opc & 2) != 0; OperandType floatSize = (op.Size == 2) ? OperandType.FP32 : OperandType.FP64; - if (op.Size != 2) - { - throw new InvalidOperationException("CVT vector mode only defined for 32-bit."); - } - if (toInteger) { EmitVectorUnaryOpF32(context, (op1) => @@ -179,18 +174,6 @@ namespace ARMeilleure.Instructions } } - private static Operand EmitF2iFBitsMul(ArmEmitterContext context, Operand value, int fBits) - { - Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64); - - if (fBits == 0) - { - return value; - } - - return context.Multiply(value, ConstF(MathF.Pow(2f, fBits))); - } - public static Operand EmitRoundMathCall(ArmEmitterContext context, MidpointRounding roundMode, Operand n) { IOpCode32Simd op = (IOpCode32Simd)context.CurrOp; diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs index 7bb0e161d9..fc9b854af2 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs @@ -28,7 +28,7 @@ namespace ARMeilleure.Instructions return (index >> 2, index & 3); } - throw new NotImplementedException("Unrecognized Vector Register Size."); + throw new ArgumentException("Unrecognized Vector Register Size."); } public static Operand ExtractScalar(ArmEmitterContext context, OperandType type, int reg) @@ -61,6 +61,7 @@ namespace ARMeilleure.Instructions vec = GetVecA32(reg >> 2); insert = context.VectorInsert(vec, value, reg & 3); } + context.Copy(vec, insert); } @@ -115,7 +116,7 @@ namespace ARMeilleure.Instructions if (op.Size < 2) { - throw new NotSupportedException("Not supported right now."); + throw new NotSupportedException("Cannot perform a scalar SIMD operation on integers smaller than 32 bits."); } Operand n = ExtractScalar(context, type, op.Vn); diff --git a/ARMeilleure/Instructions/InstEmitSimdLogical32.cs b/ARMeilleure/Instructions/InstEmitSimdLogical32.cs index c6cab229cf..e2e9e18ee1 100644 --- a/ARMeilleure/Instructions/InstEmitSimdLogical32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdLogical32.cs @@ -12,9 +12,14 @@ namespace ARMeilleure.Instructions EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseAnd(op1, op2)); } - public static void Vorr_I(ArmEmitterContext context) + public static void Vbif(ArmEmitterContext context) { - EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseOr(op1, op2)); + EmitBifBit(context, true); + } + + public static void Vbit(ArmEmitterContext context) + { + EmitBifBit(context, false); } public static void Vbsl(ArmEmitterContext context) @@ -27,14 +32,9 @@ namespace ARMeilleure.Instructions }); } - public static void Vbif(ArmEmitterContext context) + public static void Vorr_I(ArmEmitterContext context) { - EmitBifBit(context, true); - } - - public static void Vbit(ArmEmitterContext context) - { - EmitBifBit(context, false); + EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseOr(op1, op2)); } private static void EmitBifBit(ArmEmitterContext context, bool notRm) diff --git a/ARMeilleure/Instructions/InstEmitSimdMemory32.cs b/ARMeilleure/Instructions/InstEmitSimdMemory32.cs index bc85332b2e..fb9931d811 100644 --- a/ARMeilleure/Instructions/InstEmitSimdMemory32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdMemory32.cs @@ -11,26 +11,6 @@ namespace ARMeilleure.Instructions { static partial class InstEmit32 { - public static void Vst1(ArmEmitterContext context) - { - EmitVStoreOrLoadN(context, 1, false); - } - - public static void Vst2(ArmEmitterContext context) - { - EmitVStoreOrLoadN(context, 2, false); - } - - public static void Vst3(ArmEmitterContext context) - { - EmitVStoreOrLoadN(context, 3, false); - } - - public static void Vst4(ArmEmitterContext context) - { - EmitVStoreOrLoadN(context, 4, false); - } - public static void Vld1(ArmEmitterContext context) { EmitVStoreOrLoadN(context, 1, true); @@ -51,6 +31,26 @@ namespace ARMeilleure.Instructions EmitVStoreOrLoadN(context, 4, true); } + public static void Vst1(ArmEmitterContext context) + { + EmitVStoreOrLoadN(context, 1, false); + } + + public static void Vst2(ArmEmitterContext context) + { + EmitVStoreOrLoadN(context, 2, false); + } + + public static void Vst3(ArmEmitterContext context) + { + EmitVStoreOrLoadN(context, 3, false); + } + + public static void Vst4(ArmEmitterContext context) + { + EmitVStoreOrLoadN(context, 4, false); + } + public static void EmitVStoreOrLoadN(ArmEmitterContext context, int count, bool load) { if (context.CurrOp is OpCode32SimdMemSingle) @@ -212,7 +212,6 @@ namespace ARMeilleure.Instructions int sReg = (op.DoubleWidth) ? (op.Vd << 1) : op.Vd; int offset = 0; - int size = (op.DoubleWidth) ? DWordSizeLog2 : WordSizeLog2; int byteSize = 4; for (int num = 0; num < range; num++, sReg++) @@ -220,7 +219,7 @@ namespace ARMeilleure.Instructions Operand address = context.Add(baseAddress, Const(offset)); Operand vec = GetVecA32(sReg >> 2); - EmitLoadSimd(context, address, vec, sReg >> 2, sReg & 3, 2); + EmitLoadSimd(context, address, vec, sReg >> 2, sReg & 3, WordSizeLog2); offset += byteSize; } } @@ -244,14 +243,13 @@ namespace ARMeilleure.Instructions int range = op.RegisterRange; int sReg = (op.DoubleWidth) ? (op.Vd << 1) : op.Vd; - int size = (op.DoubleWidth) ? DWordSizeLog2 : WordSizeLog2; int byteSize = 4; for (int num = 0; num < range; num++, sReg++) { Operand address = context.Add(baseAddress, Const(offset)); - EmitStoreSimd(context, address, sReg >> 2, sReg & 3, 2); + EmitStoreSimd(context, address, sReg >> 2, sReg & 3, WordSizeLog2); offset += byteSize; } @@ -321,8 +319,8 @@ namespace ARMeilleure.Instructions Operand m = GetMemM(context, setCarry: false); Operand address = op.Add - ? context.Add(n, m) - : context.Subtract(n, m); + ? context.Add(n, m) + : context.Subtract(n, m); int size = op.Size; @@ -335,7 +333,7 @@ namespace ARMeilleure.Instructions else { Operand vec = GetVecA32(op.Vd >> 2); - EmitLoadSimd(context, address, vec, op.Vd >> 2, (op.Vd & 3) << (2-size), size); + EmitLoadSimd(context, address, vec, op.Vd >> 2, (op.Vd & 3) << (2 - size), size); } } else diff --git a/ARMeilleure/Instructions/InstEmitSimdMove32.cs b/ARMeilleure/Instructions/InstEmitSimdMove32.cs index 0250c34f15..3fd42cbf46 100644 --- a/ARMeilleure/Instructions/InstEmitSimdMove32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdMove32.cs @@ -65,7 +65,7 @@ namespace ARMeilleure.Instructions OpCode32SimdMovGpDouble op = (OpCode32SimdMovGpDouble)context.CurrOp; Operand vec = GetVecA32(op.Vm >> 2); - int vm1 = (op.Vm + 1); + int vm1 = op.Vm + 1; bool sameOwnerVec = (op.Vm >> 2) == (vm1 >> 2); Operand vec2 = sameOwnerVec ? vec : GetVecA32(vm1 >> 2); if (op.Op == 1) @@ -133,8 +133,8 @@ namespace ARMeilleure.Instructions int length = op.Length + 1; - (int Qx, int Ix)[] tableTuples = new (int qx, int ix)[length]; - for (int i=0; i< length; i++) + (int Qx, int Ix)[] tableTuples = new (int, int)[length]; + for (int i = 0; i < length; i++) { (int vn, int en) = GetQuadwordAndSubindex(op.Vn + i, op.RegisterSize); tableTuples[i] = (vn, en); diff --git a/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs index 6b31828d30..893854763e 100644 --- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs @@ -71,7 +71,7 @@ namespace ARMeilleure.Instructions Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0)); Operand shl = context.ShiftLeft(op, shiftLsB); - Operand shr = (unsigned) ? context.ShiftRightUI(op, negShiftLsB) : context.ShiftRightSI(op, negShiftLsB); + Operand shr = unsigned ? context.ShiftRightUI(op, negShiftLsB) : context.ShiftRightSI(op, negShiftLsB); Operand res = context.ConditionalSelect(isPositive, shl, shr); diff --git a/ARMeilleure/Instructions/InstEmitSystem32.cs b/ARMeilleure/Instructions/InstEmitSystem32.cs index 4d1c98072a..808b4fdd7a 100644 --- a/ARMeilleure/Instructions/InstEmitSystem32.cs +++ b/ARMeilleure/Instructions/InstEmitSystem32.cs @@ -57,7 +57,8 @@ namespace ARMeilleure.Instructions throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}."); } - default: throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); + default: + throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); } context.Call(dlg, GetIntA32(context, op.Rt)); @@ -95,7 +96,8 @@ namespace ARMeilleure.Instructions throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}."); } break; - default: throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); + default: + throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); } if (op.Rt == RegisterAlias.Aarch32Pc) @@ -134,7 +136,8 @@ namespace ARMeilleure.Instructions throw new NotImplementedException($"Unknown MRRC Opc1 0x{opc:X16} at 0x{op.Address:X16}."); } break; - default: throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); + default: + throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); } Operand result = context.Call(dlg); @@ -174,7 +177,8 @@ namespace ARMeilleure.Instructions throw new NotImplementedException("MVFR0"); case 0b1000: // FPEXC throw new NotImplementedException("Supervisor Only"); - default: throw new NotImplementedException($"Unknown VMRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); + default: + throw new NotImplementedException($"Unknown VMRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); } SetIntA32(context, op.Rt, context.Call(dlg)); @@ -199,7 +203,8 @@ namespace ARMeilleure.Instructions throw new NotImplementedException("MVFR0"); case 0b1000: // FPEXC throw new NotImplementedException("Supervisor Only"); - default: throw new NotImplementedException($"Unknown VMSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); + default: + throw new NotImplementedException($"Unknown VMSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); } context.Call(dlg, GetIntA32(context, op.Rt)); diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs index 6eb2250cd3..482665dbfe 100644 --- a/ARMeilleure/State/ExecutionContext.cs +++ b/ARMeilleure/State/ExecutionContext.cs @@ -91,8 +91,8 @@ namespace ARMeilleure.State public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag); public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value); - public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPstateFlag(flag); - public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPstateFlag(flag, value); + public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag); + public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPStateFlag(flag, value); internal void CheckInterrupt() { diff --git a/ARMeilleure/State/NativeContext.cs b/ARMeilleure/State/NativeContext.cs index 65e8a5de86..eb54505c6a 100644 --- a/ARMeilleure/State/NativeContext.cs +++ b/ARMeilleure/State/NativeContext.cs @@ -101,7 +101,7 @@ namespace ARMeilleure.State Marshal.WriteInt32(BasePtr, offset, value ? 1 : 0); } - public bool GetFPstateFlag(FPState flag) + public bool GetFPStateFlag(FPState flag) { if ((uint)flag >= RegisterConsts.FlagsCount) { @@ -118,7 +118,7 @@ namespace ARMeilleure.State return value != 0; } - public void SetFPstateFlag(FPState flag, bool value) + public void SetFPStateFlag(FPState flag, bool value) { if ((uint)flag >= RegisterConsts.FlagsCount) { diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs index 770c385846..3a550100b0 100644 --- a/ARMeilleure/Translation/RegisterUsage.cs +++ b/ARMeilleure/Translation/RegisterUsage.cs @@ -403,6 +403,7 @@ namespace ARMeilleure.Translation private static long ClearCallerSavedIntRegs(long mask) { + // TODO: ARM32 support. mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask); return mask; @@ -410,6 +411,7 @@ namespace ARMeilleure.Translation private static long ClearCallerSavedVecRegs(long mask) { + // TODO: ARM32 support. mask &= ~(CallerSavedVecRegistersMask | FpStateNzcvFlagsMask); return mask; diff --git a/ARMeilleure/Translation/RejitRequest.cs b/ARMeilleure/Translation/RejitRequest.cs index bfef9d56a4..e0b0e0b92a 100644 --- a/ARMeilleure/Translation/RejitRequest.cs +++ b/ARMeilleure/Translation/RejitRequest.cs @@ -2,7 +2,7 @@ namespace ARMeilleure.Translation { - class RejitRequest + struct RejitRequest { public ulong Address; public ExecutionMode Mode; diff --git a/Ryujinx.Tests.Unicorn/UnicornAArch32.cs b/Ryujinx.Tests.Unicorn/UnicornAArch32.cs index 846f5fc457..d7ae90d6e9 100644 --- a/Ryujinx.Tests.Unicorn/UnicornAArch32.cs +++ b/Ryujinx.Tests.Unicorn/UnicornAArch32.cs @@ -166,7 +166,7 @@ namespace Ryujinx.Tests.Unicorn public SimdValue GetQ(int index) { - if ((uint)index > 31) + if ((uint)index > 15) { throw new ArgumentOutOfRangeException(nameof(index)); } @@ -177,7 +177,7 @@ namespace Ryujinx.Tests.Unicorn public void SetQ(int index, SimdValue value) { - if ((uint)index > 31) + if ((uint)index > 15) { throw new ArgumentOutOfRangeException(nameof(index)); }