Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a5a9b9bc8b | ||
|
17078ad929 | ||
|
32450d45de | ||
|
ed7a0474c6 | ||
|
fe9c49949a | ||
|
052b23c83c | ||
|
e4f68592c3 | ||
|
1dcd44b94f | ||
|
61b1ce252f | ||
|
5f38086f94 | ||
|
7bae440d3a | ||
|
f1943fd0b6 | ||
|
ec8d4f3af5 | ||
|
b3f0978869 | ||
|
f614d2c435 | ||
|
40c9416097 | ||
|
618c8edc79 | ||
|
99fc4fa61b | ||
|
f6d5499a16 | ||
|
26bf13a65d | ||
|
96cf242bcf | ||
|
59755818ef |
57
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
57
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,31 +1,27 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the bug you encountered.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: Description of Issue
|
||||
label: Description of the issue
|
||||
description: What's the issue you encountered?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
label: Reproduction steps
|
||||
description: How can the issue be reproduced?
|
||||
placeholder: Describe each step as precisely as possible
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
label: Log File
|
||||
label: Log file
|
||||
description: A log file will help our developers to better diagnose and fix the issue.
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
|
||||
validations:
|
||||
@@ -34,36 +30,51 @@ body:
|
||||
id: os
|
||||
attributes:
|
||||
label: OS
|
||||
placeholder: "Example: Windows 10"
|
||||
placeholder: "e.g. Windows 10"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: ryujinx-version
|
||||
attributes:
|
||||
label: Ryujinx version
|
||||
placeholder: |
|
||||
- *(e.g. 1.0.470)*
|
||||
placeholder: "e.g. 1.0.470"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: game-version
|
||||
attributes:
|
||||
label: Game version
|
||||
placeholder: |
|
||||
- *(e.g. 1.1.1)*
|
||||
placeholder: "e.g. 1.1.1"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "e.g. i7-6700"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "e.g. NVIDIA RTX 2070"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: ram
|
||||
attributes:
|
||||
label: RAM
|
||||
placeholder: "e.g. 16GB"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: environment
|
||||
id: mods
|
||||
attributes:
|
||||
label: Environment?
|
||||
value: |
|
||||
- ##### CPU: *(e.g. i7-6700)*
|
||||
- ##### GPU: *(e.g. NVIDIA RTX 2070)*
|
||||
- ##### RAM: *(e.g. 16GB)*
|
||||
- Applied Mods: [ Yes (Which ones) / No ]
|
||||
label: List of applied mods
|
||||
placeholder: You can list applied mods here.
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
|
12
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
12
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,13 +1,7 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature for Ryujinx.
|
||||
title: "[Feature Request]"
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the feature you are requesting.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
id: overview
|
||||
attributes:
|
||||
@@ -18,14 +12,14 @@ body:
|
||||
- type: textarea
|
||||
id: details
|
||||
attributes:
|
||||
label: Smaller Details
|
||||
label: Smaller details
|
||||
description: These may include specific methods of implementation etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
label: Nature of Request
|
||||
label: Nature of request
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
@@ -1,13 +1,8 @@
|
||||
name: Missing CPU Instruction
|
||||
description: CPU Instruction is missing in Ryujinx.
|
||||
title: "[CPU]"
|
||||
labels: [cpu, not-implemented]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search for existing missing CPU instruction
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
|
10
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
10
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
@@ -1,17 +1,11 @@
|
||||
name: Missing Service Call
|
||||
description: Service call is missing in Ryujinx.
|
||||
labels: not-implemented
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search for an [existing missing service call issue](https://github.com/Ryujinx/Ryujinx/issues) first.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: Service Call
|
||||
label: Service call
|
||||
description: What service call is missing?
|
||||
validations:
|
||||
required: true
|
||||
|
@@ -44,11 +44,12 @@
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.26.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.26.1" />
|
||||
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-9c9356d" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -53,7 +53,6 @@ using Key = Ryujinx.Input.Key;
|
||||
using MouseButton = Ryujinx.Input.MouseButton;
|
||||
using Size = Avalonia.Size;
|
||||
using Switch = Ryujinx.HLE.Switch;
|
||||
using WindowState = Avalonia.Controls.WindowState;
|
||||
|
||||
namespace Ryujinx.Ava
|
||||
{
|
||||
@@ -766,7 +765,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void RenderLoop()
|
||||
private void RenderLoop()
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
@@ -802,6 +801,8 @@ namespace Ryujinx.Ava
|
||||
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
||||
Translator.IsReadyForTranslation.Set();
|
||||
|
||||
_renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync);
|
||||
|
||||
while (_isActive)
|
||||
{
|
||||
_ticks += _chrono.ElapsedTicks;
|
||||
|
@@ -132,8 +132,8 @@ namespace Ryujinx.Modules
|
||||
}
|
||||
}
|
||||
|
||||
// If build not done, assume no new update are availaible.
|
||||
if (_buildUrl == null)
|
||||
// If build not done, assume no new update are available.
|
||||
if (_buildUrl is null)
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
@@ -240,13 +240,13 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
HttpClient result = new();
|
||||
|
||||
// Required by GitHub to interract with APIs.
|
||||
// Required by GitHub to interact with APIs.
|
||||
result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async void UpdateRyujinx(Window parent, string downloadUrl)
|
||||
private static async void UpdateRyujinx(Window parent, string downloadUrl)
|
||||
{
|
||||
_updateSuccessful = false;
|
||||
|
||||
@@ -300,8 +300,6 @@ namespace Ryujinx.Modules
|
||||
ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx");
|
||||
}
|
||||
|
||||
SetFileExecutable(ryuExe);
|
||||
|
||||
Process.Start(ryuExe, CommandLineState.Arguments);
|
||||
|
||||
Environment.Exit(0);
|
||||
@@ -408,9 +406,9 @@ namespace Ryujinx.Modules
|
||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
for (int j = 0; j < webClients.Count; j++)
|
||||
foreach (WebClient webClient in webClients)
|
||||
{
|
||||
webClients[j].CancelAsync();
|
||||
webClient.CancelAsync();
|
||||
}
|
||||
|
||||
DoUpdateWithSingleThread(taskDialog, downloadUrl, updateFile);
|
||||
@@ -472,22 +470,6 @@ namespace Ryujinx.Modules
|
||||
worker.Start();
|
||||
}
|
||||
|
||||
private static void SetFileExecutable(string path)
|
||||
{
|
||||
const UnixFileMode ExecutableFileMode = UnixFileMode.UserExecute |
|
||||
UnixFileMode.UserWrite |
|
||||
UnixFileMode.UserRead |
|
||||
UnixFileMode.GroupRead |
|
||||
UnixFileMode.GroupWrite |
|
||||
UnixFileMode.OtherRead |
|
||||
UnixFileMode.OtherWrite;
|
||||
|
||||
if (!OperatingSystem.IsWindows() && File.Exists(path))
|
||||
{
|
||||
File.SetUnixFileMode(path, ExecutableFileMode);
|
||||
}
|
||||
}
|
||||
|
||||
private static async void InstallUpdate(TaskDialog taskDialog, string updateFile)
|
||||
{
|
||||
// Extract Update
|
||||
@@ -503,27 +485,30 @@ namespace Ryujinx.Modules
|
||||
await Task.Run(() =>
|
||||
{
|
||||
TarEntry tarEntry;
|
||||
while ((tarEntry = tarStream.GetNextEntry()) != null)
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
if (tarEntry.IsDirectory) continue;
|
||||
|
||||
string outPath = Path.Combine(UpdateDir, tarEntry.Name);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||
|
||||
using (FileStream outStream = File.OpenWrite(outPath))
|
||||
while ((tarEntry = tarStream.GetNextEntry()) is not null)
|
||||
{
|
||||
tarStream.CopyEntryContents(outStream);
|
||||
if (tarEntry.IsDirectory) continue;
|
||||
|
||||
string outPath = Path.Combine(UpdateDir, tarEntry.Name);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||
|
||||
using (FileStream outStream = File.OpenWrite(outPath))
|
||||
{
|
||||
tarStream.CopyEntryContents(outStream);
|
||||
}
|
||||
|
||||
File.SetUnixFileMode(outPath, (UnixFileMode)tarEntry.TarHeader.Mode);
|
||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
taskDialog.SetProgressBarState(GetPercentage(tarEntry.Size, inStream.Length), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
|
||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
||||
|
||||
TarEntry entry = tarEntry;
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
taskDialog.SetProgressBarState(GetPercentage(entry.Size, inStream.Length), TaskDialogProgressState.Normal);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -603,8 +588,6 @@ namespace Ryujinx.Modules
|
||||
|
||||
Directory.Delete(UpdateDir, true);
|
||||
|
||||
SetFileExecutable(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"));
|
||||
|
||||
_updateSuccessful = true;
|
||||
|
||||
taskDialog.Hide();
|
||||
|
@@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
static partial class MetalHelper
|
||||
{
|
||||
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
|
||||
|
||||
private struct Selector
|
||||
{
|
||||
public readonly IntPtr NativePtr;
|
||||
|
||||
public unsafe Selector(string value)
|
||||
{
|
||||
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||
byte* data = stackalloc byte[size];
|
||||
|
||||
fixed (char* pValue = value)
|
||||
{
|
||||
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||
}
|
||||
|
||||
NativePtr = sel_registerName(data);
|
||||
}
|
||||
|
||||
public static implicit operator Selector(string value) => new Selector(value);
|
||||
}
|
||||
|
||||
private static unsafe IntPtr GetClass(string value)
|
||||
{
|
||||
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||
byte* data = stackalloc byte[size];
|
||||
|
||||
fixed (char* pValue = value)
|
||||
{
|
||||
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||
}
|
||||
|
||||
return objc_getClass(data);
|
||||
}
|
||||
|
||||
private struct NSPoint
|
||||
{
|
||||
public double X;
|
||||
public double Y;
|
||||
|
||||
public NSPoint(double x, double y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
|
||||
private struct NSRect
|
||||
{
|
||||
public NSPoint Pos;
|
||||
public NSPoint Size;
|
||||
|
||||
public NSRect(double x, double y, double width, double height)
|
||||
{
|
||||
Pos = new NSPoint(x, y);
|
||||
Size = new NSPoint(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetMetalLayer(out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds)
|
||||
{
|
||||
// Create a new CAMetalLayer.
|
||||
IntPtr layerClass = GetClass("CAMetalLayer");
|
||||
IntPtr metalLayer = IntPtr_objc_msgSend(layerClass, "alloc");
|
||||
objc_msgSend(metalLayer, "init");
|
||||
|
||||
// Create a child NSView to render into.
|
||||
IntPtr nsViewClass = GetClass("NSView");
|
||||
IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc");
|
||||
objc_msgSend(child, "init", new NSRect(0, 0, 0, 0));
|
||||
|
||||
// Make its renderer our metal layer.
|
||||
objc_msgSend(child, "setWantsLayer:", (byte)1);
|
||||
objc_msgSend(child, "setLayer:", metalLayer);
|
||||
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
|
||||
// Ensure the scale factor is up to date.
|
||||
updateBounds = (Rect rect) => {
|
||||
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
};
|
||||
|
||||
nsView = child;
|
||||
return metalLayer;
|
||||
}
|
||||
|
||||
public static void DestroyMetalLayer(IntPtr nsView, IntPtr metalLayer)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static unsafe partial IntPtr sel_registerName(byte* data);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static unsafe partial IntPtr objc_getClass(byte* data);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, byte value);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
|
||||
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
||||
|
||||
[LibraryImport(LibObjCImport, EntryPoint = "objc_msgSend")]
|
||||
private static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
|
||||
}
|
||||
}
|
@@ -2,9 +2,9 @@ using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Platform;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using SPB.Graphics;
|
||||
using SPB.Platform;
|
||||
using SPB.Platform.GLX;
|
||||
@@ -30,6 +30,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
protected IntPtr NsView { get; set; }
|
||||
protected IntPtr MetalLayer { get; set; }
|
||||
|
||||
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
||||
|
||||
public event EventHandler<IntPtr> WindowCreated;
|
||||
@@ -237,8 +238,29 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
[SupportedOSPlatform("macos")]
|
||||
IPlatformHandle CreateMacOS()
|
||||
{
|
||||
MetalLayer = MetalHelper.GetMetalLayer(out IntPtr nsView, out _updateBoundsCallback);
|
||||
// Create a new CAMetalLayer.
|
||||
IntPtr layerClass = ObjectiveC.objc_getClass("CAMetalLayer");
|
||||
IntPtr metalLayer = ObjectiveC.IntPtr_objc_msgSend(layerClass, "alloc");
|
||||
ObjectiveC.objc_msgSend(metalLayer, "init");
|
||||
|
||||
// Create a child NSView to render into.
|
||||
IntPtr nsViewClass = ObjectiveC.objc_getClass("NSView");
|
||||
IntPtr child = ObjectiveC.IntPtr_objc_msgSend(nsViewClass, "alloc");
|
||||
ObjectiveC.objc_msgSend(child, "init", new ObjectiveC.NSRect(0, 0, 0, 0));
|
||||
|
||||
// Make its renderer our metal layer.
|
||||
ObjectiveC.objc_msgSend(child, "setWantsLayer:", 1);
|
||||
ObjectiveC.objc_msgSend(child, "setLayer:", metalLayer);
|
||||
ObjectiveC.objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
|
||||
// Ensure the scale factor is up to date.
|
||||
_updateBoundsCallback = rect =>
|
||||
{
|
||||
ObjectiveC.objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
};
|
||||
|
||||
IntPtr nsView = child;
|
||||
MetalLayer = metalLayer;
|
||||
NsView = nsView;
|
||||
|
||||
return new PlatformHandle(nsView, "NSView");
|
||||
@@ -260,7 +282,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
[SupportedOSPlatform("macos")]
|
||||
void DestroyMacOS()
|
||||
{
|
||||
MetalHelper.DestroyMetalLayer(NsView, MetalLayer);
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
@@ -725,10 +725,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
return;
|
||||
}
|
||||
|
||||
bool clearDepth = (argument & 1) != 0;
|
||||
bool clearStencil = (argument & 2) != 0;
|
||||
uint componentMask = (uint)((argument >> 2) & 0xf);
|
||||
int index = (argument >> 6) & 0xf;
|
||||
int layer = (argument >> 10) & 0x3ff;
|
||||
|
||||
engine.UpdateRenderTargetState(useControl: false, layered: layer != 0 || layerCount > 1, singleUse: index);
|
||||
RenderTargetUpdateFlags updateFlags = RenderTargetUpdateFlags.SingleColor;
|
||||
|
||||
if (layer != 0 || layerCount > 1)
|
||||
{
|
||||
updateFlags |= RenderTargetUpdateFlags.Layered;
|
||||
}
|
||||
|
||||
if (clearDepth || clearStencil)
|
||||
{
|
||||
updateFlags |= RenderTargetUpdateFlags.UpdateDepthStencil;
|
||||
}
|
||||
|
||||
engine.UpdateRenderTargetState(updateFlags, singleUse: componentMask != 0 ? index : -1);
|
||||
|
||||
// If there is a mismatch on the host clip region and the one explicitly defined by the guest
|
||||
// on the screen scissor state, then we need to force only one texture to be bound to avoid
|
||||
@@ -788,18 +803,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_context.Renderer.Pipeline.SetScissors(scissors);
|
||||
}
|
||||
|
||||
if (clipMismatch)
|
||||
{
|
||||
_channel.TextureManager.UpdateRenderTarget(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
_channel.TextureManager.UpdateRenderTargets();
|
||||
}
|
||||
|
||||
bool clearDepth = (argument & 1) != 0;
|
||||
bool clearStencil = (argument & 2) != 0;
|
||||
uint componentMask = (uint)((argument >> 2) & 0xf);
|
||||
_channel.TextureManager.UpdateRenderTargets();
|
||||
|
||||
if (componentMask != 0)
|
||||
{
|
||||
@@ -841,7 +845,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
engine.UpdateScissorState();
|
||||
}
|
||||
|
||||
engine.UpdateRenderTargetState(useControl: true);
|
||||
engine.UpdateRenderTargetState(RenderTargetUpdateFlags.UpdateAll);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
|
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Flags indicating how the render targets should be updated.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
enum RenderTargetUpdateFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// No flags.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Get render target index from the control register.
|
||||
/// </summary>
|
||||
UseControl = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that all render targets are 2D array textures.
|
||||
/// </summary>
|
||||
Layered = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that only a single color target will be used.
|
||||
/// </summary>
|
||||
SingleColor = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the depth-stencil target will be used.
|
||||
/// </summary>
|
||||
UpdateDepthStencil = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// Default update flags for draw.
|
||||
/// </summary>
|
||||
UpdateAll = UseControl | UpdateDepthStencil
|
||||
}
|
||||
}
|
@@ -402,20 +402,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
private void UpdateRenderTargetState()
|
||||
{
|
||||
UpdateRenderTargetState(true);
|
||||
UpdateRenderTargetState(RenderTargetUpdateFlags.UpdateAll);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
|
||||
/// </summary>
|
||||
/// <param name="useControl">Use draw buffers information from render target control register</param>
|
||||
/// <param name="layered">Indicates if the texture is layered</param>
|
||||
/// <param name="updateFlags">Flags indicating which render targets should be updated and how</param>
|
||||
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
|
||||
public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
|
||||
public void UpdateRenderTargetState(RenderTargetUpdateFlags updateFlags, int singleUse = -1)
|
||||
{
|
||||
var memoryManager = _channel.MemoryManager;
|
||||
var rtControl = _state.State.RtControl;
|
||||
|
||||
bool useControl = updateFlags.HasFlag(RenderTargetUpdateFlags.UseControl);
|
||||
bool layered = updateFlags.HasFlag(RenderTargetUpdateFlags.Layered);
|
||||
bool singleColor = updateFlags.HasFlag(RenderTargetUpdateFlags.SingleColor);
|
||||
|
||||
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
|
||||
|
||||
var msaaMode = _state.State.RtMsaaMode;
|
||||
@@ -438,7 +441,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
var colorState = _state.State.RtColorState[rtIndex];
|
||||
|
||||
if (index >= count || !IsRtEnabled(colorState))
|
||||
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
||||
{
|
||||
changedScale |= _channel.TextureManager.SetRenderTargetColor(index, null);
|
||||
|
||||
@@ -478,7 +481,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
Image.Texture depthStencil = null;
|
||||
|
||||
if (dsEnable)
|
||||
if (dsEnable && updateFlags.HasFlag(RenderTargetUpdateFlags.UpdateDepthStencil))
|
||||
{
|
||||
var dsState = _state.State.RtDepthStencilState;
|
||||
var dsSize = _state.State.RtDepthStencilSize;
|
||||
|
@@ -139,12 +139,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <summary>
|
||||
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
|
||||
/// </summary>
|
||||
/// <param name="useControl">Use draw buffers information from render target control register</param>
|
||||
/// <param name="layered">Indicates if the texture is layered</param>
|
||||
/// <param name="updateFlags">Flags indicating which render targets should be updated and how</param>
|
||||
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
|
||||
public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
|
||||
public void UpdateRenderTargetState(RenderTargetUpdateFlags updateFlags, int singleUse = -1)
|
||||
{
|
||||
_stateUpdater.UpdateRenderTargetState(useControl, layered, singleUse);
|
||||
_stateUpdater.UpdateRenderTargetState(updateFlags, singleUse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -33,10 +33,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
class AutoDeleteCache : IEnumerable<Texture>
|
||||
{
|
||||
private const int MinCountForDeletion = 32;
|
||||
private const int MaxCapacity = 2048;
|
||||
private const ulong MaxTextureSizeCapacity = 512 * 1024 * 1024; // MB;
|
||||
|
||||
private readonly LinkedList<Texture> _textures;
|
||||
private readonly ConcurrentQueue<Texture> _deferredRemovals;
|
||||
private ulong _totalSize;
|
||||
|
||||
private HashSet<ShortTextureCacheEntry> _shortCacheBuilder;
|
||||
private HashSet<ShortTextureCacheEntry> _shortCache;
|
||||
@@ -49,7 +51,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
public AutoDeleteCache()
|
||||
{
|
||||
_textures = new LinkedList<Texture>();
|
||||
_deferredRemovals = new ConcurrentQueue<Texture>();
|
||||
|
||||
_shortCacheBuilder = new HashSet<ShortTextureCacheEntry>();
|
||||
_shortCache = new HashSet<ShortTextureCacheEntry>();
|
||||
@@ -67,37 +68,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="texture">The texture to be added to the cache</param>
|
||||
public void Add(Texture texture)
|
||||
{
|
||||
texture.IncrementReferenceCount();
|
||||
_totalSize += texture.Size;
|
||||
|
||||
texture.IncrementReferenceCount();
|
||||
texture.CacheNode = _textures.AddLast(texture);
|
||||
|
||||
if (_textures.Count > MaxCapacity)
|
||||
if (_textures.Count > MaxCapacity ||
|
||||
(_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion))
|
||||
{
|
||||
Texture oldestTexture = _textures.First.Value;
|
||||
|
||||
if (!oldestTexture.CheckModified(false))
|
||||
{
|
||||
// The texture must be flushed if it falls out of the auto delete cache.
|
||||
// Flushes out of the auto delete cache do not trigger write tracking,
|
||||
// as it is expected that other overlapping textures exist that have more up-to-date contents.
|
||||
|
||||
oldestTexture.Group.SynchronizeDependents(oldestTexture);
|
||||
oldestTexture.FlushModified(false);
|
||||
}
|
||||
|
||||
_textures.RemoveFirst();
|
||||
|
||||
oldestTexture.DecrementReferenceCount();
|
||||
|
||||
oldestTexture.CacheNode = null;
|
||||
}
|
||||
|
||||
if (_deferredRemovals.Count > 0)
|
||||
{
|
||||
while (_deferredRemovals.TryDequeue(out Texture textureToRemove))
|
||||
{
|
||||
Remove(textureToRemove, false);
|
||||
}
|
||||
RemoveLeastUsedTexture();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +99,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
texture.CacheNode = _textures.AddLast(texture);
|
||||
}
|
||||
|
||||
if (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion)
|
||||
{
|
||||
RemoveLeastUsedTexture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -127,6 +111,31 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the least used texture from the cache.
|
||||
/// </summary>
|
||||
private void RemoveLeastUsedTexture()
|
||||
{
|
||||
Texture oldestTexture = _textures.First.Value;
|
||||
|
||||
_totalSize -= oldestTexture.Size;
|
||||
|
||||
if (!oldestTexture.CheckModified(false))
|
||||
{
|
||||
// The texture must be flushed if it falls out of the auto delete cache.
|
||||
// Flushes out of the auto delete cache do not trigger write tracking,
|
||||
// as it is expected that other overlapping textures exist that have more up-to-date contents.
|
||||
|
||||
oldestTexture.Group.SynchronizeDependents(oldestTexture);
|
||||
oldestTexture.FlushModified(false);
|
||||
}
|
||||
|
||||
_textures.RemoveFirst();
|
||||
|
||||
oldestTexture.DecrementReferenceCount();
|
||||
oldestTexture.CacheNode = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a texture from the cache.
|
||||
/// </summary>
|
||||
@@ -148,20 +157,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
_textures.Remove(texture.CacheNode);
|
||||
|
||||
_totalSize -= texture.Size;
|
||||
|
||||
texture.CacheNode = null;
|
||||
|
||||
return texture.DecrementReferenceCount();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues removal of a texture from the cache in a thread safe way.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to be removed from the cache</param>
|
||||
public void RemoveDeferred(Texture texture)
|
||||
{
|
||||
_deferredRemovals.Enqueue(texture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to find a texture on the short duration cache.
|
||||
/// </summary>
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
@@ -89,12 +88,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
public TextureGroup Group { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set when a texture has been changed size. This indicates that it may need to be
|
||||
/// changed again when obtained as a sampler.
|
||||
/// </summary>
|
||||
public bool ChangedSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set when a texture's GPU VA has ever been partially or fully unmapped.
|
||||
/// This indicates that the range must be fully checked when matching the texture.
|
||||
@@ -410,122 +403,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
Group.CreateCopyDependency(contained, FirstLayer + layer, FirstLevel + level, copyTo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the texture size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This operation may also change the size of all mipmap levels, including from the parent
|
||||
/// and other possible child textures, to ensure that all sizes are consistent.
|
||||
/// </remarks>
|
||||
/// <param name="width">The new texture width</param>
|
||||
/// <param name="height">The new texture height</param>
|
||||
/// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
|
||||
public void ChangeSize(int width, int height, int depthOrLayers)
|
||||
{
|
||||
int blockWidth = Info.FormatInfo.BlockWidth;
|
||||
int blockHeight = Info.FormatInfo.BlockHeight;
|
||||
|
||||
width <<= FirstLevel;
|
||||
height <<= FirstLevel;
|
||||
|
||||
if (Target == Target.Texture3D)
|
||||
{
|
||||
depthOrLayers <<= FirstLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
depthOrLayers = _viewStorage.Info.DepthOrLayers;
|
||||
}
|
||||
|
||||
_viewStorage.RecreateStorageOrView(width, height, blockWidth, blockHeight, depthOrLayers);
|
||||
|
||||
foreach (Texture view in _viewStorage._views)
|
||||
{
|
||||
int viewWidth = Math.Max(1, width >> view.FirstLevel);
|
||||
int viewHeight = Math.Max(1, height >> view.FirstLevel);
|
||||
|
||||
int viewDepthOrLayers;
|
||||
|
||||
if (view.Info.Target == Target.Texture3D)
|
||||
{
|
||||
viewDepthOrLayers = Math.Max(1, depthOrLayers >> view.FirstLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewDepthOrLayers = view.Info.DepthOrLayers;
|
||||
}
|
||||
|
||||
view.RecreateStorageOrView(viewWidth, viewHeight, blockWidth, blockHeight, viewDepthOrLayers);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recreates the texture storage (or view, in the case of child textures) of this texture.
|
||||
/// This allows recreating the texture with a new size.
|
||||
/// A copy is automatically performed from the old to the new texture.
|
||||
/// </summary>
|
||||
/// <param name="width">The new texture width</param>
|
||||
/// <param name="height">The new texture height</param>
|
||||
/// <param name="width">The block width related to the given width</param>
|
||||
/// <param name="height">The block height related to the given height</param>
|
||||
/// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
|
||||
private void RecreateStorageOrView(int width, int height, int blockWidth, int blockHeight, int depthOrLayers)
|
||||
{
|
||||
RecreateStorageOrView(
|
||||
BitUtils.DivRoundUp(width * Info.FormatInfo.BlockWidth, blockWidth),
|
||||
BitUtils.DivRoundUp(height * Info.FormatInfo.BlockHeight, blockHeight),
|
||||
depthOrLayers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recreates the texture storage (or view, in the case of child textures) of this texture.
|
||||
/// This allows recreating the texture with a new size.
|
||||
/// A copy is automatically performed from the old to the new texture.
|
||||
/// </summary>
|
||||
/// <param name="width">The new texture width</param>
|
||||
/// <param name="height">The new texture height</param>
|
||||
/// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
|
||||
private void RecreateStorageOrView(int width, int height, int depthOrLayers)
|
||||
{
|
||||
ChangedSize = true;
|
||||
|
||||
SetInfo(new TextureInfo(
|
||||
Info.GpuAddress,
|
||||
width,
|
||||
height,
|
||||
depthOrLayers,
|
||||
Info.Levels,
|
||||
Info.SamplesInX,
|
||||
Info.SamplesInY,
|
||||
Info.Stride,
|
||||
Info.IsLinear,
|
||||
Info.GobBlocksInY,
|
||||
Info.GobBlocksInZ,
|
||||
Info.GobBlocksInTileX,
|
||||
Info.Target,
|
||||
Info.FormatInfo,
|
||||
Info.DepthStencilMode,
|
||||
Info.SwizzleR,
|
||||
Info.SwizzleG,
|
||||
Info.SwizzleB,
|
||||
Info.SwizzleA));
|
||||
|
||||
TextureCreateInfo createInfo = TextureCache.GetCreateInfo(Info, _context.Capabilities, ScaleFactor);
|
||||
|
||||
if (_viewStorage != this)
|
||||
{
|
||||
ReplaceStorage(_viewStorage.HostTexture.CreateView(createInfo, FirstLayer, FirstLevel));
|
||||
}
|
||||
else
|
||||
{
|
||||
ITexture newStorage = _context.Renderer.CreateTexture(createInfo, ScaleFactor);
|
||||
|
||||
HostTexture.CopyTo(newStorage, 0, 0);
|
||||
|
||||
ReplaceStorage(newStorage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers when a texture has had its data set after being scaled, and
|
||||
/// determines if it should be blacklisted from scaling to improve performance.
|
||||
@@ -1215,7 +1092,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <returns>A value indicating how well this texture matches the given info</returns>
|
||||
public TextureMatchQuality IsExactMatch(TextureInfo info, TextureSearchFlags flags)
|
||||
{
|
||||
TextureMatchQuality matchQuality = TextureCompatibility.FormatMatches(Info, info, (flags & TextureSearchFlags.ForSampler) != 0, (flags & TextureSearchFlags.ForCopy) != 0);
|
||||
bool forSampler = (flags & TextureSearchFlags.ForSampler) != 0;
|
||||
|
||||
TextureMatchQuality matchQuality = TextureCompatibility.FormatMatches(Info, info, forSampler, (flags & TextureSearchFlags.ForCopy) != 0);
|
||||
|
||||
if (matchQuality == TextureMatchQuality.NoMatch)
|
||||
{
|
||||
@@ -1227,12 +1106,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
return TextureMatchQuality.NoMatch;
|
||||
}
|
||||
|
||||
if (!TextureCompatibility.SizeMatches(Info, info, (flags & TextureSearchFlags.Strict) == 0, FirstLevel))
|
||||
if (!TextureCompatibility.SizeMatches(Info, info, forSampler))
|
||||
{
|
||||
return TextureMatchQuality.NoMatch;
|
||||
}
|
||||
|
||||
if ((flags & TextureSearchFlags.ForSampler) != 0 || (flags & TextureSearchFlags.Strict) != 0)
|
||||
if ((flags & TextureSearchFlags.ForSampler) != 0)
|
||||
{
|
||||
if (!TextureCompatibility.SamplerParamsMatches(Info, info))
|
||||
{
|
||||
@@ -1262,12 +1141,20 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
/// <param name="info">Texture view information</param>
|
||||
/// <param name="range">Texture view physical memory ranges</param>
|
||||
/// <param name="exactSize">Indicates if the texture sizes must be exactly equal, or width is allowed to differ</param>
|
||||
/// <param name="layerSize">Layer size on the given texture</param>
|
||||
/// <param name="caps">Host GPU capabilities</param>
|
||||
/// <param name="firstLayer">Texture view initial layer on this texture</param>
|
||||
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
|
||||
/// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns>
|
||||
public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, out int firstLayer, out int firstLevel)
|
||||
public TextureViewCompatibility IsViewCompatible(
|
||||
TextureInfo info,
|
||||
MultiRange range,
|
||||
bool exactSize,
|
||||
int layerSize,
|
||||
Capabilities caps,
|
||||
out int firstLayer,
|
||||
out int firstLevel)
|
||||
{
|
||||
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
||||
|
||||
@@ -1317,7 +1204,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
return TextureViewCompatibility.LayoutIncompatible;
|
||||
}
|
||||
|
||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewSizeMatches(Info, info, firstLevel));
|
||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewSizeMatches(Info, info, exactSize, firstLevel));
|
||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewSubImagesInBounds(Info, info, firstLayer, firstLevel));
|
||||
|
||||
return result;
|
||||
@@ -1750,13 +1637,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
|
||||
RemoveFromPools(true);
|
||||
|
||||
// We only want to remove if there's no mapped region of the texture that was modified by the GPU,
|
||||
// otherwise we could lose data.
|
||||
if (!Group.AnyModified(this))
|
||||
{
|
||||
_physicalMemory.TextureCache.QueueAutoDeleteCacheRemoval(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -210,8 +210,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
ulong offset,
|
||||
FormatInfo formatInfo,
|
||||
bool shouldCreate,
|
||||
bool preferScaling = true,
|
||||
Size? sizeHint = null)
|
||||
bool preferScaling,
|
||||
Size sizeHint)
|
||||
{
|
||||
int gobBlocksInY = copyTexture.MemoryLayout.UnpackGobBlocksInY();
|
||||
int gobBlocksInZ = copyTexture.MemoryLayout.UnpackGobBlocksInZ();
|
||||
@@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
TextureInfo info = new TextureInfo(
|
||||
copyTexture.Address.Pack() + offset,
|
||||
width,
|
||||
GetMinimumWidthInGob(width, sizeHint.Width, formatInfo.BytesPerPixel, copyTexture.LinearLayout),
|
||||
copyTexture.Height,
|
||||
copyTexture.Depth,
|
||||
1,
|
||||
@@ -255,7 +255,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
flags |= TextureSearchFlags.NoCreate;
|
||||
}
|
||||
|
||||
Texture texture = FindOrCreateTexture(memoryManager, flags, info, 0, sizeHint);
|
||||
Texture texture = FindOrCreateTexture(memoryManager, flags, info, 0);
|
||||
|
||||
texture?.SynchronizeMemory();
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
TextureInfo info = new TextureInfo(
|
||||
colorState.Address.Pack(),
|
||||
width,
|
||||
GetMinimumWidthInGob(width, sizeHint.Width, formatInfo.BytesPerPixel, isLinear),
|
||||
colorState.Height,
|
||||
colorState.Depth,
|
||||
1,
|
||||
@@ -342,7 +342,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
int layerSize = !isLinear ? colorState.LayerSize * 4 : 0;
|
||||
|
||||
Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
|
||||
Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, layerSize);
|
||||
|
||||
texture?.SynchronizeMemory();
|
||||
|
||||
@@ -395,7 +395,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
TextureInfo info = new TextureInfo(
|
||||
dsState.Address.Pack(),
|
||||
size.Width,
|
||||
GetMinimumWidthInGob(size.Width, sizeHint.Width, formatInfo.BytesPerPixel, false),
|
||||
size.Height,
|
||||
size.Depth,
|
||||
1,
|
||||
@@ -409,13 +409,41 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
target,
|
||||
formatInfo);
|
||||
|
||||
Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
|
||||
Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4);
|
||||
|
||||
texture?.SynchronizeMemory();
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For block linear textures, gets the minimum width of the texture
|
||||
/// that would still have the same number of GOBs per row as the original width.
|
||||
/// </summary>
|
||||
/// <param name="width">The possibly aligned texture width</param>
|
||||
/// <param name="minimumWidth">The minimum width that the texture may have without losing data</param>
|
||||
/// <param name="bytesPerPixel">Bytes per pixel of the texture format</param>
|
||||
/// <param name="isLinear">True if the texture is linear, false for block linear</param>
|
||||
/// <returns>The minimum width of the texture with the same amount of GOBs per row</returns>
|
||||
private static int GetMinimumWidthInGob(int width, int minimumWidth, int bytesPerPixel, bool isLinear)
|
||||
{
|
||||
if (isLinear || (uint)minimumWidth >= (uint)width)
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
// Calculate the minimum possible that would not cause data loss
|
||||
// and would be still within the same GOB (aligned size would be the same).
|
||||
// This is useful for render and copy operations, where we don't know the
|
||||
// exact width of the texture, but it doesn't matter, as long the texture is
|
||||
// at least as large as the region being rendered or copied.
|
||||
|
||||
int alignment = 64 / bytesPerPixel;
|
||||
int widthAligned = BitUtils.AlignUp(width, alignment);
|
||||
|
||||
return Math.Clamp(widthAligned - alignment + 1, minimumWidth, widthAligned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find an existing texture, or create a new one if not found.
|
||||
/// </summary>
|
||||
@@ -423,7 +451,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="flags">The texture search flags, defines texture comparison rules</param>
|
||||
/// <param name="info">Texture information of the texture to be found or created</param>
|
||||
/// <param name="layerSize">Size in bytes of a single texture layer</param>
|
||||
/// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
|
||||
/// <param name="range">Optional ranges of physical memory where the texture data is located</param>
|
||||
/// <returns>The texture</returns>
|
||||
public Texture FindOrCreateTexture(
|
||||
@@ -431,7 +458,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
TextureSearchFlags flags,
|
||||
TextureInfo info,
|
||||
int layerSize = 0,
|
||||
Size? sizeHint = null,
|
||||
MultiRange? range = null)
|
||||
{
|
||||
bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0;
|
||||
@@ -448,6 +474,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
address = memoryManager.Translate(info.GpuAddress);
|
||||
|
||||
// If the start address is unmapped, let's try to find a page of memory that is mapped.
|
||||
if (address == MemoryManager.PteUnmapped)
|
||||
{
|
||||
address = memoryManager.TranslateFirstMapped(info.GpuAddress, (ulong)info.CalculateSizeInfo(layerSize).TotalSize);
|
||||
}
|
||||
|
||||
// If address is still invalid, the texture is fully unmapped, so it has no data, just return null.
|
||||
if (address == MemoryManager.PteUnmapped)
|
||||
{
|
||||
return null;
|
||||
@@ -512,8 +545,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
if (texture != null)
|
||||
{
|
||||
ChangeSizeIfNeeded(info, texture, isSamplerTexture, sizeHint);
|
||||
|
||||
texture.SynchronizeMemory();
|
||||
|
||||
return texture;
|
||||
@@ -568,6 +599,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
TextureViewCompatibility overlapCompatibility = overlap.IsViewCompatible(
|
||||
info,
|
||||
range.Value,
|
||||
isSamplerTexture,
|
||||
sizeInfo.LayerSize,
|
||||
_context.Capabilities,
|
||||
out int firstLayer,
|
||||
@@ -598,17 +630,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
if (oInfo.Compatibility == TextureViewCompatibility.Full)
|
||||
{
|
||||
TextureInfo adjInfo = AdjustSizes(overlap, info, oInfo.FirstLevel);
|
||||
|
||||
if (!isSamplerTexture)
|
||||
{
|
||||
info = adjInfo;
|
||||
// If this is not a sampler texture, the size might be different from the requested size,
|
||||
// so we need to make sure the texture information has the correct size for this base texture,
|
||||
// before creating the view.
|
||||
info = info.CreateInfoForLevelView(overlap, oInfo.FirstLevel);
|
||||
}
|
||||
|
||||
texture = overlap.CreateView(adjInfo, sizeInfo, range.Value, oInfo.FirstLayer, oInfo.FirstLevel);
|
||||
|
||||
ChangeSizeIfNeeded(info, texture, isSamplerTexture, sizeHint);
|
||||
|
||||
texture = overlap.CreateView(info, sizeInfo, range.Value, oInfo.FirstLayer, oInfo.FirstLevel);
|
||||
texture.SynchronizeMemory();
|
||||
break;
|
||||
}
|
||||
@@ -682,6 +712,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
TextureViewCompatibility compatibility = texture.IsViewCompatible(
|
||||
overlap.Info,
|
||||
overlap.Range,
|
||||
exactSize: true,
|
||||
overlap.LayerSize,
|
||||
_context.Capabilities,
|
||||
out int firstLayer,
|
||||
@@ -792,7 +823,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
continue;
|
||||
}
|
||||
|
||||
TextureInfo overlapInfo = AdjustSizes(texture, overlap.Info, oInfo.FirstLevel);
|
||||
// Note: If we allow different sizes for those overlaps,
|
||||
// we need to make sure that the "info" has the correct size for the parent texture here.
|
||||
// Since this is not allowed right now, we don't need to do it.
|
||||
|
||||
TextureInfo overlapInfo = overlap.Info;
|
||||
|
||||
if (texture.ScaleFactor != overlap.ScaleFactor)
|
||||
{
|
||||
@@ -856,44 +891,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes a texture's size to match the desired size for samplers,
|
||||
/// or increases a texture's size to fit the region indicated by a size hint.
|
||||
/// </summary>
|
||||
/// <param name="info">The desired texture info</param>
|
||||
/// <param name="texture">The texture to resize</param>
|
||||
/// <param name="isSamplerTexture">True if the texture will be used for a sampler, false otherwise</param>
|
||||
/// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
|
||||
private void ChangeSizeIfNeeded(TextureInfo info, Texture texture, bool isSamplerTexture, Size? sizeHint)
|
||||
{
|
||||
if (isSamplerTexture)
|
||||
{
|
||||
// If this is used for sampling, the size must match,
|
||||
// otherwise the shader would sample garbage data.
|
||||
// To fix that, we create a new texture with the correct
|
||||
// size, and copy the data from the old one to the new one.
|
||||
|
||||
if (!TextureCompatibility.SizeMatches(texture.Info, info))
|
||||
{
|
||||
texture.ChangeSize(info.Width, info.Height, info.DepthOrLayers);
|
||||
}
|
||||
}
|
||||
else if (sizeHint != null)
|
||||
{
|
||||
// A size hint indicates that data will be used within that range, at least.
|
||||
// If the texture is smaller than the size hint, it must be enlarged to meet it.
|
||||
// The maximum size is provided by the requested info, which generally has an aligned size.
|
||||
|
||||
int width = Math.Max(texture.Info.Width, Math.Min(sizeHint.Value.Width, info.Width));
|
||||
int height = Math.Max(texture.Info.Height, Math.Min(sizeHint.Value.Height, info.Height));
|
||||
|
||||
if (texture.Info.Width != width || texture.Info.Height != height)
|
||||
{
|
||||
texture.ChangeSize(width, height, info.DepthOrLayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to find a texture on the short duration cache.
|
||||
/// </summary>
|
||||
@@ -1000,92 +997,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the size of the texture information for a given mipmap level,
|
||||
/// based on the size of a parent texture.
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent texture</param>
|
||||
/// <param name="info">The texture information to be adjusted</param>
|
||||
/// <param name="firstLevel">The first level of the texture view</param>
|
||||
/// <returns>The adjusted texture information with the new size</returns>
|
||||
private static TextureInfo AdjustSizes(Texture parent, TextureInfo info, int firstLevel)
|
||||
{
|
||||
// When the texture is used as view of another texture, we must
|
||||
// ensure that the sizes are valid, otherwise data uploads would fail
|
||||
// (and the size wouldn't match the real size used on the host API).
|
||||
// Given a parent texture from where the view is created, we have the
|
||||
// following rules:
|
||||
// - The view size must be equal to the parent size, divided by (2 ^ l),
|
||||
// where l is the first mipmap level of the view. The division result must
|
||||
// be rounded down, and the result must be clamped to 1.
|
||||
// - If the parent format is compressed, and the view format isn't, the
|
||||
// view size is calculated as above, but the width and height of the
|
||||
// view must be also divided by the compressed format block width and height.
|
||||
// - If the parent format is not compressed, and the view is, the view
|
||||
// size is calculated as described on the first point, but the width and height
|
||||
// of the view must be also multiplied by the block width and height.
|
||||
int width = Math.Max(1, parent.Info.Width >> firstLevel);
|
||||
int height = Math.Max(1, parent.Info.Height >> firstLevel);
|
||||
|
||||
if (parent.Info.FormatInfo.IsCompressed && !info.FormatInfo.IsCompressed)
|
||||
{
|
||||
width = BitUtils.DivRoundUp(width, parent.Info.FormatInfo.BlockWidth);
|
||||
height = BitUtils.DivRoundUp(height, parent.Info.FormatInfo.BlockHeight);
|
||||
}
|
||||
else if (!parent.Info.FormatInfo.IsCompressed && info.FormatInfo.IsCompressed)
|
||||
{
|
||||
width *= info.FormatInfo.BlockWidth;
|
||||
height *= info.FormatInfo.BlockHeight;
|
||||
}
|
||||
|
||||
int depthOrLayers;
|
||||
|
||||
if (info.Target == Target.Texture3D)
|
||||
{
|
||||
depthOrLayers = Math.Max(1, parent.Info.DepthOrLayers >> firstLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
depthOrLayers = info.DepthOrLayers;
|
||||
}
|
||||
|
||||
// 2D and 2D multisample textures are not considered compatible.
|
||||
// This specific case is required for copies, where the source texture might be multisample.
|
||||
// In this case, we inherit the parent texture multisample state.
|
||||
Target target = info.Target;
|
||||
int samplesInX = info.SamplesInX;
|
||||
int samplesInY = info.SamplesInY;
|
||||
|
||||
if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample)
|
||||
{
|
||||
target = Target.Texture2DMultisample;
|
||||
samplesInX = parent.Info.SamplesInX;
|
||||
samplesInY = parent.Info.SamplesInY;
|
||||
}
|
||||
|
||||
return new TextureInfo(
|
||||
info.GpuAddress,
|
||||
width,
|
||||
height,
|
||||
depthOrLayers,
|
||||
info.Levels,
|
||||
samplesInX,
|
||||
samplesInY,
|
||||
info.Stride,
|
||||
info.IsLinear,
|
||||
info.GobBlocksInY,
|
||||
info.GobBlocksInZ,
|
||||
info.GobBlocksInTileX,
|
||||
target,
|
||||
info.FormatInfo,
|
||||
info.DepthStencilMode,
|
||||
info.SwizzleR,
|
||||
info.SwizzleG,
|
||||
info.SwizzleB,
|
||||
info.SwizzleA);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a texture creation information from texture information.
|
||||
/// This can be used to create new host textures.
|
||||
@@ -1175,19 +1086,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues the removal of a texture from the auto delete cache.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This function is thread safe and can be called from any thread.
|
||||
/// The texture will be deleted on the next time the cache is used.
|
||||
/// </remarks>
|
||||
/// <param name="texture">The texture to be removed</param>
|
||||
public void QueueAutoDeleteCacheRemoval(Texture texture)
|
||||
{
|
||||
_cache.RemoveDeferred(texture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a texture to the short duration cache. This typically keeps it alive for two ticks.
|
||||
/// </summary>
|
||||
|
@@ -380,42 +380,37 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
/// <param name="lhs">Texture information of the texture view</param>
|
||||
/// <param name="rhs">Texture information of the texture view to match against</param>
|
||||
/// <param name="exact">Indicates if the sizes must be exactly equal</param>
|
||||
/// <param name="level">Mipmap level of the texture view in relation to this texture</param>
|
||||
/// <returns>The view compatibility level of the view sizes</returns>
|
||||
public static TextureViewCompatibility ViewSizeMatches(TextureInfo lhs, TextureInfo rhs, int level)
|
||||
public static TextureViewCompatibility ViewSizeMatches(TextureInfo lhs, TextureInfo rhs, bool exact, int level)
|
||||
{
|
||||
Size size = GetAlignedSize(lhs, level);
|
||||
Size lhsAlignedSize = GetAlignedSize(lhs, level);
|
||||
Size rhsAlignedSize = GetAlignedSize(rhs);
|
||||
|
||||
Size otherSize = GetAlignedSize(rhs);
|
||||
Size lhsSize = GetSizeInBlocks(lhs, level);
|
||||
Size rhsSize = GetSizeInBlocks(rhs);
|
||||
|
||||
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
||||
|
||||
// For copies, we can copy a subset of the 3D texture slices,
|
||||
// so the depth may be different in this case.
|
||||
if (rhs.Target == Target.Texture3D && size.Depth != otherSize.Depth)
|
||||
if (rhs.Target == Target.Texture3D && lhsSize.Depth != rhsSize.Depth)
|
||||
{
|
||||
result = TextureViewCompatibility.CopyOnly;
|
||||
}
|
||||
|
||||
if (size.Width == otherSize.Width && size.Height == otherSize.Height)
|
||||
// Some APIs align the width for copy and render target textures,
|
||||
// so the width may not match in this case for different uses of the same texture.
|
||||
// To account for this, we compare the aligned width here.
|
||||
// We expect height to always match exactly, if the texture is the same.
|
||||
if (lhsAlignedSize.Width == rhsAlignedSize.Width && lhsSize.Height == rhsSize.Height)
|
||||
{
|
||||
if (level > 0 && result == TextureViewCompatibility.Full)
|
||||
{
|
||||
// A resize should not change the aligned size of the largest mip.
|
||||
// If it would, then create a copy dependency rather than a full view.
|
||||
|
||||
Size mip0SizeLhs = GetAlignedSize(lhs);
|
||||
Size mip0SizeRhs = GetLargestAlignedSize(rhs, level);
|
||||
|
||||
if (mip0SizeLhs.Width != mip0SizeRhs.Width || mip0SizeLhs.Height != mip0SizeRhs.Height)
|
||||
{
|
||||
result = TextureViewCompatibility.CopyOnly;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return (exact && lhsSize.Width != rhsSize.Width) || lhsSize.Width < rhsSize.Width
|
||||
? TextureViewCompatibility.CopyOnly
|
||||
: result;
|
||||
}
|
||||
else if (lhs.IsLinear && rhs.IsLinear)
|
||||
else if (lhs.IsLinear && rhs.IsLinear && lhsSize.Height == rhsSize.Height)
|
||||
{
|
||||
// Copy between linear textures with matching stride.
|
||||
int stride = BitUtils.AlignUp(Math.Max(1, lhs.Stride >> level), Constants.StrideAlignment);
|
||||
@@ -454,57 +449,33 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
/// <param name="lhs">Texture information to compare</param>
|
||||
/// <param name="rhs">Texture information to compare with</param>
|
||||
/// <returns>True if the size matches, false otherwise</returns>
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs)
|
||||
{
|
||||
return SizeMatches(lhs, rhs, alignSizes: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture sizes of the supplied texture informations match the given level
|
||||
/// </summary>
|
||||
/// <param name="lhs">Texture information to compare</param>
|
||||
/// <param name="rhs">Texture information to compare with</param>
|
||||
/// <param name="level">Mipmap level of this texture to compare with</param>
|
||||
/// <returns>True if the size matches with the level, false otherwise</returns>
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, int level)
|
||||
{
|
||||
return Math.Max(1, lhs.Width >> level) == rhs.Width &&
|
||||
Math.Max(1, lhs.Height >> level) == rhs.Height &&
|
||||
Math.Max(1, lhs.GetDepth() >> level) == rhs.GetDepth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture sizes of the supplied texture informations match.
|
||||
/// </summary>
|
||||
/// <param name="lhs">Texture information to compare</param>
|
||||
/// <param name="rhs">Texture information to compare with</param>
|
||||
/// <param name="alignSizes">True to align the sizes according to the texture layout for comparison</param>
|
||||
/// <param name="lhsLevel">Mip level of the lhs texture. Aligned sizes are compared for the largest mip</param>
|
||||
/// <param name="exact">Indicates if the size must be exactly equal between the textures, or if <paramref name="rhs"/> is allowed to be larger</param>
|
||||
/// <returns>True if the sizes matches, false otherwise</returns>
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, bool alignSizes, int lhsLevel = 0)
|
||||
public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, bool exact)
|
||||
{
|
||||
if (lhs.GetLayers() != rhs.GetLayers())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isTextureBuffer = lhs.Target == Target.TextureBuffer || rhs.Target == Target.TextureBuffer;
|
||||
Size lhsSize = GetSizeInBlocks(lhs);
|
||||
Size rhsSize = GetSizeInBlocks(rhs);
|
||||
|
||||
if (alignSizes && !isTextureBuffer)
|
||||
if (exact || lhs.IsLinear || rhs.IsLinear)
|
||||
{
|
||||
Size size0 = GetLargestAlignedSize(lhs, lhsLevel);
|
||||
Size size1 = GetLargestAlignedSize(rhs, lhsLevel);
|
||||
|
||||
return size0.Width == size1.Width &&
|
||||
size0.Height == size1.Height &&
|
||||
size0.Depth == size1.Depth;
|
||||
return lhsSize.Width == rhsSize.Width &&
|
||||
lhsSize.Height == rhsSize.Height &&
|
||||
lhsSize.Depth == rhsSize.Depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs.Width == rhs.Width &&
|
||||
lhs.Height == rhs.Height &&
|
||||
lhs.GetDepth() == rhs.GetDepth();
|
||||
Size lhsAlignedSize = GetAlignedSize(lhs);
|
||||
Size rhsAlignedSize = GetAlignedSize(rhs);
|
||||
|
||||
return lhsAlignedSize.Width == rhsAlignedSize.Width &&
|
||||
lhsSize.Width >= rhsSize.Width &&
|
||||
lhsSize.Height == rhsSize.Height &&
|
||||
lhsSize.Depth == rhsSize.Depth;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,22 +514,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the aligned sizes of the specified texture information, shifted to the largest mip from a given level.
|
||||
/// The alignment depends on the texture layout and format bytes per pixel.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to calculate the aligned size from</param>
|
||||
/// <param name="level">Mipmap level for texture views. Shifts the aligned size to represent the largest mip level</param>
|
||||
/// <returns>The aligned texture size of the largest mip level</returns>
|
||||
public static Size GetLargestAlignedSize(TextureInfo info, int level)
|
||||
{
|
||||
int width = info.Width << level;
|
||||
int height = info.Height << level;
|
||||
int depth = info.GetDepth() << level;
|
||||
|
||||
return GetAlignedSize(info, width, height, depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the aligned sizes of the specified texture information.
|
||||
/// The alignment depends on the texture layout and format bytes per pixel.
|
||||
@@ -575,6 +530,25 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
return GetAlignedSize(info, width, height, depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size in blocks for the given texture information.
|
||||
/// For non-compressed formats, that's the same as the regular size.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information to calculate the aligned size from</param>
|
||||
/// <param name="level">Mipmap level for texture views</param>
|
||||
/// <returns>The texture size in blocks</returns>
|
||||
public static Size GetSizeInBlocks(TextureInfo info, int level = 0)
|
||||
{
|
||||
int width = Math.Max(1, info.Width >> level);
|
||||
int height = Math.Max(1, info.Height >> level);
|
||||
int depth = Math.Max(1, info.GetDepth() >> level);
|
||||
|
||||
return new Size(
|
||||
BitUtils.DivRoundUp(width, info.FormatInfo.BlockWidth),
|
||||
BitUtils.DivRoundUp(height, info.FormatInfo.BlockHeight),
|
||||
depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if it's possible to create a view with the layout of the second texture information from the first.
|
||||
/// The layout information is composed of the Stride for linear textures, or GOB block size
|
||||
|
@@ -336,24 +336,23 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
if (_loadNeeded[baseHandle + i])
|
||||
{
|
||||
var info = GetHandleInformation(baseHandle + i);
|
||||
int offsetIndex = info.Index;
|
||||
|
||||
// Only one of these will be greater than 1, as partial sync is only called when there are sub-image views.
|
||||
for (int layer = 0; layer < info.Layers; layer++)
|
||||
{
|
||||
for (int level = 0; level < info.Levels; level++)
|
||||
{
|
||||
int offsetIndex = GetOffsetIndex(info.BaseLayer + layer, info.BaseLevel + level);
|
||||
|
||||
int offset = _allOffsets[offsetIndex];
|
||||
int endOffset = Math.Min(offset + _sliceSizes[info.BaseLevel + level], (int)Storage.Size);
|
||||
int size = endOffset - offset;
|
||||
|
||||
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
|
||||
|
||||
SpanOrArray<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true);
|
||||
SpanOrArray<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
|
||||
|
||||
Storage.SetData(result, info.BaseLayer, info.BaseLevel);
|
||||
|
||||
offsetIndex++;
|
||||
Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,32 +433,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a texture was modified by the GPU.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture to be checked</param>
|
||||
/// <returns>True if any region of the texture was modified by the GPU, false otherwise</returns>
|
||||
public bool AnyModified(Texture texture)
|
||||
{
|
||||
bool anyModified = false;
|
||||
|
||||
EvaluateRelevantHandles(texture, (baseHandle, regionCount, split) =>
|
||||
{
|
||||
for (int i = 0; i < regionCount; i++)
|
||||
{
|
||||
TextureGroupHandle group = _handles[baseHandle + i];
|
||||
|
||||
if (group.Modified)
|
||||
{
|
||||
anyModified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return anyModified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush modified ranges for a given texture.
|
||||
/// </summary>
|
||||
|
@@ -1,5 +1,7 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
@@ -292,5 +294,88 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
layerSize);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates texture information for a given mipmap level of the specified parent texture and this information.
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent texture</param>
|
||||
/// <param name="firstLevel">The first level of the texture view</param>
|
||||
/// <returns>The adjusted texture information with the new size</returns>
|
||||
public TextureInfo CreateInfoForLevelView(Texture parent, int firstLevel)
|
||||
{
|
||||
// When the texture is used as view of another texture, we must
|
||||
// ensure that the sizes are valid, otherwise data uploads would fail
|
||||
// (and the size wouldn't match the real size used on the host API).
|
||||
// Given a parent texture from where the view is created, we have the
|
||||
// following rules:
|
||||
// - The view size must be equal to the parent size, divided by (2 ^ l),
|
||||
// where l is the first mipmap level of the view. The division result must
|
||||
// be rounded down, and the result must be clamped to 1.
|
||||
// - If the parent format is compressed, and the view format isn't, the
|
||||
// view size is calculated as above, but the width and height of the
|
||||
// view must be also divided by the compressed format block width and height.
|
||||
// - If the parent format is not compressed, and the view is, the view
|
||||
// size is calculated as described on the first point, but the width and height
|
||||
// of the view must be also multiplied by the block width and height.
|
||||
int width = Math.Max(1, parent.Info.Width >> firstLevel);
|
||||
int height = Math.Max(1, parent.Info.Height >> firstLevel);
|
||||
|
||||
if (parent.Info.FormatInfo.IsCompressed && !FormatInfo.IsCompressed)
|
||||
{
|
||||
width = BitUtils.DivRoundUp(width, parent.Info.FormatInfo.BlockWidth);
|
||||
height = BitUtils.DivRoundUp(height, parent.Info.FormatInfo.BlockHeight);
|
||||
}
|
||||
else if (!parent.Info.FormatInfo.IsCompressed && FormatInfo.IsCompressed)
|
||||
{
|
||||
width *= FormatInfo.BlockWidth;
|
||||
height *= FormatInfo.BlockHeight;
|
||||
}
|
||||
|
||||
int depthOrLayers;
|
||||
|
||||
if (Target == Target.Texture3D)
|
||||
{
|
||||
depthOrLayers = Math.Max(1, parent.Info.DepthOrLayers >> firstLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
depthOrLayers = DepthOrLayers;
|
||||
}
|
||||
|
||||
// 2D and 2D multisample textures are not considered compatible.
|
||||
// This specific case is required for copies, where the source texture might be multisample.
|
||||
// In this case, we inherit the parent texture multisample state.
|
||||
Target target = Target;
|
||||
int samplesInX = SamplesInX;
|
||||
int samplesInY = SamplesInY;
|
||||
|
||||
if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample)
|
||||
{
|
||||
target = Target.Texture2DMultisample;
|
||||
samplesInX = parent.Info.SamplesInX;
|
||||
samplesInY = parent.Info.SamplesInY;
|
||||
}
|
||||
|
||||
return new TextureInfo(
|
||||
GpuAddress,
|
||||
width,
|
||||
height,
|
||||
depthOrLayers,
|
||||
Levels,
|
||||
samplesInX,
|
||||
samplesInY,
|
||||
Stride,
|
||||
IsLinear,
|
||||
GobBlocksInY,
|
||||
GobBlocksInZ,
|
||||
GobBlocksInTileX,
|
||||
target,
|
||||
FormatInfo,
|
||||
DepthStencilMode,
|
||||
SwizzleR,
|
||||
SwizzleG,
|
||||
SwizzleB,
|
||||
SwizzleA);
|
||||
}
|
||||
}
|
||||
}
|
@@ -437,22 +437,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update host framebuffer attachments based on currently bound render target buffers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All attachments other than <paramref name="index"/> will be unbound.
|
||||
/// </remarks>
|
||||
/// <param name="index">Index of the render target color to be updated</param>
|
||||
public void UpdateRenderTarget(int index)
|
||||
{
|
||||
new Span<ITexture>(_rtHostColors).Fill(null);
|
||||
_rtHostColors[index] = _rtColors[index]?.HostTexture;
|
||||
_rtHostDs = null;
|
||||
|
||||
_context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update host framebuffer attachments based on currently bound render target buffers.
|
||||
/// </summary>
|
||||
|
@@ -77,22 +77,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
else
|
||||
{
|
||||
if (texture.ChangedSize)
|
||||
{
|
||||
// Texture changed size at one point - it may be a different size than the sampler expects.
|
||||
// This can be triggered when the size is changed by a size hint on copy or draw, but the texture has been sampled before.
|
||||
|
||||
int baseLevel = descriptor.UnpackBaseLevel();
|
||||
int width = Math.Max(1, descriptor.UnpackWidth() >> baseLevel);
|
||||
int height = Math.Max(1, descriptor.UnpackHeight() >> baseLevel);
|
||||
|
||||
if (texture.Info.Width != width || texture.Info.Height != height)
|
||||
{
|
||||
texture.ChangeSize(width, height, texture.Info.DepthOrLayers);
|
||||
}
|
||||
}
|
||||
|
||||
// Memory is automatically synchronized on texture creation.
|
||||
// On the path above (texture not yet in the pool), memory is automatically synchronized on texture creation.
|
||||
texture.SynchronizeMemory();
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
enum TextureSearchFlags
|
||||
{
|
||||
None = 0,
|
||||
Strict = 1 << 0,
|
||||
ForSampler = 1 << 1,
|
||||
ForCopy = 1 << 2,
|
||||
WithUpscale = 1 << 3,
|
||||
|
@@ -583,6 +583,38 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
return UnpackPaFromPte(pte) + (va & PageMask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a GPU virtual address to a CPU virtual address on the first mapped page of memory
|
||||
/// on the specified region.
|
||||
/// If no page is mapped on the specified region, <see cref="PteUnmapped"/> is returned.
|
||||
/// </summary>
|
||||
/// <param name="va">GPU virtual address to be translated</param>
|
||||
/// <param name="size">Size of the range to be translated</param>
|
||||
/// <returns>CPU virtual address, or <see cref="PteUnmapped"/> if unmapped</returns>
|
||||
public ulong TranslateFirstMapped(ulong va, ulong size)
|
||||
{
|
||||
if (!ValidateAddress(va))
|
||||
{
|
||||
return PteUnmapped;
|
||||
}
|
||||
|
||||
ulong endVa = va + size;
|
||||
|
||||
ulong pte = GetPte(va);
|
||||
|
||||
for (; va < endVa && pte == PteUnmapped; va += PageSize - (va & PageMask))
|
||||
{
|
||||
pte = GetPte(va);
|
||||
}
|
||||
|
||||
if (pte == PteUnmapped)
|
||||
{
|
||||
return PteUnmapped;
|
||||
}
|
||||
|
||||
return UnpackPaFromPte(pte) + (va & PageMask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the kind of a given memory page.
|
||||
/// This might indicate the type of resource that can be allocated on the page, and also texture tiling.
|
||||
|
@@ -202,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
pt.AcquireCallback(_context, pt.UserObj);
|
||||
|
||||
Texture texture = pt.Cache.FindOrCreateTexture(null, TextureSearchFlags.WithUpscale, pt.Info, 0, null, pt.Range);
|
||||
Texture texture = pt.Cache.FindOrCreateTexture(null, TextureSearchFlags.WithUpscale, pt.Info, 0, pt.Range);
|
||||
|
||||
pt.Cache.Tick();
|
||||
|
||||
|
@@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
class Program : IProgram
|
||||
{
|
||||
private const int MaxShaderLogLength = 2048;
|
||||
|
||||
public int Handle { get; private set; }
|
||||
|
||||
public bool IsLinked
|
||||
@@ -115,9 +117,16 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
// Use GL.GetProgramInfoLog(Handle), it may be too long to print on the log.
|
||||
_status = ProgramLinkStatus.Failure;
|
||||
Logger.Debug?.Print(LogClass.Gpu, "Shader linking failed.");
|
||||
|
||||
string log = GL.GetProgramInfoLog(Handle);
|
||||
|
||||
if (log.Length > MaxShaderLogLength)
|
||||
{
|
||||
log = log.Substring(0, MaxShaderLogLength) + "...";
|
||||
}
|
||||
|
||||
Logger.Warning?.Print(LogClass.Gpu, $"Shader linking failed: \n{log}");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -397,6 +397,31 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch)
|
||||
{
|
||||
bool iaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing);
|
||||
|
||||
if (iaIndexing && !perPatch)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Input, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Input);
|
||||
|
||||
if (context.Config.PassthroughAttributes != 0 && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.InputsArray = spvVar;
|
||||
}
|
||||
|
||||
var inputs = perPatch ? info.InputsPerPatch : info.Inputs;
|
||||
|
||||
foreach (int attr in inputs)
|
||||
@@ -410,60 +435,56 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
if (iaIndexing && isUserAttr && !perPatch)
|
||||
{
|
||||
if (context.InputsArray == null)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Input, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Input);
|
||||
|
||||
if (context.Config.PassthroughAttributes != 0 && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.InputsArray = spvVar;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
PixelImap iq = PixelImap.Unused;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
PixelImap iq = PixelImap.Unused;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment)
|
||||
if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||
}
|
||||
else
|
||||
{
|
||||
AttributeInfo attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr: false);
|
||||
AggregateType elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||
}
|
||||
else
|
||||
{
|
||||
AttributeInfo attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr: false);
|
||||
AggregateType elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (attrInfo.IsBuiltin && (elemType == AggregateType.S32 || elemType == AggregateType.U32))
|
||||
{
|
||||
iq = PixelImap.Constant;
|
||||
}
|
||||
if (attrInfo.IsBuiltin && (elemType == AggregateType.S32 || elemType == AggregateType.U32))
|
||||
{
|
||||
iq = PixelImap.Constant;
|
||||
}
|
||||
}
|
||||
|
||||
DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq);
|
||||
}
|
||||
|
||||
DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch)
|
||||
{
|
||||
bool oaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing);
|
||||
|
||||
if (oaIndexing && !perPatch)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
if (context.Config.Stage == ShaderStage.TessellationControl)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Output, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Output);
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.OutputsArray = spvVar;
|
||||
}
|
||||
|
||||
var outputs = perPatch ? info.OutputsPerPatch : info.Outputs;
|
||||
|
||||
foreach (int attr in outputs)
|
||||
@@ -477,29 +498,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
if (oaIndexing && isUserAttr && !perPatch)
|
||||
{
|
||||
if (context.OutputsArray == null)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
if (context.Config.Stage == ShaderStage.TessellationControl)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Output, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Output);
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.OutputsArray = spvVar;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DeclareOutputAttribute(context, attr, perPatch);
|
||||
continue;
|
||||
}
|
||||
|
||||
DeclareOutputAttribute(context, attr, perPatch);
|
||||
}
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
|
@@ -10,11 +10,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly static long FramebufferFlushTimer = Stopwatch.Frequency / 1000;
|
||||
|
||||
private const int MinDrawCountForFlush = 10;
|
||||
private const int MinConsecutiveQueryForFlush = 10;
|
||||
private const int InitialQueryCountForFlush = 32;
|
||||
|
||||
private long _lastFlush;
|
||||
private ulong _lastDrawCount;
|
||||
private bool _hasPendingQuery;
|
||||
private int _consecutiveQueries;
|
||||
private int _queryCount;
|
||||
|
||||
private int[] _queryCountHistory = new int[3];
|
||||
@@ -27,11 +29,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_lastDrawCount = drawCount;
|
||||
|
||||
_hasPendingQuery = false;
|
||||
_consecutiveQueries = 0;
|
||||
}
|
||||
|
||||
public bool RegisterPendingQuery()
|
||||
{
|
||||
_hasPendingQuery = true;
|
||||
_consecutiveQueries++;
|
||||
_remainingQueries--;
|
||||
|
||||
_queryCountHistory[_queryCountHistoryIndex]++;
|
||||
@@ -65,15 +69,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return _hasPendingQuery;
|
||||
}
|
||||
|
||||
public bool ShouldFlush(ulong drawCount)
|
||||
public bool ShouldFlushAttachmentChange(ulong drawCount)
|
||||
{
|
||||
_queryCount = 0;
|
||||
|
||||
if (_hasPendingQuery)
|
||||
// Flush when there's an attachment change out of a large block of queries.
|
||||
if (_consecutiveQueries > MinConsecutiveQueryForFlush)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_consecutiveQueries = 0;
|
||||
|
||||
long draws = (long)(drawCount - _lastDrawCount);
|
||||
|
||||
if (draws < MinDrawCountForFlush)
|
||||
|
@@ -39,7 +39,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
BufferUsageFlags.VertexBufferBit |
|
||||
BufferUsageFlags.TransformFeedbackBufferBitExt;
|
||||
|
||||
private readonly PhysicalDevice _physicalDevice;
|
||||
private readonly Device _device;
|
||||
|
||||
private readonly IdList<BufferHolder> _buffers;
|
||||
@@ -48,9 +47,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public StagingBuffer StagingBuffer { get; }
|
||||
|
||||
public BufferManager(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device)
|
||||
public BufferManager(VulkanRenderer gd, Device device)
|
||||
{
|
||||
_physicalDevice = physicalDevice;
|
||||
_device = device;
|
||||
_buffers = new IdList<BufferHolder>();
|
||||
StagingBuffer = new StagingBuffer(gd, this);
|
||||
@@ -114,7 +112,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
allocateFlagsAlt = DefaultBufferMemoryAltFlags;
|
||||
}
|
||||
|
||||
var allocation = gd.MemoryAllocator.AllocateDeviceMemory(_physicalDevice, requirements, allocateFlags, allocateFlagsAlt);
|
||||
var allocation = gd.MemoryAllocator.AllocateDeviceMemory(requirements, allocateFlags, allocateFlagsAlt);
|
||||
|
||||
if (allocation.Memory.Handle == 0UL)
|
||||
{
|
||||
|
@@ -8,11 +8,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
None = 0,
|
||||
|
||||
VertexBufferAlignment4B = 1,
|
||||
NoTriangleFans = 1 << 1,
|
||||
NoPointMode = 1 << 2,
|
||||
No3DImageView = 1 << 3,
|
||||
NoLodBias = 1 << 4
|
||||
NoTriangleFans = 1,
|
||||
NoPointMode = 1 << 1,
|
||||
No3DImageView = 1 << 2,
|
||||
NoLodBias = 1 << 3
|
||||
}
|
||||
|
||||
readonly struct HardwareCapabilities
|
||||
@@ -40,6 +39,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly ShaderStageFlags RequiredSubgroupSizeStages;
|
||||
public readonly SampleCountFlags SupportedSampleCounts;
|
||||
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||
public readonly uint VertexBufferAlignment;
|
||||
|
||||
public HardwareCapabilities(
|
||||
bool supportsIndexTypeUint8,
|
||||
@@ -64,7 +64,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
uint maxSubgroupSize,
|
||||
ShaderStageFlags requiredSubgroupSizeStages,
|
||||
SampleCountFlags supportedSampleCounts,
|
||||
PortabilitySubsetFlags portabilitySubset)
|
||||
PortabilitySubsetFlags portabilitySubset,
|
||||
uint vertexBufferAlignment)
|
||||
{
|
||||
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
||||
SupportsCustomBorderColor = supportsCustomBorderColor;
|
||||
@@ -89,6 +90,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
RequiredSubgroupSizeStages = requiredSubgroupSizeStages;
|
||||
SupportedSampleCounts = supportedSampleCounts;
|
||||
PortabilitySubset = portabilitySubset;
|
||||
VertexBufferAlignment = vertexBufferAlignment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,34 +9,36 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private ulong MaxDeviceMemoryUsageEstimate = 16UL * 1024 * 1024 * 1024;
|
||||
|
||||
private readonly Vk _api;
|
||||
private readonly PhysicalDevice _physicalDevice;
|
||||
private readonly Device _device;
|
||||
private readonly List<MemoryAllocatorBlockList> _blockLists;
|
||||
private readonly int _blockAlignment;
|
||||
private readonly PhysicalDeviceMemoryProperties _physicalDeviceMemoryProperties;
|
||||
|
||||
private int _blockAlignment;
|
||||
|
||||
public MemoryAllocator(Vk api, Device device, uint maxMemoryAllocationCount)
|
||||
public MemoryAllocator(Vk api, PhysicalDevice physicalDevice, Device device, uint maxMemoryAllocationCount)
|
||||
{
|
||||
_api = api;
|
||||
_physicalDevice = physicalDevice;
|
||||
_device = device;
|
||||
_blockLists = new List<MemoryAllocatorBlockList>();
|
||||
_blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / (ulong)maxMemoryAllocationCount);
|
||||
|
||||
_api.GetPhysicalDeviceMemoryProperties(_physicalDevice, out _physicalDeviceMemoryProperties);
|
||||
}
|
||||
|
||||
public MemoryAllocation AllocateDeviceMemory(
|
||||
PhysicalDevice physicalDevice,
|
||||
MemoryRequirements requirements,
|
||||
MemoryPropertyFlags flags = 0)
|
||||
{
|
||||
return AllocateDeviceMemory(physicalDevice, requirements, flags, flags);
|
||||
return AllocateDeviceMemory(requirements, flags, flags);
|
||||
}
|
||||
|
||||
public MemoryAllocation AllocateDeviceMemory(
|
||||
PhysicalDevice physicalDevice,
|
||||
MemoryRequirements requirements,
|
||||
MemoryPropertyFlags flags,
|
||||
MemoryPropertyFlags alternativeFlags)
|
||||
{
|
||||
int memoryTypeIndex = FindSuitableMemoryTypeIndex(_api, physicalDevice, requirements.MemoryTypeBits, flags, alternativeFlags);
|
||||
int memoryTypeIndex = FindSuitableMemoryTypeIndex(requirements.MemoryTypeBits, flags, alternativeFlags);
|
||||
if (memoryTypeIndex < 0)
|
||||
{
|
||||
return default;
|
||||
@@ -65,20 +67,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return newBl.Allocate(size, alignment, map);
|
||||
}
|
||||
|
||||
private static int FindSuitableMemoryTypeIndex(
|
||||
Vk api,
|
||||
PhysicalDevice physicalDevice,
|
||||
private int FindSuitableMemoryTypeIndex(
|
||||
uint memoryTypeBits,
|
||||
MemoryPropertyFlags flags,
|
||||
MemoryPropertyFlags alternativeFlags)
|
||||
{
|
||||
int bestCandidateIndex = -1;
|
||||
|
||||
api.GetPhysicalDeviceMemoryProperties(physicalDevice, out var properties);
|
||||
|
||||
for (int i = 0; i < properties.MemoryTypeCount; i++)
|
||||
for (int i = 0; i < _physicalDeviceMemoryProperties.MemoryTypeCount; i++)
|
||||
{
|
||||
var type = properties.MemoryTypes[i];
|
||||
var type = _physicalDeviceMemoryProperties.MemoryTypes[i];
|
||||
|
||||
if ((memoryTypeBits & (1 << i)) != 0)
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
@@ -650,9 +651,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
||||
_newState.Topology = oldTopology;
|
||||
|
||||
DynamicState.Viewports = oldViewports;
|
||||
DynamicState.ViewportsCount = (int)oldViewportsCount;
|
||||
DynamicState.SetViewportsDirty();
|
||||
DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
|
||||
|
||||
_newState.ViewportsCount = oldViewportsCount;
|
||||
SignalStateChange();
|
||||
@@ -1138,7 +1137,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
buffer.Dispose();
|
||||
|
||||
if (!Gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B) &&
|
||||
if (Gd.Capabilities.VertexBufferAlignment < 2 &&
|
||||
(vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0)
|
||||
{
|
||||
buffer = new VertexBufferState(
|
||||
@@ -1183,6 +1182,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return Math.Clamp(value, 0f, 1f);
|
||||
}
|
||||
|
||||
DynamicState.ViewportsCount = (uint)count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var viewport = viewports[i];
|
||||
@@ -1196,8 +1197,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Clamp(viewport.DepthFar)));
|
||||
}
|
||||
|
||||
DynamicState.ViewportsCount = count;
|
||||
|
||||
float disableTransformF = disableTransform ? 1.0f : 0.0f;
|
||||
if (SupportBufferUpdater.Data.ViewportInverse.W != disableTransformF || disableTransform)
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
|
||||
@@ -27,6 +28,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
int attachmentCount = 0;
|
||||
int colorCount = 0;
|
||||
int maxColorAttachmentIndex = -1;
|
||||
|
||||
for (int i = 0; i < state.AttachmentEnable.Length; i++)
|
||||
{
|
||||
@@ -36,6 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
attachmentIndices[attachmentCount++] = i;
|
||||
colorCount++;
|
||||
maxColorAttachmentIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,12 +76,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (colorAttachmentsCount != 0)
|
||||
{
|
||||
int maxAttachmentIndex = Constants.MaxRenderTargets - 1;
|
||||
subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1;
|
||||
subpass.ColorAttachmentCount = (uint)maxColorAttachmentIndex + 1;
|
||||
subpass.PColorAttachments = &attachmentReferences[0];
|
||||
|
||||
// Fill with VK_ATTACHMENT_UNUSED to cover any gaps.
|
||||
for (int i = 0; i <= maxAttachmentIndex; i++)
|
||||
for (int i = 0; i <= maxColorAttachmentIndex; i++)
|
||||
{
|
||||
subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined);
|
||||
}
|
||||
@@ -252,7 +254,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (gd.NeedsVertexBufferAlignment(vbScalarSizes[i], out int alignment))
|
||||
{
|
||||
alignedStride = (vertexBuffer.Stride + (alignment - 1)) & -alignment;
|
||||
alignedStride = BitUtils.AlignUp(vertexBuffer.Stride, alignment);
|
||||
}
|
||||
|
||||
// TODO: Support divisor > 1
|
||||
|
@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
private Array4<float> _blendConstants;
|
||||
|
||||
public int ViewportsCount;
|
||||
public uint ViewportsCount;
|
||||
public Array16<Viewport> Viewports;
|
||||
|
||||
private enum DirtyFlags
|
||||
@@ -88,9 +88,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_dirty |= DirtyFlags.Viewport;
|
||||
}
|
||||
|
||||
public void SetViewportsDirty()
|
||||
public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount)
|
||||
{
|
||||
_dirty |= DirtyFlags.Viewport;
|
||||
Viewports = viewports;
|
||||
ViewportsCount = viewportsCount;
|
||||
|
||||
if (ViewportsCount != 0)
|
||||
{
|
||||
_dirty |= DirtyFlags.Viewport;
|
||||
}
|
||||
}
|
||||
|
||||
public void ForceAllDirty()
|
||||
@@ -155,7 +161,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
private void RecordViewport(Vk api, CommandBuffer commandBuffer)
|
||||
{
|
||||
api.CmdSetViewport(commandBuffer, 0, (uint)ViewportsCount, Viewports.AsSpan());
|
||||
if (ViewportsCount != 0)
|
||||
{
|
||||
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
private const ulong MinByteWeightForFlush = 256 * 1024 * 1024; // MiB
|
||||
|
||||
private readonly List<QueryPool> _activeQueries;
|
||||
private readonly List<(QueryPool, bool)> _activeQueries;
|
||||
private CounterQueueEvent _activeConditionalRender;
|
||||
|
||||
private readonly List<BufferedQuery> _pendingQueryCopies;
|
||||
@@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public PipelineFull(VulkanRenderer gd, Device device) : base(gd, device)
|
||||
{
|
||||
_activeQueries = new List<QueryPool>();
|
||||
_activeQueries = new List<(QueryPool, bool)>();
|
||||
_pendingQueryCopies = new();
|
||||
|
||||
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
||||
@@ -202,7 +202,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
AutoFlush.RegisterFlush(DrawCount);
|
||||
EndRenderPass();
|
||||
|
||||
foreach (var queryPool in _activeQueries)
|
||||
foreach ((var queryPool, _) in _activeQueries)
|
||||
{
|
||||
Gd.Api.CmdEndQuery(CommandBuffer, queryPool, 0);
|
||||
}
|
||||
@@ -220,10 +220,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
// Restore per-command buffer state.
|
||||
|
||||
foreach (var queryPool in _activeQueries)
|
||||
foreach ((var queryPool, var isOcclusion) in _activeQueries)
|
||||
{
|
||||
bool isPrecise = Gd.Capabilities.SupportsPreciseOcclusionQueries && isOcclusion;
|
||||
|
||||
Gd.Api.CmdResetQueryPool(CommandBuffer, queryPool, 0, 1);
|
||||
Gd.Api.CmdBeginQuery(CommandBuffer, queryPool, 0, Gd.Capabilities.SupportsPreciseOcclusionQueries ? QueryControlFlags.PreciseBit : 0);
|
||||
Gd.Api.CmdBeginQuery(CommandBuffer, queryPool, 0, isPrecise ? QueryControlFlags.PreciseBit : 0);
|
||||
}
|
||||
|
||||
Gd.ResetCounterPool();
|
||||
@@ -231,7 +233,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Restore();
|
||||
}
|
||||
|
||||
public void BeginQuery(BufferedQuery query, QueryPool pool, bool needsReset, bool fromSamplePool)
|
||||
public void BeginQuery(BufferedQuery query, QueryPool pool, bool needsReset, bool isOcclusion, bool fromSamplePool)
|
||||
{
|
||||
if (needsReset)
|
||||
{
|
||||
@@ -247,16 +249,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
Gd.Api.CmdBeginQuery(CommandBuffer, pool, 0, Gd.Capabilities.SupportsPreciseOcclusionQueries ? QueryControlFlags.PreciseBit : 0);
|
||||
bool isPrecise = Gd.Capabilities.SupportsPreciseOcclusionQueries && isOcclusion;
|
||||
Gd.Api.CmdBeginQuery(CommandBuffer, pool, 0, isPrecise ? QueryControlFlags.PreciseBit : 0);
|
||||
|
||||
_activeQueries.Add(pool);
|
||||
_activeQueries.Add((pool, isOcclusion));
|
||||
}
|
||||
|
||||
public void EndQuery(QueryPool pool)
|
||||
{
|
||||
Gd.Api.CmdEndQuery(CommandBuffer, pool, 0);
|
||||
|
||||
_activeQueries.Remove(pool);
|
||||
for (int i = 0; i < _activeQueries.Count; i++)
|
||||
{
|
||||
if (_activeQueries[i].Item1.Handle == pool.Handle)
|
||||
{
|
||||
_activeQueries.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyQueryResults(BufferedQuery query)
|
||||
@@ -271,7 +281,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
protected override void SignalAttachmentChange()
|
||||
{
|
||||
if (AutoFlush.ShouldFlush(DrawCount))
|
||||
if (AutoFlush.ShouldFlushAttachmentChange(DrawCount))
|
||||
{
|
||||
FlushCommandsImpl();
|
||||
}
|
||||
|
@@ -100,7 +100,8 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
if (_isSupported)
|
||||
{
|
||||
bool needsReset = resetSequence == null || _resetSequence == null || resetSequence.Value != _resetSequence.Value;
|
||||
_pipeline.BeginQuery(this, _queryPool, needsReset, _type == CounterType.SamplesPassed && resetSequence != null);
|
||||
bool isOcclusion = _type == CounterType.SamplesPassed;
|
||||
_pipeline.BeginQuery(this, _queryPool, needsReset, isOcclusion, isOcclusion && resetSequence != null);
|
||||
}
|
||||
_resetSequence = null;
|
||||
}
|
||||
|
@@ -55,7 +55,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public unsafe TextureStorage(
|
||||
VulkanRenderer gd,
|
||||
PhysicalDevice physicalDevice,
|
||||
Device device,
|
||||
TextureCreateInfo info,
|
||||
float scaleFactor,
|
||||
@@ -118,7 +117,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
if (foreignAllocation == null)
|
||||
{
|
||||
gd.Api.GetImageMemoryRequirements(device, _image, out var requirements);
|
||||
var allocation = gd.MemoryAllocator.AllocateDeviceMemory(physicalDevice, requirements, DefaultImageMemoryFlags);
|
||||
var allocation = gd.MemoryAllocator.AllocateDeviceMemory(requirements, DefaultImageMemoryFlags);
|
||||
|
||||
if (allocation.Memory.Handle == 0UL)
|
||||
{
|
||||
@@ -173,7 +172,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
var info = NewCreateInfoWith(ref _info, format, _info.BytesPerPixel);
|
||||
|
||||
storage = new TextureStorage(_gd, default, _device, info, ScaleFactor, _allocationAuto);
|
||||
storage = new TextureStorage(_gd, _device, info, ScaleFactor, _allocationAuto);
|
||||
|
||||
_aliasedStorages.Add(format, storage);
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var componentMapping = new ComponentMapping(swizzleR, swizzleG, swizzleB, swizzleA);
|
||||
|
||||
var aspectFlags = info.Format.ConvertAspectFlags(info.DepthStencilMode);
|
||||
var aspectFlagsDepth = info.Format.ConvertAspectFlags(DepthStencilMode.Depth);
|
||||
var aspectFlagsDepth = info.Format.ConvertAspectFlags();
|
||||
|
||||
var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers);
|
||||
var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers);
|
||||
@@ -712,7 +712,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
for (int level = 0; level < levels; level++)
|
||||
{
|
||||
int mipSize = GetBufferDataLength(Info.GetMipSize(dstLevel + level));
|
||||
int mipSize = GetBufferDataLength(Info.GetMipSize2D(dstLevel + level) * dstLayers);
|
||||
|
||||
int endOffset = offset + mipSize;
|
||||
|
||||
|
@@ -14,6 +14,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public unsafe static class VulkanInitialization
|
||||
{
|
||||
private const uint InvalidIndex = uint.MaxValue;
|
||||
private static uint MinimalVulkanVersion = Vk.Version11.Value;
|
||||
private static uint MinimalInstanceVulkanVersion = Vk.Version12.Value;
|
||||
private static uint MaximumVulkanVersion = Vk.Version12.Value;
|
||||
private const string AppName = "Ryujinx.Graphics.Vulkan";
|
||||
private const int QueuesCount = 2;
|
||||
|
||||
@@ -33,7 +36,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
"VK_KHR_shader_float16_int8",
|
||||
"VK_EXT_shader_subgroup_ballot",
|
||||
"VK_EXT_subgroup_size_control",
|
||||
"VK_NV_geometry_shader_passthrough"
|
||||
"VK_NV_geometry_shader_passthrough",
|
||||
"VK_KHR_portability_subset", // By spec, we should enable this if present.
|
||||
};
|
||||
|
||||
public static string[] RequiredExtensions { get; } = new string[]
|
||||
@@ -99,7 +103,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ApplicationVersion = 1,
|
||||
PEngineName = (byte*)appName,
|
||||
EngineVersion = 1,
|
||||
ApiVersion = Vk.Version12.Value
|
||||
ApiVersion = MaximumVulkanVersion
|
||||
};
|
||||
|
||||
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
||||
@@ -224,7 +228,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ApplicationVersion = 1,
|
||||
PEngineName = (byte*)appName,
|
||||
EngineVersion = 1,
|
||||
ApiVersion = Vk.Version12.Value
|
||||
ApiVersion = MaximumVulkanVersion
|
||||
};
|
||||
|
||||
var instanceCreateInfo = new InstanceCreateInfo
|
||||
@@ -239,6 +243,27 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
|
||||
|
||||
// We ensure that vkEnumerateInstanceVersion is present (added in 1.1).
|
||||
// If the instance doesn't support it, no device is going to be 1.1 compatible.
|
||||
if (api.GetInstanceProcAddr(instance, "vkEnumerateInstanceVersion") == IntPtr.Zero)
|
||||
{
|
||||
api.DestroyInstance(instance, null);
|
||||
|
||||
return Array.Empty<DeviceInfo>();
|
||||
}
|
||||
|
||||
// We currently assume that the instance is compatible with Vulkan 1.2
|
||||
// TODO: Remove this once we relax our initialization codepaths.
|
||||
uint instanceApiVerison = 0;
|
||||
api.EnumerateInstanceVersion(ref instanceApiVerison).ThrowOnError();
|
||||
|
||||
if (instanceApiVerison < MinimalInstanceVulkanVersion)
|
||||
{
|
||||
api.DestroyInstance(instance, null);
|
||||
|
||||
return Array.Empty<DeviceInfo>();
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(appName);
|
||||
|
||||
uint physicalDeviceCount;
|
||||
@@ -259,6 +284,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var physicalDevice = physicalDevices[i];
|
||||
api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
||||
|
||||
if (properties.ApiVersion < MinimalVulkanVersion)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
devices[i] = new DeviceInfo(
|
||||
StringFromIdPair(properties.VendorID, properties.DeviceID),
|
||||
VendorUtils.GetNameFromId(properties.VendorID),
|
||||
|
@@ -234,10 +234,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
||||
|
||||
var portabilityFlags = PortabilitySubsetFlags.None;
|
||||
uint vertexBufferAlignment = 1;
|
||||
|
||||
if (usePortability)
|
||||
{
|
||||
portabilityFlags |= propertiesPortabilitySubset.MinVertexInputBindingStrideAlignment > 1 ? PortabilitySubsetFlags.VertexBufferAlignment4B : 0;
|
||||
vertexBufferAlignment = propertiesPortabilitySubset.MinVertexInputBindingStrideAlignment;
|
||||
|
||||
portabilityFlags |= featuresPortabilitySubset.TriangleFans ? 0 : PortabilitySubsetFlags.NoTriangleFans;
|
||||
portabilityFlags |= featuresPortabilitySubset.PointPolygons ? 0 : PortabilitySubsetFlags.NoPointMode;
|
||||
portabilityFlags |= featuresPortabilitySubset.ImageView2DOn3DImage ? 0 : PortabilitySubsetFlags.No3DImageView;
|
||||
@@ -278,9 +280,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
propertiesSubgroupSizeControl.MaxSubgroupSize,
|
||||
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
||||
supportedSampleCounts,
|
||||
portabilityFlags);
|
||||
portabilityFlags,
|
||||
vertexBufferAlignment);
|
||||
|
||||
MemoryAllocator = new MemoryAllocator(Api, _device, properties.Limits.MaxMemoryAllocationCount);
|
||||
MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount);
|
||||
|
||||
CommandBufferPool = VulkanInitialization.CreateCommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
||||
|
||||
@@ -290,7 +293,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
BackgroundResources = new BackgroundResources(this, _device);
|
||||
|
||||
BufferManager = new BufferManager(this, _physicalDevice, _device);
|
||||
BufferManager = new BufferManager(this, _device);
|
||||
|
||||
_syncManager = new SyncManager(this, _device);
|
||||
_pipeline = new PipelineFull(this, _device);
|
||||
@@ -388,7 +391,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
internal TextureStorage CreateTextureStorage(TextureCreateInfo info, float scale)
|
||||
{
|
||||
return new TextureStorage(this, _physicalDevice, _device, info, scale);
|
||||
return new TextureStorage(this, _device, info, scale);
|
||||
}
|
||||
|
||||
public void DeleteBuffer(BufferHandle buffer)
|
||||
@@ -636,11 +639,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PrintGpuInformation();
|
||||
}
|
||||
|
||||
public bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment)
|
||||
internal bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment)
|
||||
{
|
||||
if (Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B))
|
||||
if (Capabilities.VertexBufferAlignment > 1)
|
||||
{
|
||||
alignment = 4;
|
||||
alignment = (int)Capabilities.VertexBufferAlignment;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -229,7 +229,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower();
|
||||
string ncaId = Convert.ToHexString(cnmt.ContentEntries[0].NcaId).ToLower();
|
||||
|
||||
AddAocItem(cnmt.TitleId, containerPath, $"{ncaId}.nca", true);
|
||||
}
|
||||
|
@@ -696,8 +696,8 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
var buildIds = programs.Select(p => p switch
|
||||
{
|
||||
NsoExecutable nso => BitConverter.ToString(nso.BuildId.ItemsRo.ToArray()).Replace("-", "").TrimEnd('0'),
|
||||
NroExecutable nro => BitConverter.ToString(nro.Header.BuildId).Replace("-", "").TrimEnd('0'),
|
||||
NsoExecutable nso => Convert.ToHexString(nso.BuildId.ItemsRo.ToArray()).TrimEnd('0'),
|
||||
NroExecutable nro => Convert.ToHexString(nro.Header.BuildId).TrimEnd('0'),
|
||||
_ => string.Empty
|
||||
}).ToList();
|
||||
|
||||
|
@@ -51,11 +51,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
|
||||
|
||||
var payload = new JwtPayload
|
||||
{
|
||||
{ "sub", BitConverter.ToString(rawUserId).Replace("-", "").ToLower() },
|
||||
{ "sub", Convert.ToHexString(rawUserId).ToLower() },
|
||||
{ "aud", "ed9e2f05d286f7b8" },
|
||||
{ "di", BitConverter.ToString(deviceId).Replace("-", "").ToLower() },
|
||||
{ "di", Convert.ToHexString(deviceId).ToLower() },
|
||||
{ "sn", "XAW10000000000" },
|
||||
{ "bs:did", BitConverter.ToString(deviceAccountId).Replace("-", "").ToLower() },
|
||||
{ "bs:did", Convert.ToHexString(deviceAccountId).ToLower() },
|
||||
{ "iss", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com" },
|
||||
{ "typ", "id_token" },
|
||||
{ "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
|
||||
|
@@ -101,7 +101,7 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
};
|
||||
|
||||
// NOTE: The hex hash is a HMAC-SHA256 (first 32 bytes) using a hardcoded secret key over the titleId, we can simulate it by hashing the titleId instead.
|
||||
string hash = BitConverter.ToString(SHA256.HashData(BitConverter.GetBytes(titleId))).Replace("-", "").Remove(0x20);
|
||||
string hash = Convert.ToHexString(SHA256.HashData(BitConverter.GetBytes(titleId))).Remove(0x20);
|
||||
string folderPath = Path.Combine(_sdCardPath, "Nintendo", "Album", currentDateTime.Year.ToString("00"), currentDateTime.Month.ToString("00"), currentDateTime.Day.ToString("00"));
|
||||
string filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
|
||||
|
@@ -38,7 +38,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
|
||||
|
||||
public static bool IsValidNpadIdType(NpadIdType npadIdType)
|
||||
{
|
||||
return npadIdType <= NpadIdType.Player8 || npadIdType == NpadIdType.Handheld || npadIdType == NpadIdType.Unknown;
|
||||
return (npadIdType >= NpadIdType.Player1 && npadIdType <= NpadIdType.Player8) ||
|
||||
npadIdType == NpadIdType.Handheld ||
|
||||
npadIdType == NpadIdType.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
@@ -722,7 +722,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
|
||||
for (int i = 0; i < supportedPlayerIds.Length; ++i)
|
||||
{
|
||||
if (supportedPlayerIds[i] >= 0)
|
||||
if (HidUtils.IsValidNpadIdType(supportedPlayerIds[i]))
|
||||
{
|
||||
context.Device.Hid.Npads.SetSupportedPlayer(HidUtils.GetIndexFromNpadIdType(supportedPlayerIds[i]));
|
||||
}
|
||||
@@ -1101,7 +1101,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
|
||||
if (deviceType < NpadStyleIndex.System || deviceType >= NpadStyleIndex.FullKey)
|
||||
{
|
||||
if (npadIdType >= (NpadIdType.Player8 + 1) && npadIdType != NpadIdType.Handheld && npadIdType != NpadIdType.Unknown)
|
||||
if (!HidUtils.IsValidNpadIdType(npadIdType))
|
||||
{
|
||||
return ResultCode.InvalidNpadIdType;
|
||||
}
|
||||
|
@@ -1,11 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
[Flags]
|
||||
public enum MemoryPermission
|
||||
{
|
||||
NONE = 0,
|
||||
READ = 1,
|
||||
WRITE = 2,
|
||||
EXEC = 4,
|
||||
ALL = 7,
|
||||
None = 0,
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
Exec = 4,
|
||||
All = 7,
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Arch
|
||||
{
|
||||
ARM = 1,
|
||||
ARM64 = 2,
|
||||
MIPS = 3,
|
||||
X86 = 4,
|
||||
PPC = 5,
|
||||
SPARC = 6,
|
||||
M68K = 7,
|
||||
RISCV = 8,
|
||||
S390X = 9,
|
||||
TRICORE = 10,
|
||||
MAX = 11,
|
||||
}
|
||||
}
|
@@ -1,200 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Arm
|
||||
{
|
||||
|
||||
// ARM CPU
|
||||
|
||||
CPU_ARM_926 = 0,
|
||||
CPU_ARM_946 = 1,
|
||||
CPU_ARM_1026 = 2,
|
||||
CPU_ARM_1136_R2 = 3,
|
||||
CPU_ARM_1136 = 4,
|
||||
CPU_ARM_1176 = 5,
|
||||
CPU_ARM_11MPCORE = 6,
|
||||
CPU_ARM_CORTEX_M0 = 7,
|
||||
CPU_ARM_CORTEX_M3 = 8,
|
||||
CPU_ARM_CORTEX_M4 = 9,
|
||||
CPU_ARM_CORTEX_M7 = 10,
|
||||
CPU_ARM_CORTEX_M33 = 11,
|
||||
CPU_ARM_CORTEX_R5 = 12,
|
||||
CPU_ARM_CORTEX_R5F = 13,
|
||||
CPU_ARM_CORTEX_A7 = 14,
|
||||
CPU_ARM_CORTEX_A8 = 15,
|
||||
CPU_ARM_CORTEX_A9 = 16,
|
||||
CPU_ARM_CORTEX_A15 = 17,
|
||||
CPU_ARM_TI925T = 18,
|
||||
CPU_ARM_SA1100 = 19,
|
||||
CPU_ARM_SA1110 = 20,
|
||||
CPU_ARM_PXA250 = 21,
|
||||
CPU_ARM_PXA255 = 22,
|
||||
CPU_ARM_PXA260 = 23,
|
||||
CPU_ARM_PXA261 = 24,
|
||||
CPU_ARM_PXA262 = 25,
|
||||
CPU_ARM_PXA270 = 26,
|
||||
CPU_ARM_PXA270A0 = 27,
|
||||
CPU_ARM_PXA270A1 = 28,
|
||||
CPU_ARM_PXA270B0 = 29,
|
||||
CPU_ARM_PXA270B1 = 30,
|
||||
CPU_ARM_PXA270C0 = 31,
|
||||
CPU_ARM_PXA270C5 = 32,
|
||||
CPU_ARM_MAX = 33,
|
||||
CPU_ARM_ENDING = 34,
|
||||
|
||||
// ARM registers
|
||||
|
||||
REG_INVALID = 0,
|
||||
REG_APSR = 1,
|
||||
REG_APSR_NZCV = 2,
|
||||
REG_CPSR = 3,
|
||||
REG_FPEXC = 4,
|
||||
REG_FPINST = 5,
|
||||
REG_FPSCR = 6,
|
||||
REG_FPSCR_NZCV = 7,
|
||||
REG_FPSID = 8,
|
||||
REG_ITSTATE = 9,
|
||||
REG_LR = 10,
|
||||
REG_PC = 11,
|
||||
REG_SP = 12,
|
||||
REG_SPSR = 13,
|
||||
REG_D0 = 14,
|
||||
REG_D1 = 15,
|
||||
REG_D2 = 16,
|
||||
REG_D3 = 17,
|
||||
REG_D4 = 18,
|
||||
REG_D5 = 19,
|
||||
REG_D6 = 20,
|
||||
REG_D7 = 21,
|
||||
REG_D8 = 22,
|
||||
REG_D9 = 23,
|
||||
REG_D10 = 24,
|
||||
REG_D11 = 25,
|
||||
REG_D12 = 26,
|
||||
REG_D13 = 27,
|
||||
REG_D14 = 28,
|
||||
REG_D15 = 29,
|
||||
REG_D16 = 30,
|
||||
REG_D17 = 31,
|
||||
REG_D18 = 32,
|
||||
REG_D19 = 33,
|
||||
REG_D20 = 34,
|
||||
REG_D21 = 35,
|
||||
REG_D22 = 36,
|
||||
REG_D23 = 37,
|
||||
REG_D24 = 38,
|
||||
REG_D25 = 39,
|
||||
REG_D26 = 40,
|
||||
REG_D27 = 41,
|
||||
REG_D28 = 42,
|
||||
REG_D29 = 43,
|
||||
REG_D30 = 44,
|
||||
REG_D31 = 45,
|
||||
REG_FPINST2 = 46,
|
||||
REG_MVFR0 = 47,
|
||||
REG_MVFR1 = 48,
|
||||
REG_MVFR2 = 49,
|
||||
REG_Q0 = 50,
|
||||
REG_Q1 = 51,
|
||||
REG_Q2 = 52,
|
||||
REG_Q3 = 53,
|
||||
REG_Q4 = 54,
|
||||
REG_Q5 = 55,
|
||||
REG_Q6 = 56,
|
||||
REG_Q7 = 57,
|
||||
REG_Q8 = 58,
|
||||
REG_Q9 = 59,
|
||||
REG_Q10 = 60,
|
||||
REG_Q11 = 61,
|
||||
REG_Q12 = 62,
|
||||
REG_Q13 = 63,
|
||||
REG_Q14 = 64,
|
||||
REG_Q15 = 65,
|
||||
REG_R0 = 66,
|
||||
REG_R1 = 67,
|
||||
REG_R2 = 68,
|
||||
REG_R3 = 69,
|
||||
REG_R4 = 70,
|
||||
REG_R5 = 71,
|
||||
REG_R6 = 72,
|
||||
REG_R7 = 73,
|
||||
REG_R8 = 74,
|
||||
REG_R9 = 75,
|
||||
REG_R10 = 76,
|
||||
REG_R11 = 77,
|
||||
REG_R12 = 78,
|
||||
REG_S0 = 79,
|
||||
REG_S1 = 80,
|
||||
REG_S2 = 81,
|
||||
REG_S3 = 82,
|
||||
REG_S4 = 83,
|
||||
REG_S5 = 84,
|
||||
REG_S6 = 85,
|
||||
REG_S7 = 86,
|
||||
REG_S8 = 87,
|
||||
REG_S9 = 88,
|
||||
REG_S10 = 89,
|
||||
REG_S11 = 90,
|
||||
REG_S12 = 91,
|
||||
REG_S13 = 92,
|
||||
REG_S14 = 93,
|
||||
REG_S15 = 94,
|
||||
REG_S16 = 95,
|
||||
REG_S17 = 96,
|
||||
REG_S18 = 97,
|
||||
REG_S19 = 98,
|
||||
REG_S20 = 99,
|
||||
REG_S21 = 100,
|
||||
REG_S22 = 101,
|
||||
REG_S23 = 102,
|
||||
REG_S24 = 103,
|
||||
REG_S25 = 104,
|
||||
REG_S26 = 105,
|
||||
REG_S27 = 106,
|
||||
REG_S28 = 107,
|
||||
REG_S29 = 108,
|
||||
REG_S30 = 109,
|
||||
REG_S31 = 110,
|
||||
REG_C1_C0_2 = 111,
|
||||
REG_C13_C0_2 = 112,
|
||||
REG_C13_C0_3 = 113,
|
||||
REG_IPSR = 114,
|
||||
REG_MSP = 115,
|
||||
REG_PSP = 116,
|
||||
REG_CONTROL = 117,
|
||||
REG_IAPSR = 118,
|
||||
REG_EAPSR = 119,
|
||||
REG_XPSR = 120,
|
||||
REG_EPSR = 121,
|
||||
REG_IEPSR = 122,
|
||||
REG_PRIMASK = 123,
|
||||
REG_BASEPRI = 124,
|
||||
REG_BASEPRI_MAX = 125,
|
||||
REG_FAULTMASK = 126,
|
||||
REG_APSR_NZCVQ = 127,
|
||||
REG_APSR_G = 128,
|
||||
REG_APSR_NZCVQG = 129,
|
||||
REG_IAPSR_NZCVQ = 130,
|
||||
REG_IAPSR_G = 131,
|
||||
REG_IAPSR_NZCVQG = 132,
|
||||
REG_EAPSR_NZCVQ = 133,
|
||||
REG_EAPSR_G = 134,
|
||||
REG_EAPSR_NZCVQG = 135,
|
||||
REG_XPSR_NZCVQ = 136,
|
||||
REG_XPSR_G = 137,
|
||||
REG_XPSR_NZCVQG = 138,
|
||||
REG_CP_REG = 139,
|
||||
REG_ENDING = 140,
|
||||
|
||||
// alias registers
|
||||
REG_R13 = 12,
|
||||
REG_R14 = 10,
|
||||
REG_R15 = 11,
|
||||
REG_SB = 75,
|
||||
REG_SL = 76,
|
||||
REG_FP = 77,
|
||||
REG_IP = 78,
|
||||
}
|
||||
}
|
@@ -1,341 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Arm64
|
||||
{
|
||||
|
||||
// ARM64 CPU
|
||||
|
||||
CPU_ARM64_A57 = 0,
|
||||
CPU_ARM64_A53 = 1,
|
||||
CPU_ARM64_A72 = 2,
|
||||
CPU_ARM64_MAX = 3,
|
||||
CPU_ARM64_ENDING = 4,
|
||||
|
||||
// ARM64 registers
|
||||
|
||||
REG_INVALID = 0,
|
||||
REG_X29 = 1,
|
||||
REG_X30 = 2,
|
||||
REG_NZCV = 3,
|
||||
REG_SP = 4,
|
||||
REG_WSP = 5,
|
||||
REG_WZR = 6,
|
||||
REG_XZR = 7,
|
||||
REG_B0 = 8,
|
||||
REG_B1 = 9,
|
||||
REG_B2 = 10,
|
||||
REG_B3 = 11,
|
||||
REG_B4 = 12,
|
||||
REG_B5 = 13,
|
||||
REG_B6 = 14,
|
||||
REG_B7 = 15,
|
||||
REG_B8 = 16,
|
||||
REG_B9 = 17,
|
||||
REG_B10 = 18,
|
||||
REG_B11 = 19,
|
||||
REG_B12 = 20,
|
||||
REG_B13 = 21,
|
||||
REG_B14 = 22,
|
||||
REG_B15 = 23,
|
||||
REG_B16 = 24,
|
||||
REG_B17 = 25,
|
||||
REG_B18 = 26,
|
||||
REG_B19 = 27,
|
||||
REG_B20 = 28,
|
||||
REG_B21 = 29,
|
||||
REG_B22 = 30,
|
||||
REG_B23 = 31,
|
||||
REG_B24 = 32,
|
||||
REG_B25 = 33,
|
||||
REG_B26 = 34,
|
||||
REG_B27 = 35,
|
||||
REG_B28 = 36,
|
||||
REG_B29 = 37,
|
||||
REG_B30 = 38,
|
||||
REG_B31 = 39,
|
||||
REG_D0 = 40,
|
||||
REG_D1 = 41,
|
||||
REG_D2 = 42,
|
||||
REG_D3 = 43,
|
||||
REG_D4 = 44,
|
||||
REG_D5 = 45,
|
||||
REG_D6 = 46,
|
||||
REG_D7 = 47,
|
||||
REG_D8 = 48,
|
||||
REG_D9 = 49,
|
||||
REG_D10 = 50,
|
||||
REG_D11 = 51,
|
||||
REG_D12 = 52,
|
||||
REG_D13 = 53,
|
||||
REG_D14 = 54,
|
||||
REG_D15 = 55,
|
||||
REG_D16 = 56,
|
||||
REG_D17 = 57,
|
||||
REG_D18 = 58,
|
||||
REG_D19 = 59,
|
||||
REG_D20 = 60,
|
||||
REG_D21 = 61,
|
||||
REG_D22 = 62,
|
||||
REG_D23 = 63,
|
||||
REG_D24 = 64,
|
||||
REG_D25 = 65,
|
||||
REG_D26 = 66,
|
||||
REG_D27 = 67,
|
||||
REG_D28 = 68,
|
||||
REG_D29 = 69,
|
||||
REG_D30 = 70,
|
||||
REG_D31 = 71,
|
||||
REG_H0 = 72,
|
||||
REG_H1 = 73,
|
||||
REG_H2 = 74,
|
||||
REG_H3 = 75,
|
||||
REG_H4 = 76,
|
||||
REG_H5 = 77,
|
||||
REG_H6 = 78,
|
||||
REG_H7 = 79,
|
||||
REG_H8 = 80,
|
||||
REG_H9 = 81,
|
||||
REG_H10 = 82,
|
||||
REG_H11 = 83,
|
||||
REG_H12 = 84,
|
||||
REG_H13 = 85,
|
||||
REG_H14 = 86,
|
||||
REG_H15 = 87,
|
||||
REG_H16 = 88,
|
||||
REG_H17 = 89,
|
||||
REG_H18 = 90,
|
||||
REG_H19 = 91,
|
||||
REG_H20 = 92,
|
||||
REG_H21 = 93,
|
||||
REG_H22 = 94,
|
||||
REG_H23 = 95,
|
||||
REG_H24 = 96,
|
||||
REG_H25 = 97,
|
||||
REG_H26 = 98,
|
||||
REG_H27 = 99,
|
||||
REG_H28 = 100,
|
||||
REG_H29 = 101,
|
||||
REG_H30 = 102,
|
||||
REG_H31 = 103,
|
||||
REG_Q0 = 104,
|
||||
REG_Q1 = 105,
|
||||
REG_Q2 = 106,
|
||||
REG_Q3 = 107,
|
||||
REG_Q4 = 108,
|
||||
REG_Q5 = 109,
|
||||
REG_Q6 = 110,
|
||||
REG_Q7 = 111,
|
||||
REG_Q8 = 112,
|
||||
REG_Q9 = 113,
|
||||
REG_Q10 = 114,
|
||||
REG_Q11 = 115,
|
||||
REG_Q12 = 116,
|
||||
REG_Q13 = 117,
|
||||
REG_Q14 = 118,
|
||||
REG_Q15 = 119,
|
||||
REG_Q16 = 120,
|
||||
REG_Q17 = 121,
|
||||
REG_Q18 = 122,
|
||||
REG_Q19 = 123,
|
||||
REG_Q20 = 124,
|
||||
REG_Q21 = 125,
|
||||
REG_Q22 = 126,
|
||||
REG_Q23 = 127,
|
||||
REG_Q24 = 128,
|
||||
REG_Q25 = 129,
|
||||
REG_Q26 = 130,
|
||||
REG_Q27 = 131,
|
||||
REG_Q28 = 132,
|
||||
REG_Q29 = 133,
|
||||
REG_Q30 = 134,
|
||||
REG_Q31 = 135,
|
||||
REG_S0 = 136,
|
||||
REG_S1 = 137,
|
||||
REG_S2 = 138,
|
||||
REG_S3 = 139,
|
||||
REG_S4 = 140,
|
||||
REG_S5 = 141,
|
||||
REG_S6 = 142,
|
||||
REG_S7 = 143,
|
||||
REG_S8 = 144,
|
||||
REG_S9 = 145,
|
||||
REG_S10 = 146,
|
||||
REG_S11 = 147,
|
||||
REG_S12 = 148,
|
||||
REG_S13 = 149,
|
||||
REG_S14 = 150,
|
||||
REG_S15 = 151,
|
||||
REG_S16 = 152,
|
||||
REG_S17 = 153,
|
||||
REG_S18 = 154,
|
||||
REG_S19 = 155,
|
||||
REG_S20 = 156,
|
||||
REG_S21 = 157,
|
||||
REG_S22 = 158,
|
||||
REG_S23 = 159,
|
||||
REG_S24 = 160,
|
||||
REG_S25 = 161,
|
||||
REG_S26 = 162,
|
||||
REG_S27 = 163,
|
||||
REG_S28 = 164,
|
||||
REG_S29 = 165,
|
||||
REG_S30 = 166,
|
||||
REG_S31 = 167,
|
||||
REG_W0 = 168,
|
||||
REG_W1 = 169,
|
||||
REG_W2 = 170,
|
||||
REG_W3 = 171,
|
||||
REG_W4 = 172,
|
||||
REG_W5 = 173,
|
||||
REG_W6 = 174,
|
||||
REG_W7 = 175,
|
||||
REG_W8 = 176,
|
||||
REG_W9 = 177,
|
||||
REG_W10 = 178,
|
||||
REG_W11 = 179,
|
||||
REG_W12 = 180,
|
||||
REG_W13 = 181,
|
||||
REG_W14 = 182,
|
||||
REG_W15 = 183,
|
||||
REG_W16 = 184,
|
||||
REG_W17 = 185,
|
||||
REG_W18 = 186,
|
||||
REG_W19 = 187,
|
||||
REG_W20 = 188,
|
||||
REG_W21 = 189,
|
||||
REG_W22 = 190,
|
||||
REG_W23 = 191,
|
||||
REG_W24 = 192,
|
||||
REG_W25 = 193,
|
||||
REG_W26 = 194,
|
||||
REG_W27 = 195,
|
||||
REG_W28 = 196,
|
||||
REG_W29 = 197,
|
||||
REG_W30 = 198,
|
||||
REG_X0 = 199,
|
||||
REG_X1 = 200,
|
||||
REG_X2 = 201,
|
||||
REG_X3 = 202,
|
||||
REG_X4 = 203,
|
||||
REG_X5 = 204,
|
||||
REG_X6 = 205,
|
||||
REG_X7 = 206,
|
||||
REG_X8 = 207,
|
||||
REG_X9 = 208,
|
||||
REG_X10 = 209,
|
||||
REG_X11 = 210,
|
||||
REG_X12 = 211,
|
||||
REG_X13 = 212,
|
||||
REG_X14 = 213,
|
||||
REG_X15 = 214,
|
||||
REG_X16 = 215,
|
||||
REG_X17 = 216,
|
||||
REG_X18 = 217,
|
||||
REG_X19 = 218,
|
||||
REG_X20 = 219,
|
||||
REG_X21 = 220,
|
||||
REG_X22 = 221,
|
||||
REG_X23 = 222,
|
||||
REG_X24 = 223,
|
||||
REG_X25 = 224,
|
||||
REG_X26 = 225,
|
||||
REG_X27 = 226,
|
||||
REG_X28 = 227,
|
||||
REG_V0 = 228,
|
||||
REG_V1 = 229,
|
||||
REG_V2 = 230,
|
||||
REG_V3 = 231,
|
||||
REG_V4 = 232,
|
||||
REG_V5 = 233,
|
||||
REG_V6 = 234,
|
||||
REG_V7 = 235,
|
||||
REG_V8 = 236,
|
||||
REG_V9 = 237,
|
||||
REG_V10 = 238,
|
||||
REG_V11 = 239,
|
||||
REG_V12 = 240,
|
||||
REG_V13 = 241,
|
||||
REG_V14 = 242,
|
||||
REG_V15 = 243,
|
||||
REG_V16 = 244,
|
||||
REG_V17 = 245,
|
||||
REG_V18 = 246,
|
||||
REG_V19 = 247,
|
||||
REG_V20 = 248,
|
||||
REG_V21 = 249,
|
||||
REG_V22 = 250,
|
||||
REG_V23 = 251,
|
||||
REG_V24 = 252,
|
||||
REG_V25 = 253,
|
||||
REG_V26 = 254,
|
||||
REG_V27 = 255,
|
||||
REG_V28 = 256,
|
||||
REG_V29 = 257,
|
||||
REG_V30 = 258,
|
||||
REG_V31 = 259,
|
||||
|
||||
// pseudo registers
|
||||
REG_PC = 260,
|
||||
REG_CPACR_EL1 = 261,
|
||||
|
||||
// thread registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_TPIDR_EL0 = 262,
|
||||
REG_TPIDRRO_EL0 = 263,
|
||||
REG_TPIDR_EL1 = 264,
|
||||
REG_PSTATE = 265,
|
||||
|
||||
// exception link registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_ELR_EL0 = 266,
|
||||
REG_ELR_EL1 = 267,
|
||||
REG_ELR_EL2 = 268,
|
||||
REG_ELR_EL3 = 269,
|
||||
|
||||
// stack pointers registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_SP_EL0 = 270,
|
||||
REG_SP_EL1 = 271,
|
||||
REG_SP_EL2 = 272,
|
||||
REG_SP_EL3 = 273,
|
||||
|
||||
// other CP15 registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_TTBR0_EL1 = 274,
|
||||
REG_TTBR1_EL1 = 275,
|
||||
REG_ESR_EL0 = 276,
|
||||
REG_ESR_EL1 = 277,
|
||||
REG_ESR_EL2 = 278,
|
||||
REG_ESR_EL3 = 279,
|
||||
REG_FAR_EL0 = 280,
|
||||
REG_FAR_EL1 = 281,
|
||||
REG_FAR_EL2 = 282,
|
||||
REG_FAR_EL3 = 283,
|
||||
REG_PAR_EL1 = 284,
|
||||
REG_MAIR_EL1 = 285,
|
||||
REG_VBAR_EL0 = 286,
|
||||
REG_VBAR_EL1 = 287,
|
||||
REG_VBAR_EL2 = 288,
|
||||
REG_VBAR_EL3 = 289,
|
||||
REG_CP_REG = 290,
|
||||
|
||||
// floating point control and status registers
|
||||
REG_FPCR = 291,
|
||||
REG_FPSR = 292,
|
||||
REG_ENDING = 293,
|
||||
|
||||
// alias registers
|
||||
REG_IP0 = 215,
|
||||
REG_IP1 = 216,
|
||||
REG_FP = 1,
|
||||
REG_LR = 2,
|
||||
|
||||
// ARM64 instructions
|
||||
|
||||
INS_INVALID = 0,
|
||||
INS_MRS = 1,
|
||||
INS_MSR = 2,
|
||||
INS_SYS = 3,
|
||||
INS_SYSL = 4,
|
||||
INS_ENDING = 5,
|
||||
}
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Common
|
||||
{
|
||||
API_MAJOR = 2,
|
||||
|
||||
API_MINOR = 0,
|
||||
|
||||
API_PATCH = 0,
|
||||
API_EXTRA = 255,
|
||||
VERSION_MAJOR = 2,
|
||||
|
||||
VERSION_MINOR = 0,
|
||||
|
||||
VERSION_PATCH = 0,
|
||||
VERSION_EXTRA = 255,
|
||||
SECOND_SCALE = 1000000,
|
||||
MILISECOND_SCALE = 1000,
|
||||
QUERY_MODE = 1,
|
||||
QUERY_PAGE_SIZE = 2,
|
||||
QUERY_ARCH = 3,
|
||||
QUERY_TIMEOUT = 4,
|
||||
|
||||
CTL_IO_NONE = 0,
|
||||
CTL_IO_WRITE = 1,
|
||||
CTL_IO_READ = 2,
|
||||
CTL_IO_READ_WRITE = 3,
|
||||
|
||||
CTL_UC_MODE = 0,
|
||||
CTL_UC_PAGE_SIZE = 1,
|
||||
CTL_UC_ARCH = 2,
|
||||
CTL_UC_TIMEOUT = 3,
|
||||
CTL_UC_USE_EXITS = 4,
|
||||
CTL_UC_EXITS_CNT = 5,
|
||||
CTL_UC_EXITS = 6,
|
||||
CTL_CPU_MODEL = 7,
|
||||
CTL_TB_REQUEST_CACHE = 8,
|
||||
CTL_TB_REMOVE_CACHE = 9,
|
||||
CTL_TB_FLUSH = 10,
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Error
|
||||
{
|
||||
OK = 0,
|
||||
NOMEM = 1,
|
||||
ARCH = 2,
|
||||
HANDLE = 3,
|
||||
MODE = 4,
|
||||
VERSION = 5,
|
||||
READ_UNMAPPED = 6,
|
||||
WRITE_UNMAPPED = 7,
|
||||
FETCH_UNMAPPED = 8,
|
||||
HOOK = 9,
|
||||
INSN_INVALID = 10,
|
||||
MAP = 11,
|
||||
WRITE_PROT = 12,
|
||||
READ_PROT = 13,
|
||||
FETCH_PROT = 14,
|
||||
ARG = 15,
|
||||
READ_UNALIGNED = 16,
|
||||
WRITE_UNALIGNED = 17,
|
||||
FETCH_UNALIGNED = 18,
|
||||
HOOK_EXIST = 19,
|
||||
RESOURCE = 20,
|
||||
EXCEPTION = 21,
|
||||
}
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Hook
|
||||
{
|
||||
INTR = 1,
|
||||
INSN = 2,
|
||||
CODE = 4,
|
||||
BLOCK = 8,
|
||||
MEM_READ_UNMAPPED = 16,
|
||||
MEM_WRITE_UNMAPPED = 32,
|
||||
MEM_FETCH_UNMAPPED = 64,
|
||||
MEM_READ_PROT = 128,
|
||||
MEM_WRITE_PROT = 256,
|
||||
MEM_FETCH_PROT = 512,
|
||||
MEM_READ = 1024,
|
||||
MEM_WRITE = 2048,
|
||||
MEM_FETCH = 4096,
|
||||
MEM_READ_AFTER = 8192,
|
||||
INSN_INVALID = 16384,
|
||||
EDGE_GENERATED = 32768,
|
||||
TCG_OPCODE = 65536,
|
||||
MEM_UNMAPPED = 112,
|
||||
MEM_PROT = 896,
|
||||
MEM_READ_INVALID = 144,
|
||||
MEM_WRITE_INVALID = 288,
|
||||
MEM_FETCH_INVALID = 576,
|
||||
MEM_INVALID = 1008,
|
||||
MEM_VALID = 7168,
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Memory
|
||||
{
|
||||
READ = 16,
|
||||
WRITE = 17,
|
||||
FETCH = 18,
|
||||
READ_UNMAPPED = 19,
|
||||
WRITE_UNMAPPED = 20,
|
||||
FETCH_UNMAPPED = 21,
|
||||
WRITE_PROT = 22,
|
||||
READ_PROT = 23,
|
||||
FETCH_PROT = 24,
|
||||
READ_AFTER = 25,
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Mode
|
||||
{
|
||||
LITTLE_ENDIAN = 0,
|
||||
BIG_ENDIAN = 1073741824,
|
||||
ARM = 0,
|
||||
THUMB = 16,
|
||||
MCLASS = 32,
|
||||
V8 = 64,
|
||||
ARMBE8 = 1024,
|
||||
ARM926 = 128,
|
||||
ARM946 = 256,
|
||||
ARM1176 = 512,
|
||||
MICRO = 16,
|
||||
MIPS3 = 32,
|
||||
MIPS32R6 = 64,
|
||||
MIPS32 = 4,
|
||||
MIPS64 = 8,
|
||||
MODE_16 = 2,
|
||||
MODE_32 = 4,
|
||||
MODE_64 = 8,
|
||||
PPC32 = 4,
|
||||
PPC64 = 8,
|
||||
QPX = 16,
|
||||
SPARC32 = 4,
|
||||
SPARC64 = 8,
|
||||
V9 = 16,
|
||||
RISCV32 = 4,
|
||||
RISCV64 = 8,
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Permission
|
||||
{
|
||||
NONE = 0,
|
||||
READ = 1,
|
||||
WRITE = 2,
|
||||
EXEC = 4,
|
||||
ALL = 7,
|
||||
}
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum TCG
|
||||
{
|
||||
OP_SUB = 0,
|
||||
OP_FLAG_CMP = 1,
|
||||
OP_FLAG_DIRECT = 2,
|
||||
}
|
||||
}
|
@@ -1,101 +0,0 @@
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn.Native
|
||||
{
|
||||
public static partial class Interface
|
||||
{
|
||||
public static bool IsUnicornAvailable { get; private set; } = true;
|
||||
|
||||
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||
{
|
||||
if (libraryName == "unicorn")
|
||||
{
|
||||
string loadPath = $"{Path.GetDirectoryName(assembly.Location)}/";
|
||||
loadPath += OperatingSystem.IsWindows() ? $"{libraryName}.dll" : $"lib{libraryName}.so";
|
||||
|
||||
if (!NativeLibrary.TryLoad(loadPath, out IntPtr libraryPtr))
|
||||
{
|
||||
IsUnicornAvailable = false;
|
||||
Console.Error.WriteLine($"ERROR: Could not find unicorn at: {loadPath}");
|
||||
}
|
||||
|
||||
return libraryPtr;
|
||||
}
|
||||
|
||||
// Otherwise, fallback to default import resolver.
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
static Interface()
|
||||
{
|
||||
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), ImportResolver);
|
||||
}
|
||||
|
||||
public static void Checked(Error error)
|
||||
{
|
||||
if (error != Error.OK)
|
||||
{
|
||||
throw new UnicornException(error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarshalArrayOf<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(IntPtr input, int length, out T[] output)
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
output = new T[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
IntPtr item = new IntPtr(input.ToInt64() + i * size);
|
||||
|
||||
output[i] = Marshal.PtrToStructure<T>(item);
|
||||
}
|
||||
}
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial uint uc_version(out uint major, out uint minor);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_open(Arch arch, Mode mode, out IntPtr uc);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_close(IntPtr uc);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial IntPtr uc_strerror(Error err);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_reg_write(IntPtr uc, int regid, byte[] value);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_reg_read(IntPtr uc, int regid, byte[] value);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_mem_write(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_mem_read(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_emu_start(IntPtr uc, ulong begin, ulong until, ulong timeout, ulong count);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_mem_map(IntPtr uc, ulong address, ulong size, uint perms);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_mem_unmap(IntPtr uc, ulong address, ulong size);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_mem_protect(IntPtr uc, ulong address, ulong size, uint perms);
|
||||
|
||||
[LibraryImport("unicorn")]
|
||||
public static partial Error uc_mem_regions(IntPtr uc, out IntPtr regions, out uint count);
|
||||
}
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn.Native
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct UnicornMemoryRegion
|
||||
{
|
||||
public UInt64 begin; // begin address of the region (inclusive)
|
||||
public UInt64 end; // end address of the region (inclusive)
|
||||
public UInt32 perms; // memory permissions of the region
|
||||
}
|
||||
}
|
@@ -10,4 +10,8 @@
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="UnicornEngine.Unicorn" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -1,62 +1,45 @@
|
||||
using Ryujinx.Tests.Unicorn.Native;
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
using System;
|
||||
using UnicornEngine.Const;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
public class UnicornAArch32 : IDisposable
|
||||
{
|
||||
internal readonly IntPtr uc;
|
||||
private bool _isDisposed = false;
|
||||
internal readonly UnicornEngine.Unicorn uc;
|
||||
private bool _isDisposed;
|
||||
|
||||
public IndexedProperty<int, uint> R
|
||||
{
|
||||
get
|
||||
{
|
||||
return new IndexedProperty<int, uint>(
|
||||
(int i) => GetX(i),
|
||||
(int i, uint value) => SetX(i, value));
|
||||
}
|
||||
}
|
||||
public IndexedProperty<int, uint> R => new(GetX, SetX);
|
||||
|
||||
public IndexedProperty<int, SimdValue> Q
|
||||
{
|
||||
get
|
||||
{
|
||||
return new IndexedProperty<int, SimdValue>(
|
||||
(int i) => GetQ(i),
|
||||
(int i, SimdValue value) => SetQ(i, value));
|
||||
}
|
||||
}
|
||||
public IndexedProperty<int, SimdValue> Q => new(GetQ, SetQ);
|
||||
|
||||
public uint LR
|
||||
{
|
||||
get => GetRegister(Arm.REG_LR);
|
||||
set => SetRegister(Arm.REG_LR, value);
|
||||
get => GetRegister(Arm.UC_ARM_REG_LR);
|
||||
set => SetRegister(Arm.UC_ARM_REG_LR, value);
|
||||
}
|
||||
|
||||
public uint SP
|
||||
{
|
||||
get => GetRegister(Arm.REG_SP);
|
||||
set => SetRegister(Arm.REG_SP, value);
|
||||
get => GetRegister(Arm.UC_ARM_REG_SP);
|
||||
set => SetRegister(Arm.UC_ARM_REG_SP, value);
|
||||
}
|
||||
|
||||
public uint PC
|
||||
{
|
||||
get => GetRegister(Arm.REG_PC) & 0xfffffffeu;
|
||||
set => SetRegister(Arm.REG_PC, (value & 0xfffffffeu) | (ThumbFlag ? 1u : 0u));
|
||||
get => GetRegister(Arm.UC_ARM_REG_PC) & 0xfffffffeu;
|
||||
set => SetRegister(Arm.UC_ARM_REG_PC, (value & 0xfffffffeu) | (ThumbFlag ? 1u : 0u));
|
||||
}
|
||||
|
||||
public uint CPSR
|
||||
{
|
||||
get => GetRegister(Arm.REG_CPSR);
|
||||
set => SetRegister(Arm.REG_CPSR, value);
|
||||
get => GetRegister(Arm.UC_ARM_REG_CPSR);
|
||||
set => SetRegister(Arm.UC_ARM_REG_CPSR, value);
|
||||
}
|
||||
|
||||
public int Fpscr
|
||||
{
|
||||
get => (int)GetRegister(Arm.REG_FPSCR) | ((int)GetRegister(Arm.REG_FPSCR_NZCV));
|
||||
set => SetRegister(Arm.REG_FPSCR, (uint)value);
|
||||
get => (int)GetRegister(Arm.UC_ARM_REG_FPSCR) | ((int)GetRegister(Arm.UC_ARM_REG_FPSCR_NZCV));
|
||||
set => SetRegister(Arm.UC_ARM_REG_FPSCR, (uint)value);
|
||||
}
|
||||
|
||||
public bool QFlag
|
||||
@@ -95,16 +78,16 @@ namespace Ryujinx.Tests.Unicorn
|
||||
set
|
||||
{
|
||||
CPSR = (CPSR & ~0x00000020u) | (value ? 0x00000020u : 0u);
|
||||
SetRegister(Arm.REG_PC, (GetRegister(Arm.REG_PC) & 0xfffffffeu) | (value ? 1u : 0u));
|
||||
SetRegister(Arm.UC_ARM_REG_PC, (GetRegister(Arm.UC_ARM_REG_PC) & 0xfffffffeu) | (value ? 1u : 0u));
|
||||
}
|
||||
}
|
||||
|
||||
public UnicornAArch32()
|
||||
{
|
||||
Interface.Checked(Interface.uc_open(Arch.ARM, Mode.LITTLE_ENDIAN, out uc));
|
||||
uc = new UnicornEngine.Unicorn(Common.UC_ARCH_ARM, Common.UC_MODE_LITTLE_ENDIAN);
|
||||
|
||||
SetRegister(Arm.REG_C1_C0_2, GetRegister(Arm.REG_C1_C0_2) | 0xf00000);
|
||||
SetRegister(Arm.REG_FPEXC, 0x40000000);
|
||||
SetRegister(Arm.UC_ARM_REG_C1_C0_2, GetRegister(Arm.UC_ARM_REG_C1_C0_2) | 0xf00000);
|
||||
SetRegister(Arm.UC_ARM_REG_FPEXC, 0x40000000);
|
||||
}
|
||||
|
||||
~UnicornAArch32()
|
||||
@@ -122,14 +105,15 @@ namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Interface.Checked(Interface.uc_close(uc));
|
||||
uc.Close();
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void RunForCount(ulong count)
|
||||
{
|
||||
Interface.Checked(Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count));
|
||||
// FIXME: untilAddr should be 0xFFFFFFFFFFFFFFFFu
|
||||
uc.EmuStart(this.PC, -1, 0, (long)count);
|
||||
}
|
||||
|
||||
public void Step()
|
||||
@@ -137,44 +121,44 @@ namespace Ryujinx.Tests.Unicorn
|
||||
RunForCount(1);
|
||||
}
|
||||
|
||||
private static Arm[] XRegisters = new Arm[16]
|
||||
private static int[] XRegisters =
|
||||
{
|
||||
Arm.REG_R0,
|
||||
Arm.REG_R1,
|
||||
Arm.REG_R2,
|
||||
Arm.REG_R3,
|
||||
Arm.REG_R4,
|
||||
Arm.REG_R5,
|
||||
Arm.REG_R6,
|
||||
Arm.REG_R7,
|
||||
Arm.REG_R8,
|
||||
Arm.REG_R9,
|
||||
Arm.REG_R10,
|
||||
Arm.REG_R11,
|
||||
Arm.REG_R12,
|
||||
Arm.REG_R13,
|
||||
Arm.REG_R14,
|
||||
Arm.REG_R15,
|
||||
Arm.UC_ARM_REG_R0,
|
||||
Arm.UC_ARM_REG_R1,
|
||||
Arm.UC_ARM_REG_R2,
|
||||
Arm.UC_ARM_REG_R3,
|
||||
Arm.UC_ARM_REG_R4,
|
||||
Arm.UC_ARM_REG_R5,
|
||||
Arm.UC_ARM_REG_R6,
|
||||
Arm.UC_ARM_REG_R7,
|
||||
Arm.UC_ARM_REG_R8,
|
||||
Arm.UC_ARM_REG_R9,
|
||||
Arm.UC_ARM_REG_R10,
|
||||
Arm.UC_ARM_REG_R11,
|
||||
Arm.UC_ARM_REG_R12,
|
||||
Arm.UC_ARM_REG_R13,
|
||||
Arm.UC_ARM_REG_R14,
|
||||
Arm.UC_ARM_REG_R15,
|
||||
};
|
||||
|
||||
private static Arm[] QRegisters = new Arm[16]
|
||||
private static int[] QRegisters =
|
||||
{
|
||||
Arm.REG_Q0,
|
||||
Arm.REG_Q1,
|
||||
Arm.REG_Q2,
|
||||
Arm.REG_Q3,
|
||||
Arm.REG_Q4,
|
||||
Arm.REG_Q5,
|
||||
Arm.REG_Q6,
|
||||
Arm.REG_Q7,
|
||||
Arm.REG_Q8,
|
||||
Arm.REG_Q9,
|
||||
Arm.REG_Q10,
|
||||
Arm.REG_Q11,
|
||||
Arm.REG_Q12,
|
||||
Arm.REG_Q13,
|
||||
Arm.REG_Q14,
|
||||
Arm.REG_Q15
|
||||
Arm.UC_ARM_REG_Q0,
|
||||
Arm.UC_ARM_REG_Q1,
|
||||
Arm.UC_ARM_REG_Q2,
|
||||
Arm.UC_ARM_REG_Q3,
|
||||
Arm.UC_ARM_REG_Q4,
|
||||
Arm.UC_ARM_REG_Q5,
|
||||
Arm.UC_ARM_REG_Q6,
|
||||
Arm.UC_ARM_REG_Q7,
|
||||
Arm.UC_ARM_REG_Q8,
|
||||
Arm.UC_ARM_REG_Q9,
|
||||
Arm.UC_ARM_REG_Q10,
|
||||
Arm.UC_ARM_REG_Q11,
|
||||
Arm.UC_ARM_REG_Q12,
|
||||
Arm.UC_ARM_REG_Q13,
|
||||
Arm.UC_ARM_REG_Q14,
|
||||
Arm.UC_ARM_REG_Q15
|
||||
};
|
||||
|
||||
public uint GetX(int index)
|
||||
@@ -205,7 +189,7 @@ namespace Ryujinx.Tests.Unicorn
|
||||
}
|
||||
|
||||
// Getting quadword registers from Unicorn A32 seems to be broken, so we combine its 2 doubleword registers instead.
|
||||
return GetVector((Arm)((int)Arm.REG_D0 + index * 2));
|
||||
return GetVector(Arm.UC_ARM_REG_D0 + index * 2);
|
||||
}
|
||||
|
||||
public void SetQ(int index, SimdValue value)
|
||||
@@ -215,96 +199,85 @@ namespace Ryujinx.Tests.Unicorn
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
SetVector((Arm)((int)Arm.REG_D0 + index * 2), value);
|
||||
SetVector(Arm.UC_ARM_REG_D0 + index * 2, value);
|
||||
}
|
||||
|
||||
public uint GetRegister(Arm register)
|
||||
public uint GetRegister(int register)
|
||||
{
|
||||
byte[] data = new byte[4];
|
||||
|
||||
Interface.Checked(Interface.uc_reg_read(uc, (int)register, data));
|
||||
uc.RegRead(register, data);
|
||||
|
||||
return (uint)BitConverter.ToInt32(data, 0);
|
||||
return BitConverter.ToUInt32(data, 0);
|
||||
}
|
||||
|
||||
public void SetRegister(Arm register, uint value)
|
||||
public void SetRegister(int register, uint value)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(value);
|
||||
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register, data));
|
||||
uc.RegWrite(register, data);
|
||||
}
|
||||
|
||||
public SimdValue GetVector(Arm register)
|
||||
public SimdValue GetVector(int register)
|
||||
{
|
||||
byte[] data = new byte[8];
|
||||
|
||||
Interface.Checked(Interface.uc_reg_read(uc, (int)register, data));
|
||||
uc.RegRead(register, data);
|
||||
ulong lo = BitConverter.ToUInt64(data, 0);
|
||||
Interface.Checked(Interface.uc_reg_read(uc, (int)register + 1, data));
|
||||
uc.RegRead(register + 1, data);
|
||||
ulong hi = BitConverter.ToUInt64(data, 0);
|
||||
|
||||
return new SimdValue(lo, hi);
|
||||
}
|
||||
|
||||
private void SetVector(Arm register, SimdValue value)
|
||||
private void SetVector(int register, SimdValue value)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(value.GetUInt64(0));
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register, data));
|
||||
uc.RegWrite(register, data);
|
||||
data = BitConverter.GetBytes(value.GetUInt64(1));
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register + 1, data));
|
||||
uc.RegWrite(register + 1, data);
|
||||
}
|
||||
|
||||
public byte[] MemoryRead(ulong address, ulong size)
|
||||
{
|
||||
byte[] value = new byte[size];
|
||||
|
||||
Interface.Checked(Interface.uc_mem_read(uc, address, value, size));
|
||||
uc.MemRead((long)address, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte MemoryRead8(ulong address) => MemoryRead(address, 1)[0];
|
||||
public UInt16 MemoryRead16(ulong address) => (UInt16)BitConverter.ToInt16(MemoryRead(address, 2), 0);
|
||||
public UInt32 MemoryRead32(ulong address) => (UInt32)BitConverter.ToInt32(MemoryRead(address, 4), 0);
|
||||
public UInt64 MemoryRead64(ulong address) => (UInt64)BitConverter.ToInt64(MemoryRead(address, 8), 0);
|
||||
public ushort MemoryRead16(ulong address) => BitConverter.ToUInt16(MemoryRead(address, 2), 0);
|
||||
public uint MemoryRead32(ulong address) => BitConverter.ToUInt32(MemoryRead(address, 4), 0);
|
||||
public ulong MemoryRead64(ulong address) => BitConverter.ToUInt64(MemoryRead(address, 8), 0);
|
||||
|
||||
public void MemoryWrite(ulong address, byte[] value)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_write(uc, address, value, (ulong)value.Length));
|
||||
uc.MemWrite((long)address, value);
|
||||
}
|
||||
|
||||
public void MemoryWrite8(ulong address, byte value) => MemoryWrite(address, new byte[] { value });
|
||||
public void MemoryWrite16(ulong address, Int16 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite16(ulong address, UInt16 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, Int32 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, UInt32 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, Int64 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, UInt64 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite8(ulong address, byte value) => MemoryWrite(address, new[] { value });
|
||||
public void MemoryWrite16(ulong address, short value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite16(ulong address, ushort value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, int value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, uint value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, long value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, ulong value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
|
||||
public void MemoryMap(ulong address, ulong size, MemoryPermission permissions)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_map(uc, address, size, (uint)permissions));
|
||||
uc.MemMap((long)address, (long)size, (int)permissions);
|
||||
}
|
||||
|
||||
public void MemoryUnmap(ulong address, ulong size)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_unmap(uc, address, size));
|
||||
uc.MemUnmap((long)address, (long)size);
|
||||
}
|
||||
|
||||
public void MemoryProtect(ulong address, ulong size, MemoryPermission permissions)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_protect(uc, address, size, (uint)permissions));
|
||||
}
|
||||
|
||||
public static bool IsAvailable()
|
||||
{
|
||||
try
|
||||
{
|
||||
Interface.uc_version(out _, out _);
|
||||
}
|
||||
catch (DllNotFoundException) { }
|
||||
|
||||
return Interface.IsUnicornAvailable;
|
||||
uc.MemProtect((long)address, (long)size, (int)permissions);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,68 +1,51 @@
|
||||
using Ryujinx.Tests.Unicorn.Native;
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
using UnicornEngine.Const;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
public class UnicornAArch64 : IDisposable
|
||||
{
|
||||
internal readonly IntPtr uc;
|
||||
private bool _isDisposed = false;
|
||||
internal readonly UnicornEngine.Unicorn uc;
|
||||
private bool _isDisposed;
|
||||
|
||||
public IndexedProperty<int, ulong> X
|
||||
{
|
||||
get
|
||||
{
|
||||
return new IndexedProperty<int, ulong>(
|
||||
(int i) => GetX(i),
|
||||
(int i, ulong value) => SetX(i, value));
|
||||
}
|
||||
}
|
||||
public IndexedProperty<int, ulong> X => new(GetX, SetX);
|
||||
|
||||
public IndexedProperty<int, SimdValue> Q
|
||||
{
|
||||
get
|
||||
{
|
||||
return new IndexedProperty<int, SimdValue>(
|
||||
(int i) => GetQ(i),
|
||||
(int i, SimdValue value) => SetQ(i, value));
|
||||
}
|
||||
}
|
||||
public IndexedProperty<int, SimdValue> Q => new(GetQ, SetQ);
|
||||
|
||||
public ulong LR
|
||||
{
|
||||
get => GetRegister(Arm64.REG_LR);
|
||||
set => SetRegister(Arm64.REG_LR, value);
|
||||
get => GetRegister(Arm64.UC_ARM64_REG_LR);
|
||||
set => SetRegister(Arm64.UC_ARM64_REG_LR, value);
|
||||
}
|
||||
|
||||
public ulong SP
|
||||
{
|
||||
get => GetRegister(Arm64.REG_SP);
|
||||
set => SetRegister(Arm64.REG_SP, value);
|
||||
get => GetRegister(Arm64.UC_ARM64_REG_SP);
|
||||
set => SetRegister(Arm64.UC_ARM64_REG_SP, value);
|
||||
}
|
||||
|
||||
public ulong PC
|
||||
{
|
||||
get => GetRegister(Arm64.REG_PC);
|
||||
set => SetRegister(Arm64.REG_PC, value);
|
||||
get => GetRegister(Arm64.UC_ARM64_REG_PC);
|
||||
set => SetRegister(Arm64.UC_ARM64_REG_PC, value);
|
||||
}
|
||||
|
||||
public uint Pstate
|
||||
{
|
||||
get => (uint)GetRegister(Arm64.REG_PSTATE);
|
||||
set => SetRegister(Arm64.REG_PSTATE, (uint)value);
|
||||
get => (uint)GetRegister(Arm64.UC_ARM64_REG_PSTATE);
|
||||
set => SetRegister(Arm64.UC_ARM64_REG_PSTATE, value);
|
||||
}
|
||||
|
||||
public int Fpcr
|
||||
{
|
||||
get => (int)GetRegister(Arm64.REG_FPCR);
|
||||
set => SetRegister(Arm64.REG_FPCR, (uint)value);
|
||||
get => (int)GetRegister(Arm64.UC_ARM64_REG_FPCR);
|
||||
set => SetRegister(Arm64.UC_ARM64_REG_FPCR, (uint)value);
|
||||
}
|
||||
|
||||
public int Fpsr
|
||||
{
|
||||
get => (int)GetRegister(Arm64.REG_FPSR);
|
||||
set => SetRegister(Arm64.REG_FPSR, (uint)value);
|
||||
get => (int)GetRegister(Arm64.UC_ARM64_REG_FPSR);
|
||||
set => SetRegister(Arm64.UC_ARM64_REG_FPSR, (uint)value);
|
||||
}
|
||||
|
||||
public bool OverflowFlag
|
||||
@@ -91,9 +74,9 @@ namespace Ryujinx.Tests.Unicorn
|
||||
|
||||
public UnicornAArch64()
|
||||
{
|
||||
Interface.Checked(Interface.uc_open(Arch.ARM64, Mode.LITTLE_ENDIAN, out uc));
|
||||
uc = new UnicornEngine.Unicorn(Common.UC_ARCH_ARM64, Common.UC_MODE_LITTLE_ENDIAN);
|
||||
|
||||
SetRegister(Arm64.REG_CPACR_EL1, 0x00300000);
|
||||
SetRegister(Arm64.UC_ARM64_REG_CPACR_EL1, 0x00300000);
|
||||
}
|
||||
|
||||
~UnicornAArch64()
|
||||
@@ -111,14 +94,15 @@ namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Interface.Checked(Interface.uc_close(uc));
|
||||
uc.Close();
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void RunForCount(ulong count)
|
||||
{
|
||||
Interface.Checked(Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count));
|
||||
// FIXME: untilAddr should be 0xFFFFFFFFFFFFFFFFul
|
||||
uc.EmuStart((long)this.PC, -1, 0, (long)count);
|
||||
}
|
||||
|
||||
public void Step()
|
||||
@@ -126,75 +110,75 @@ namespace Ryujinx.Tests.Unicorn
|
||||
RunForCount(1);
|
||||
}
|
||||
|
||||
private static Arm64[] XRegisters = new Arm64[31]
|
||||
private static int[] XRegisters =
|
||||
{
|
||||
Arm64.REG_X0,
|
||||
Arm64.REG_X1,
|
||||
Arm64.REG_X2,
|
||||
Arm64.REG_X3,
|
||||
Arm64.REG_X4,
|
||||
Arm64.REG_X5,
|
||||
Arm64.REG_X6,
|
||||
Arm64.REG_X7,
|
||||
Arm64.REG_X8,
|
||||
Arm64.REG_X9,
|
||||
Arm64.REG_X10,
|
||||
Arm64.REG_X11,
|
||||
Arm64.REG_X12,
|
||||
Arm64.REG_X13,
|
||||
Arm64.REG_X14,
|
||||
Arm64.REG_X15,
|
||||
Arm64.REG_X16,
|
||||
Arm64.REG_X17,
|
||||
Arm64.REG_X18,
|
||||
Arm64.REG_X19,
|
||||
Arm64.REG_X20,
|
||||
Arm64.REG_X21,
|
||||
Arm64.REG_X22,
|
||||
Arm64.REG_X23,
|
||||
Arm64.REG_X24,
|
||||
Arm64.REG_X25,
|
||||
Arm64.REG_X26,
|
||||
Arm64.REG_X27,
|
||||
Arm64.REG_X28,
|
||||
Arm64.REG_X29,
|
||||
Arm64.REG_X30,
|
||||
Arm64.UC_ARM64_REG_X0,
|
||||
Arm64.UC_ARM64_REG_X1,
|
||||
Arm64.UC_ARM64_REG_X2,
|
||||
Arm64.UC_ARM64_REG_X3,
|
||||
Arm64.UC_ARM64_REG_X4,
|
||||
Arm64.UC_ARM64_REG_X5,
|
||||
Arm64.UC_ARM64_REG_X6,
|
||||
Arm64.UC_ARM64_REG_X7,
|
||||
Arm64.UC_ARM64_REG_X8,
|
||||
Arm64.UC_ARM64_REG_X9,
|
||||
Arm64.UC_ARM64_REG_X10,
|
||||
Arm64.UC_ARM64_REG_X11,
|
||||
Arm64.UC_ARM64_REG_X12,
|
||||
Arm64.UC_ARM64_REG_X13,
|
||||
Arm64.UC_ARM64_REG_X14,
|
||||
Arm64.UC_ARM64_REG_X15,
|
||||
Arm64.UC_ARM64_REG_X16,
|
||||
Arm64.UC_ARM64_REG_X17,
|
||||
Arm64.UC_ARM64_REG_X18,
|
||||
Arm64.UC_ARM64_REG_X19,
|
||||
Arm64.UC_ARM64_REG_X20,
|
||||
Arm64.UC_ARM64_REG_X21,
|
||||
Arm64.UC_ARM64_REG_X22,
|
||||
Arm64.UC_ARM64_REG_X23,
|
||||
Arm64.UC_ARM64_REG_X24,
|
||||
Arm64.UC_ARM64_REG_X25,
|
||||
Arm64.UC_ARM64_REG_X26,
|
||||
Arm64.UC_ARM64_REG_X27,
|
||||
Arm64.UC_ARM64_REG_X28,
|
||||
Arm64.UC_ARM64_REG_X29,
|
||||
Arm64.UC_ARM64_REG_X30,
|
||||
};
|
||||
|
||||
private static Arm64[] QRegisters = new Arm64[32]
|
||||
private static int[] QRegisters =
|
||||
{
|
||||
Arm64.REG_Q0,
|
||||
Arm64.REG_Q1,
|
||||
Arm64.REG_Q2,
|
||||
Arm64.REG_Q3,
|
||||
Arm64.REG_Q4,
|
||||
Arm64.REG_Q5,
|
||||
Arm64.REG_Q6,
|
||||
Arm64.REG_Q7,
|
||||
Arm64.REG_Q8,
|
||||
Arm64.REG_Q9,
|
||||
Arm64.REG_Q10,
|
||||
Arm64.REG_Q11,
|
||||
Arm64.REG_Q12,
|
||||
Arm64.REG_Q13,
|
||||
Arm64.REG_Q14,
|
||||
Arm64.REG_Q15,
|
||||
Arm64.REG_Q16,
|
||||
Arm64.REG_Q17,
|
||||
Arm64.REG_Q18,
|
||||
Arm64.REG_Q19,
|
||||
Arm64.REG_Q20,
|
||||
Arm64.REG_Q21,
|
||||
Arm64.REG_Q22,
|
||||
Arm64.REG_Q23,
|
||||
Arm64.REG_Q24,
|
||||
Arm64.REG_Q25,
|
||||
Arm64.REG_Q26,
|
||||
Arm64.REG_Q27,
|
||||
Arm64.REG_Q28,
|
||||
Arm64.REG_Q29,
|
||||
Arm64.REG_Q30,
|
||||
Arm64.REG_Q31,
|
||||
Arm64.UC_ARM64_REG_Q0,
|
||||
Arm64.UC_ARM64_REG_Q1,
|
||||
Arm64.UC_ARM64_REG_Q2,
|
||||
Arm64.UC_ARM64_REG_Q3,
|
||||
Arm64.UC_ARM64_REG_Q4,
|
||||
Arm64.UC_ARM64_REG_Q5,
|
||||
Arm64.UC_ARM64_REG_Q6,
|
||||
Arm64.UC_ARM64_REG_Q7,
|
||||
Arm64.UC_ARM64_REG_Q8,
|
||||
Arm64.UC_ARM64_REG_Q9,
|
||||
Arm64.UC_ARM64_REG_Q10,
|
||||
Arm64.UC_ARM64_REG_Q11,
|
||||
Arm64.UC_ARM64_REG_Q12,
|
||||
Arm64.UC_ARM64_REG_Q13,
|
||||
Arm64.UC_ARM64_REG_Q14,
|
||||
Arm64.UC_ARM64_REG_Q15,
|
||||
Arm64.UC_ARM64_REG_Q16,
|
||||
Arm64.UC_ARM64_REG_Q17,
|
||||
Arm64.UC_ARM64_REG_Q18,
|
||||
Arm64.UC_ARM64_REG_Q19,
|
||||
Arm64.UC_ARM64_REG_Q20,
|
||||
Arm64.UC_ARM64_REG_Q21,
|
||||
Arm64.UC_ARM64_REG_Q22,
|
||||
Arm64.UC_ARM64_REG_Q23,
|
||||
Arm64.UC_ARM64_REG_Q24,
|
||||
Arm64.UC_ARM64_REG_Q25,
|
||||
Arm64.UC_ARM64_REG_Q26,
|
||||
Arm64.UC_ARM64_REG_Q27,
|
||||
Arm64.UC_ARM64_REG_Q28,
|
||||
Arm64.UC_ARM64_REG_Q29,
|
||||
Arm64.UC_ARM64_REG_Q30,
|
||||
Arm64.UC_ARM64_REG_Q31,
|
||||
};
|
||||
|
||||
public ulong GetX(int index)
|
||||
@@ -237,89 +221,78 @@ namespace Ryujinx.Tests.Unicorn
|
||||
SetVector(QRegisters[index], value);
|
||||
}
|
||||
|
||||
private ulong GetRegister(Arm64 register)
|
||||
private ulong GetRegister(int register)
|
||||
{
|
||||
byte[] data = new byte[8];
|
||||
|
||||
Interface.Checked(Interface.uc_reg_read(uc, (int)register, data));
|
||||
uc.RegRead(register, data);
|
||||
|
||||
return (ulong)BitConverter.ToInt64(data, 0);
|
||||
return BitConverter.ToUInt64(data, 0);
|
||||
}
|
||||
|
||||
private void SetRegister(Arm64 register, ulong value)
|
||||
private void SetRegister(int register, ulong value)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(value);
|
||||
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register, data));
|
||||
uc.RegWrite(register, data);
|
||||
}
|
||||
|
||||
private SimdValue GetVector(Arm64 register)
|
||||
private SimdValue GetVector(int register)
|
||||
{
|
||||
byte[] data = new byte[16];
|
||||
|
||||
Interface.Checked(Interface.uc_reg_read(uc, (int)register, data));
|
||||
uc.RegRead(register, data);
|
||||
|
||||
return new SimdValue(data);
|
||||
}
|
||||
|
||||
private void SetVector(Arm64 register, SimdValue value)
|
||||
private void SetVector(int register, SimdValue value)
|
||||
{
|
||||
byte[] data = value.ToArray();
|
||||
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register, data));
|
||||
uc.RegWrite(register, data);
|
||||
}
|
||||
|
||||
public byte[] MemoryRead(ulong address, ulong size)
|
||||
{
|
||||
byte[] value = new byte[size];
|
||||
|
||||
Interface.Checked(Interface.uc_mem_read(uc, address, value, size));
|
||||
uc.MemRead((long)address, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte MemoryRead8 (ulong address) => MemoryRead(address, 1)[0];
|
||||
public UInt16 MemoryRead16(ulong address) => (UInt16)BitConverter.ToInt16(MemoryRead(address, 2), 0);
|
||||
public UInt32 MemoryRead32(ulong address) => (UInt32)BitConverter.ToInt32(MemoryRead(address, 4), 0);
|
||||
public UInt64 MemoryRead64(ulong address) => (UInt64)BitConverter.ToInt64(MemoryRead(address, 8), 0);
|
||||
public ushort MemoryRead16(ulong address) => BitConverter.ToUInt16(MemoryRead(address, 2), 0);
|
||||
public uint MemoryRead32(ulong address) => BitConverter.ToUInt32(MemoryRead(address, 4), 0);
|
||||
public ulong MemoryRead64(ulong address) => BitConverter.ToUInt64(MemoryRead(address, 8), 0);
|
||||
|
||||
public void MemoryWrite(ulong address, byte[] value)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_write(uc, address, value, (ulong)value.Length));
|
||||
uc.MemWrite((long)address, value);
|
||||
}
|
||||
|
||||
public void MemoryWrite8 (ulong address, byte value) => MemoryWrite(address, new byte[]{value});
|
||||
public void MemoryWrite16(ulong address, Int16 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite16(ulong address, UInt16 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, Int32 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, UInt32 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, Int64 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, UInt64 value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite8 (ulong address, byte value) => MemoryWrite(address, new[]{ value });
|
||||
public void MemoryWrite16(ulong address, short value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite16(ulong address, ushort value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, int value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite32(ulong address, uint value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, long value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
public void MemoryWrite64(ulong address, ulong value) => MemoryWrite(address, BitConverter.GetBytes(value));
|
||||
|
||||
public void MemoryMap(ulong address, ulong size, MemoryPermission permissions)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_map(uc, address, size, (uint)permissions));
|
||||
uc.MemMap((long)address, (long)size, (int)permissions);
|
||||
}
|
||||
|
||||
public void MemoryUnmap(ulong address, ulong size)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_unmap(uc, address, size));
|
||||
uc.MemUnmap((long)address, (long)size);
|
||||
}
|
||||
|
||||
public void MemoryProtect(ulong address, ulong size, MemoryPermission permissions)
|
||||
{
|
||||
Interface.Checked(Interface.uc_mem_protect(uc, address, size, (uint)permissions));
|
||||
}
|
||||
|
||||
public static bool IsAvailable()
|
||||
{
|
||||
try
|
||||
{
|
||||
Interface.uc_version(out _, out _);
|
||||
}
|
||||
catch (DllNotFoundException) { }
|
||||
|
||||
return Interface.IsUnicornAvailable;
|
||||
uc.MemProtect((long)address, (long)size, (int)permissions);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
public class UnicornException : Exception
|
||||
{
|
||||
public readonly Error Error;
|
||||
|
||||
internal UnicornException(Error error)
|
||||
{
|
||||
Error = error;
|
||||
}
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return Marshal.PtrToStringAnsi(Native.Interface.uc_strerror(Error));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
# Unicorn
|
||||
|
||||
Unicorn is a CPU simulator with bindings in many languages, including
|
||||
C#/.NET.
|
||||
It is used by the Ryujinx test suite for comparative testing with its built-in
|
||||
CPU simulator, Armeilleure.
|
||||
|
||||
## Windows
|
||||
|
||||
On Windows, Unicorn is shipped as a pre-compiled dynamic library (`.dll`), licenced under the GPLv2.
|
||||
|
||||
The source code for `windows/unicorn.dll` is available at: https://github.com/unicorn-engine/unicorn/tree/df3aa0fccbce9e1420e82110cbae5951755a0698
|
||||
|
||||
## Linux
|
||||
|
||||
On Windows, Unicorn is shipped as a pre-compiled shared object (`.so`), licenced under the GPLv2.
|
||||
|
||||
The source code for `linux/unicorn.so` is available at: https://github.com/unicorn-engine/unicorn/tree/df3aa0fccbce9e1420e82110cbae5951755a0698
|
||||
|
||||
See https://github.com/Ryujinx/Ryujinx/pull/1433 for details.
|
Binary file not shown.
Binary file not shown.
@@ -1,199 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Unicorn Engine
|
||||
# By Dang Hoang Vu, 2013
|
||||
# Modified for Ryujinx from: https://github.com/unicorn-engine/unicorn/blob/6c1cbef6ac505d355033aef1176b684d02e1eb3a/bindings/const_generator.py
|
||||
from __future__ import print_function
|
||||
import sys, re, os
|
||||
|
||||
include = [ 'arm.h', 'arm64.h', 'unicorn.h' ]
|
||||
split_common = [ 'ARCH', 'MODE', 'ERR', 'MEM', 'TCG', 'HOOK', 'PROT' ]
|
||||
|
||||
template = {
|
||||
'dotnet': {
|
||||
'header': "// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\n// ReSharper disable InconsistentNaming\nnamespace Ryujinx.Tests.Unicorn.Native.Const\n{\n public enum %s\n {\n",
|
||||
'footer': " }\n}\n",
|
||||
'line_format': ' %s = %s,\n',
|
||||
'out_file': os.path.join(os.path.dirname(__file__), 'Native', 'Const', '%s.cs'),
|
||||
# prefixes for constant filenames of all archs - case sensitive
|
||||
'arm.h': 'Arm',
|
||||
'arm64.h': 'Arm64',
|
||||
'unicorn.h': 'Common',
|
||||
# prefixes for filenames of split_common values - case sensitive
|
||||
'ARCH': 'Arch',
|
||||
'MODE': 'Mode',
|
||||
'ERR': 'Error',
|
||||
'MEM': 'Memory',
|
||||
'TCG': 'TCG',
|
||||
'HOOK': 'Hook',
|
||||
'PROT': 'Permission',
|
||||
'comment_open': ' //',
|
||||
'comment_close': '',
|
||||
}
|
||||
}
|
||||
|
||||
# markup for comments to be added to autogen files
|
||||
MARKUP = '//>'
|
||||
|
||||
def gen(unicorn_repo_path):
|
||||
global include
|
||||
include_dir = os.path.join(unicorn_repo_path, 'include', 'unicorn')
|
||||
templ = template["dotnet"]
|
||||
for target in include:
|
||||
prefix = templ[target]
|
||||
outfile = open(templ['out_file'] %(prefix), 'wb') # open as binary prevents windows newlines
|
||||
outfile.write((templ['header'] % (prefix)).encode("utf-8"))
|
||||
if target == 'unicorn.h':
|
||||
prefix = ''
|
||||
for cat in split_common:
|
||||
with open(templ['out_file'] %(templ[cat]), 'wb') as file:
|
||||
file.write((templ['header'] %(templ[cat])).encode("utf-8"))
|
||||
with open(os.path.join(include_dir, target)) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
previous = {}
|
||||
count = 0
|
||||
skip = 0
|
||||
in_comment = False
|
||||
|
||||
for lno, line in enumerate(lines):
|
||||
if "/*" in line:
|
||||
in_comment = True
|
||||
if "*/" in line:
|
||||
in_comment = False
|
||||
if in_comment:
|
||||
continue
|
||||
if skip > 0:
|
||||
# Due to clang-format, values may come up in the next line
|
||||
skip -= 1
|
||||
continue
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith(MARKUP): # markup for comments
|
||||
outfile.write(("\n%s%s%s\n" %(templ['comment_open'], \
|
||||
line.replace(MARKUP, ''), templ['comment_close'])).encode("utf-8"))
|
||||
continue
|
||||
|
||||
if line == '' or line.startswith('//'):
|
||||
continue
|
||||
|
||||
tmp = line.strip().split(',')
|
||||
if len(tmp) >= 2 and tmp[0] != "#define" and not tmp[0].startswith("UC_"):
|
||||
continue
|
||||
for t in tmp:
|
||||
t = t.strip()
|
||||
if not t or t.startswith('//'): continue
|
||||
f = re.split('\s+', t)
|
||||
|
||||
# parse #define UC_TARGET (num)
|
||||
define = False
|
||||
if f[0] == '#define' and len(f) >= 3:
|
||||
define = True
|
||||
f.pop(0)
|
||||
f.insert(1, '=')
|
||||
if f[0].startswith("UC_" + prefix.upper()) or f[0].startswith("UC_CPU"):
|
||||
if len(f) > 1 and f[1] not in ('//', '='):
|
||||
print("WARNING: Unable to convert %s" % f)
|
||||
print(" Line =", line)
|
||||
continue
|
||||
elif len(f) > 1 and f[1] == '=':
|
||||
# Like:
|
||||
# UC_A =
|
||||
# (1 << 2)
|
||||
# #define UC_B \
|
||||
# (UC_A | UC_C)
|
||||
# Let's search the next line
|
||||
if len(f) == 2:
|
||||
if lno == len(lines) - 1:
|
||||
print("WARNING: Unable to convert %s" % f)
|
||||
print(" Line =", line)
|
||||
continue
|
||||
skip += 1
|
||||
next_line = lines[lno + 1]
|
||||
next_line_tmp = next_line.strip().split(",")
|
||||
rhs = next_line_tmp[0]
|
||||
elif f[-1] == "\\":
|
||||
idx = 0
|
||||
rhs = ""
|
||||
while True:
|
||||
idx += 1
|
||||
if lno + idx == len(lines):
|
||||
print("WARNING: Unable to convert %s" % f)
|
||||
print(" Line =", line)
|
||||
continue
|
||||
skip += 1
|
||||
next_line = lines[lno + idx]
|
||||
next_line_f = re.split('\s+', next_line.strip())
|
||||
if next_line_f[-1] == "\\":
|
||||
rhs += "".join(next_line_f[:-1])
|
||||
else:
|
||||
rhs += next_line.strip()
|
||||
break
|
||||
else:
|
||||
rhs = ''.join(f[2:])
|
||||
else:
|
||||
rhs = str(count)
|
||||
|
||||
|
||||
lhs = f[0].strip()
|
||||
#print(f'lhs: {lhs} rhs: {rhs} f:{f}')
|
||||
# evaluate bitshifts in constants e.g. "UC_X86 = 1 << 1"
|
||||
match = re.match(r'(?P<rhs>\s*\d+\s*<<\s*\d+\s*)', rhs)
|
||||
if match:
|
||||
rhs = str(eval(match.group(1)))
|
||||
else:
|
||||
# evaluate references to other constants e.g. "UC_ARM_REG_X = UC_ARM_REG_SP"
|
||||
match = re.match(r'^([^\d]\w+)$', rhs)
|
||||
if match:
|
||||
rhs = previous[match.group(1)]
|
||||
|
||||
if not rhs.isdigit():
|
||||
for k, v in previous.items():
|
||||
rhs = re.sub(r'\b%s\b' % k, v, rhs)
|
||||
rhs = str(eval(rhs))
|
||||
|
||||
lhs_strip = re.sub(r'^UC_', '', lhs)
|
||||
count = int(rhs) + 1
|
||||
|
||||
if target == "unicorn.h":
|
||||
matched_cat = False
|
||||
for cat in split_common:
|
||||
if lhs_strip.startswith(f"{cat}_"):
|
||||
with open(templ['out_file'] %(templ[cat]), 'ab') as cat_file:
|
||||
cat_lhs_strip = lhs_strip
|
||||
if not lhs_strip.lstrip(f"{cat}_").isnumeric():
|
||||
cat_lhs_strip = lhs_strip.replace(f"{cat}_", "", 1)
|
||||
cat_file.write(
|
||||
(templ['line_format'] % (cat_lhs_strip, rhs)).encode("utf-8"))
|
||||
matched_cat = True
|
||||
break
|
||||
if matched_cat:
|
||||
previous[lhs] = str(rhs)
|
||||
continue
|
||||
|
||||
if (count == 1):
|
||||
outfile.write(("\n").encode("utf-8"))
|
||||
|
||||
if lhs_strip.startswith(f"{prefix.upper()}_") and not lhs_strip.replace(f"{prefix.upper()}_", "", 1).isnumeric():
|
||||
lhs_strip = lhs_strip.replace(f"{prefix.upper()}_", "", 1)
|
||||
|
||||
outfile.write((templ['line_format'] % (lhs_strip, rhs)).encode("utf-8"))
|
||||
previous[lhs] = str(rhs)
|
||||
|
||||
outfile.write((templ['footer']).encode("utf-8"))
|
||||
outfile.close()
|
||||
|
||||
if target == "unicorn.h":
|
||||
for cat in split_common:
|
||||
with open(templ['out_file'] %(templ[cat]), 'ab') as cat_file:
|
||||
cat_file.write(templ['footer'].encode('utf-8'))
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:", sys.argv[0], " <path to unicorn repo>")
|
||||
sys.exit(1)
|
||||
unicorn_repo_path = sys.argv[1]
|
||||
if os.path.isdir(unicorn_repo_path):
|
||||
print("Generating constants for dotnet")
|
||||
gen(unicorn_repo_path)
|
||||
else:
|
||||
print("Couldn't find unicorn repo at:", unicorn_repo_path)
|
@@ -6,7 +6,6 @@ using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Tests.Unicorn;
|
||||
using System;
|
||||
|
||||
using MemoryPermission = Ryujinx.Tests.Unicorn.MemoryPermission;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -33,18 +32,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private CpuContext _cpuContext;
|
||||
|
||||
private static bool _unicornAvailable;
|
||||
private UnicornAArch64 _unicornEmu;
|
||||
|
||||
private bool _usingMemory;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
_unicornAvailable = UnicornAArch64.IsAvailable();
|
||||
Assume.That(_unicornAvailable, "Unicorn is not available");
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
@@ -65,23 +56,17 @@ namespace Ryujinx.Tests.Cpu
|
||||
Optimizations.AllowLcqInFunctionTable = false;
|
||||
Optimizations.UseUnmanagedDispatchLoop = false;
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu = new UnicornAArch64();
|
||||
_unicornEmu.MemoryMap(CodeBaseAddress, Size, MemoryPermission.READ | MemoryPermission.EXEC);
|
||||
_unicornEmu.MemoryMap(DataBaseAddress, Size, MemoryPermission.READ | MemoryPermission.WRITE);
|
||||
_unicornEmu.PC = CodeBaseAddress;
|
||||
}
|
||||
_unicornEmu = new UnicornAArch64();
|
||||
_unicornEmu.MemoryMap(CodeBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Exec);
|
||||
_unicornEmu.MemoryMap(DataBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Write);
|
||||
_unicornEmu.PC = CodeBaseAddress;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
}
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
@@ -105,10 +90,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
_memory.Write(_currAddress, opcode);
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.MemoryWrite32(_currAddress, opcode);
|
||||
}
|
||||
_unicornEmu.MemoryWrite32(_currAddress, opcode);
|
||||
|
||||
_currAddress += 4;
|
||||
}
|
||||
@@ -158,38 +140,35 @@ namespace Ryujinx.Tests.Cpu
|
||||
_context.Fpcr = (FPCR)fpcr;
|
||||
_context.Fpsr = (FPSR)fpsr;
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.X[0] = x0;
|
||||
_unicornEmu.X[1] = x1;
|
||||
_unicornEmu.X[2] = x2;
|
||||
_unicornEmu.X[3] = x3;
|
||||
_unicornEmu.SP = x31;
|
||||
_unicornEmu.X[0] = x0;
|
||||
_unicornEmu.X[1] = x1;
|
||||
_unicornEmu.X[2] = x2;
|
||||
_unicornEmu.X[3] = x3;
|
||||
_unicornEmu.SP = x31;
|
||||
|
||||
_unicornEmu.Q[0] = V128ToSimdValue(v0);
|
||||
_unicornEmu.Q[1] = V128ToSimdValue(v1);
|
||||
_unicornEmu.Q[2] = V128ToSimdValue(v2);
|
||||
_unicornEmu.Q[3] = V128ToSimdValue(v3);
|
||||
_unicornEmu.Q[4] = V128ToSimdValue(v4);
|
||||
_unicornEmu.Q[5] = V128ToSimdValue(v5);
|
||||
_unicornEmu.Q[30] = V128ToSimdValue(v30);
|
||||
_unicornEmu.Q[31] = V128ToSimdValue(v31);
|
||||
_unicornEmu.Q[0] = V128ToSimdValue(v0);
|
||||
_unicornEmu.Q[1] = V128ToSimdValue(v1);
|
||||
_unicornEmu.Q[2] = V128ToSimdValue(v2);
|
||||
_unicornEmu.Q[3] = V128ToSimdValue(v3);
|
||||
_unicornEmu.Q[4] = V128ToSimdValue(v4);
|
||||
_unicornEmu.Q[5] = V128ToSimdValue(v5);
|
||||
_unicornEmu.Q[30] = V128ToSimdValue(v30);
|
||||
_unicornEmu.Q[31] = V128ToSimdValue(v31);
|
||||
|
||||
_unicornEmu.OverflowFlag = overflow;
|
||||
_unicornEmu.CarryFlag = carry;
|
||||
_unicornEmu.ZeroFlag = zero;
|
||||
_unicornEmu.NegativeFlag = negative;
|
||||
_unicornEmu.OverflowFlag = overflow;
|
||||
_unicornEmu.CarryFlag = carry;
|
||||
_unicornEmu.ZeroFlag = zero;
|
||||
_unicornEmu.NegativeFlag = negative;
|
||||
|
||||
_unicornEmu.Fpcr = fpcr;
|
||||
_unicornEmu.Fpsr = fpsr;
|
||||
}
|
||||
_unicornEmu.Fpcr = fpcr;
|
||||
_unicornEmu.Fpsr = fpsr;
|
||||
}
|
||||
|
||||
protected void ExecuteOpcodes(bool runUnicorn = true)
|
||||
{
|
||||
_cpuContext.Execute(_context, CodeBaseAddress);
|
||||
|
||||
if (_unicornAvailable && runUnicorn)
|
||||
if (runUnicorn)
|
||||
{
|
||||
_unicornEmu.RunForCount((_currAddress - CodeBaseAddress - 4) / 4);
|
||||
}
|
||||
@@ -239,10 +218,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
_memory.Write(DataBaseAddress + offset, data);
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.MemoryWrite(DataBaseAddress + offset, data);
|
||||
}
|
||||
_unicornEmu.MemoryWrite(DataBaseAddress + offset, data);
|
||||
|
||||
_usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
|
||||
}
|
||||
@@ -251,10 +227,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
_memory.Write(DataBaseAddress + offset, data);
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.MemoryWrite8(DataBaseAddress + offset, data);
|
||||
}
|
||||
_unicornEmu.MemoryWrite8(DataBaseAddress + offset, data);
|
||||
|
||||
_usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
|
||||
}
|
||||
@@ -331,11 +304,6 @@ namespace Ryujinx.Tests.Cpu
|
||||
FpSkips fpSkips = FpSkips.None,
|
||||
FpTolerances fpTolerances = FpTolerances.None)
|
||||
{
|
||||
if (!_unicornAvailable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IgnoreAllExcept_FpsrQc)
|
||||
{
|
||||
fpsrMask &= Fpsr.Qc;
|
||||
|
@@ -6,7 +6,6 @@ using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Tests.Unicorn;
|
||||
using System;
|
||||
|
||||
using MemoryPermission = Ryujinx.Tests.Unicorn.MemoryPermission;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -27,19 +26,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
private ExecutionContext _context;
|
||||
|
||||
private CpuContext _cpuContext;
|
||||
|
||||
private static bool _unicornAvailable;
|
||||
private UnicornAArch32 _unicornEmu;
|
||||
|
||||
private bool _usingMemory;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
_unicornAvailable = UnicornAArch32.IsAvailable();
|
||||
Assume.That(_unicornAvailable, "Unicorn is not available");
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
@@ -61,23 +51,17 @@ namespace Ryujinx.Tests.Cpu
|
||||
Optimizations.AllowLcqInFunctionTable = false;
|
||||
Optimizations.UseUnmanagedDispatchLoop = false;
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu = new UnicornAArch32();
|
||||
_unicornEmu.MemoryMap(CodeBaseAddress, Size, MemoryPermission.READ | MemoryPermission.EXEC);
|
||||
_unicornEmu.MemoryMap(DataBaseAddress, Size, MemoryPermission.READ | MemoryPermission.WRITE);
|
||||
_unicornEmu.PC = CodeBaseAddress;
|
||||
}
|
||||
_unicornEmu = new UnicornAArch32();
|
||||
_unicornEmu.MemoryMap(CodeBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Exec);
|
||||
_unicornEmu.MemoryMap(DataBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Write);
|
||||
_unicornEmu.PC = CodeBaseAddress;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
}
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
@@ -101,10 +85,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
_memory.Write(_currAddress, opcode);
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.MemoryWrite32(_currAddress, opcode);
|
||||
}
|
||||
_unicornEmu.MemoryWrite32(_currAddress, opcode);
|
||||
|
||||
_currAddress += 4;
|
||||
}
|
||||
@@ -113,10 +94,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
_memory.Write(_currAddress, opcode);
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.MemoryWrite16(_currAddress, opcode);
|
||||
}
|
||||
_unicornEmu.MemoryWrite16(_currAddress, opcode);
|
||||
|
||||
_currAddress += 2;
|
||||
}
|
||||
@@ -169,40 +147,37 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
_context.SetPstateFlag(PState.TFlag, thumb);
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.R[0] = r0;
|
||||
_unicornEmu.R[1] = r1;
|
||||
_unicornEmu.R[2] = r2;
|
||||
_unicornEmu.R[3] = r3;
|
||||
_unicornEmu.SP = sp;
|
||||
_unicornEmu.R[0] = r0;
|
||||
_unicornEmu.R[1] = r1;
|
||||
_unicornEmu.R[2] = r2;
|
||||
_unicornEmu.R[3] = r3;
|
||||
_unicornEmu.SP = sp;
|
||||
|
||||
_unicornEmu.Q[0] = V128ToSimdValue(v0);
|
||||
_unicornEmu.Q[1] = V128ToSimdValue(v1);
|
||||
_unicornEmu.Q[2] = V128ToSimdValue(v2);
|
||||
_unicornEmu.Q[3] = V128ToSimdValue(v3);
|
||||
_unicornEmu.Q[4] = V128ToSimdValue(v4);
|
||||
_unicornEmu.Q[5] = V128ToSimdValue(v5);
|
||||
_unicornEmu.Q[14] = V128ToSimdValue(v14);
|
||||
_unicornEmu.Q[15] = V128ToSimdValue(v15);
|
||||
_unicornEmu.Q[0] = V128ToSimdValue(v0);
|
||||
_unicornEmu.Q[1] = V128ToSimdValue(v1);
|
||||
_unicornEmu.Q[2] = V128ToSimdValue(v2);
|
||||
_unicornEmu.Q[3] = V128ToSimdValue(v3);
|
||||
_unicornEmu.Q[4] = V128ToSimdValue(v4);
|
||||
_unicornEmu.Q[5] = V128ToSimdValue(v5);
|
||||
_unicornEmu.Q[14] = V128ToSimdValue(v14);
|
||||
_unicornEmu.Q[15] = V128ToSimdValue(v15);
|
||||
|
||||
_unicornEmu.QFlag = saturation;
|
||||
_unicornEmu.OverflowFlag = overflow;
|
||||
_unicornEmu.CarryFlag = carry;
|
||||
_unicornEmu.ZeroFlag = zero;
|
||||
_unicornEmu.NegativeFlag = negative;
|
||||
_unicornEmu.QFlag = saturation;
|
||||
_unicornEmu.OverflowFlag = overflow;
|
||||
_unicornEmu.CarryFlag = carry;
|
||||
_unicornEmu.ZeroFlag = zero;
|
||||
_unicornEmu.NegativeFlag = negative;
|
||||
|
||||
_unicornEmu.Fpscr = fpscr;
|
||||
_unicornEmu.Fpscr = fpscr;
|
||||
|
||||
_unicornEmu.ThumbFlag = thumb;
|
||||
}
|
||||
_unicornEmu.ThumbFlag = thumb;
|
||||
}
|
||||
|
||||
protected void ExecuteOpcodes(bool runUnicorn = true)
|
||||
{
|
||||
_cpuContext.Execute(_context, CodeBaseAddress);
|
||||
|
||||
if (_unicornAvailable && runUnicorn)
|
||||
if (runUnicorn)
|
||||
{
|
||||
_unicornEmu.RunForCount((_currAddress - CodeBaseAddress - 4) / 4);
|
||||
}
|
||||
@@ -322,10 +297,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
_memory.Write(DataBaseAddress + offset, data);
|
||||
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.MemoryWrite(DataBaseAddress + offset, data);
|
||||
}
|
||||
_unicornEmu.MemoryWrite(DataBaseAddress + offset, data);
|
||||
|
||||
_usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
|
||||
}
|
||||
@@ -407,11 +379,6 @@ namespace Ryujinx.Tests.Cpu
|
||||
FpSkips fpSkips = FpSkips.None,
|
||||
FpTolerances fpTolerances = FpTolerances.None)
|
||||
{
|
||||
if (!_unicornAvailable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (fpSkips != FpSkips.None)
|
||||
{
|
||||
ManageFpSkips(fpSkips);
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#define Alu
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -91,12 +90,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("CLS <Xd>, <Xn>")]
|
||||
public void Cls_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_GenLeadingSignsX_")] [Random(RndCnt)] ulong xn)
|
||||
[ValueSource(nameof(_GenLeadingSignsX_))] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC01400; // CLS X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -111,7 +108,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("CLS <Wd>, <Wn>")]
|
||||
public void Cls_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_GenLeadingSignsW_")] [Random(RndCnt)] uint wn)
|
||||
[ValueSource(nameof(_GenLeadingSignsW_))] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC01400; // CLS W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -126,7 +123,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("CLZ <Xd>, <Xn>")]
|
||||
public void Clz_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_GenLeadingZerosX_")] [Random(RndCnt)] ulong xn)
|
||||
[ValueSource(nameof(_GenLeadingZerosX_))] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC01000; // CLZ X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -141,7 +138,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("CLZ <Wd>, <Wn>")]
|
||||
public void Clz_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_GenLeadingZerosW_")] [Random(RndCnt)] uint wn)
|
||||
[ValueSource(nameof(_GenLeadingZerosW_))] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC01000; // CLZ W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -157,7 +154,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rbit_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00000; // RBIT X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -173,7 +170,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rbit_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC00000; // RBIT W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -189,7 +186,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rev16_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00400; // REV16 X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -205,7 +202,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rev16_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC00400; // REV16 W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -221,7 +218,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rev32_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00800; // REV32 X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -237,7 +234,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rev32_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC00800; // REV W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -253,7 +250,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rev64_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00C00; // REV64 X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -266,4 +263,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _SU_H_AddSub_8_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe6100f90u, // SADD8 R0, R0, R0
|
||||
0xe6100ff0u, // SSUB8 R0, R0, R0
|
||||
@@ -27,7 +27,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Ssat_Usat_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe6a00010u, // SSAT R0, #1, R0, LSL #0
|
||||
0xe6a00050u, // SSAT R0, #1, R0, ASR #32
|
||||
@@ -38,7 +38,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Ssat16_Usat16_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe6a00f30u, // SSAT16 R0, #1, R0
|
||||
0xe6e00f30u, // USAT16 R0, #0, R0
|
||||
@@ -47,7 +47,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Lsr_Lsl_Asr_Ror_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe1b00030u, // LSRS R0, R0, R0
|
||||
0xe1b00010u, // LSLS R0, R0, R0
|
||||
@@ -63,7 +63,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Rbit_32bit([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0xe6ff0f30u; // RBIT R0, R0
|
||||
opcode |= ((rm & 15) << 0) | ((rd & 15) << 12);
|
||||
@@ -76,10 +76,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Lsr_Lsl_Asr_Ror([ValueSource("_Lsr_Lsl_Asr_Ror_")] uint opcode,
|
||||
public void Lsr_Lsl_Asr_Ror([ValueSource(nameof(_Lsr_Lsl_Asr_Ror_))] uint opcode,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint shiftValue,
|
||||
[Range(0, 31)] [Values(32, 256, 768, -1, -23)] int shiftAmount)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint shiftValue,
|
||||
[Range(0, 31)] int shiftAmount)
|
||||
{
|
||||
uint rd = 0;
|
||||
uint rm = 1;
|
||||
@@ -130,13 +130,13 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Ssat_Usat([ValueSource("_Ssat_Usat_")] uint opcode,
|
||||
public void Ssat_Usat([ValueSource(nameof(_Ssat_Usat_))] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Values(0u, 7u, 8u, 0xfu, 0x10u, 0x1fu)] uint sat,
|
||||
[Values(0u, 7u, 8u, 0xfu, 0x10u, 0x1fu)] uint shift,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((shift & 31) << 7) | ((rd & 15) << 12) | ((sat & 31) << 16);
|
||||
|
||||
@@ -148,12 +148,12 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Ssat16_Usat16([ValueSource("_Ssat16_Usat16_")] uint opcode,
|
||||
public void Ssat16_Usat16([ValueSource(nameof(_Ssat16_Usat16_))] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Values(0u, 7u, 8u, 0xfu)] uint sat,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rd & 15) << 12) | ((sat & 15) << 16);
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void SU_H_AddSub_8([ValueSource("_SU_H_AddSub_8_")] uint opcode,
|
||||
public void SU_H_AddSub_8([ValueSource(nameof(_SU_H_AddSub_8_))] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u)] uint rm,
|
||||
[Values(2u)] uint rn,
|
||||
@@ -206,4 +206,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -36,7 +36,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
// - xor 0
|
||||
// Only includes non-C variant, as the other can be tested with unicorn.
|
||||
|
||||
return new CrcTest[]
|
||||
return new[]
|
||||
{
|
||||
new CrcTest(0x00000000u, 0x00_00_00_00_00_00_00_00u, false, 0x00000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
new CrcTest(0x00000000u, 0x7f_ff_ff_ff_ff_ff_ff_ffu, false, 0x2d02ef8d, 0xbe2612ff, 0xdebb20e3, 0xa9de8355),
|
||||
@@ -53,14 +53,12 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Combinatorial]
|
||||
public void Crc32_b_h_w_x([Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(2u)] uint rm,
|
||||
[Range(0u, 3u)] uint size,
|
||||
[ValueSource("_CRC32_Test_Values_")] CrcTest test)
|
||||
[ValueSource(nameof(_CRC32_Test_Values_))] CrcTest test)
|
||||
{
|
||||
uint opcode = 0x1AC04000; // CRC32B W0, W0, W0
|
||||
|
||||
@@ -85,11 +83,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32x([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ulong)0x00_00_00_00_00_00_00_00,
|
||||
(ulong)0x7F_FF_FF_FF_FF_FF_FF_FF,
|
||||
(ulong)0x80_00_00_00_00_00_00_00,
|
||||
(ulong)0xFF_FF_FF_FF_FF_FF_FF_FF)] [Random(RndCnt)] ulong xm)
|
||||
0x80_00_00_00_00_00_00_00,
|
||||
0xFF_FF_FF_FF_FF_FF_FF_FF)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC04C00; // CRC32X W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -105,9 +103,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32w([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((uint)0x00_00_00_00, (uint)0x7F_FF_FF_FF,
|
||||
(uint)0x80_00_00_00, (uint)0xFF_FF_FF_FF)] [Random(RndCnt)] uint wm)
|
||||
0x80_00_00_00, 0xFF_FF_FF_FF)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC04800; // CRC32W W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -123,9 +121,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32h([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ushort)0x00_00, (ushort)0x7F_FF,
|
||||
(ushort)0x80_00, (ushort)0xFF_FF)] [Random(RndCnt)] ushort wm)
|
||||
(ushort)0x80_00, (ushort)0xFF_FF)] ushort wm)
|
||||
{
|
||||
uint opcode = 0x1AC04400; // CRC32H W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -141,9 +139,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32b([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm)
|
||||
(byte)0x80, (byte)0xFF)] byte wm)
|
||||
{
|
||||
uint opcode = 0x1AC04000; // CRC32B W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -159,11 +157,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32cx([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ulong)0x00_00_00_00_00_00_00_00,
|
||||
(ulong)0x7F_FF_FF_FF_FF_FF_FF_FF,
|
||||
(ulong)0x80_00_00_00_00_00_00_00,
|
||||
(ulong)0xFF_FF_FF_FF_FF_FF_FF_FF)] [Random(RndCnt)] ulong xm)
|
||||
0x80_00_00_00_00_00_00_00,
|
||||
0xFF_FF_FF_FF_FF_FF_FF_FF)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC05C00; // CRC32CX W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -179,9 +177,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32cw([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((uint)0x00_00_00_00, (uint)0x7F_FF_FF_FF,
|
||||
(uint)0x80_00_00_00, (uint)0xFF_FF_FF_FF)] [Random(RndCnt)] uint wm)
|
||||
0x80_00_00_00, 0xFF_FF_FF_FF)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC05800; // CRC32CW W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -197,9 +195,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32ch([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ushort)0x00_00, (ushort)0x7F_FF,
|
||||
(ushort)0x80_00, (ushort)0xFF_FF)] [Random(RndCnt)] ushort wm)
|
||||
(ushort)0x80_00, (ushort)0xFF_FF)] ushort wm)
|
||||
{
|
||||
uint opcode = 0x1AC05400; // CRC32CH W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -215,9 +213,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Crc32cb([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm)
|
||||
(byte)0x80, (byte)0xFF)] byte wm)
|
||||
{
|
||||
uint opcode = 0x1AC05000; // CRC32CB W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -234,9 +232,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC00C00; // SDIV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -253,9 +251,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC00C00; // SDIV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -272,9 +270,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC00800; // UDIV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -291,9 +289,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC00800; // UDIV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -306,4 +304,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -36,7 +36,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
// - bytes in order of increasing significance
|
||||
// - xor 0
|
||||
|
||||
return new CrcTest32[]
|
||||
return new[]
|
||||
{
|
||||
new CrcTest32(0x00000000u, 0x00_00_00_00u, false, 0x00000000, 0x00000000, 0x00000000),
|
||||
new CrcTest32(0x00000000u, 0x7f_ff_ff_ffu, false, 0x2d02ef8d, 0xbe2612ff, 0x3303a3c3),
|
||||
@@ -70,7 +70,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u)] uint rn,
|
||||
[Values(2u)] uint rm,
|
||||
[Range(0u, 2u)] uint size,
|
||||
[ValueSource("_CRC32_Test_Values_")] CrcTest32 test)
|
||||
[ValueSource(nameof(_CRC32_Test_Values_))] CrcTest32 test)
|
||||
{
|
||||
// Unicorn does not yet support 32bit crc instructions, so test against a known table of results/values.
|
||||
|
||||
|
@@ -8,17 +8,13 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestAluImm : CpuTest
|
||||
{
|
||||
#if AluImm
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntImm = 2;
|
||||
private const int RndCntImms = 2;
|
||||
private const int RndCntImmr = 2;
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||
public void Add_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x91000000; // ADD X0, X0, #0, LSL #0
|
||||
@@ -41,8 +37,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Add_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x11000000; // ADD W0, W0, #0, LSL #0
|
||||
@@ -65,8 +61,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Adds_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0xB1000000; // ADDS X0, X0, #0, LSL #0
|
||||
@@ -89,8 +85,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Adds_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x31000000; // ADDS W0, W0, #0, LSL #0
|
||||
@@ -113,9 +109,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void And_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] [Random(0u, 62u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x92400000; // AND X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -132,9 +128,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void And_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x92000000; // AND X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -151,9 +147,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void And_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x12000000; // AND W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -170,9 +166,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ands_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] [Random(0u, 62u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xF2400000; // ANDS X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -189,9 +185,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ands_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xF2000000; // ANDS X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -208,9 +204,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ands_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x72000000; // ANDS W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -227,9 +223,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Eor_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] [Random(0u, 62u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xD2400000; // EOR X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -246,9 +242,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Eor_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xD2000000; // EOR X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -265,9 +261,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Eor_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x52000000; // EOR W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -284,9 +280,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Orr_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] [Random(0u, 62u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xB2400000; // ORR X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -303,9 +299,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Orr_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xB2000000; // ORR X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -322,9 +318,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Orr_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] [Random(0u, 30u, RndCntImms)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr) // <imm>
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x32000000; // ORR W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -341,8 +337,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Sub_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0xD1000000; // SUB X0, X0, #0, LSL #0
|
||||
@@ -365,8 +361,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Sub_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x51000000; // SUB W0, W0, #0, LSL #0
|
||||
@@ -389,8 +385,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Subs_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0xF1000000; // SUBS X0, X0, #0, LSL #0
|
||||
@@ -413,8 +409,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Subs_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x71000000; // SUBS W0, W0, #0, LSL #0
|
||||
@@ -434,4 +430,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _opcodes()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe2a00000u, // ADC R0, R0, #0
|
||||
0xe2b00000u, // ADCS R0, R0, #0
|
||||
@@ -33,10 +33,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntAmount = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void TestCpuTestAluImm32([ValueSource("_opcodes")] uint opcode,
|
||||
public void TestCpuTestAluImm32([ValueSource(nameof(_opcodes))] uint opcode,
|
||||
[Values(0u, 13u)] uint rd,
|
||||
[Values(1u, 13u)] uint rn,
|
||||
[Random(RndCnt)] uint imm,
|
||||
@@ -53,4 +52,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,18 +8,15 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestAluRs : CpuTest
|
||||
{
|
||||
#if AluRs
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntAmount = 2;
|
||||
private const int RndCntLsb = 2;
|
||||
|
||||
[Test, Pairwise, Description("ADC <Xd>, <Xn>, <Xm>")]
|
||||
public void Adc_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x9A000000; // ADC X0, X0, X0
|
||||
@@ -37,9 +34,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x1A000000; // ADC W0, W0, W0
|
||||
@@ -57,9 +54,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0xBA000000; // ADCS X0, X0, X0
|
||||
@@ -77,9 +74,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x3A000000; // ADCS W0, W0, W0
|
||||
@@ -97,11 +94,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8B000000; // ADD X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -119,11 +116,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0B000000; // ADD W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -141,11 +138,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAB000000; // ADDS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -163,11 +160,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2B000000; // ADDS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -185,11 +182,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8A000000; // AND X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -207,11 +204,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0A000000; // AND W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -229,11 +226,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEA000000; // ANDS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -251,11 +248,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6A000000; // ANDS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -273,9 +270,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02800; // ASRV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -292,9 +289,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02800; // ASRV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -311,11 +308,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8A200000; // BIC X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -333,11 +330,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0A200000; // BIC W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -355,11 +352,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEA200000; // BICS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -377,11 +374,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6A200000; // BICS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -399,11 +396,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCA200000; // EON X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -421,11 +418,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4A200000; // EON W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -443,11 +440,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCA000000; // EOR X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -465,11 +462,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4A000000; // EOR W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -487,10 +484,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntLsb)] uint lsb)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0u, 31u, 32u, 63u)] uint lsb)
|
||||
{
|
||||
uint opcode = 0x93C00000; // EXTR X0, X0, X0, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -508,10 +505,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntLsb)] uint lsb)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb)
|
||||
{
|
||||
uint opcode = 0x13800000; // EXTR W0, W0, W0, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -529,9 +526,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02000; // LSLV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -548,9 +545,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02000; // LSLV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -567,9 +564,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02400; // LSRV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -586,9 +583,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02400; // LSRV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -605,11 +602,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAA200000; // ORN X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -627,11 +624,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2A200000; // ORN W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -649,11 +646,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAA000000; // ORR X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -671,11 +668,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2A000000; // ORR W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -693,9 +690,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02C00; // RORV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -712,9 +709,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02C00; // RORV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -731,9 +728,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0xDA000000; // SBC X0, X0, X0
|
||||
@@ -751,9 +748,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x5A000000; // SBC W0, W0, W0
|
||||
@@ -771,9 +768,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0xFA000000; // SBCS X0, X0, X0
|
||||
@@ -791,9 +788,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x7A000000; // SBCS W0, W0, W0
|
||||
@@ -811,11 +808,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCB000000; // SUB X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -833,11 +830,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4B000000; // SUB W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -855,11 +852,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEB000000; // SUBS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -877,11 +874,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6B000000; // SUBS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -895,4 +892,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Add_Adds_Rsb_Rsbs_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe0800000u, // ADD R0, R0, R0, LSL #0
|
||||
0xe0900000u, // ADDS R0, R0, R0, LSL #0
|
||||
@@ -23,7 +23,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Adc_Adcs_Rsc_Rscs_Sbc_Sbcs_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe0a00000u, // ADC R0, R0, R0
|
||||
0xe0b00000u, // ADCS R0, R0, R0
|
||||
@@ -35,8 +35,6 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntAmount = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Adc_Adcs_Rsc_Rscs_Sbc_Sbcs([ValueSource("_Adc_Adcs_Rsc_Rscs_Sbc_Sbcs_")] uint opcode,
|
||||
@@ -44,9 +42,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 13u)] uint rn,
|
||||
[Values(2u, 13u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
opcode |= ((rm & 15) << 0) | ((rn & 15) << 16) | ((rd & 15) << 12);
|
||||
@@ -64,11 +62,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 13u)] uint rn,
|
||||
[Values(2u, 13u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntAmount)] uint amount)
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
opcode |= ((rm & 15) << 0) | ((rn & 15) << 16) | ((rd & 15) << 12);
|
||||
opcode |= ((shift & 3) << 5) | ((amount & 31) << 7);
|
||||
@@ -81,4 +79,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,16 +8,15 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestAluRx : CpuTest
|
||||
{
|
||||
#if AluRx
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd|SP>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||
public void Add_X_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
(ulong)0x8000000000000000, (ulong)0xFFFFFFFFFFFFFFFF)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
@@ -44,9 +43,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -74,9 +73,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -104,9 +103,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -134,9 +133,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -164,9 +163,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -194,9 +193,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -224,9 +223,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
(ulong)0x8000000000000000, (ulong)0xFFFFFFFFFFFFFFFF)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
@@ -244,9 +243,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -265,9 +264,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -286,9 +285,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -307,9 +306,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -328,9 +327,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -349,9 +348,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -370,9 +369,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
(ulong)0x8000000000000000, (ulong)0xFFFFFFFFFFFFFFFF)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
@@ -399,9 +398,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -429,9 +428,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -459,9 +458,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -489,9 +488,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -519,9 +518,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -549,9 +548,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -579,9 +578,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
(ulong)0x8000000000000000, (ulong)0xFFFFFFFFFFFFFFFF)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
@@ -599,9 +598,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -620,9 +619,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -641,9 +640,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xnSp,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -662,9 +661,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
(uint)0x80000000, (uint)0xFFFFFFFF)] [Random(RndCnt)] uint wm,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -683,9 +682,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] [Random(RndCnt)] ushort wm,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -704,9 +703,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wnWsp,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] [Random(RndCnt)] byte wm,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
@@ -721,4 +720,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,15 +10,13 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
#if Bf32
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntImmr = 2;
|
||||
private const int RndCntImms = 2;
|
||||
|
||||
[Test, Pairwise, Description("BFC <Rd>, #<lsb>, #<width>")]
|
||||
public void Bfc([Values(0u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wd,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImms)] uint msb)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wd,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint msb)
|
||||
{
|
||||
msb = Math.Max(lsb, msb); // Don't test unpredictable for now.
|
||||
uint opcode = 0xe7c0001fu; // BFC R0, #0, #1
|
||||
@@ -37,9 +35,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[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 msb)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint msb)
|
||||
{
|
||||
msb = Math.Max(lsb, msb); // Don't test unpredictable for now.
|
||||
uint opcode = 0xe7c00010u; // BFI R0, R0, #0, #1
|
||||
@@ -59,9 +57,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[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)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint widthm1)
|
||||
{
|
||||
if (lsb + widthm1 > 31)
|
||||
{
|
||||
@@ -84,9 +82,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[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)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint widthm1)
|
||||
{
|
||||
if (lsb + widthm1 > 31)
|
||||
{
|
||||
@@ -105,4 +103,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,17 +9,15 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
#if Bfm
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntImmr = 2;
|
||||
private const int RndCntImms = 2;
|
||||
|
||||
[Test, Pairwise, Description("BFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
||||
public void Bfm_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Random(RndCnt)] ulong xd,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImmr)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImms)] uint imms)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] uint imms)
|
||||
{
|
||||
uint opcode = 0xB3400000; // BFM X0, X0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -37,9 +35,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] 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 immr,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImms)] uint imms)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x33000000; // BFM W0, W0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -56,9 +54,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Sbfm_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImmr)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImms)] uint imms)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x93400000; // SBFM X0, X0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -75,9 +73,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Sbfm_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImms)] uint imms)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x13000000; // SBFM W0, W0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -94,9 +92,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ubfm_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImmr)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] [Random(0u, 63u, RndCntImms)] uint imms)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] uint imms)
|
||||
{
|
||||
uint opcode = 0xD3400000; // UBFM X0, X0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -113,9 +111,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ubfm_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImmr)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] [Random(0u, 31u, RndCntImms)] uint imms)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x53000000; // UBFM W0, W0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -129,4 +127,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,15 +8,13 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestCcmpImm : CpuTest
|
||||
{
|
||||
#if CcmpImm
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntImm = 2;
|
||||
private const int RndCntNzcv = 2;
|
||||
|
||||
[Test, Pairwise, Description("CCMN <Xn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmn_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u)] [Random(0u, 31u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -37,8 +35,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("CCMN <Wn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmn_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 31u)] [Random(0u, 31u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -59,8 +57,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("CCMP <Xn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmp_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 31u)] [Random(0u, 31u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -81,8 +79,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("CCMP <Wn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmp_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 31u)] [Random(0u, 31u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -101,4 +99,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,16 +8,15 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestCcmpReg : CpuTest
|
||||
{
|
||||
#if CcmpReg
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntNzcv = 2;
|
||||
|
||||
[Test, Pairwise, Description("CCMN <Xn>, <Xm>, #<nzcv>, <cond>")]
|
||||
public void Ccmn_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -39,9 +38,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ccmn_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -63,9 +62,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ccmp_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -87,9 +86,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ccmp_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -108,4 +107,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,16 +8,15 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestCsel : CpuTest
|
||||
{
|
||||
#if Csel
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("CSEL <Xd>, <Xn>, <Xm>, <cond>")]
|
||||
public void Csel_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -39,9 +38,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -63,9 +62,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -87,9 +86,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -111,9 +110,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -135,9 +134,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -159,9 +158,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -183,9 +182,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -203,4 +202,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
#define Misc
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -59,7 +57,6 @@ namespace Ryujinx.Tests.Cpu
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntImm = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
@@ -68,8 +65,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "AluImm & Csel"
|
||||
[Test, Pairwise]
|
||||
public void Adds_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -93,8 +90,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Adds_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -118,8 +115,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Subs_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -143,8 +140,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Subs_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -412,9 +409,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise]
|
||||
public void Misc4([ValueSource("_1S_F_")] ulong a,
|
||||
[ValueSource("_1S_F_")] ulong b,
|
||||
[ValueSource("_1S_F_")] ulong c,
|
||||
public void Misc4([ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[ValueSource(nameof(_1S_F_))] ulong c,
|
||||
[Values(0ul, 1ul, 2ul, 3ul)] ulong displacement)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
@@ -460,7 +457,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Explicit]
|
||||
[Test]
|
||||
public void Misc5([ValueSource("_1S_F_")] ulong a)
|
||||
public void Misc5([ValueSource(nameof(_1S_F_))] ulong a)
|
||||
{
|
||||
SetContext(
|
||||
v0: MakeVectorE0E1(a, TestContext.CurrentContext.Random.NextULong()),
|
||||
@@ -482,4 +479,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
#define Misc32
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -64,8 +62,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vmsr_Vcmp_Vmrs([ValueSource("_1S_F_")] ulong a,
|
||||
[ValueSource("_1S_F_")] ulong b,
|
||||
public void Vmsr_Vcmp_Vmrs([ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[Values] bool mode1,
|
||||
[Values] bool mode2,
|
||||
[Values] bool mode3)
|
||||
|
@@ -9,12 +9,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
#if Mov
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntImm = 2;
|
||||
|
||||
[Test, Pairwise, Description("MOVK <Xd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movk_64bit([Values(0u, 31u)] uint rd,
|
||||
[Random(RndCnt)] ulong xd,
|
||||
[Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u, 32u, 48u)] uint shift)
|
||||
{
|
||||
uint opcode = 0xF2800000; // MOVK X0, #0, LSL #0
|
||||
@@ -31,7 +30,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("MOVK <Wd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movk_32bit([Values(0u, 31u)] uint rd,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x72800000; // MOVK W0, #0, LSL #0
|
||||
@@ -47,7 +46,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Test, Pairwise, Description("MOVN <Xd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movn_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u, 32u, 48u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x92800000; // MOVN X0, #0, LSL #0
|
||||
@@ -63,7 +62,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Test, Pairwise, Description("MOVN <Wd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movn_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x12800000; // MOVN W0, #0, LSL #0
|
||||
@@ -79,7 +78,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Test, Pairwise, Description("MOVZ <Xd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movz_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u, 32u, 48u)] uint shift)
|
||||
{
|
||||
uint opcode = 0xD2800000; // MOVZ X0, #0, LSL #0
|
||||
@@ -95,7 +94,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
[Test, Pairwise, Description("MOVZ <Wd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movz_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x52800000; // MOVZ W0, #0, LSL #0
|
||||
@@ -110,4 +109,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,19 +8,17 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestMul : CpuTest
|
||||
{
|
||||
#if Mul
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("MADD <Xd>, <Xn>, <Xm>, <Xa>")]
|
||||
public void Madd_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xa)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B000000; // MADD X0, X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -38,11 +36,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wa)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
uint opcode = 0x1B000000; // MADD W0, W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -60,11 +58,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xa)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B008000; // MSUB X0, X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -82,11 +80,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wa)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
uint opcode = 0x1B008000; // MSUB W0, W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -104,11 +102,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xa)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B200000; // SMADDL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -126,11 +124,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xa)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9BA00000; // UMADDL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -148,11 +146,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xa)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B208000; // SMSUBL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -170,11 +168,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xa)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9BA08000; // UMSUBL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -191,9 +189,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9B407C00; // SMULH X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -210,9 +208,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xm)
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9BC07C00; // UMULH X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -225,4 +223,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Smlabb_Smlabt_Smlatb_Smlatt_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe1000080u, // SMLABB R0, R0, R0, R0
|
||||
0xe10000C0u, // SMLABT R0, R0, R0, R0
|
||||
@@ -23,7 +23,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Smlawb_Smlawt_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe1200080u, // SMLAWB R0, R0, R0, R0
|
||||
0xe12000C0u, // SMLAWT R0, R0, R0, R0
|
||||
@@ -32,7 +32,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Smulbb_Smulbt_Smultb_Smultt_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe1600080u, // SMULBB R0, R0, R0
|
||||
0xe16000C0u, // SMULBT R0, R0, R0
|
||||
@@ -43,7 +43,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Smulwb_Smulwt_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xe12000a0u, // SMULWB R0, R0, R0
|
||||
0xe12000e0u, // SMULWT R0, R0, R0
|
||||
@@ -51,8 +51,6 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("SMLA<x><y> <Rd>, <Rn>, <Rm>, <Ra>")]
|
||||
public void Smla___32bit([ValueSource("_Smlabb_Smlabt_Smlatb_Smlatt_")] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rn,
|
||||
@@ -60,11 +58,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 0xdu)] uint ra,
|
||||
[Values(3u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wa)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((ra & 15) << 12) | ((rd & 15) << 16);
|
||||
|
||||
@@ -82,11 +80,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(2u, 0xdu)] uint ra,
|
||||
[Values(3u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wa)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((ra & 15) << 12) | ((rd & 15) << 16);
|
||||
|
||||
@@ -103,9 +101,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(2u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((rd & 15) << 16);
|
||||
|
||||
@@ -122,9 +120,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(2u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wm)
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((rd & 15) << 16);
|
||||
|
||||
@@ -136,4 +134,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Vabs_Vneg_Vpaddl_I_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xf3b10300u, // VABS.S8 D0, D0
|
||||
0xf3b10380u, // VNEG.S8 D0, D0
|
||||
@@ -24,7 +24,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Vabs_Vneg_F_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xf3b90700u, // VABS.F32 D0, D0
|
||||
0xf3b90780u // VNEG.F32 D0, D0
|
||||
@@ -35,10 +35,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _8B4H2S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
@@ -211,11 +211,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vabs_Vneg_Vpaddl_V_I([ValueSource("_Vabs_Vneg_Vpaddl_I_")] uint opcode,
|
||||
public void Vabs_Vneg_Vpaddl_V_I([ValueSource(nameof(_Vabs_Vneg_Vpaddl_I_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u)] uint size, // <S8, S16, S32>
|
||||
[Values] bool q)
|
||||
{
|
||||
@@ -241,11 +241,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vabs_Vneg_V_F32([ValueSource("_Vabs_Vneg_F_")] uint opcode,
|
||||
public void Vabs_Vneg_V_F32([ValueSource(nameof(_Vabs_Vneg_F_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource("_2S_F_")] ulong z,
|
||||
[ValueSource("_2S_F_")] ulong b,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
if (q)
|
||||
@@ -270,7 +270,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("VCNT.8 D0, D0 | VCNT.8 Q0, Q0")]
|
||||
public void Vcnt([Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[ValueSource(nameof(_GenPopCnt8B_))] [Random(RndCnt)] ulong d0,
|
||||
[ValueSource(nameof(_GenPopCnt8B_))] ulong d0,
|
||||
[Values] bool q)
|
||||
{
|
||||
ulong d1 = ~d0; // It's expensive to have a second generator.
|
||||
@@ -298,8 +298,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise]
|
||||
public void Vmovn_V([Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint op,
|
||||
[Values(0u, 1u, 2u)] uint size) // <S8, S16, S32>
|
||||
{
|
||||
@@ -322,4 +322,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
#define SimdCvt
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -17,14 +15,14 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Types)"
|
||||
private static uint[] _W_()
|
||||
{
|
||||
return new uint[] { 0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
return new[] { 0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
}
|
||||
|
||||
private static ulong[] _X_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1S_F_WX_()
|
||||
@@ -89,13 +87,13 @@ namespace Ryujinx.Tests.Cpu
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
ulong rnd1 = (uint)BitConverter.SingleToInt32Bits(
|
||||
(float)((int)TestContext.CurrentContext.Random.NextUInt()));
|
||||
(int)TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd2 = (uint)BitConverter.SingleToInt32Bits(
|
||||
(float)((long)TestContext.CurrentContext.Random.NextULong()));
|
||||
(long)TestContext.CurrentContext.Random.NextULong());
|
||||
ulong rnd3 = (uint)BitConverter.SingleToInt32Bits(
|
||||
(float)((uint)TestContext.CurrentContext.Random.NextUInt()));
|
||||
TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd4 = (uint)BitConverter.SingleToInt32Bits(
|
||||
(float)((ulong)TestContext.CurrentContext.Random.NextULong()));
|
||||
TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
ulong rnd5 = GenNormalS();
|
||||
ulong rnd6 = GenSubnormalS();
|
||||
@@ -170,13 +168,13 @@ namespace Ryujinx.Tests.Cpu
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
(double)((int)TestContext.CurrentContext.Random.NextUInt()));
|
||||
(int)TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd2 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
(double)((long)TestContext.CurrentContext.Random.NextULong()));
|
||||
(long)TestContext.CurrentContext.Random.NextULong());
|
||||
ulong rnd3 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
(double)((uint)TestContext.CurrentContext.Random.NextUInt()));
|
||||
TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd4 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
(double)((ulong)TestContext.CurrentContext.Random.NextULong()));
|
||||
TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
ulong rnd5 = GenNormalD();
|
||||
ulong rnd6 = GenSubnormalD();
|
||||
@@ -195,7 +193,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_SW_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E240000u, // FCVTAS W0, S0
|
||||
0x1E250000u, // FCVTAU W0, S0
|
||||
@@ -211,7 +209,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_SX_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E240000u, // FCVTAS X0, S0
|
||||
0x9E250000u, // FCVTAU X0, S0
|
||||
@@ -227,7 +225,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_DW_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E640000u, // FCVTAS W0, D0
|
||||
0x1E650000u, // FCVTAU W0, D0
|
||||
@@ -243,7 +241,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_DX_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E640000u, // FCVTAS X0, D0
|
||||
0x9E650000u, // FCVTAU X0, D0
|
||||
@@ -259,7 +257,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_SW_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E188000u, // FCVTZS W0, S0, #32
|
||||
0x1E198000u // FCVTZU W0, S0, #32
|
||||
@@ -268,7 +266,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_SX_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E180000u, // FCVTZS X0, S0, #64
|
||||
0x9E190000u // FCVTZU X0, S0, #64
|
||||
@@ -277,7 +275,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_DW_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E588000u, // FCVTZS W0, D0, #32
|
||||
0x1E598000u // FCVTZU W0, D0, #32
|
||||
@@ -286,7 +284,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_DX_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E580000u, // FCVTZS X0, D0, #64
|
||||
0x9E590000u // FCVTZU X0, D0, #64
|
||||
@@ -295,7 +293,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_WS_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E220000u, // SCVTF S0, W0
|
||||
0x1E230000u // UCVTF S0, W0
|
||||
@@ -304,7 +302,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_WD_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E620000u, // SCVTF D0, W0
|
||||
0x1E630000u // UCVTF D0, W0
|
||||
@@ -313,7 +311,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_XS_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E220000u, // SCVTF S0, X0
|
||||
0x9E230000u // UCVTF S0, X0
|
||||
@@ -322,7 +320,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_XD_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E620000u, // SCVTF D0, X0
|
||||
0x9E630000u // UCVTF D0, X0
|
||||
@@ -331,7 +329,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_WS_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E028000u, // SCVTF S0, W0, #32
|
||||
0x1E038000u // UCVTF S0, W0, #32
|
||||
@@ -340,7 +338,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_WD_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E428000u, // SCVTF D0, W0, #32
|
||||
0x1E438000u // UCVTF D0, W0, #32
|
||||
@@ -349,7 +347,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_XS_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E020000u, // SCVTF S0, X0, #64
|
||||
0x9E030000u // UCVTF S0, X0, #64
|
||||
@@ -358,7 +356,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_XD_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x9E420000u, // SCVTF D0, X0, #64
|
||||
0x9E430000u // UCVTF D0, X0, #64
|
||||
@@ -367,17 +365,16 @@ namespace Ryujinx.Tests.Cpu
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntFBits = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_SW([ValueSource("_F_Cvt_AMPZ_SU_Gp_SW_")] uint opcodes,
|
||||
public void F_Cvt_AMPZ_SU_Gp_SW([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_SW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1S_F_WX_")] ulong a)
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -391,10 +388,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_SX([ValueSource("_F_Cvt_AMPZ_SU_Gp_SX_")] uint opcodes,
|
||||
public void F_Cvt_AMPZ_SU_Gp_SX([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_SX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1S_F_WX_")] ulong a)
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -407,10 +404,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_DW([ValueSource("_F_Cvt_AMPZ_SU_Gp_DW_")] uint opcodes,
|
||||
public void F_Cvt_AMPZ_SU_Gp_DW([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_DW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1D_F_WX_")] ulong a)
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -424,10 +421,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_DX([ValueSource("_F_Cvt_AMPZ_SU_Gp_DX_")] uint opcodes,
|
||||
public void F_Cvt_AMPZ_SU_Gp_DX([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_DX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1D_F_WX_")] ulong a)
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -440,11 +437,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_SW([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_SW_")] uint opcodes,
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_SW([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_SW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1S_F_WX_")] ulong a,
|
||||
[Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -461,11 +458,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_SX([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_SX_")] uint opcodes,
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_SX([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_SX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1S_F_WX_")] ulong a,
|
||||
[Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -481,11 +478,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_DW([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_DW_")] uint opcodes,
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_DW([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_DW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1D_F_WX_")] ulong a,
|
||||
[Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -502,11 +499,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_DX([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_DX_")] uint opcodes,
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_DX([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_DX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1D_F_WX_")] ulong a,
|
||||
[Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -522,10 +519,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_WS([ValueSource("_SU_Cvt_F_Gp_WS_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_WS([ValueSource(nameof(_SU_Cvt_F_Gp_WS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn)
|
||||
[ValueSource(nameof(_W_))] uint wn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -539,10 +536,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_WD([ValueSource("_SU_Cvt_F_Gp_WD_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_WD([ValueSource(nameof(_SU_Cvt_F_Gp_WD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn)
|
||||
[ValueSource(nameof(_W_))] uint wn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -556,10 +553,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_XS([ValueSource("_SU_Cvt_F_Gp_XS_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_XS([ValueSource(nameof(_SU_Cvt_F_Gp_XS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_X_")] [Random(RndCnt)] ulong xn)
|
||||
[ValueSource(nameof(_X_))] ulong xn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -573,10 +570,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_XD([ValueSource("_SU_Cvt_F_Gp_XD_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_XD([ValueSource(nameof(_SU_Cvt_F_Gp_XD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_X_")] [Random(RndCnt)] ulong xn)
|
||||
[ValueSource(nameof(_X_))] ulong xn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
@@ -590,11 +587,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_WS([ValueSource("_SU_Cvt_F_Gp_Fixed_WS_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_Fixed_WS([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_WS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn,
|
||||
[Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -611,11 +608,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_WD([ValueSource("_SU_Cvt_F_Gp_Fixed_WD_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_Fixed_WD([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_WD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn,
|
||||
[Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -632,11 +629,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_XS([ValueSource("_SU_Cvt_F_Gp_Fixed_XS_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_Fixed_XS([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_XS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_X_")] [Random(RndCnt)] ulong xn,
|
||||
[Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_X_))] ulong xn,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -653,11 +650,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_XD([ValueSource("_SU_Cvt_F_Gp_Fixed_XD_")] uint opcodes,
|
||||
public void SU_Cvt_F_Gp_Fixed_XD([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_XD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_X_")] [Random(RndCnt)] ulong xn,
|
||||
[Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits)
|
||||
[ValueSource(nameof(_X_))] ulong xn,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
@@ -674,4 +671,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Vrint_AMNP_V_F32_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xf3ba0500u, // VRINTA.F32 Q0, Q0
|
||||
0xf3ba0680u, // VRINTM.F32 Q0, Q0
|
||||
@@ -28,8 +28,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Types)"
|
||||
private static uint[] _1S_()
|
||||
{
|
||||
return new uint[] { 0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
return new[] { 0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
@@ -219,10 +219,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("VCVT.F32.<dt> <Sd>, <Sm>")]
|
||||
public void Vcvt_I32_F32([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s0,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s1,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s2,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s3,
|
||||
[ValueSource(nameof(_1S_))] uint s0,
|
||||
[ValueSource(nameof(_1S_))] uint s1,
|
||||
[ValueSource(nameof(_1S_))] uint s2,
|
||||
[ValueSource(nameof(_1S_))] uint s3,
|
||||
[Values] bool unsigned, // <U32, S32>
|
||||
[Values(RMode.Rn)] RMode rMode)
|
||||
{
|
||||
@@ -249,10 +249,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("VCVT.F64.<dt> <Dd>, <Sm>")]
|
||||
public void Vcvt_I32_F64([Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s0,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s1,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s2,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s3,
|
||||
[ValueSource(nameof(_1S_))] uint s0,
|
||||
[ValueSource(nameof(_1S_))] uint s1,
|
||||
[ValueSource(nameof(_1S_))] uint s2,
|
||||
[ValueSource(nameof(_1S_))] uint s3,
|
||||
[Values] bool unsigned, // <U32, S32>
|
||||
[Values(RMode.Rn)] RMode rMode)
|
||||
{
|
||||
@@ -344,10 +344,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("VCVT<top>.F16.F32 <Sd>, <Dm>")]
|
||||
public void Vcvt_F32_F16([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s0,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s1,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s2,
|
||||
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s3,
|
||||
[ValueSource(nameof(_1S_))] uint s0,
|
||||
[ValueSource(nameof(_1S_))] uint s1,
|
||||
[ValueSource(nameof(_1S_))] uint s2,
|
||||
[ValueSource(nameof(_1S_))] uint s3,
|
||||
[Values] bool top)
|
||||
{
|
||||
uint opcode = 0xeeb30a40; // VCVTB.F16.F32 S0, D0
|
||||
@@ -428,4 +428,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
#define SimdExt
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -14,22 +13,19 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource"
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntIndex = 2;
|
||||
|
||||
[Test, Pairwise, Description("EXT <Vd>.8B, <Vn>.8B, <Vm>.8B, #<index>")]
|
||||
public void Ext_V_8B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong b,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[ValueSource(nameof(_8B_))] ulong b,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
uint imm4 = index & 0x7u;
|
||||
|
||||
@@ -50,10 +46,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Ext_V_16B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong b,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[ValueSource(nameof(_8B_))] ulong b,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
uint imm4 = index & 0xFu;
|
||||
|
||||
@@ -71,4 +67,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
#define SimdFcond
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -101,7 +99,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _F_Ccmp_Ccmpe_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E220420u, // FCCMP S1, S2, #0, EQ
|
||||
0x1E220430u // FCCMPE S1, S2, #0, EQ
|
||||
@@ -110,7 +108,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Ccmp_Ccmpe_S_D_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E620420u, // FCCMP D1, D2, #0, EQ
|
||||
0x1E620430u // FCCMPE D1, D2, #0, EQ
|
||||
@@ -119,7 +117,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Csel_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E220C20u // FCSEL S0, S1, S2, EQ
|
||||
};
|
||||
@@ -127,7 +125,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Csel_S_D_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E620C20u // FCSEL D0, D1, D2, EQ
|
||||
};
|
||||
@@ -142,9 +140,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Ccmp_Ccmpe_S_S([ValueSource("_F_Ccmp_Ccmpe_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a,
|
||||
[ValueSource("_1S_F_")] ulong b,
|
||||
public void F_Ccmp_Ccmpe_S_S([ValueSource(nameof(_F_Ccmp_Ccmpe_S_S_))] uint opcodes,
|
||||
[ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -167,9 +165,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Ccmp_Ccmpe_S_D([ValueSource("_F_Ccmp_Ccmpe_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_F_")] ulong a,
|
||||
[ValueSource("_1D_F_")] ulong b,
|
||||
public void F_Ccmp_Ccmpe_S_D([ValueSource(nameof(_F_Ccmp_Ccmpe_S_D_))] uint opcodes,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
@@ -192,9 +190,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Csel_S_S([ValueSource("_F_Csel_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a,
|
||||
[ValueSource("_1S_F_")] ulong b,
|
||||
public void F_Csel_S_S([ValueSource(nameof(_F_Csel_S_S_))] uint opcodes,
|
||||
[ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
@@ -213,9 +211,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Csel_S_D([ValueSource("_F_Csel_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_F_")] ulong a,
|
||||
[ValueSource("_1D_F_")] ulong b,
|
||||
public void F_Csel_S_D([ValueSource(nameof(_F_Csel_S_D_))] uint opcodes,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#define SimdFmov
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -14,7 +13,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource"
|
||||
private static uint[] _F_Mov_Si_S_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E201000u // FMOV S0, #2.0
|
||||
};
|
||||
@@ -22,7 +21,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Mov_Si_D_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x1E601000u // FMOV D0, #2.0
|
||||
};
|
||||
@@ -30,7 +29,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Si_S([ValueSource("_F_Mov_Si_S_")] uint opcodes,
|
||||
public void F_Mov_Si_S([ValueSource(nameof(_F_Mov_Si_S_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint imm8)
|
||||
{
|
||||
opcodes |= ((imm8 & 0xFFu) << 13);
|
||||
@@ -44,7 +43,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Si_D([ValueSource("_F_Mov_Si_D_")] uint opcodes,
|
||||
public void F_Mov_Si_D([ValueSource(nameof(_F_Mov_Si_D_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint imm8)
|
||||
{
|
||||
opcodes |= ((imm8 & 0xFFu) << 13);
|
||||
|
@@ -1,9 +1,7 @@
|
||||
#define SimdImm
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -50,14 +48,14 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> _8BIT_IMM_()
|
||||
@@ -94,7 +92,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Bic_Orr_Vi_16bit_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x2F009400u, // BIC V0.4H, #0
|
||||
0x0F009400u // ORR V0.4H, #0
|
||||
@@ -103,7 +101,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Bic_Orr_Vi_32bit_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x2F001400u, // BIC V0.2S, #0
|
||||
0x0F001400u // ORR V0.2S, #0
|
||||
@@ -112,7 +110,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Mov_Vi_2S_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x0F00F400u // FMOV V0.2S, #2.0
|
||||
};
|
||||
@@ -120,7 +118,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Mov_Vi_4S_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x4F00F400u // FMOV V0.4S, #2.0
|
||||
};
|
||||
@@ -128,7 +126,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _F_Mov_Vi_2D_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x6F00F400u // FMOV V0.2D, #2.0
|
||||
};
|
||||
@@ -136,7 +134,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Movi_V_8bit_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x0F00E400u // MOVI V0.8B, #0
|
||||
};
|
||||
@@ -144,7 +142,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Movi_Mvni_V_16bit_shifted_imm_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x0F008400u, // MOVI V0.4H, #0
|
||||
0x2F008400u // MVNI V0.4H, #0
|
||||
@@ -153,7 +151,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Movi_Mvni_V_32bit_shifted_imm_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x0F000400u, // MOVI V0.2S, #0
|
||||
0x2F000400u // MVNI V0.2S, #0
|
||||
@@ -162,7 +160,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Movi_Mvni_V_32bit_shifting_ones_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x0F00C400u, // MOVI V0.2S, #0, MSL #8
|
||||
0x2F00C400u // MVNI V0.2S, #0, MSL #8
|
||||
@@ -171,7 +169,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Movi_V_64bit_scalar_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x2F00E400u // MOVI D0, #0
|
||||
};
|
||||
@@ -179,21 +177,20 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Movi_V_64bit_vector_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0x6F00E400u // MOVI V0.2D, #0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntImm8 = 2;
|
||||
private const int RndCntImm64 = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Bic_Orr_Vi_16bit([ValueSource("_Bic_Orr_Vi_16bit_")] uint opcodes,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8BIT_IMM_")] byte imm8,
|
||||
public void Bic_Orr_Vi_16bit([ValueSource(nameof(_Bic_Orr_Vi_16bit_))] uint opcodes,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint amount, // <0, 8>
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
@@ -212,9 +209,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Bic_Orr_Vi_32bit([ValueSource("_Bic_Orr_Vi_32bit_")] uint opcodes,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8BIT_IMM_")] byte imm8,
|
||||
public void Bic_Orr_Vi_32bit([ValueSource(nameof(_Bic_Orr_Vi_32bit_))] uint opcodes,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint amount, // <0, 8, 16, 24>
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
@@ -233,7 +230,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Vi_2S([ValueSource("_F_Mov_Vi_2S_")] uint opcodes,
|
||||
public void F_Mov_Vi_2S([ValueSource(nameof(_F_Mov_Vi_2S_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint abcdefgh)
|
||||
{
|
||||
uint abc = (abcdefgh & 0xE0u) >> 5;
|
||||
@@ -250,7 +247,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Vi_4S([ValueSource("_F_Mov_Vi_4S_")] uint opcodes,
|
||||
public void F_Mov_Vi_4S([ValueSource(nameof(_F_Mov_Vi_4S_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint abcdefgh)
|
||||
{
|
||||
uint abc = (abcdefgh & 0xE0u) >> 5;
|
||||
@@ -264,7 +261,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Vi_2D([ValueSource("_F_Mov_Vi_2D_")] uint opcodes,
|
||||
public void F_Mov_Vi_2D([ValueSource(nameof(_F_Mov_Vi_2D_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint abcdefgh)
|
||||
{
|
||||
uint abc = (abcdefgh & 0xE0u) >> 5;
|
||||
@@ -278,8 +275,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_V_8bit([ValueSource("_Movi_V_8bit_")] uint opcodes,
|
||||
[ValueSource("_8BIT_IMM_")] byte imm8,
|
||||
public void Movi_V_8bit([ValueSource(nameof(_Movi_V_8bit_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
@@ -297,8 +294,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_Mvni_V_16bit_shifted_imm([ValueSource("_Movi_Mvni_V_16bit_shifted_imm_")] uint opcodes,
|
||||
[ValueSource("_8BIT_IMM_")] byte imm8,
|
||||
public void Movi_Mvni_V_16bit_shifted_imm([ValueSource(nameof(_Movi_Mvni_V_16bit_shifted_imm_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint amount, // <0, 8>
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
@@ -318,8 +315,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_Mvni_V_32bit_shifted_imm([ValueSource("_Movi_Mvni_V_32bit_shifted_imm_")] uint opcodes,
|
||||
[ValueSource("_8BIT_IMM_")] byte imm8,
|
||||
public void Movi_Mvni_V_32bit_shifted_imm([ValueSource(nameof(_Movi_Mvni_V_32bit_shifted_imm_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint amount, // <0, 8, 16, 24>
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
@@ -339,8 +336,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_Mvni_V_32bit_shifting_ones([ValueSource("_Movi_Mvni_V_32bit_shifting_ones_")] uint opcodes,
|
||||
[ValueSource("_8BIT_IMM_")] byte imm8,
|
||||
public void Movi_Mvni_V_32bit_shifting_ones([ValueSource(nameof(_Movi_Mvni_V_32bit_shifting_ones_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint amount, // <8, 16>
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
@@ -360,8 +357,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_V_64bit_scalar([ValueSource("_Movi_V_64bit_scalar_")] uint opcodes,
|
||||
[ValueSource("_64BIT_IMM_")] ulong imm)
|
||||
public void Movi_V_64bit_scalar([ValueSource(nameof(_Movi_V_64bit_scalar_))] uint opcodes,
|
||||
[ValueSource(nameof(_64BIT_IMM_))] ulong imm)
|
||||
{
|
||||
byte imm8 = ShrinkImm64(imm);
|
||||
|
||||
@@ -379,8 +376,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_V_64bit_vector([ValueSource("_Movi_V_64bit_vector_")] uint opcodes,
|
||||
[ValueSource("_64BIT_IMM_")] ulong imm)
|
||||
public void Movi_V_64bit_vector([ValueSource(nameof(_Movi_V_64bit_vector_))] uint opcodes,
|
||||
[ValueSource(nameof(_64BIT_IMM_))] ulong imm)
|
||||
{
|
||||
byte imm8 = ShrinkImm64(imm);
|
||||
|
||||
@@ -395,4 +392,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
#define SimdIns
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
@@ -14,66 +13,63 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource"
|
||||
private static ulong[] _1D_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B4H_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B4H2S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static uint[] _W_()
|
||||
{
|
||||
return new uint[] { 0x00000000u, 0x0000007Fu,
|
||||
0x00000080u, 0x000000FFu,
|
||||
0x00007FFFu, 0x00008000u,
|
||||
0x0000FFFFu, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
return new[] { 0x00000000u, 0x0000007Fu,
|
||||
0x00000080u, 0x000000FFu,
|
||||
0x00007FFFu, 0x00008000u,
|
||||
0x0000FFFFu, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
}
|
||||
|
||||
private static ulong[] _X_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntIndex = 2;
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, W<n>")]
|
||||
public void Dup_Gp_W([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0, 1, 2)] int size, // Q0: <8B, 4H, 2S>
|
||||
[Values(0b0u, 0b1u)] uint q) // Q1: <16B, 8H, 4S>
|
||||
{
|
||||
@@ -96,7 +92,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, X<n>")]
|
||||
public void Dup_Gp_X([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_X_")] [Random(RndCnt)] ulong xn)
|
||||
[ValueSource(nameof(_X_))] ulong xn)
|
||||
{
|
||||
uint opcode = 0x4E080C00; // DUP V0.2D, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
@@ -111,8 +107,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP B0, V1.B[<index>]")]
|
||||
public void Dup_S_B([ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index)
|
||||
public void Dup_S_B([ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
@@ -131,8 +127,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP H0, V1.H[<index>]")]
|
||||
public void Dup_S_H([ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index)
|
||||
public void Dup_S_H([ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
@@ -151,7 +147,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP S0, V1.S[<index>]")]
|
||||
public void Dup_S_S([ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
public void Dup_S_S([ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
@@ -171,7 +167,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP D0, V1.D[<index>]")]
|
||||
public void Dup_S_D([ValueSource("_1D_")] [Random(RndCnt)] ulong a,
|
||||
public void Dup_S_D([ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
const int size = 3;
|
||||
@@ -193,9 +189,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.B[<index>]")]
|
||||
public void Dup_V_8B_16B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
const int size = 0;
|
||||
@@ -218,9 +214,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.H[<index>]")]
|
||||
public void Dup_V_4H_8H([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
const int size = 1;
|
||||
@@ -243,8 +239,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.S[<index>]")]
|
||||
public void Dup_V_2S_4S([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
@@ -268,8 +264,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.D[<index>]")]
|
||||
public void Dup_V_2D([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource(nameof(_1D_))] ulong z,
|
||||
[ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint index,
|
||||
[Values(0b1u)] uint q) // <2D>
|
||||
{
|
||||
@@ -293,9 +289,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.B[<index>], W<n>")]
|
||||
public void Ins_Gp_WB([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
@@ -316,9 +312,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.H[<index>], W<n>")]
|
||||
public void Ins_Gp_WH([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
@@ -339,8 +335,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.S[<index>], W<n>")]
|
||||
public void Ins_Gp_WS([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_W_")] [Random(RndCnt)] uint wn,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
@@ -362,8 +358,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.D[<index>], X<n>")]
|
||||
public void Ins_Gp_XD([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_X_")] [Random(RndCnt)] ulong xn,
|
||||
[ValueSource(nameof(_1D_))] ulong z,
|
||||
[ValueSource(nameof(_X_))] ulong xn,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
const int size = 3;
|
||||
@@ -385,10 +381,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.B[<index1>], <Vn>.B[<index2>]")]
|
||||
public void Ins_V_BB([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint dstIndex,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint srcIndex)
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint dstIndex,
|
||||
[Values(0u, 15u)] uint srcIndex)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
@@ -411,10 +407,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.H[<index1>], <Vn>.H[<index2>]")]
|
||||
public void Ins_V_HH([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint dstIndex,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint srcIndex)
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint dstIndex,
|
||||
[Values(0u, 7u)] uint srcIndex)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
@@ -437,8 +433,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.S[<index1>], <Vn>.S[<index2>]")]
|
||||
public void Ins_V_SS([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint dstIndex,
|
||||
[Values(0u, 1u, 2u, 3u)] uint srcIndex)
|
||||
{
|
||||
@@ -463,8 +459,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("INS <Vd>.D[<index1>], <Vn>.D[<index2>]")]
|
||||
public void Ins_V_DD([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource(nameof(_1D_))] ulong z,
|
||||
[ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint dstIndex,
|
||||
[Values(0u, 1u)] uint srcIndex)
|
||||
{
|
||||
@@ -489,8 +485,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("SMOV <Wd>, <Vn>.B[<index>]")]
|
||||
public void Smov_S_BW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
@@ -512,8 +508,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("SMOV <Wd>, <Vn>.H[<index>]")]
|
||||
public void Smov_S_HW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
@@ -535,8 +531,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("SMOV <Xd>, <Vn>.B[<index>]")]
|
||||
public void Smov_S_BX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
@@ -557,8 +553,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("SMOV <Xd>, <Vn>.H[<index>]")]
|
||||
public void Smov_S_HX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
@@ -579,7 +575,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("SMOV <Xd>, <Vn>.S[<index>]")]
|
||||
public void Smov_S_SX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
@@ -601,8 +597,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("UMOV <Wd>, <Vn>.B[<index>]")]
|
||||
public void Umov_S_BW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
@@ -624,8 +620,8 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("UMOV <Wd>, <Vn>.H[<index>]")]
|
||||
public void Umov_S_HW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index)
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
@@ -647,7 +643,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("UMOV <Wd>, <Vn>.S[<index>]")]
|
||||
public void Umov_S_SW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
@@ -670,7 +666,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("UMOV <Xd>, <Vn>.D[<index>]")]
|
||||
public void Umov_S_DX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
const int size = 3;
|
||||
@@ -690,4 +686,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,17 +13,17 @@ namespace Ryujinx.Tests.Cpu
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _8B4H2S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xf2100110u, // VBIC D0, D0, D0
|
||||
0xf3300110u, // VBIF D0, D0, D0
|
||||
@@ -38,7 +38,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private static uint[] _Vbic_Vorr_II_()
|
||||
{
|
||||
return new uint[]
|
||||
return new[]
|
||||
{
|
||||
0xf2800130u, // VBIC.I32 D0, #0 (A1)
|
||||
0xf2800930u, // VBIC.I16 D0, #0 (A2)
|
||||
@@ -48,16 +48,14 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I([ValueSource("_Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I_")] uint opcode,
|
||||
public void Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I([ValueSource(nameof(_Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I_))] uint opcode,
|
||||
[Range(0u, 5u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] [Random(RndCnt)] ulong z,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] [Random(RndCnt)] ulong a,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] [Random(RndCnt)] ulong b,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong z,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong a,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
if (q)
|
||||
@@ -83,10 +81,10 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vbic_Vorr_II([ValueSource("_Vbic_Vorr_II_")] uint opcode,
|
||||
public void Vbic_Vorr_II([ValueSource(nameof(_Vbic_Vorr_II_))] uint opcode,
|
||||
[Values(0u, 1u)] uint rd,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] [Random(RndCnt)] ulong z,
|
||||
[Values(byte.MinValue, byte.MaxValue)] [Random(RndCnt)] byte imm,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong z,
|
||||
[Values(byte.MinValue, byte.MaxValue)] byte imm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint cMode,
|
||||
[Values] bool q)
|
||||
{
|
||||
@@ -119,9 +117,9 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Vtst([Range(0u, 5u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong a,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Values] bool q)
|
||||
{
|
||||
@@ -152,4 +150,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,7 +10,6 @@ namespace Ryujinx.Tests.Cpu
|
||||
public sealed class CpuTestSimdMemory32 : CpuTest32
|
||||
{
|
||||
#if SimdMemory32
|
||||
private const int RndCntImm = 2;
|
||||
|
||||
private uint[] _ldStModes =
|
||||
{
|
||||
@@ -41,7 +40,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Range(0u, 3u)] uint n,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
@@ -71,7 +70,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Range(0u, 3u)] uint n,
|
||||
[Range(0u, 2u)] uint size,
|
||||
[Values] bool t,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
@@ -97,7 +96,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 10u)] uint mode,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
@@ -127,7 +126,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Range(0u, 3u)] uint n,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
@@ -158,7 +157,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 10u)] uint mode,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
@@ -187,7 +186,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Vldm([Values(0u, 13u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 2u)] uint mode,
|
||||
[Values(0x1u, 0x32u)] [Random(2u, 31u, RndCntImm)] uint regs,
|
||||
[Values(0x1u, 0x32u)] uint regs,
|
||||
[Values] bool single)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
@@ -235,7 +234,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Vldr([Values(2u, 3u)] uint size, // FP16 is not supported for now
|
||||
[Values(0u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint sd,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint imm,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool sub)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
@@ -270,7 +269,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
public void Vstr([Values(2u, 3u)] uint size, // FP16 is not supported for now
|
||||
[Values(0u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint sd,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint imm,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool sub)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
@@ -329,4 +328,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,7 +14,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("VMOV.I<size> <Dd/Qd>, #<imm>")]
|
||||
public void Movi_V([Range(0u, 10u)] uint variant,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0x0u)] [Random(1u, 0xffu, RndCntImm)] uint imm,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint[] variants =
|
||||
@@ -62,7 +62,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("VMOV.F<size> <Sd>, #<imm>")]
|
||||
public void Movi_S([Range(2u, 3u)] uint size,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint imm)
|
||||
[Values(0x0u)] uint imm)
|
||||
{
|
||||
uint opcode = 0xeeb00800u;
|
||||
opcode |= (size & 3) << 8;
|
||||
@@ -292,7 +292,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
[Test, Pairwise, Description("VMVN.I<size> <Dd/Qd>, #<imm>")]
|
||||
public void Mvni_V([Range(0u, 7u)] uint variant,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0x0u)] [Random(1u, 0xffu, RndCntImm)] uint imm,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint[] variants =
|
||||
@@ -596,4 +596,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user