Fix incorrect opcode decoders and a few more instructions.
This commit is contained in:
parent
9e2e45f852
commit
8068eb23e5
10 changed files with 159 additions and 9 deletions
24
ARMeilleure/Decoders/OpCode32SimdSel.cs
Normal file
24
ARMeilleure/Decoders/OpCode32SimdSel.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32SimdSel : OpCode32SimdRegS
|
||||
{
|
||||
public OpCode32SimdSelMode Cc { get; private set; }
|
||||
|
||||
public OpCode32SimdSel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Cc = (OpCode32SimdSelMode)((opCode >> 20) & 3);
|
||||
}
|
||||
}
|
||||
|
||||
enum OpCode32SimdSelMode : int
|
||||
{
|
||||
Eq = 0,
|
||||
Vs,
|
||||
Ge,
|
||||
Gt
|
||||
}
|
||||
}
|
|
@ -683,8 +683,9 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("<<<<00010100xxxxxxxxxxxx1xx0xxxx", InstName.Smlal, InstEmit32.Smlal, 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(OpCode32AluRsReg));
|
||||
SetA32("<<<<0000110xxxxxxxxxxxxxxxx0xxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<0000110xxxxxxxxxxxxx0xx1xxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluRsReg));
|
||||
SetA32("<<<<0111101xxxxxxxxxxxxxx101xxxx", InstName.Sbfx, InstEmit32.Sbfx, typeof(OpCode32AluBf));
|
||||
SetA32("<<<<00011000xxxx111111001001xxxx", InstName.Stl, InstEmit32.Stl, typeof(OpCode32MemStEx));
|
||||
SetA32("<<<<00011100xxxx111111001001xxxx", InstName.Stlb, InstEmit32.Stlb, typeof(OpCode32MemStEx));
|
||||
SetA32("<<<<00011000xxxxxxxx11101001xxxx", InstName.Stlex, InstEmit32.Stlex, typeof(OpCode32MemStEx));
|
||||
|
@ -708,17 +709,17 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("<<<<000xx0x0xxxxxxxx00001011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemReg));
|
||||
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<0000010xxxxxxxxxxxxx0xx1xxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<0000010xxxxxxxxxxxxx0xx1xxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluRsReg));
|
||||
SetA32("<<<<1111xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Svc, InstEmit32.Svc, typeof(OpCode32Exception));
|
||||
SetA32("<<<<01101010xxxxxxxxxx000111xxxx", InstName.Sxtb, InstEmit32.Sxtb, typeof(OpCode32AluUx));
|
||||
SetA32("<<<<01101011xxxxxxxxxx000111xxxx", InstName.Sxth, InstEmit32.Sxth, typeof(OpCode32AluUx));
|
||||
SetA32("<<<<00110011xxxx0000xxxxxxxxxxxx", InstName.Teq, InstEmit32.Teq, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<00010011xxxx0000xxxxxxx0xxxx", InstName.Teq, InstEmit32.Teq, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<00010011xxxx0000xxxx0xx1xxxx", InstName.Teq, InstEmit32.Teq, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<00010011xxxx0000xxxx0xx1xxxx", InstName.Teq, InstEmit32.Teq, typeof(OpCode32AluRsReg));
|
||||
SetA32("<<<<0111111111111101111011111110", InstName.Trap, InstEmit32.Trap, typeof(OpCode32Exception));
|
||||
SetA32("<<<<00110001xxxx0000xxxxxxxxxxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<00010001xxxx0000xxxxxxx0xxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<00010001xxxx0000xxxx0xx1xxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<00010001xxxx0000xxxx0xx1xxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluRsReg));
|
||||
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, typeof(OpCode32AluBf));
|
||||
SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, typeof(OpCode32AluMla));
|
||||
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, typeof(OpCode32AluUmull));
|
||||
|
@ -773,6 +774,9 @@ namespace ARMeilleure.Decoders
|
|||
|
||||
SetA32("<<<<1101xx01xxxxxxxx10xxxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, typeof(OpCode32SimdMemImm));
|
||||
|
||||
SetA32("111111101x00xxxxxxxx10xxxxx0xxxx", InstName.VMMmn, InstEmit32.VmaxminNm_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("111100110xxxxxxxxxxx1111xxx1xxxx", InstName.VMMmn, InstEmit32.VmaxminNm_V, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("<<<<11100x00xxxxxxxx10xxx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("111100100x0xxxxxxxxx1101xxx1xxxx", InstName.Vmla, InstEmit32.Vmla_V, typeof(OpCode32SimdReg));
|
||||
SetA32("111100100xxxxxxxxxxx1001xxx0xxxx", InstName.Vmla, InstEmit32.Vmla_I, typeof(OpCode32SimdReg));
|
||||
|
@ -803,6 +807,8 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("111100111x11xx01xxxx0x111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, typeof(OpCode32Simd));
|
||||
SetA32("<<<<11101x110001xxxx10xx01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, typeof(OpCode32SimdS));
|
||||
|
||||
SetA32("111111100xxxxxxxxxxx10xxx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, typeof(OpCode32SimdSel));
|
||||
|
||||
SetA32("111101001x00xxxxxxxx0000xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx0100xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx1000xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
|
|
|
@ -523,6 +523,19 @@ namespace ARMeilleure.Instructions
|
|||
SetIntA32(context, op.Rd, res);
|
||||
}
|
||||
|
||||
public static void Sbfx(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
||||
|
||||
var msb = op.Lsb + op.Msb; //for this instruction, the msb is actually a width
|
||||
var mask = (int)(0xFFFFFFFF >> (31 - msb)) << op.Lsb;
|
||||
|
||||
Operand n = GetIntOrZR(context, op.Rn);
|
||||
Operand res = context.ShiftRightSI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
||||
|
||||
SetIntA32(context, op.Rd, res);
|
||||
}
|
||||
|
||||
private static void EmitAluStore(ArmEmitterContext context, Operand value)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -7,6 +8,7 @@ using System.Text;
|
|||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
|
||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
|
@ -81,6 +83,23 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
}
|
||||
|
||||
//TODO: probably important to have a fast path for these instead of calling fucking standard math min/max
|
||||
public static void VmaxminNm_S(ArmEmitterContext context)
|
||||
{
|
||||
bool max = (context.CurrOp.RawOpCode & (1 << 6)) == 0;
|
||||
Delegate dlg = max ? new _F32_F32_F32(Math.Max) : new _F32_F32_F32(Math.Min);
|
||||
|
||||
EmitScalarBinaryOpF32(context, (op1, op2) => context.Call(dlg, op1, op2));
|
||||
}
|
||||
|
||||
public static void VmaxminNm_V(ArmEmitterContext context)
|
||||
{
|
||||
bool max = (context.CurrOp.RawOpCode & (1 << 21)) == 0;
|
||||
Delegate dlg = max ? new _F32_F32_F32(Math.Max) : new _F32_F32_F32(Math.Min);
|
||||
|
||||
EmitVectorBinaryOpSx32(context, (op1, op2) => context.Call(dlg, op1, op2));
|
||||
}
|
||||
|
||||
public static void Vmul_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP)
|
||||
|
@ -192,6 +211,31 @@ namespace ARMeilleure.Instructions
|
|||
EmitVectorTernaryOpZx32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)));
|
||||
}
|
||||
|
||||
public static void Vsel(ArmEmitterContext context)
|
||||
{
|
||||
var op = (OpCode32SimdSel)context.CurrOp;
|
||||
EmitScalarBinaryOpI32(context, (op1, op2) =>
|
||||
{
|
||||
Operand condition = null;
|
||||
switch (op.Cc)
|
||||
{
|
||||
case OpCode32SimdSelMode.Eq:
|
||||
condition = GetCondTrue(context, Condition.Eq);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Ge:
|
||||
condition = GetCondTrue(context, Condition.Ge);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Gt:
|
||||
condition = GetCondTrue(context, Condition.Gt);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Vs:
|
||||
condition = GetCondTrue(context, Condition.Vs);
|
||||
break;
|
||||
}
|
||||
return context.ConditionalSelect(condition, op1, op2);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Vsqrt_S(ArmEmitterContext context)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static Operand ExtractScalar(ArmEmitterContext context, OperandType type, int reg)
|
||||
{
|
||||
if (type == OperandType.FP64)
|
||||
if (type == OperandType.FP64 || type == OperandType.I64)
|
||||
{
|
||||
// from dreg
|
||||
return context.VectorExtract(type, GetVecA32(reg >> 1), reg & 1);
|
||||
|
@ -49,7 +49,7 @@ namespace ARMeilleure.Instructions
|
|||
public static void InsertScalar(ArmEmitterContext context, int reg, Operand value)
|
||||
{
|
||||
Operand vec, insert;
|
||||
if (value.Type == OperandType.FP64)
|
||||
if (value.Type == OperandType.FP64 || value.Type == OperandType.I64)
|
||||
{
|
||||
// from dreg
|
||||
vec = GetVecA32(reg >> 1);
|
||||
|
@ -107,6 +107,19 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
InsertScalar(context, op.Vd, emit(n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpI32(ArmEmitterContext context, Func2I emit)
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
OperandType type = (op.Size & 1) != 0 ? OperandType.I64 : OperandType.I32;
|
||||
|
||||
Operand n = ExtractScalar(context, type, op.Vn);
|
||||
Operand m = ExtractScalar(context, type, op.Vm);
|
||||
|
||||
InsertScalar(context, op.Vd, emit(n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarTernaryOpF32(ArmEmitterContext context, Func3I emit)
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
|
|
@ -481,6 +481,7 @@ namespace ARMeilleure.Instructions
|
|||
Mvn,
|
||||
Rsb,
|
||||
Rsc,
|
||||
Sbfx,
|
||||
Smlab,
|
||||
Smlal,
|
||||
Smmul,
|
||||
|
@ -519,12 +520,14 @@ namespace ARMeilleure.Instructions
|
|||
Vld4,
|
||||
Vldm,
|
||||
Vldr,
|
||||
VMMmn,
|
||||
Vmla,
|
||||
Vmls,
|
||||
Vmrs,
|
||||
Vmsr,
|
||||
Vmul,
|
||||
Vneg,
|
||||
Vsel,
|
||||
Vst1,
|
||||
Vst2,
|
||||
Vst3,
|
||||
|
|
|
@ -205,6 +205,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return MapSharedMemory(handle, address, size, permission);
|
||||
}
|
||||
|
||||
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission)
|
||||
{
|
||||
return MapSharedMemory(handle, address, size, permission);
|
||||
}
|
||||
|
||||
private KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
|
||||
{
|
||||
if (!PageAligned(address))
|
||||
|
@ -256,6 +261,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return UnmapSharedMemory(handle, address, size);
|
||||
}
|
||||
|
||||
public KernelResult UnmapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size)
|
||||
{
|
||||
return UnmapSharedMemory(handle, address, size);
|
||||
}
|
||||
|
||||
private KernelResult UnmapSharedMemory(int handle, ulong address, ulong size)
|
||||
{
|
||||
if (!PageAligned(address))
|
||||
|
|
|
@ -659,5 +659,16 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult FlushProcessDataCache32(
|
||||
[R(0)] uint processHandle,
|
||||
[R(2)] uint addressLow,
|
||||
[R(3)] uint addressHigh,
|
||||
[R(1)] uint sizeLow,
|
||||
[R(4)] uint sizeHigh)
|
||||
{
|
||||
_process.CpuMemory.WriteBytes(addressLow, new byte[sizeLow]);
|
||||
return KernelResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,16 +99,23 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{ 0x0d, nameof(SvcHandler.SetThreadPriority32) },
|
||||
{ 0x0f, nameof(SvcHandler.SetThreadCoreMask32) },
|
||||
{ 0x10, nameof(SvcHandler.GetCurrentProcessorNumber32) },
|
||||
{ 0x13, nameof(SvcHandler.MapSharedMemory32) },
|
||||
{ 0x14, nameof(SvcHandler.UnmapSharedMemory32) },
|
||||
{ 0x15, nameof(SvcHandler.CreateTransferMemory32) },
|
||||
{ 0x16, nameof(SvcHandler.CloseHandle32) },
|
||||
{ 0x18, nameof(SvcHandler.WaitSynchronization32) },
|
||||
{ 0x1a, nameof(SvcHandler.ArbitrateLock32) },
|
||||
{ 0x1b, nameof(SvcHandler.ArbitrateUnlock32) },
|
||||
{ 0x1c, nameof(SvcHandler.WaitProcessWideKeyAtomic32) },
|
||||
{ 0x1d, nameof(SvcHandler.SignalProcessWideKey32) },
|
||||
{ 0x1f, nameof(SvcHandler.ConnectToNamedPort32) },
|
||||
{ 0x21, nameof(SvcHandler.SendSyncRequest32) },
|
||||
{ 0x25, nameof(SvcHandler.GetThreadId32) },
|
||||
{ 0x26, nameof(SvcHandler.Break32) },
|
||||
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
|
||||
{ 0x29, nameof(SvcHandler.GetInfo32) }
|
||||
{ 0x29, nameof(SvcHandler.GetInfo32) },
|
||||
|
||||
{ 0x5F, nameof(SvcHandler.FlushProcessDataCache32) }
|
||||
};
|
||||
|
||||
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
|
||||
|
@ -126,8 +133,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
Dictionary<int, string> funcTable = aarch32 ? _svcFuncs32 : _svcFuncs64;
|
||||
if (funcTable.TryGetValue(svcId, out string svcName))
|
||||
{
|
||||
if (svcId == 0x08) { }
|
||||
|
||||
Action<SvcHandler, ExecutionContext> svcFunc;
|
||||
|
||||
if (aarch32)
|
||||
|
|
|
@ -76,6 +76,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
|
||||
}
|
||||
|
||||
public KernelResult ArbitrateLock32([R(0)] int ownerHandle, [R(1)] ulong mutexAddress, [R(2)] int requesterHandle)
|
||||
{
|
||||
return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
|
||||
}
|
||||
|
||||
private KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
|
||||
{
|
||||
if (IsPointingInsideKernel(mutexAddress))
|
||||
|
@ -98,6 +103,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return ArbitrateUnlock(mutexAddress);
|
||||
}
|
||||
|
||||
public KernelResult ArbitrateUnlock32([R(0)] uint mutexAddress)
|
||||
{
|
||||
return ArbitrateUnlock(mutexAddress);
|
||||
}
|
||||
|
||||
private KernelResult ArbitrateUnlock(ulong mutexAddress)
|
||||
{
|
||||
if (IsPointingInsideKernel(mutexAddress))
|
||||
|
@ -124,6 +134,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
|
||||
}
|
||||
|
||||
public KernelResult WaitProcessWideKeyAtomic32(
|
||||
[R(0)] uint mutexAddress,
|
||||
[R(1)] uint condVarAddress,
|
||||
[R(2)] int handle,
|
||||
[R(3)] uint timeoutLow,
|
||||
[R(4)] uint timeoutHigh)
|
||||
{
|
||||
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
|
||||
return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
|
||||
}
|
||||
|
||||
private KernelResult WaitProcessWideKeyAtomic(
|
||||
ulong mutexAddress,
|
||||
ulong condVarAddress,
|
||||
|
|
Loading…
Add table
Reference in a new issue