Address Feedback 2
This commit is contained in:
parent
e62df3db95
commit
f244fb26fb
42 changed files with 511 additions and 514 deletions
|
@ -2,6 +2,6 @@
|
|||
{
|
||||
interface IOpCode32MemEx : IOpCode32Mem
|
||||
{
|
||||
public int Rd { get; }
|
||||
int Rd { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
if (Size == -1)
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
return;
|
||||
}
|
||||
Q = ((opCode >> 21) & 0x1) != 0;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
{
|
||||
Size = (opCode >> 8) & 0x3;
|
||||
|
||||
var single = Size != 3;
|
||||
bool single = Size != 3;
|
||||
|
||||
if (single)
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
bool u = (opCode & (1 << 23)) != 0;
|
||||
Add = u;
|
||||
|
||||
var single = Size != 0b11;
|
||||
bool single = Size != 3;
|
||||
|
||||
if (single)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
if (p == u && w)
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
DoubleWidth = (opCode & (1 << 8)) != 0;
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
class RejitRequest
|
||||
struct RejitRequest
|
||||
{
|
||||
public ulong Address;
|
||||
public ExecutionMode Mode;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue