Merge branch 'master' into features/crash-verification-ex

This commit is contained in:
kekkon 2023-06-14 18:02:56 +02:00 committed by GitHub
commit 87d19fba43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 427 additions and 112 deletions

8
.github/assign/audio.yml vendored Normal file
View file

@ -0,0 +1,8 @@
addReviewers: true
reviewers:
- marysaka
filterLabels:
include:
- audio

11
.github/assign/cpu.yml vendored Normal file
View file

@ -0,0 +1,11 @@
addReviewers: true
reviewers:
- gdkchan
- riperiperi
- marysaka
- LDj3SNuD
filterLabels:
include:
- cpu

4
.github/assign/global.yml vendored Normal file
View file

@ -0,0 +1,4 @@
addReviewers: true
reviewers:
- Ryujinx/developers

10
.github/assign/gpu.yml vendored Normal file
View file

@ -0,0 +1,10 @@
addReviewers: true
reviewers:
- gdkchan
- riperiperi
- marysaka
filterLabels:
include:
- gpu

11
.github/assign/gui.yml vendored Normal file
View file

@ -0,0 +1,11 @@
addReviewers: true
reviewers:
- Ack77
- emmauss
- TSRBerry
- marysaka
filterLabels:
include:
- gui

11
.github/assign/horizon.yml vendored Normal file
View file

@ -0,0 +1,11 @@
addReviewers: true
reviewers:
- gdkchan
- Ack77
- marysaka
- TSRBerry
filterLabels:
include:
- horizon

9
.github/assign/infra.yml vendored Normal file
View file

@ -0,0 +1,9 @@
addReviewers: true
reviewers:
- marysaka
- TSRBerry
filterLabels:
include:
- infra

33
.github/labeler.yml vendored Normal file
View file

@ -0,0 +1,33 @@
audio: 'src/Ryujinx.Audio*/**'
cpu:
- 'src/ARMeilleure/**'
- 'src/Ryujinx.Cpu/**'
- 'src/Ryujinx.Memory/**'
gpu:
- 'src/Ryujinx.Graphics.*/**'
- 'src/Spv.Generator/**'
- 'src/Ryujinx.ShaderTools/**'
'graphics-backend:opengl': 'src/Ryujinx.Graphics.OpenGL/**'
'graphics-backend:vulkan':
- 'src/Ryujinx.Graphics.Vulkan/**'
- 'src/Spv.Generator/**'
gui:
- 'src/Ryujinx/**'
- 'src/Ryujinx.Ui.Common/**'
- 'src/Ryujinx.Ui.LocaleGenerator/**'
- 'src/Ryujinx.Ava/**'
horizon:
- 'src/Ryujinx.HLE/**'
- 'src/Ryujinx.Horizon*/**'
kernel: 'src/Ryujinx.HLE/HOS/Kernel/**'
infra:
- '.github/**'
- 'distribution/**'
- 'Directory.Packages.props'

View file

@ -3,19 +3,13 @@ name: Build job
on:
workflow_dispatch:
inputs: {}
#push:
# branches: [ master ]
# paths-ignore:
# - '.github/*'
# - '.github/ISSUE_TEMPLATE/**'
# - '*.yml'
# - 'README.md'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/*'
- '.github/ISSUE_TEMPLATE/**'
- '.github/**'
- '*.yml'
- '*.json'
- '*.config'
- 'README.md'
concurrency:

54
.github/workflows/pr_triage.yml vendored Normal file
View file

@ -0,0 +1,54 @@
name: "Pull Request Triage"
on:
pull_request_target:
types: [opened, ready_for_review]
jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Update labels based on changes
uses: actions/labeler@v4
with:
sync-labels: true
dot: true
- name: Auto Assign [Audio]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/audio.yml'
- name: Auto Assign [CPU]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/cpu.yml'
- name: Auto Assign [GPU]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/gpu.yml'
- name: Auto Assign [GUI]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/gui.yml'
- name: Auto Assign [Horizon]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/horizon.yml'
- name: Auto Assign [Infra]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/infra.yml'
- name: Auto Assign [Global]
uses: kentaro-m/auto-assign-action@v1.2.5
with:
configuration-path: '.github/assign/global.yml'

View file

@ -6,9 +6,10 @@ on:
push:
branches: [ master ]
paths-ignore:
- '.github/*'
- '.github/ISSUE_TEMPLATE/**'
- '.github/**'
- '*.yml'
- '*.json'
- '*.config'
- 'README.md'
concurrency: release

View file

@ -165,7 +165,7 @@ namespace ARMeilleure.Instructions
{
Operand m = GetVecA32(op.Vm >> 1);
Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, doubleSize);
Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, true);
Intrinsic inst = (unsigned ? Intrinsic.Arm64FcvtzuGp : Intrinsic.Arm64FcvtzsGp) | Intrinsic.Arm64VDouble;
@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
}
else
{
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS);
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS, false);
}
}
else if (!roundWithFpscr && Optimizations.UseSse41)
@ -259,6 +259,41 @@ namespace ARMeilleure.Instructions
Intrinsic inst;
if (Optimizations.UseAdvSimd)
{
bool doubleSize = floatSize == OperandType.FP64;
if (doubleSize)
{
Operand m = GetVecA32(op.Vm >> 1);
Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, true);
if (unsigned)
{
inst = rm switch {
0b00 => Intrinsic.Arm64FcvtauGp,
0b01 => Intrinsic.Arm64FcvtnuGp,
0b10 => Intrinsic.Arm64FcvtpuGp,
0b11 => Intrinsic.Arm64FcvtmuGp,
_ => throw new ArgumentOutOfRangeException(nameof(rm))
};
}
else
{
inst = rm switch {
0b00 => Intrinsic.Arm64FcvtasGp,
0b01 => Intrinsic.Arm64FcvtnsGp,
0b10 => Intrinsic.Arm64FcvtpsGp,
0b11 => Intrinsic.Arm64FcvtmsGp,
_ => throw new ArgumentOutOfRangeException(nameof(rm))
};
}
Operand asInteger = context.AddIntrinsicInt(inst | Intrinsic.Arm64VDouble, toConvert);
InsertScalar(context, op.Vd, asInteger);
}
else
{
if (unsigned)
{
@ -283,6 +318,7 @@ namespace ARMeilleure.Instructions
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
}
}
else if (Optimizations.UseSse41)
{
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);

View file

@ -192,11 +192,10 @@ namespace ARMeilleure.Instructions
EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(inst, d, n, m));
}
public static void EmitScalarUnaryOpSimd32(ArmEmitterContext context, Func1I scalarFunc)
public static void EmitScalarUnaryOpSimd32(ArmEmitterContext context, Func1I scalarFunc, bool doubleSize)
{
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
bool doubleSize = (op.Size & 1) != 0;
int shift = doubleSize ? 1 : 2;
Operand m = GetVecA32(op.Vm >> shift);
Operand d = GetVecA32(op.Vd >> shift);
@ -215,8 +214,13 @@ namespace ARMeilleure.Instructions
{
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m));
EmitScalarUnaryOpF32(context, inst, (op.Size & 1) != 0);
}
public static void EmitScalarUnaryOpF32(ArmEmitterContext context, Intrinsic inst, bool doubleSize)
{
inst |= (doubleSize ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m), doubleSize);
}
public static void EmitScalarBinaryOpSimd32(ArmEmitterContext context, Func2I scalarFunc)

View file

@ -2,6 +2,7 @@ using ARMeilleure.CodeGen;
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Memory;
using ARMeilleure.Native;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -12,8 +13,8 @@ namespace ARMeilleure.Translation.Cache
{
static partial class JitCache
{
private const int PageSize = 4 * 1024;
private const int PageMask = PageSize - 1;
private static readonly int PageSize = (int)MemoryBlock.GetPageSize();
private static readonly int PageMask = PageSize - 1;
private const int CodeAlignment = 4; // Bytes.
private const int CacheSize = 2047 * 1024 * 1024;

View file

@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 5281; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 5292; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";

View file

@ -24,6 +24,24 @@ namespace Ryujinx.Common.Memory
return value;
}
public bool TryRead<T>(out T value) where T : unmanaged
{
int valueSize = Unsafe.SizeOf<T>();
if (valueSize > _input.Length)
{
value = default;
return false;
}
value = MemoryMarshal.Cast<byte, T>(_input)[0];
_input = _input.Slice(valueSize);
return true;
}
public ReadOnlySpan<byte> GetSpan(int size)
{
ReadOnlySpan<byte> data = _input.Slice(0, size);

View file

@ -154,7 +154,7 @@ namespace Ryujinx.HLE.HOS
}
private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId)
=> contentsDir.EnumerateDirectories($"{titleId}*", DirEnumOptions).FirstOrDefault();
=> contentsDir.EnumerateDirectories(titleId, DirEnumOptions).FirstOrDefault();
private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, string titleId)
{

View file

@ -1,8 +1,29 @@
namespace Ryujinx.HLE.HOS.Services.Hid
using Ryujinx.Common;
using Ryujinx.Common.Logging;
namespace Ryujinx.HLE.HOS.Services.Hid
{
[Service("hidbus")]
class IHidbusServer : IpcService
{
public IHidbusServer(ServiceCtx context) { }
[CommandCmif(1)]
// GetBusHandle(nn::hid::NpadIdType, nn::hidbus::BusType, nn::applet::AppletResourceUserId) -> (bool HasHandle, nn::hidbus::BusHandle)
public ResultCode GetBusHandle(ServiceCtx context)
{
NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadInt32();
context.RequestData.BaseStream.Position += 4; // Padding
BusType busType = (BusType)context.RequestData.ReadInt64();
long appletResourceUserId = context.RequestData.ReadInt64();
context.ResponseData.Write(false);
context.ResponseData.BaseStream.Position += 7; // Padding
context.ResponseData.WriteStruct(new BusHandle());
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { npadIdType, busType, appletResourceUserId });
return ResultCode.Success;
}
}
}

View file

@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Hid
{
[StructLayout(LayoutKind.Sequential)]
struct BusHandle
{
public int AbstractedPadId;
public byte InternalIndex;
public byte PlayerNumber;
public byte BusTypeId;
public byte IsValid;
}
}

View file

@ -0,0 +1,9 @@
namespace Ryujinx.HLE.HOS.Services.Hid
{
public enum BusType : long
{
LeftJoyRail = 0,
RightJoyRail = 1,
InternalBus = 2
}
}

View file

@ -75,7 +75,11 @@ namespace Ryujinx.Horizon.LogManager.Ipc
private bool LogImpl(ReadOnlySpan<byte> message)
{
SpanReader reader = new(message);
LogPacketHeader header = reader.Read<LogPacketHeader>();
if (!reader.TryRead(out LogPacketHeader header))
{
return true;
}
bool isHeadPacket = (header.Flags & LogPacketFlags.IsHead) != 0;
bool isTailPacket = (header.Flags & LogPacketFlags.IsTail) != 0;
@ -84,8 +88,10 @@ namespace Ryujinx.Horizon.LogManager.Ipc
while (reader.Length > 0)
{
int type = ReadUleb128(ref reader);
int size = ReadUleb128(ref reader);
if (!TryReadUleb128(ref reader, out int type) || !TryReadUleb128(ref reader, out int size))
{
return true;
}
LogDataChunkKey key = (LogDataChunkKey)type;
@ -101,15 +107,24 @@ namespace Ryujinx.Horizon.LogManager.Ipc
}
else if (key == LogDataChunkKey.Line)
{
_logPacket.Line = reader.Read<int>();
if (!reader.TryRead<int>(out _logPacket.Line))
{
return true;
}
}
else if (key == LogDataChunkKey.DropCount)
{
_logPacket.DropCount = reader.Read<long>();
if (!reader.TryRead<long>(out _logPacket.DropCount))
{
return true;
}
}
else if (key == LogDataChunkKey.Time)
{
_logPacket.Time = reader.Read<long>();
if (!reader.TryRead<long>(out _logPacket.Time))
{
return true;
}
}
else if (key == LogDataChunkKey.Message)
{
@ -154,23 +169,25 @@ namespace Ryujinx.Horizon.LogManager.Ipc
return isTailPacket;
}
private static int ReadUleb128(ref SpanReader reader)
private static bool TryReadUleb128(ref SpanReader reader, out int result)
{
int result = 0;
result = 0;
int count = 0;
byte encoded;
do
{
encoded = reader.Read<byte>();
if (!reader.TryRead<byte>(out encoded))
{
return false;
}
result += (encoded & 0x7F) << (7 * count);
count++;
} while ((encoded & 0x80) != 0);
return result;
return true;
}
}
}

View file

