Add a few instructions and fix others. re-disable highCq for now.
Disabled the svc memory clear since i'm not sure about it.
This commit is contained in:
parent
8068eb23e5
commit
50f3985b6f
17 changed files with 558 additions and 17 deletions
|
@ -294,13 +294,15 @@ namespace ARMeilleure.Decoders
|
|||
{
|
||||
// TODO (CQ): ARM32 support.
|
||||
return opCode.Instruction.Name == InstName.Bl ||
|
||||
opCode.Instruction.Name == InstName.Blr;
|
||||
opCode.Instruction.Name == InstName.Blr ||
|
||||
opCode.Instruction.Name == InstName.Blx;
|
||||
}
|
||||
|
||||
private static bool IsException(OpCode opCode)
|
||||
{
|
||||
return opCode.Instruction.Name == InstName.Brk ||
|
||||
opCode.Instruction.Name == InstName.Svc ||
|
||||
opCode.Instruction.Name == InstName.Trap ||
|
||||
opCode.Instruction.Name == InstName.Und;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace ARMeilleure.Decoders
|
|||
public int Size { get; protected set; }
|
||||
public bool Q { get; private set; }
|
||||
public bool F { get; private set; }
|
||||
public bool U { get; private set; }
|
||||
public int Elems => GetBytesCount() >> ((Size == 1) ? 1 : 2);
|
||||
|
||||
public OpCode32Simd(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
|
@ -19,6 +20,7 @@ namespace ARMeilleure.Decoders
|
|||
Size = (opCode >> 20) & 0x1; //fvector size: 1 for 16 bit
|
||||
Q = ((opCode >> 6) & 0x1) != 0;
|
||||
F = ((opCode >> 10) & 0x1) != 0;
|
||||
U = ((opCode >> 24) & 0x1) != 0;
|
||||
|
||||
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
|
||||
|
||||
|
|
17
ARMeilleure/Decoders/OpCode32SimdBinary.cs
Normal file
17
ARMeilleure/Decoders/OpCode32SimdBinary.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
/// <summary>
|
||||
/// A special alias that always runs in 64 bit int, to speed up binary ops a little.
|
||||
/// </summary>
|
||||
class OpCode32SimdBinary : OpCode32SimdReg
|
||||
{
|
||||
public OpCode32SimdBinary(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Size = 3;
|
||||
}
|
||||
}
|
||||
}
|
14
ARMeilleure/Decoders/OpCode32SimdCmpZ.cs
Normal file
14
ARMeilleure/Decoders/OpCode32SimdCmpZ.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32SimdCmpZ : OpCode32Simd
|
||||
{
|
||||
public OpCode32SimdCmpZ(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Size = (opCode >> 18) & 0x1; //fvector size: 1 for 16 bit
|
||||
}
|
||||
}
|
||||
}
|
26
ARMeilleure/Decoders/OpCode32SimdVdupGP.cs
Normal file
26
ARMeilleure/Decoders/OpCode32SimdVdupGP.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32SimdVdupGP : OpCode32, IOpCode32Simd
|
||||
{
|
||||
public int Elems => GetBytesCount() >> ((Size == 1) ? 1 : 2);
|
||||
public int Size { get; private set; }
|
||||
public int Vd { get; private set; }
|
||||
public int Rt { get; private set; }
|
||||
public bool Q { get; private set; }
|
||||
|
||||
public OpCode32SimdVdupGP(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Size = 2 - (((opCode >> 21) & 0x2) | ((opCode >> 5) & 0x1)); //B:E - 0 for 32, 16 then 8.
|
||||
Q = ((opCode >> 21) & 0x1) != 0;
|
||||
|
||||
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
|
||||
|
||||
Vd = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf);
|
||||
Rt = ((opCode >> 12) & 0xf);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -671,7 +671,13 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("<<<<0011100xxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0001100xxxxxxxxxxxxxxxx0xxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<0001100xxxxxxxxxxxxx0xx1xxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluRsReg));
|
||||
SetA32("<<<<01101000xxxxxxxxxxxxxx01xxxx", InstName.Pkh, InstEmit32.Pkh, typeof(OpCode32AluRsImm));
|
||||
SetA32("11110101xx01xxxx1111xxxxxxxxxxxx", InstName.Pld, InstEmit32.Nop, typeof(OpCode32)); //preload hint for cache - nop
|
||||
SetA32("11110111xx01xxxx1111xxxxxxx0xxxx", InstName.Pld, InstEmit32.Nop, typeof(OpCode32)); //rs imm
|
||||
SetA32("<<<<011011111111xxxx11110011xxxx", InstName.Rbit, InstEmit32.Rbit, typeof(OpCode32AluReg));
|
||||
SetA32("<<<<011010111111xxxx11110011xxxx", InstName.Rev, InstEmit32.Rev, typeof(OpCode32AluReg));
|
||||
SetA32("<<<<011010111111xxxx11111011xxxx", InstName.Rev16, InstEmit32.Rev16, typeof(OpCode32AluReg));
|
||||
SetA32("<<<<011011111111xxxx11111011xxxx", InstName.Revsh, InstEmit32.Revsh, typeof(OpCode32AluReg));
|
||||
SetA32("<<<<0010011xxxxxxxxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000011xxxxxxxxxxxxxxxx0xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<0000011xxxxxxxxxxxxx0xx1xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsReg));
|
||||
|
@ -680,7 +686,8 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("<<<<0000111xxxxxxxxxxxxx0xx1xxxx", InstName.Rsc, InstEmit32.Rsc, typeof(OpCode32AluRsReg));
|
||||
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, typeof(OpCode32AluMla));
|
||||
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smlab, InstEmit32.Smlab, typeof(OpCode32AluMla));
|
||||
SetA32("<<<<00010100xxxxxxxxxxxx1xx0xxxx", InstName.Smlal, InstEmit32.Smlal, typeof(OpCode32AluUmull));
|
||||
SetA32("<<<<0000111xxxxxxxxxxxxx1001xxxx", InstName.Smlal, InstEmit32.Smlal, typeof(OpCode32AluUmull));
|
||||
SetA32("<<<<00010100xxxxxxxxxxxx1xx0xxxx", InstName.Smlalh,InstEmit32.Smlalh,typeof(OpCode32AluUmull));
|
||||
SetA32("<<<<01110101xxxx1111xxxx00x1xxxx", InstName.Smmul, InstEmit32.Smmul, typeof(OpCode32AluMla));
|
||||
SetA32("<<<<0010110xxxxxxxxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000110xxxxxxxxxxxxxxxx0xxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluRsImm));
|
||||
|
@ -730,13 +737,37 @@ namespace ARMeilleure.Decoders
|
|||
|
||||
SetA32("<<<<11100x11xxxxxxxx10xxx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("111100100x0xxxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, typeof(OpCode32SimdReg));
|
||||
SetA32("111100100x0xxxxxxxxx1100xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, typeof(OpCode32SimdReg));
|
||||
SetA32("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111100100x00xxxxxxxx0001xxx1xxxx", InstName.Vand, InstEmit32.Vand_I, typeof(OpCode32SimdBinary));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x010xx0xxxx", InstName.Vceq, InstEmit32.Vceq_Z, typeof(OpCode32SimdCmpZ));
|
||||
SetA32("111100100x0xxxxxxxxx1110xxx0xxxx", InstName.Vceq, InstEmit32.Vceq_V, typeof(OpCode32SimdReg)); //note: size is 16/32 only
|
||||
SetA32("111100110xxxxxxxxxxx1000xxx1xxxx", InstName.Vceq, InstEmit32.Vceq_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x001xx0xxxx", InstName.Vcge, InstEmit32.Vcge_Z, typeof(OpCode32SimdCmpZ));
|
||||
SetA32("111100110x0xxxxxxxxx1110xxx0xxxx", InstName.Vcge, InstEmit32.Vcge_V, typeof(OpCode32SimdReg)); //note: size is 16/32 only
|
||||
SetA32("1111001x0xxxxxxxxxxx0011xxx1xxxx", InstName.Vcge, InstEmit32.Vcge_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x000xx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_Z, typeof(OpCode32SimdCmpZ));
|
||||
SetA32("111100110x1xxxxxxxxx1110xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_V, typeof(OpCode32SimdReg)); //note: size is 16/32 only
|
||||
SetA32("1111001x0xxxxxxxxxxx0011xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, typeof(OpCode32SimdCmpZ));
|
||||
//SetA32("111100110x0xxxxxxxxx1110xxx0xxxx", InstName.Vcle, InstEmit32.Vcle_V, typeof(OpCode32SimdReg)); //note: size is 16/32 only
|
||||
//SetA32("1111001x0xxxxxxxxxxx0011xxx1xxxx", InstName.Vcle, InstEmit32.Vcle_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, typeof(OpCode32SimdCmpZ));
|
||||
//SetA32("111100110x1xxxxxxxxx1110xxx0xxxx", InstName.Vclt, InstEmit32.Vclt_V, typeof(OpCode32SimdReg)); //note: size is 16/32 only
|
||||
//SetA32("1111001x0xxxxxxxxxxx0011xxx0xxxx", InstName.Vclt, InstEmit32.Vclt_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("<<<<11101x11010xxxxx10xx01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, typeof(OpCode32SimdS));
|
||||
SetA32("<<<<11101x11010xxxxx10xx11x0xxxx", InstName.Vcmpe,InstEmit32.Vcmpe, typeof(OpCode32SimdS));
|
||||
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, typeof(OpCode32SimdS));
|
||||
SetA32("<<<<11101x11110xxxxx10xx11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI));
|
||||
SetA32("<<<<11101x111000xxxx10xxx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI));
|
||||
SetA32("<<<<11101x00xxxxxxxx10xxx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, typeof(OpCode32SimdVdupGP));
|
||||
|
||||
// VLD# missing single to all lanes
|
||||
|
||||
|
@ -807,6 +838,12 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("111100111x11xx01xxxx0x111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, typeof(OpCode32Simd));
|
||||
SetA32("<<<<11101x110001xxxx10xx01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, typeof(OpCode32SimdS));
|
||||
|
||||
SetA32("<<<<11100x10xxxxxxxx10xxx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("<<<<11100x01xxxxxxxx10xxx1x0xxxx", InstName.Vnmla, InstEmit32.Vnmla_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("<<<<11100x01xxxxxxxx10xxx0x0xxxx", InstName.Vnmls, InstEmit32.Vnmls_S, typeof(OpCode32SimdRegS));
|
||||
|
||||
SetA32("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, typeof(OpCode32SimdBinary));
|
||||
|
||||
SetA32("111111100xxxxxxxxxxx10xxx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, typeof(OpCode32SimdSel));
|
||||
|
||||
SetA32("111101001x00xxxxxxxx0000xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
|
|
|
@ -478,6 +478,29 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
public static void Pkh(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluRsImm op = (OpCode32AluRsImm)context.CurrOp;
|
||||
|
||||
Operand n = GetAluN(context);
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
Operand res = context.Call(new _U32_U32(SoftFallback.ReverseBits32), m);
|
||||
|
||||
bool tbform = op.ShiftType == ShiftType.Asr;
|
||||
if (tbform)
|
||||
{
|
||||
res = context.BitwiseOr(context.BitwiseAnd(n, Const(0xFFFF0000)), context.BitwiseAnd(m, Const(0xFFFF)));
|
||||
}
|
||||
else
|
||||
{
|
||||
res = context.BitwiseOr(context.BitwiseAnd(m, Const(0xFFFF0000)), context.BitwiseAnd(n, Const(0xFFFF)));
|
||||
}
|
||||
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
public static void Rbit(ArmEmitterContext context)
|
||||
{
|
||||
Operand m = GetAluM(context);
|
||||
|
@ -486,6 +509,39 @@ namespace ARMeilleure.Instructions
|
|||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
public static void Rev(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Alu op = (OpCode32Alu)context.CurrOp;
|
||||
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
Operand res = context.Call(new _U32_U32(System.Buffers.Binary.BinaryPrimitives.ReverseEndianness), m);
|
||||
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
public static void Rev16(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Alu op = (OpCode32Alu)context.CurrOp;
|
||||
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
Operand res = context.Call(new _U32_U32(SoftFallback.ReverseBytes16_32), m);
|
||||
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
public static void Revsh(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Alu op = (OpCode32Alu)context.CurrOp;
|
||||
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
Operand res = context.Call(new _U32_U32(SoftFallback.ReverseBytes16_32), m);
|
||||
|
||||
EmitAluStore(context, context.SignExtend16(OperandType.I32, res));
|
||||
}
|
||||
|
||||
public static void Bfc(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
||||
|
|
|
@ -75,13 +75,13 @@ namespace ARMeilleure.Instructions
|
|||
uint pc = op.GetPc();
|
||||
|
||||
Operand addr = GetIntA32(context, op.Rm);
|
||||
Operand bitOne = context.BitwiseAnd(addr, Const(0));
|
||||
Operand bitOne = context.BitwiseAnd(addr, Const(1));
|
||||
|
||||
bool isThumb = IsThumb(context.CurrOp);
|
||||
|
||||
uint currentPc = isThumb
|
||||
? op.GetPc() | 1
|
||||
: op.GetPc() - 4;
|
||||
? pc | 1
|
||||
: pc - 4;
|
||||
|
||||
SetIntOrSP(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
||||
|
||||
|
@ -90,5 +90,9 @@ namespace ARMeilleure.Instructions
|
|||
addr = context.BitwiseOr(addr, Const(1)); // set call flag
|
||||
context.Return(addr); // call
|
||||
}
|
||||
|
||||
public static void Nop(ArmEmitterContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,20 +73,20 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
if (op.NHigh)
|
||||
{
|
||||
n = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16)));
|
||||
n = context.SignExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16)));
|
||||
}
|
||||
else
|
||||
{
|
||||
n = context.ZeroExtend16(OperandType.I32, n);
|
||||
n = context.SignExtend16(OperandType.I32, n);
|
||||
}
|
||||
|
||||
if (op.MHigh)
|
||||
{
|
||||
m = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(m, Const(16)));
|
||||
m = context.SignExtend16(OperandType.I32, context.ShiftRightUI(m, Const(16)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m = context.ZeroExtend16(OperandType.I32, m);
|
||||
m = context.SignExtend16(OperandType.I32, m);
|
||||
}
|
||||
|
||||
Operand res = context.Multiply(n, m);
|
||||
|
@ -106,22 +106,50 @@ namespace ARMeilleure.Instructions
|
|||
Operand n = GetIntA32(context, op.Rn);
|
||||
Operand m = GetIntA32(context, op.Rm);
|
||||
|
||||
n = context.SignExtend32(OperandType.I64, n);
|
||||
m = context.SignExtend32(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);
|
||||
}
|
||||
|
||||
EmitGenericStore(context, op.RdHi, op.SetFlags, hi);
|
||||
EmitGenericStore(context, op.RdLo, op.SetFlags, lo);
|
||||
}
|
||||
|
||||
public static void Smlalh(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
|
||||
|
||||
Operand n = GetIntA32(context, op.Rn);
|
||||
Operand m = GetIntA32(context, op.Rm);
|
||||
|
||||
if (op.NHigh)
|
||||
{
|
||||
n = context.ZeroExtend16(OperandType.I64, context.ShiftRightUI(n, Const(16)));
|
||||
n = context.SignExtend16(OperandType.I64, context.ShiftRightUI(n, Const(16)));
|
||||
}
|
||||
else
|
||||
{
|
||||
n = context.ZeroExtend16(OperandType.I64, n);
|
||||
n = context.SignExtend16(OperandType.I64, n);
|
||||
}
|
||||
|
||||
if (op.MHigh)
|
||||
{
|
||||
m = context.ZeroExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16)));
|
||||
m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m = context.ZeroExtend16(OperandType.I64, m);
|
||||
m = context.SignExtend16(OperandType.I64, m);
|
||||
}
|
||||
|
||||
Operand res = context.Multiply(n, m);
|
||||
|
|
|
@ -31,6 +31,45 @@ namespace ARMeilleure.Instructions
|
|||
EmitVectorBinaryOpZx32(context, (op1, op2) => context.Add(op1, op2));
|
||||
}
|
||||
|
||||
public static void Vand_I(ArmEmitterContext context)
|
||||
{
|
||||
EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseAnd(op1, op2));
|
||||
}
|
||||
|
||||
public static void Vdup(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdVdupGP op = (OpCode32SimdVdupGP)context.CurrOp;
|
||||
|
||||
Operand insert = GetIntA32(context, op.Rt);
|
||||
|
||||
// zero extend into an I64, then replicate. Saves the most time over elementwise inserts
|
||||
switch (op.Size)
|
||||
{
|
||||
case 2:
|
||||
insert = context.Multiply(context.ZeroExtend32(OperandType.I64, insert), Const(0x0000000100000001u));
|
||||
break;
|
||||
case 1:
|
||||
insert = context.Multiply(context.ZeroExtend16(OperandType.I64, insert), Const(0x0001000100010001u));
|
||||
break;
|
||||
case 0:
|
||||
insert = context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u));
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown Vdup Size!");
|
||||
}
|
||||
|
||||
InsertScalar(context, op.Vd, insert);
|
||||
if (op.Q)
|
||||
{
|
||||
InsertScalar(context, op.Vd | 1, insert);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vorr_I(ArmEmitterContext context)
|
||||
{
|
||||
EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseOr(op1, op2));
|
||||
}
|
||||
|
||||
public static void Vmov_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarUnaryOpF32(context, (op1) => op1);
|
||||
|
@ -41,6 +80,47 @@ namespace ARMeilleure.Instructions
|
|||
EmitScalarUnaryOpF32(context, (op1) => context.Negate(op1));
|
||||
}
|
||||
|
||||
public static void Vnmul_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarBinaryOpF32(context, (op1, op2) => context.Negate(context.Multiply(op1, op2)));
|
||||
}
|
||||
|
||||
public static void Vnmla_S(ArmEmitterContext context)
|
||||
{
|
||||
if (false) //Optimizations.FastFP)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||
{
|
||||
return context.Negate(context.Add(op1, context.Multiply(op2, op3)));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||
{
|
||||
return EmitSoftFloatCall(context, SoftFloat32.FPNegMulAdd, SoftFloat64.FPNegMulAdd, op1, op2, op3);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vnmls_S(ArmEmitterContext context)
|
||||
{
|
||||
if (false)//Optimizations.FastFP)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||
{
|
||||
return context.Subtract(op1, context.Multiply(op2, op3));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||
{
|
||||
return EmitSoftFloatCall(context, SoftFloat32.FPNegMulSub, SoftFloat64.FPNegMulSub, op1, op2, op3);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vneg_V(ArmEmitterContext context)
|
||||
{
|
||||
if ((context.CurrOp as OpCode32Simd).F)
|
||||
|
@ -132,7 +212,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static void Vmul_I(ArmEmitterContext context)
|
||||
{
|
||||
EmitVectorBinaryOpZx32(context, (op1, op2) => context.Multiply(op1, op2));
|
||||
EmitVectorBinaryOpSx32(context, (op1, op2) => context.Multiply(op1, op2));
|
||||
}
|
||||
|
||||
public static void Vmla_S(ArmEmitterContext context)
|
||||
|
|
|
@ -12,8 +12,204 @@ using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
|||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
|
||||
static partial class InstEmit32
|
||||
{
|
||||
public static void Vceq_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, false);
|
||||
}
|
||||
|
||||
public static void Vceq_I(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
EmitCmpOpI32(context, context.ICompareEqual, context.ICompareEqual, false, false);
|
||||
}
|
||||
|
||||
public static void Vceq_Z(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
if (op.F)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmpOpI32(context, context.ICompareEqual, context.ICompareEqual, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vcge_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, false);
|
||||
}
|
||||
|
||||
public static void Vcge_I(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
EmitCmpOpI32(context, context.ICompareGreaterOrEqual, context.ICompareGreaterOrEqualUI, false, !op.U);
|
||||
}
|
||||
|
||||
public static void Vcge_Z(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
if (op.F)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmpOpI32(context, context.ICompareGreaterOrEqual, context.ICompareGreaterOrEqualUI, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vcgt_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, false);
|
||||
}
|
||||
|
||||
public static void Vcgt_I(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
EmitCmpOpI32(context, context.ICompareGreater, context.ICompareGreaterUI, false, !op.U);
|
||||
}
|
||||
|
||||
public static void Vcgt_Z(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
if (op.F)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmpOpI32(context, context.ICompareGreater, context.ICompareGreaterUI, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vcle_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, false);
|
||||
}
|
||||
|
||||
public static void Vcle_I(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
EmitCmpOpI32(context, context.ICompareLessOrEqual, context.ICompareLessOrEqualUI, false, !op.U);
|
||||
}
|
||||
|
||||
public static void Vcle_Z(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
if (op.F)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmpOpI32(context, context.ICompareLessOrEqual, context.ICompareLessOrEqualUI, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vclt_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, false);
|
||||
}
|
||||
|
||||
public static void Vclt_I(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
EmitCmpOpI32(context, context.ICompareLess, context.ICompareLessUI, false, !op.U);
|
||||
}
|
||||
|
||||
public static void Vclt_Z(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
if (op.F)
|
||||
{
|
||||
EmitCmpOpF32(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmpOpI32(context, context.ICompareLess, context.ICompareLessUI, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitCmpOpF32(
|
||||
ArmEmitterContext context,
|
||||
_F32_F32_F32 f32,
|
||||
_F64_F64_F64 f64,
|
||||
bool zero)
|
||||
{
|
||||
if (zero)
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, (m) =>
|
||||
{
|
||||
OperandType type = m.Type;
|
||||
|
||||
if (type == OperandType.FP64) return context.Call(f64, m, new Operand(0.0));
|
||||
else return context.Call(f32, m, new Operand(0.0));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF32(context, (n, m) =>
|
||||
{
|
||||
OperandType type = n.Type;
|
||||
|
||||
if (type == OperandType.FP64) return context.Call(f64, n, m);
|
||||
else return context.Call(f32, n, m);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand ZerosOrOnes(ArmEmitterContext context, Operand fromBool, OperandType baseType)
|
||||
{
|
||||
return context.ConditionalSelect(fromBool, Const(baseType, -1L), Const(baseType, 0L));
|
||||
}
|
||||
|
||||
private static void EmitCmpOpI32(
|
||||
ArmEmitterContext context,
|
||||
Func2I signedOp,
|
||||
Func2I unsignedOp,
|
||||
bool zero,
|
||||
bool signed)
|
||||
{
|
||||
if (zero)
|
||||
{
|
||||
if (signed)
|
||||
{
|
||||
EmitVectorUnaryOpSx32(context, (m) =>
|
||||
{
|
||||
OperandType type = m.Type;
|
||||
Operand zeroV = (type == OperandType.I64) ? Const(0L) : Const(0);
|
||||
return ZerosOrOnes(context, signedOp(m, zeroV), type);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorUnaryOpZx32(context, (m) =>
|
||||
{
|
||||
OperandType type = m.Type;
|
||||
Operand zeroV = (type == OperandType.I64) ? Const(0L) : Const(0);
|
||||
return ZerosOrOnes(context, unsignedOp(m, zeroV), type);
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (signed)
|
||||
{
|
||||
EmitVectorBinaryOpSx32(context, (n, m) => ZerosOrOnes(context, signedOp(n, m), n.Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx32(context, (n, m) => ZerosOrOnes(context, unsignedOp(n, m), n.Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vcmp(ArmEmitterContext context)
|
||||
{
|
||||
EmitVcmpOrVcmpe(context, false);
|
||||
|
|
|
@ -479,11 +479,16 @@ namespace ARMeilleure.Instructions
|
|||
Mrc,
|
||||
Mrrc,
|
||||
Mvn,
|
||||
Pkh,
|
||||
Pld,
|
||||
Rev,
|
||||
Revsh,
|
||||
Rsb,
|
||||
Rsc,
|
||||
Sbfx,
|
||||
Smlab,
|
||||
Smlal,
|
||||
Smlalh,
|
||||
Smmul,
|
||||
Stl,
|
||||
Stlb,
|
||||
|
@ -510,10 +515,17 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
// FP & SIMD (AArch32)
|
||||
Vadd,
|
||||
Vand,
|
||||
Vceq,
|
||||
Vcge,
|
||||
Vcgt,
|
||||
Vcle,
|
||||
Vclt,
|
||||
Vcmp,
|
||||
Vcmpe,
|
||||
Vcvt,
|
||||
Vdiv,
|
||||
Vdup,
|
||||
Vld1,
|
||||
Vld2,
|
||||
Vld3,
|
||||
|
@ -527,6 +539,10 @@ namespace ARMeilleure.Instructions
|
|||
Vmsr,
|
||||
Vmul,
|
||||
Vneg,
|
||||
Vnmul,
|
||||
Vnmla,
|
||||
Vnmls,
|
||||
Vorr,
|
||||
Vsel,
|
||||
Vst1,
|
||||
Vst2,
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public bool ShouldRejit()
|
||||
{
|
||||
return _rejit && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
|
||||
return false && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -667,7 +667,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
[R(1)] uint sizeLow,
|
||||
[R(4)] uint sizeHigh)
|
||||
{
|
||||
_process.CpuMemory.WriteBytes(addressLow, new byte[sizeLow]);
|
||||
//_process.CpuMemory.WriteBytes(addressLow, new byte[sizeLow]);
|
||||
return KernelResult.Success;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{ 0x26, nameof(SvcHandler.Break32) },
|
||||
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
|
||||
{ 0x29, nameof(SvcHandler.GetInfo32) },
|
||||
{ 0x34, nameof(SvcHandler.WaitForAddress32) },
|
||||
{ 0x35, nameof(SvcHandler.SignalToAddress32) },
|
||||
|
||||
{ 0x5F, nameof(SvcHandler.FlushProcessDataCache32) }
|
||||
};
|
||||
|
|
|
@ -194,6 +194,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return WaitForAddress(address, type, value, timeout);
|
||||
}
|
||||
|
||||
public KernelResult WaitForAddress32([R(0)] uint address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] uint timeoutLow, [R(4)] uint timeoutHigh)
|
||||
{
|
||||
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
|
||||
return WaitForAddress(address, type, value, timeout);
|
||||
}
|
||||
|
||||
private KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
|
||||
{
|
||||
if (IsPointingInsideKernel(address))
|
||||
|
@ -237,6 +243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return SignalToAddress(address, type, value, count);
|
||||
}
|
||||
|
||||
public KernelResult SignalToAddress32([R(0)] uint address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
|
||||
{
|
||||
return SignalToAddress(address, type, value, count);
|
||||
}
|
||||
|
||||
private KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
|
||||
{
|
||||
if (IsPointingInsideKernel(address))
|
||||
|
|
|
@ -52,5 +52,55 @@ namespace Ryujinx.Tests.Cpu
|
|||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UBFX <Rd>, <Rn>, #<lsb>, #<width>")]
|
||||
public void Ubfx([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImms)] uint widthm1)
|
||||
{
|
||||
if (lsb + widthm1 > 31)
|
||||
{
|
||||
widthm1 -= (lsb + widthm1) - 31;
|
||||
}
|
||||
uint opcode = 0xe7e00050; // UBFX r0, r0, #0, #1
|
||||
opcode |= ((rd & 0xf) << 12);
|
||||
opcode |= ((rn & 0xf) << 0);
|
||||
opcode |= ((widthm1 & 31) << 16) | ((lsb & 31) << 7);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wd, r1: wn, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBFX <Rd>, <Rn>, #<lsb>, #<width>")]
|
||||
public void Sbfx([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImms)] uint widthm1)
|
||||
{
|
||||
if (lsb + widthm1 > 31)
|
||||
{
|
||||
widthm1 -= (lsb + widthm1) - 31;
|
||||
}
|
||||
uint opcode = 0xe7a00050; // SBFX r0, r0, #0, #1
|
||||
opcode |= ((rd & 0xf) << 12);
|
||||
opcode |= ((rn & 0xf) << 0);
|
||||
opcode |= ((widthm1 & 31) << 16) | ((lsb & 31) << 7);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wd, r1: wn, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue