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.
|
// TODO (CQ): ARM32 support.
|
||||||
return opCode.Instruction.Name == InstName.Bl ||
|
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)
|
private static bool IsException(OpCode opCode)
|
||||||
{
|
{
|
||||||
return opCode.Instruction.Name == InstName.Brk ||
|
return opCode.Instruction.Name == InstName.Brk ||
|
||||||
opCode.Instruction.Name == InstName.Svc ||
|
opCode.Instruction.Name == InstName.Svc ||
|
||||||
|
opCode.Instruction.Name == InstName.Trap ||
|
||||||
opCode.Instruction.Name == InstName.Und;
|
opCode.Instruction.Name == InstName.Und;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace ARMeilleure.Decoders
|
||||||
public int Size { get; protected set; }
|
public int Size { get; protected set; }
|
||||||
public bool Q { get; private set; }
|
public bool Q { get; private set; }
|
||||||
public bool F { get; private set; }
|
public bool F { get; private set; }
|
||||||
|
public bool U { get; private set; }
|
||||||
public int Elems => GetBytesCount() >> ((Size == 1) ? 1 : 2);
|
public int Elems => GetBytesCount() >> ((Size == 1) ? 1 : 2);
|
||||||
|
|
||||||
public OpCode32Simd(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
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
|
Size = (opCode >> 20) & 0x1; //fvector size: 1 for 16 bit
|
||||||
Q = ((opCode >> 6) & 0x1) != 0;
|
Q = ((opCode >> 6) & 0x1) != 0;
|
||||||
F = ((opCode >> 10) & 0x1) != 0;
|
F = ((opCode >> 10) & 0x1) != 0;
|
||||||
|
U = ((opCode >> 24) & 0x1) != 0;
|
||||||
|
|
||||||
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
|
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("<<<<0011100xxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0001100xxxxxxxxxxxxxxxx0xxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluRsImm));
|
SetA32("<<<<0001100xxxxxxxxxxxxxxxx0xxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluRsImm));
|
||||||
SetA32("<<<<0001100xxxxxxxxxxxxx0xx1xxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluRsReg));
|
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("<<<<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("<<<<0010011xxxxxxxxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0000011xxxxxxxxxxxxxxxx0xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsImm));
|
SetA32("<<<<0000011xxxxxxxxxxxxxxxx0xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsImm));
|
||||||
SetA32("<<<<0000011xxxxxxxxxxxxx0xx1xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsReg));
|
SetA32("<<<<0000011xxxxxxxxxxxxx0xx1xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsReg));
|
||||||
|
@ -680,7 +686,8 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<0000111xxxxxxxxxxxxx0xx1xxxx", InstName.Rsc, InstEmit32.Rsc, typeof(OpCode32AluRsReg));
|
SetA32("<<<<0000111xxxxxxxxxxxxx0xx1xxxx", InstName.Rsc, InstEmit32.Rsc, typeof(OpCode32AluRsReg));
|
||||||
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, typeof(OpCode32AluMla));
|
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, typeof(OpCode32AluMla));
|
||||||
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smlab, InstEmit32.Smlab, 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("<<<<01110101xxxx1111xxxx00x1xxxx", InstName.Smmul, InstEmit32.Smmul, typeof(OpCode32AluMla));
|
||||||
SetA32("<<<<0010110xxxxxxxxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluImm));
|
SetA32("<<<<0010110xxxxxxxxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0000110xxxxxxxxxxxxxxxx0xxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluRsImm));
|
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("<<<<11100x11xxxxxxxx10xxx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, typeof(OpCode32SimdRegS));
|
||||||
SetA32("111100100x0xxxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, typeof(OpCode32SimdReg));
|
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("<<<<11101x11010xxxxx10xx01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, typeof(OpCode32SimdS));
|
||||||
SetA32("<<<<11101x11010xxxxx10xx11x0xxxx", InstName.Vcmpe,InstEmit32.Vcmpe, typeof(OpCode32SimdS));
|
SetA32("<<<<11101x11010xxxxx10xx11x0xxxx", InstName.Vcmpe,InstEmit32.Vcmpe, typeof(OpCode32SimdS));
|
||||||
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, typeof(OpCode32SimdS));
|
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, typeof(OpCode32SimdS));
|
||||||
SetA32("<<<<11101x11110xxxxx10xx11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI));
|
SetA32("<<<<11101x11110xxxxx10xx11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI));
|
||||||
SetA32("<<<<11101x111000xxxx10xxx1x0xxxx", 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("<<<<11101x00xxxxxxxx10xxx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, typeof(OpCode32SimdRegS));
|
||||||
|
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, typeof(OpCode32SimdVdupGP));
|
||||||
|
|
||||||
// VLD# missing single to all lanes
|
// VLD# missing single to all lanes
|
||||||
|
|
||||||
|
@ -807,6 +838,12 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("111100111x11xx01xxxx0x111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, typeof(OpCode32Simd));
|
SetA32("111100111x11xx01xxxx0x111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, typeof(OpCode32Simd));
|
||||||
SetA32("<<<<11101x110001xxxx10xx01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, typeof(OpCode32SimdS));
|
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("111111100xxxxxxxxxxx10xxx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, typeof(OpCode32SimdSel));
|
||||||
|
|
||||||
SetA32("111101001x00xxxxxxxx0000xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
SetA32("111101001x00xxxxxxxx0000xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||||
|
|
|
@ -478,6 +478,29 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
EmitAluStore(context, res);
|
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)
|
public static void Rbit(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
Operand m = GetAluM(context);
|
Operand m = GetAluM(context);
|
||||||
|
@ -486,6 +509,39 @@ namespace ARMeilleure.Instructions
|
||||||
EmitAluStore(context, res);
|
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)
|
public static void Bfc(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
||||||
|
|
|
@ -75,13 +75,13 @@ namespace ARMeilleure.Instructions
|
||||||
uint pc = op.GetPc();
|
uint pc = op.GetPc();
|
||||||
|
|
||||||
Operand addr = GetIntA32(context, op.Rm);
|
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);
|
bool isThumb = IsThumb(context.CurrOp);
|
||||||
|
|
||||||
uint currentPc = isThumb
|
uint currentPc = isThumb
|
||||||
? op.GetPc() | 1
|
? pc | 1
|
||||||
: op.GetPc() - 4;
|
: pc - 4;
|
||||||
|
|
||||||
SetIntOrSP(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
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
|
addr = context.BitwiseOr(addr, Const(1)); // set call flag
|
||||||
context.Return(addr); // call
|
context.Return(addr); // call
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Nop(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -73,20 +73,20 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
if (op.NHigh)
|
if (op.NHigh)
|
||||||
{
|
{
|
||||||
n = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16)));
|
n = context.SignExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
n = context.ZeroExtend16(OperandType.I32, n);
|
n = context.SignExtend16(OperandType.I32, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op.MHigh)
|
if (op.MHigh)
|
||||||
{
|
{
|
||||||
m = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(m, Const(16)));
|
m = context.SignExtend16(OperandType.I32, context.ShiftRightUI(m, Const(16)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m = context.ZeroExtend16(OperandType.I32, m);
|
m = context.SignExtend16(OperandType.I32, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand res = context.Multiply(n, m);
|
Operand res = context.Multiply(n, m);
|
||||||
|
@ -106,22 +106,50 @@ namespace ARMeilleure.Instructions
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
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)
|
if (op.NHigh)
|
||||||
{
|
{
|
||||||
n = context.ZeroExtend16(OperandType.I64, context.ShiftRightUI(n, Const(16)));
|
n = context.SignExtend16(OperandType.I64, context.ShiftRightUI(n, Const(16)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
n = context.ZeroExtend16(OperandType.I64, n);
|
n = context.SignExtend16(OperandType.I64, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op.MHigh)
|
if (op.MHigh)
|
||||||
{
|
{
|
||||||
m = context.ZeroExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16)));
|
m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m = context.ZeroExtend16(OperandType.I64, m);
|
m = context.SignExtend16(OperandType.I64, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand res = context.Multiply(n, m);
|
Operand res = context.Multiply(n, m);
|
||||||
|
|
|
@ -31,6 +31,45 @@ namespace ARMeilleure.Instructions
|
||||||
EmitVectorBinaryOpZx32(context, (op1, op2) => context.Add(op1, op2));
|
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)
|
public static void Vmov_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitScalarUnaryOpF32(context, (op1) => op1);
|
EmitScalarUnaryOpF32(context, (op1) => op1);
|
||||||
|
@ -41,6 +80,47 @@ namespace ARMeilleure.Instructions
|
||||||
EmitScalarUnaryOpF32(context, (op1) => context.Negate(op1));
|
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)
|
public static void Vneg_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
if ((context.CurrOp as OpCode32Simd).F)
|
if ((context.CurrOp as OpCode32Simd).F)
|
||||||
|
@ -132,7 +212,7 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
public static void Vmul_I(ArmEmitterContext context)
|
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)
|
public static void Vmla_S(ArmEmitterContext context)
|
||||||
|
|
|
@ -12,8 +12,204 @@ using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
|
using Func2I = Func<Operand, Operand, Operand>;
|
||||||
|
|
||||||
static partial class InstEmit32
|
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)
|
public static void Vcmp(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitVcmpOrVcmpe(context, false);
|
EmitVcmpOrVcmpe(context, false);
|
||||||
|
|
|
@ -479,11 +479,16 @@ namespace ARMeilleure.Instructions
|
||||||
Mrc,
|
Mrc,
|
||||||
Mrrc,
|
Mrrc,
|
||||||
Mvn,
|
Mvn,
|
||||||
|
Pkh,
|
||||||
|
Pld,
|
||||||
|
Rev,
|
||||||
|
Revsh,
|
||||||
Rsb,
|
Rsb,
|
||||||
Rsc,
|
Rsc,
|
||||||
Sbfx,
|
Sbfx,
|
||||||
Smlab,
|
Smlab,
|
||||||
Smlal,
|
Smlal,
|
||||||
|
Smlalh,
|
||||||
Smmul,
|
Smmul,
|
||||||
Stl,
|
Stl,
|
||||||
Stlb,
|
Stlb,
|
||||||
|
@ -510,10 +515,17 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
// FP & SIMD (AArch32)
|
// FP & SIMD (AArch32)
|
||||||
Vadd,
|
Vadd,
|
||||||
|
Vand,
|
||||||
|
Vceq,
|
||||||
|
Vcge,
|
||||||
|
Vcgt,
|
||||||
|
Vcle,
|
||||||
|
Vclt,
|
||||||
Vcmp,
|
Vcmp,
|
||||||
Vcmpe,
|
Vcmpe,
|
||||||
Vcvt,
|
Vcvt,
|
||||||
Vdiv,
|
Vdiv,
|
||||||
|
Vdup,
|
||||||
Vld1,
|
Vld1,
|
||||||
Vld2,
|
Vld2,
|
||||||
Vld3,
|
Vld3,
|
||||||
|
@ -527,6 +539,10 @@ namespace ARMeilleure.Instructions
|
||||||
Vmsr,
|
Vmsr,
|
||||||
Vmul,
|
Vmul,
|
||||||
Vneg,
|
Vneg,
|
||||||
|
Vnmul,
|
||||||
|
Vnmla,
|
||||||
|
Vnmls,
|
||||||
|
Vorr,
|
||||||
Vsel,
|
Vsel,
|
||||||
Vst1,
|
Vst1,
|
||||||
Vst2,
|
Vst2,
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace ARMeilleure.Translation
|
||||||
|
|
||||||
public bool ShouldRejit()
|
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(1)] uint sizeLow,
|
||||||
[R(4)] uint sizeHigh)
|
[R(4)] uint sizeHigh)
|
||||||
{
|
{
|
||||||
_process.CpuMemory.WriteBytes(addressLow, new byte[sizeLow]);
|
//_process.CpuMemory.WriteBytes(addressLow, new byte[sizeLow]);
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
{ 0x26, nameof(SvcHandler.Break32) },
|
{ 0x26, nameof(SvcHandler.Break32) },
|
||||||
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
|
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
|
||||||
{ 0x29, nameof(SvcHandler.GetInfo32) },
|
{ 0x29, nameof(SvcHandler.GetInfo32) },
|
||||||
|
{ 0x34, nameof(SvcHandler.WaitForAddress32) },
|
||||||
|
{ 0x35, nameof(SvcHandler.SignalToAddress32) },
|
||||||
|
|
||||||
{ 0x5F, nameof(SvcHandler.FlushProcessDataCache32) }
|
{ 0x5F, nameof(SvcHandler.FlushProcessDataCache32) }
|
||||||
};
|
};
|
||||||
|
|
|
@ -194,6 +194,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return WaitForAddress(address, type, value, timeout);
|
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)
|
private KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
|
||||||
{
|
{
|
||||||
if (IsPointingInsideKernel(address))
|
if (IsPointingInsideKernel(address))
|
||||||
|
@ -237,6 +243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return SignalToAddress(address, type, value, count);
|
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)
|
private KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
|
||||||
{
|
{
|
||||||
if (IsPointingInsideKernel(address))
|
if (IsPointingInsideKernel(address))
|
||||||
|
|
|
@ -52,5 +52,55 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
CompareAgainstUnicorn();
|
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
Add a link
Reference in a new issue