@ -7,7 +7,7 @@ namespace Ryujinx.Tests.Memory
{
public class Tests
{
private const ulong MemorySize = 0x8000;
private static readonly ulong MemorySize = MemoryBlock.GetPageSize() * 8;
private MemoryBlock _memoryBlock;
@ -44,14 +44,17 @@ namespace Ryujinx.Tests.Memory
[Platform(Exclude = "MacOsX")]
public void Test_Alias()
{
using MemoryBlock backing = new MemoryBlock(0x10000, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(0x10000, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
ulong pageSize = MemoryBlock.GetPageSize();
ulong blockSize = MemoryBlock.GetPageSize() * 16;
toAlias.MapView(backing, 0x1000, 0, 0x4000);
toAlias.UnmapView(backing, 0x3000, 0x1000);
using MemoryBlock backing = new MemoryBlock(blockSize, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(blockSize, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
toAlias.MapView(backing, pageSize, 0, pageSize * 4);
toAlias.UnmapView(backing, pageSize * 3, pageSize);
toAlias.Write(0, 0xbadc0de);
Assert.AreEqual(Marshal.ReadInt32(backing.Pointer, 0x1000), 0xbadc0de);
Assert.AreEqual(Marshal.ReadInt32(backing.Pointer, (int)pageSize), 0xbadc0de);
}
[Test]
@ -59,8 +62,12 @@ namespace Ryujinx.Tests.Memory
[Platform(Exclude = "MacOsX")]
public void Test_AliasRandom()
{
using MemoryBlock backing = new MemoryBlock(0x80000, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(0x80000, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
ulong pageSize = MemoryBlock.GetPageSize();
int pageBits = (int)ulong.Log2(pageSize);
ulong blockSize = MemoryBlock.GetPageSize() * 128;
using MemoryBlock backing = new MemoryBlock(blockSize, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(blockSize, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
Random rng = new Random(123);
@ -72,16 +79,16 @@ namespace Ryujinx.Tests.Memory
if ((rng.Next() & 1) != 0)
{
toAlias.MapView(backing, (ulong)srcPage << 12, (ulong)dstPage << 12, (ulong)pages << 12);
toAlias.MapView(backing, (ulong)srcPage << pageBits, (ulong)dstPage << pageBits, (ulong)pages << pageBits);
int offset = rng.Next(0, 0x1000 - sizeof(int));
int offset = rng.Next(0, (int)pageSize - sizeof(int));
toAlias.Write((ulong)((dstPage << 12) + offset), 0xbadc0de);
Assert.AreEqual(Marshal.ReadInt32(backing.Pointer, (srcPage << 12) + offset), 0xbadc0de);
toAlias.Write((ulong)((dstPage << pageBits) + offset), 0xbadc0de);
Assert.AreEqual(Marshal.ReadInt32(backing.Pointer, (srcPage << pageBits) + offset), 0xbadc0de);
}
else
{
toAlias.UnmapView(backing, (ulong)dstPage << 12, (ulong)pages << 12);
toAlias.UnmapView(backing, (ulong)dstPage << pageBits, (ulong)pages << pageBits);
}
}
}
@ -91,7 +98,7 @@ namespace Ryujinx.Tests.Memory
[Platform(Exclude = "MacOsX")]
public void Test_AliasMapLeak()
{
ulong pageSize = 4096;
ulong pageSize = MemoryBlock.GetPageSize();
ulong size = 100000 * pageSize; // The mappings limit on Linux is usually around 65K, so let's make sure we are above that.
using MemoryBlock backing = new MemoryBlock(pageSize, MemoryAllocationFlags.Mirrorable);

View file

@ -13,9 +13,9 @@ namespace Ryujinx.Tests.Cpu
[TestFixture]
public class CpuTest
{
protected const ulong Size = 0x1000;
protected const ulong CodeBaseAddress = 0x1000;
protected const ulong DataBaseAddress = CodeBaseAddress + Size;
protected static readonly ulong Size = MemoryBlock.GetPageSize();
protected static ulong CodeBaseAddress = Size;
protected static ulong DataBaseAddress = CodeBaseAddress + Size;
private static bool Ignore_FpcrFz = false;
private static bool Ignore_FpcrDn = false;
@ -39,12 +39,24 @@ namespace Ryujinx.Tests.Cpu
[SetUp]
public void Setup()
{
_currAddress = CodeBaseAddress;
int pageBits = (int)ulong.Log2(Size);
_ram = new MemoryBlock(Size * 2);
_memory = new MemoryManager(_ram, 1ul << 16);
_memory = new MemoryManager(_ram, 1ul << (pageBits + 4));
_memory.IncrementReferenceCount();
_memory.Map(CodeBaseAddress, 0, Size * 2, MemoryMapFlags.Private);
// Some tests depends on hardcoded address that were computed for 4KiB.
// We change the layout on non 4KiB platforms to keep compat here.
if (Size > 0x1000)
{
DataBaseAddress = 0;
CodeBaseAddress = Size;
}
_currAddress = CodeBaseAddress;
_memory.Map(CodeBaseAddress, 0, Size, MemoryMapFlags.Private);
_memory.Map(DataBaseAddress, Size, Size, MemoryMapFlags.Private);
_context = CpuContext.CreateExecutionContext();
Translator.IsReadyForTranslation.Set();

View file

@ -13,9 +13,9 @@ namespace Ryujinx.Tests.Cpu
[TestFixture]
public class CpuTest32
{
protected const uint Size = 0x1000;
protected const uint CodeBaseAddress = 0x1000;
protected const uint DataBaseAddress = CodeBaseAddress + Size;
protected static readonly uint Size = (uint)MemoryBlock.GetPageSize();
protected static uint CodeBaseAddress = Size;
protected static uint DataBaseAddress = CodeBaseAddress + Size;
private uint _currAddress;
@ -33,12 +33,24 @@ namespace Ryujinx.Tests.Cpu
[SetUp]
public void Setup()
{
_currAddress = CodeBaseAddress;
int pageBits = (int)ulong.Log2(Size);
_ram = new MemoryBlock(Size * 2);
_memory = new MemoryManager(_ram, 1ul << 16);
_memory = new MemoryManager(_ram, 1ul << (pageBits + 4));
_memory.IncrementReferenceCount();
_memory.Map(CodeBaseAddress, 0, Size * 2, MemoryMapFlags.Private);
// Some tests depends on hardcoded address that were computed for 4KiB.
// We change the layout on non 4KiB platforms to keep compat here.
if (Size > 0x1000)
{
DataBaseAddress = 0;
CodeBaseAddress = Size;
}
_currAddress = CodeBaseAddress;
_memory.Map(CodeBaseAddress, 0, Size, MemoryMapFlags.Private);
_memory.Map(DataBaseAddress, Size, Size, MemoryMapFlags.Private);
_context = CpuContext.CreateExecutionContext();
_context.IsAarch32 = true;

View file

@ -1,6 +1,7 @@
#define SimdMemory32
using ARMeilleure.State;
using Ryujinx.Memory;
using NUnit.Framework;
using System;
@ -9,6 +10,7 @@ namespace Ryujinx.Tests.Cpu
[Category("SimdMemory32")]
public sealed class CpuTestSimdMemory32 : CpuTest32
{
private static readonly uint TestOffset = DataBaseAddress + 0x500;
#if SimdMemory32
private uint[] _ldStModes =
@ -42,7 +44,7 @@ namespace Ryujinx.Tests.Cpu
[Range(0u, 3u)] uint n,
[Values(0x0u)] uint offset)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
uint opcode = 0xf4a00000u; // VLD1.8 {D0[0]}, [R0], R0
@ -58,7 +60,7 @@ namespace Ryujinx.Tests.Cpu
opcode |= (n & 3) << 8; // LD1 is 0, LD2 is 1 etc.
SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
SingleOpcode(opcode, r0: TestOffset, r1: offset, sp: TestOffset);
CompareAgainstUnicorn();
}
@ -72,7 +74,7 @@ namespace Ryujinx.Tests.Cpu
[Values] bool t,
[Values(0x0u)] uint offset)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
uint opcode = 0xf4a00c00u; // VLD1.8 {D0[0]}, [R0], R0
@ -85,7 +87,7 @@ namespace Ryujinx.Tests.Cpu
opcode |= (n & 3) << 8; // LD1 is 0, LD2 is 1 etc.
if (t) opcode |= 1 << 5;
SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
SingleOpcode(opcode, r0: TestOffset, r1: offset, sp: TestOffset);
CompareAgainstUnicorn();
}
@ -98,7 +100,7 @@ namespace Ryujinx.Tests.Cpu
[Range(0u, 10u)] uint mode,
[Values(0x0u)] uint offset)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
uint opcode = 0xf4200000u; // VLD4.8 {D0, D1, D2, D3}, [R0], R0
@ -114,7 +116,7 @@ namespace Ryujinx.Tests.Cpu
opcode |= ((vd & 0x10) << 18);
opcode |= ((vd & 0xf) << 12);
SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
SingleOpcode(opcode, r0: TestOffset, r1: offset, sp: TestOffset);
CompareAgainstUnicorn();
}
@ -128,7 +130,7 @@ namespace Ryujinx.Tests.Cpu
[Range(0u, 3u)] uint n,
[Values(0x0u)] uint offset)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
(V128 vec1, V128 vec2, V128 vec3, V128 vec4) = GenerateTestVectors();
@ -146,7 +148,7 @@ namespace Ryujinx.Tests.Cpu
opcode |= (n & 3) << 8; // ST1 is 0, ST2 is 1 etc.
SingleOpcode(opcode, r0: 0x2500, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: 0x2500);
SingleOpcode(opcode, r0: TestOffset, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: TestOffset);
CompareAgainstUnicorn();
}
@ -159,7 +161,7 @@ namespace Ryujinx.Tests.Cpu
[Range(0u, 10u)] uint mode,
[Values(0x0u)] uint offset)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
(V128 vec1, V128 vec2, V128 vec3, V128 vec4) = GenerateTestVectors();
@ -177,7 +179,7 @@ namespace Ryujinx.Tests.Cpu
opcode |= ((vd & 0x10) << 18);
opcode |= ((vd & 0xf) << 12);
SingleOpcode(opcode, r0: 0x2500, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: 0x2500);
SingleOpcode(opcode, r0: TestOffset, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: TestOffset);
CompareAgainstUnicorn();
}
@ -189,7 +191,7 @@ namespace Ryujinx.Tests.Cpu
[Values(0x1u, 0x32u)] uint regs,
[Values] bool single)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
uint opcode = 0xec100a00u; // VST4.8 {D0, D1, D2, D3}, [R0], R0
@ -225,7 +227,7 @@ namespace Ryujinx.Tests.Cpu
opcode |= regs & 0xff;
SingleOpcode(opcode, r0: 0x2500, sp: 0x2500);
SingleOpcode(opcode, r0: TestOffset, sp: TestOffset);
CompareAgainstUnicorn();
}
@ -237,7 +239,7 @@ namespace Ryujinx.Tests.Cpu
[Values(0x0u)] uint imm,
[Values] bool sub)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
uint opcode = 0xed900a00u; // VLDR.32 S0, [R0, #0]
@ -260,7 +262,7 @@ namespace Ryujinx.Tests.Cpu
}
opcode |= imm & 0xff;
SingleOpcode(opcode, r0: 0x2500);
SingleOpcode(opcode, r0: TestOffset);
CompareAgainstUnicorn();
}
@ -272,7 +274,7 @@ namespace Ryujinx.Tests.Cpu
[Values(0x0u)] uint imm,
[Values] bool sub)
{
var data = GenerateVectorSequence(0x1000);
var data = GenerateVectorSequence((int)MemoryBlock.GetPageSize());
SetWorkingMemory(0, data);
uint opcode = 0xed800a00u; // VSTR.32 S0, [R0, #0]
@ -297,7 +299,7 @@ namespace Ryujinx.Tests.Cpu
(V128 vec1, V128 vec2, _, _) = GenerateTestVectors();
SingleOpcode(opcode, r0: 0x2500, v0: vec1, v1: vec2);
SingleOpcode(opcode, r0: TestOffset, v0: vec1, v1: vec2);
CompareAgainstUnicorn();
}

