Address Feedback 2

This commit is contained in:
riperiperi 2020-02-02 22:43:42 +00:00
parent e62df3db95
commit f244fb26fb
42 changed files with 511 additions and 514 deletions

View file

@ -2,6 +2,6 @@
{
interface IOpCode32MemEx : IOpCode32Mem
{
public int Rd { get; }
int Rd { get; }
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -13,6 +13,7 @@
if (Size == -1)
{
Instruction = InstDescriptor.Undefined;
return;
}
Q = ((opCode >> 21) & 0x1) != 0;

View file

@ -11,7 +11,7 @@
{
Size = (opCode >> 8) & 0x3;
var single = Size != 3;
bool single = Size != 3;
if (single)
{

View file

@ -20,7 +20,7 @@
bool u = (opCode & (1 << 23)) != 0;
Add = u;
var single = Size != 0b11;
bool single = Size != 3;
if (single)
{

View file

@ -24,6 +24,7 @@
if (p == u && w)
{
Instruction = InstDescriptor.Undefined;
return;
}
DoubleWidth = (opCode & (1 << 8)) != 0;

View file

@ -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];

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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));
}
}
}

View file

@ -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

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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)

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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));

View file

@ -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()
{

View file

@ -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)
{

View file

@ -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;

View file

@ -2,7 +2,7 @@
namespace ARMeilleure.Translation
{
class RejitRequest
struct RejitRequest
{
public ulong Address;
public ExecutionMode Mode;

View file

@ -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));
}