Fix incorrect opcode decoders and a few more instructions.

This commit is contained in:
Thog 2020-01-04 03:33:34 +01:00
parent 9e2e45f852
commit 8068eb23e5
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
10 changed files with 159 additions and 9 deletions

View 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
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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