View file

@ -3,6 +3,7 @@
using ARMeilleure.State;
using NUnit.Framework;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Ryujinx.Tests.Cpu
{
@ -703,6 +704,11 @@ namespace Ryujinx.Tests.Cpu
[Values] bool q,
[Values] bool u)
{
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
Assert.Ignore("Unicorn on ARM64 crash while executing this test");
}
uint opcode = 0xf2000400u; // VSHL.S8 D0, D0, D0
if (q)
{

View file

@ -109,7 +109,7 @@ namespace Ryujinx.Tests.Cpu
ExecuteOpcodes(runUnicorn: false);
Assert.That(GetContext().GetX(0), Is.EqualTo(0x1005));
Assert.That(GetContext().GetX(0), Is.EqualTo(CodeBaseAddress + 0x5));
}
[Test]
@ -133,7 +133,7 @@ namespace Ryujinx.Tests.Cpu
ExecuteOpcodes(runUnicorn: false);
Assert.That(GetContext().GetX(0), Is.EqualTo(0x1005));
Assert.That(GetContext().GetX(0), Is.EqualTo(CodeBaseAddress + 0x5));
Assert.That(GetContext().GetPstateFlag(PState.TFlag), Is.EqualTo(false));
}
@ -160,7 +160,7 @@ namespace Ryujinx.Tests.Cpu
ExecuteOpcodes(runUnicorn: false);
Assert.That(GetContext().GetX(0), Is.EqualTo(0x1007));
Assert.That(GetContext().GetX(0), Is.EqualTo(CodeBaseAddress + 0x7));
Assert.That(GetContext().GetPstateFlag(PState.TFlag), Is.EqualTo(false));
}
}

