From 3d9d492b228908cb455a7eedebd74d83c4121114 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Sat, 11 Jan 2020 23:48:47 +0000 Subject: [PATCH] Implement some more instructions, fix others. Uxtab16/Sxtab16 are untested. --- ARMeilleure/Decoders/OpCode32AluMla.cs | 2 + ARMeilleure/Decoders/OpCodeTable.cs | 13 +++- ARMeilleure/Instructions/InstEmitAlu32.cs | 66 +++++++++++++++++++ .../Instructions/InstEmitMemoryEx32.cs | 2 +- ARMeilleure/Instructions/InstEmitMul32.cs | 32 +++++++-- .../Instructions/InstEmitSimdArithmetic32.cs | 52 +++++++++++++-- ARMeilleure/Instructions/InstName.cs | 6 ++ .../HOS/Kernel/SupervisorCall/SvcSystem.cs | 5 ++ .../HOS/Kernel/SupervisorCall/SvcTable.cs | 1 + 9 files changed, 169 insertions(+), 10 deletions(-) diff --git a/ARMeilleure/Decoders/OpCode32AluMla.cs b/ARMeilleure/Decoders/OpCode32AluMla.cs index d774666d79..1c87226a32 100644 --- a/ARMeilleure/Decoders/OpCode32AluMla.cs +++ b/ARMeilleure/Decoders/OpCode32AluMla.cs @@ -13,6 +13,7 @@ namespace ARMeilleure.Decoders public bool NHigh { get; private set; } public bool MHigh { get; private set; } + public bool R { get; private set; } public bool SetFlags { get; private set; } public OpCode32AluMla(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) @@ -21,6 +22,7 @@ namespace ARMeilleure.Decoders Rm = (opCode >> 8) & 0xf; Ra = (opCode >> 12) & 0xf; Rd = (opCode >> 16) & 0xf; + R = (opCode & (1 << 5)) != 0; NHigh = ((opCode >> 5) * 0x1) == 1; MHigh = ((opCode >> 6) * 0x1) == 1; diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index a41286f53b..15d72077b7 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -652,7 +652,9 @@ namespace ARMeilleure.Decoders SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemImm8)); SetA32("<<<<000xx0x1xxxxxxxx00001011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemReg)); SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, InstEmit32.Ldrsb, typeof(OpCode32MemImm8)); + SetA32("<<<<000xx0x1xxxxxxxx00001101xxxx", InstName.Ldrsb, InstEmit32.Ldrsb, typeof(OpCode32MemReg)); SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, InstEmit32.Ldrsh, typeof(OpCode32MemImm8)); + SetA32("<<<<000xx0x1xxxxxxxx00001111xxxx", InstName.Ldrsh, InstEmit32.Ldrsh, typeof(OpCode32MemReg)); SetA32("<<<<1110xxx0xxxxxxxx111xxxx1xxxx", InstName.Mcr, InstEmit32.Mcr, typeof(OpCode32System)); SetA32("<<<<0000001xxxxxxxxxxxxx1001xxxx", InstName.Mla, InstEmit32.Mla, typeof(OpCode32AluMla)); SetA32("<<<<00000110xxxxxxxxxxxx1001xxxx", InstName.Mls, InstEmit32.Mls, typeof(OpCode32AluMla)); @@ -688,7 +690,8 @@ namespace ARMeilleure.Decoders SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smlab, InstEmit32.Smlab, typeof(OpCode32AluMla)); 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("<<<<01110101xxxxxxxxxxxx00x1xxxx", InstName.Smmla, InstEmit32.Smmla, typeof(OpCode32AluMla)); + SetA32("<<<<01110101xxxxxxxxxxxx11x1xxxx", InstName.Smmls, InstEmit32.Smmls, typeof(OpCode32AluMla)); SetA32("<<<<0010110xxxxxxxxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluImm)); SetA32("<<<<0000110xxxxxxxxxxxxxxxx0xxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluRsImm)); SetA32("<<<<0000110xxxxxxxxxxxxx0xx1xxxx", InstName.Sbc, InstEmit32.Sbc, typeof(OpCode32AluRsReg)); @@ -719,6 +722,7 @@ namespace ARMeilleure.Decoders 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("<<<<01101000xxxxxxxxxx000111xxxx", InstName.Sxtb16,InstEmit32.Sxtb16,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)); @@ -731,6 +735,7 @@ namespace ARMeilleure.Decoders SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, typeof(OpCode32AluMla)); SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, typeof(OpCode32AluUmull)); SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, typeof(OpCode32AluUx)); + SetA32("<<<<01101100xxxxxxxxxx000111xxxx", InstName.Uxtb16,InstEmit32.Uxtb16,typeof(OpCode32AluUx)); SetA32("<<<<01101111xxxxxxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, typeof(OpCode32AluUx)); // FP & SIMD (AArch32) @@ -805,6 +810,12 @@ namespace ARMeilleure.Decoders SetA32("<<<<1101xx01xxxxxxxx10xxxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, typeof(OpCode32SimdMemImm)); + SetA32("111100100x0xxxxxxxxx1111xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_V, typeof(OpCode32SimdReg)); + SetA32("1111001x0xxxxxxxxxxx0110xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_I, typeof(OpCode32SimdReg)); + + SetA32("111100100x1xxxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, typeof(OpCode32SimdReg)); + SetA32("1111001x0xxxxxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, typeof(OpCode32SimdReg)); + SetA32("111111101x00xxxxxxxx10xxxxx0xxxx", InstName.VMMmn, InstEmit32.VmaxminNm_S, typeof(OpCode32SimdRegS)); SetA32("111100110xxxxxxxxxxx1111xxx1xxxx", InstName.VMMmn, InstEmit32.VmaxminNm_V, typeof(OpCode32SimdReg)); diff --git a/ARMeilleure/Instructions/InstEmitAlu32.cs b/ARMeilleure/Instructions/InstEmitAlu32.cs index 49ab949505..c9387c03e1 100644 --- a/ARMeilleure/Instructions/InstEmitAlu32.cs +++ b/ARMeilleure/Instructions/InstEmitAlu32.cs @@ -322,11 +322,72 @@ namespace ARMeilleure.Instructions EmitAluStore(context, res); } + private static void EmitExtend16(ArmEmitterContext context, bool signed) + { + IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp; + + Operand m = GetAluM(context); + Operand res; + + if (op.RotateBits == 0) + { + res = m; + } + else + { + Operand rotate = Const(op.RotateBits); + res = context.RotateRight(m, rotate); + } + + Operand low16, high16; + if (signed) + { + low16 = context.SignExtend8(OperandType.I32, res); + high16 = context.SignExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); + } + else + { + low16 = context.ZeroExtend8(OperandType.I32, res); + high16 = context.ZeroExtend8(OperandType.I32, context.ShiftRightUI(res, Const(16))); + } + + if (op.Add) + { + Operand n = GetAluN(context); + Operand lowAdd, highAdd; + if (signed) + { + lowAdd = context.SignExtend16(OperandType.I32, n); + highAdd = context.SignExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); + } + else + { + lowAdd = context.ZeroExtend16(OperandType.I32, n); + highAdd = context.ZeroExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16))); + } + + low16 = context.Add(low16, lowAdd); + high16 = context.Add(high16, highAdd); + } + + res = context.BitwiseOr( + context.ZeroExtend16(OperandType.I32, low16), + context.ShiftLeft(context.ZeroExtend16(OperandType.I32, high16), Const(16)) + ); + + EmitAluStore(context, res); + } + public static void Uxtb(ArmEmitterContext context) { EmitSignExtend(context, false, 8); } + public static void Uxtb16(ArmEmitterContext context) + { + EmitExtend16(context, false); + } + public static void Uxth(ArmEmitterContext context) { EmitSignExtend(context, false, 16); @@ -337,6 +398,11 @@ namespace ARMeilleure.Instructions EmitSignExtend(context, true, 8); } + public static void Sxtb16(ArmEmitterContext context) + { + EmitExtend16(context, true); + } + public static void Sxth(ArmEmitterContext context) { EmitSignExtend(context, true, 16); diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs index 764c9cf0b8..fd9850785d 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs @@ -71,7 +71,7 @@ namespace ARMeilleure.Instructions public static void Ldah(ArmEmitterContext context) { - EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Ordered); + EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Ordered); } // stores diff --git a/ARMeilleure/Instructions/InstEmitMul32.cs b/ARMeilleure/Instructions/InstEmitMul32.cs index 1ed9c1347d..ac9cbffcf6 100644 --- a/ARMeilleure/Instructions/InstEmitMul32.cs +++ b/ARMeilleure/Instructions/InstEmitMul32.cs @@ -15,9 +15,9 @@ namespace ARMeilleure.Instructions [Flags] private enum MullFlags { - Subtract = 0, - Add = 1 << 0, - Signed = 1 << 1, + Subtract = 1, + Add = 1 << 1, + Signed = 1 << 2, SignedAdd = Signed | Add, SignedSubtract = Signed | Subtract @@ -44,7 +44,22 @@ namespace ARMeilleure.Instructions EmitGenericStore(context, op.RdLo, op.SetFlags, lo); } + public static void Smmla(ArmEmitterContext context) + { + EmitSmmul(context, MullFlags.SignedAdd); + } + + public static void Smmls(ArmEmitterContext context) + { + EmitSmmul(context, MullFlags.SignedSubtract); + } + public static void Smmul(ArmEmitterContext context) + { + EmitSmmul(context, MullFlags.Signed); + } + + private static void EmitSmmul(ArmEmitterContext context, MullFlags flags) { OpCode32AluMla op = (OpCode32AluMla)context.CurrOp; @@ -53,7 +68,16 @@ namespace ARMeilleure.Instructions Operand res = context.Multiply(n, m); - if ((op.RawOpCode & (1 << 5)) != 0) + if (flags.HasFlag(MullFlags.Add) && op.Ra != 0xf) + { + res = context.Add(context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Ra)), Const(32)), res); + } + else if (flags.HasFlag(MullFlags.Subtract)) + { + res = context.Subtract(context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Ra)), Const(32)), res); + } + + if (op.R) { res = context.Add(res, Const(0x80000000L)); } diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs index 4196452f0a..282aec2769 100644 --- a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs @@ -163,21 +163,65 @@ namespace ARMeilleure.Instructions } } + public static void Vmax_V(ArmEmitterContext context) + { + EmitVectorBinaryOpF32(context, (op1, op2) => + { + return EmitSoftFloatCall(context, SoftFloat32.FPMax, SoftFloat64.FPMax, op1, op2); + }); + } + + public static void Vmax_I(ArmEmitterContext context) + { + OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; + if (op.U) + { + EmitVectorBinaryOpZx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareGreaterUI(op1, op2), op1, op2)); + } + else + { + EmitVectorBinaryOpSx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareGreater(op1, op2), op1, op2)); + } + } + + public static void Vmin_V(ArmEmitterContext context) + { + EmitVectorBinaryOpF32(context, (op1, op2) => + { + return EmitSoftFloatCall(context, SoftFloat32.FPMin, SoftFloat64.FPMin, op1, op2); + }); + } + + public static void Vmin_I(ArmEmitterContext context) + { + OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; + if (op.U) + { + EmitVectorBinaryOpZx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareLessUI(op1, op2), op1, op2)); + } + else + { + EmitVectorBinaryOpSx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareLess(op1, op2), op1, op2)); + } + } + //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); + _F32_F32_F32 f32 = max ? new _F32_F32_F32(SoftFloat32.FPMaxNum) : new _F32_F32_F32(SoftFloat32.FPMinNum); + _F64_F64_F64 f64 = max ? new _F64_F64_F64(SoftFloat64.FPMaxNum) : new _F64_F64_F64(SoftFloat64.FPMinNum); - EmitScalarBinaryOpF32(context, (op1, op2) => context.Call(dlg, op1, op2)); + EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, f32, f64, 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); + _F32_F32_F32 f32 = max ? new _F32_F32_F32(SoftFloat32.FPMaxNum) : new _F32_F32_F32(SoftFloat32.FPMinNum); + _F64_F64_F64 f64 = max ? new _F64_F64_F64(SoftFloat64.FPMaxNum) : new _F64_F64_F64(SoftFloat64.FPMinNum); - EmitVectorBinaryOpSx32(context, (op1, op2) => context.Call(dlg, op1, op2)); + EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCall(context, f32, f64, op1, op2)); } public static void Vmul_S(ArmEmitterContext context) diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs index 7c69528357..64cd95aa76 100644 --- a/ARMeilleure/Instructions/InstName.cs +++ b/ARMeilleure/Instructions/InstName.cs @@ -489,6 +489,8 @@ namespace ARMeilleure.Instructions Smlab, Smlal, Smlalh, + Smmla, + Smmls, Smmul, Stl, Stlb, @@ -505,12 +507,14 @@ namespace ARMeilleure.Instructions Strexd, Strexh, Strh, + Sxtb16, Teq, Trap, Tst, Ubfx, Umull, Uxtb, + Uxtb16, Uxth, // FP & SIMD (AArch32) @@ -532,6 +536,8 @@ namespace ARMeilleure.Instructions Vld4, Vldm, Vldr, + Vmax, + Vmin, VMMmn, Vmla, Vmls, diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs index 2e4ba038e6..4fbda07db7 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs @@ -149,6 +149,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return ResetSignal(handle); } + public KernelResult ResetSignal32([R(0)] int handle) + { + return ResetSignal(handle); + } + private KernelResult ResetSignal(int handle) { KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs index 980f20a064..3a356ad8c4 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs @@ -103,6 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { 0x14, nameof(SvcHandler.UnmapSharedMemory32) }, { 0x15, nameof(SvcHandler.CreateTransferMemory32) }, { 0x16, nameof(SvcHandler.CloseHandle32) }, + { 0x17, nameof(SvcHandler.ResetSignal32) }, { 0x18, nameof(SvcHandler.WaitSynchronization32) }, { 0x1a, nameof(SvcHandler.ArbitrateLock32) }, { 0x1b, nameof(SvcHandler.ArbitrateUnlock32) },