View file

@ -268,6 +268,12 @@ namespace Ryujinx.Tests.Cpu
[Test]
public void TestRandomTestCases([ValueSource(nameof(RandomTestCases))] PrecomputedThumbTestCase test)
{
if (Size != 0x1000)
{
// TODO: Change it to depend on DataBaseAddress instead.
Assert.Ignore("This test currently only support 4KiB page size");
}
RunPrecomputedTestCase(test);
}

View file

@ -11,10 +11,10 @@ namespace Ryujinx.Ui.Common.Helper
{
public static partial class FileAssociationHelper
{
private static string[] _fileExtensions = new string[] { ".nca", ".nro", ".nso", ".nsp", ".xci" };
private static readonly string[] _fileExtensions = { ".nca", ".nro", ".nso", ".nsp", ".xci" };
[SupportedOSPlatform("linux")]
private static string _mimeDbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "mime");
private static readonly string _mimeDbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "mime");
private const int SHCNE_ASSOCCHANGED = 0x8000000;
private const int SHCNF_FLUSH = 0x1000;
@ -32,7 +32,7 @@ namespace Ryujinx.Ui.Common.Helper
{
string installKeyword = uninstall ? "uninstall" : "install";
if (!AreMimeTypesRegisteredLinux())
if ((uninstall && AreMimeTypesRegisteredLinux()) || (!uninstall && !AreMimeTypesRegisteredLinux()))
{
string mimeTypesFile = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "mime", "Ryujinx.xml");
string additionalArgs = !uninstall ? "--novendor" : "";
@ -81,9 +81,9 @@ namespace Ryujinx.Ui.Common.Helper
return false;
}
key.OpenSubKey(@"shell\open\command");
var openCmd = key.OpenSubKey(@"shell\open\command");
string keyValue = (string)key.GetValue("");
string keyValue = (string)openCmd.GetValue("");
return keyValue is not null && (keyValue.Contains("Ryujinx") || keyValue.Contains(AppDomain.CurrentDomain.FriendlyName));
}
@ -107,30 +107,31 @@ namespace Ryujinx.Ui.Common.Helper
if (uninstall)
{
// If the types don't already exist, there's nothing to do and we can call this operation successful.
if (!AreMimeTypesRegisteredWindows())
{
return false;
return true;
}
Logger.Debug?.Print(LogClass.Application, $"Removing type association {ext}");
Registry.CurrentUser.DeleteSubKeyTree(keyString);
Logger.Debug?.Print(LogClass.Application, $"Removed type association {ext}");
}
else
{
RegistryKey key = Registry.CurrentUser.CreateSubKey(keyString);
using var key = Registry.CurrentUser.CreateSubKey(keyString);
if (key is null)
{
return false;
}
key.CreateSubKey(@"shell\open\command");
Logger.Debug?.Print(LogClass.Application, $"Adding type association {ext}");
using var openCmd = key.CreateSubKey(@"shell\open\command");
openCmd.SetValue("", $"\"{Environment.ProcessPath}\" \"%1\"");
Logger.Debug?.Print(LogClass.Application, $"Added type association {ext}");
key.SetValue("", $"\"{Environment.ProcessPath}\" \"%1\"");
key.Close();
}
// Notify Explorer the file association has been changed.
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
return true;
}
@ -141,6 +142,9 @@ namespace Ryujinx.Ui.Common.Helper
registered |= RegisterExtension(ext, uninstall);
}
// Notify Explorer the file association has been changed.
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
return registered;
}