mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-30 14:39:42 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7337683c16 |
@@ -37,3 +37,5 @@ packages/
|
|||||||
Thumbs.db
|
Thumbs.db
|
||||||
Desktop.ini
|
Desktop.ini
|
||||||
ehthumbs.db
|
ehthumbs.db
|
||||||
|
|
||||||
|
.vs/
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "10.0.103",
|
"version": "10.0.103",
|
||||||
"rollForward": "disable"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<Win32Icon>..\..\assets\images\SharpEmu.ico</Win32Icon>
|
<Win32Icon>..\..\assets\images\SharpEmu.ico</Win32Icon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="..\..\LICENSE.txt">
|
<Content Include="..\..\LICENSE.txt">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"net10.0": {
|
"net10.0": {
|
||||||
"Microsoft.NET.ILLink.Tasks": {
|
"Microsoft.NET.ILLink.Tasks": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[10.0.3, )",
|
"requested": "[10.0.9, )",
|
||||||
"resolved": "10.0.3",
|
"resolved": "10.0.9",
|
||||||
"contentHash": "0B6nZyCHWXnvmlB559oduOspVdNOnpNXPjhpWVMovLPAsDVG7A4jJR9rzECf67JUzxP8/ee/wA8clwIzJcWNFA=="
|
"contentHash": "4Iw41e2h7I4t70SJcX2GCmbyKJIlA273Cfm9RJMM050/3VBejGAG1KcthP5Z2L6SQcbfbf6BhNWO26+ZG+GzMg=="
|
||||||
},
|
},
|
||||||
"Avalonia.Angle.Windows.Natives": {
|
"Avalonia.Angle.Windows.Natives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
|
|||||||
@@ -415,8 +415,8 @@ public sealed class CpuDispatcher : ICpuDispatcher, IDisposable
|
|||||||
|
|
||||||
const ulong entryParamsSize = 0x20;
|
const ulong entryParamsSize = 0x20;
|
||||||
var entryParamsAddress = AlignDown(argv0Address - entryParamsSize, 16);
|
var entryParamsAddress = AlignDown(argv0Address - entryParamsSize, 16);
|
||||||
if (!TryWriteUInt32(context, entryParamsAddress + 0x00, 1) ||
|
if (!context.TryWriteUInt32(entryParamsAddress + 0x00, 1) ||
|
||||||
!TryWriteUInt32(context, entryParamsAddress + 0x04, 0) ||
|
!context.TryWriteUInt32(entryParamsAddress + 0x04, 0) ||
|
||||||
!context.TryWriteUInt64(entryParamsAddress + 0x08, argv0Address) ||
|
!context.TryWriteUInt64(entryParamsAddress + 0x08, argv0Address) ||
|
||||||
!context.TryWriteUInt64(entryParamsAddress + 0x10, 0) ||
|
!context.TryWriteUInt64(entryParamsAddress + 0x10, 0) ||
|
||||||
!context.TryWriteUInt64(entryParamsAddress + 0x18, 0))
|
!context.TryWriteUInt64(entryParamsAddress + 0x18, 0))
|
||||||
@@ -456,13 +456,6 @@ public sealed class CpuDispatcher : ICpuDispatcher, IDisposable
|
|||||||
return value & ~(alignment - 1);
|
return value & ~(alignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext context, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
|
||||||
return context.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string BuildEntryFrameDiagnostic(
|
private static string BuildEntryFrameDiagnostic(
|
||||||
ulong entryPoint,
|
ulong entryPoint,
|
||||||
CpuContext context,
|
CpuContext context,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright (C) 2026 SharpEmu Emulator Project
|
Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
SPDX-License-Identifier: GPL-2.0-or-later
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
-->
|
-->
|
||||||
@@ -14,6 +14,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<PackageReference Include="Iced" />
|
<PackageReference Include="Iced" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -2,25 +2,20 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpEmu.HLE;
|
namespace SharpEmu.HLE;
|
||||||
|
|
||||||
public sealed class CpuContext
|
public sealed class CpuContext(ICpuMemory memory, Generation generation)
|
||||||
{
|
{
|
||||||
private readonly ulong[] _registers = new ulong[16];
|
private readonly ulong[] _registers = new ulong[16];
|
||||||
private readonly ulong[] _xmmRegisters = new ulong[32];
|
private readonly ulong[] _xmmRegisters = new ulong[32];
|
||||||
private readonly ulong[] _ymmUpperRegisters = new ulong[32];
|
private readonly ulong[] _ymmUpperRegisters = new ulong[32];
|
||||||
private bool _raxWritten;
|
private bool _raxWritten;
|
||||||
|
|
||||||
public CpuContext(ICpuMemory memory, Generation generation)
|
public ICpuMemory Memory { get; } = memory ?? throw new ArgumentNullException(nameof(memory));
|
||||||
{
|
|
||||||
Memory = memory ?? throw new ArgumentNullException(nameof(memory));
|
|
||||||
TargetGeneration = generation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICpuMemory Memory { get; }
|
public Generation TargetGeneration { get; } = generation;
|
||||||
|
|
||||||
public Generation TargetGeneration { get; }
|
|
||||||
|
|
||||||
public ulong Rip { get; set; }
|
public ulong Rip { get; set; }
|
||||||
|
|
||||||
@@ -130,6 +125,39 @@ public sealed class CpuContext
|
|||||||
SetYmmUpper(registerIndex, highLow, highHigh);
|
SetYmmUpper(registerIndex, highLow, highHigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryReadByte(ulong address, out byte value)
|
||||||
|
{
|
||||||
|
Span<byte> buffer = stackalloc byte[1];
|
||||||
|
if (!Memory.TryRead(address, buffer))
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = buffer[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryReadUInt32(ulong address, out uint value)
|
||||||
|
{
|
||||||
|
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
||||||
|
if (!Memory.TryRead(address, buffer))
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryWriteUInt32(ulong address, uint value)
|
||||||
|
{
|
||||||
|
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
||||||
|
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
||||||
|
return Memory.TryWrite(address, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryReadUInt64(ulong address, out ulong value)
|
public bool TryReadUInt64(ulong address, out ulong value)
|
||||||
{
|
{
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
||||||
@@ -150,6 +178,33 @@ public sealed class CpuContext
|
|||||||
return Memory.TryWrite(address, buffer);
|
return Memory.TryWrite(address, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryReadNullTerminatedUtf8(ulong address, int capacity, out string value)
|
||||||
|
{
|
||||||
|
value = string.Empty;
|
||||||
|
if (address == 0 || capacity <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = new byte[capacity];
|
||||||
|
for (var index = 0; index < bytes.Length; index++)
|
||||||
|
{
|
||||||
|
if (!Memory.TryRead(address + (ulong)index, bytes.AsSpan(index, 1)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes[index] == 0)
|
||||||
|
{
|
||||||
|
value = Encoding.UTF8.GetString(bytes, 0, index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = Encoding.UTF8.GetString(bytes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool PushUInt64(ulong value)
|
public bool PushUInt64(ulong value)
|
||||||
{
|
{
|
||||||
var rsp = this[CpuRegister.Rsp];
|
var rsp = this[CpuRegister.Rsp];
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Aerolib\aerolib.bin" />
|
<EmbeddedResource Include="Aerolib\aerolib.bin" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
+302
-356
File diff suppressed because it is too large
Load Diff
@@ -18,9 +18,9 @@ internal static class Gen5ShaderMetadataReader
|
|||||||
out Gen5ShaderMetadata metadata)
|
out Gen5ShaderMetadata metadata)
|
||||||
{
|
{
|
||||||
metadata = default!;
|
metadata = default!;
|
||||||
if (!TryReadUInt64(ctx, shaderHeaderAddress + ShaderUserDataOffset, out var userDataAddress) ||
|
if (!ctx.TryReadUInt64(shaderHeaderAddress + ShaderUserDataOffset, out var userDataAddress) ||
|
||||||
userDataAddress == 0 ||
|
userDataAddress == 0 ||
|
||||||
!TryReadUInt64(ctx, userDataAddress, out var directResourceOffsetsAddress))
|
!ctx.TryReadUInt64(userDataAddress, out var directResourceOffsetsAddress))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -28,8 +28,7 @@ internal static class Gen5ShaderMetadataReader
|
|||||||
var resourceOffsets = new ulong[ResourceClassCount];
|
var resourceOffsets = new ulong[ResourceClassCount];
|
||||||
for (var resourceClass = 0; resourceClass < ResourceClassCount; resourceClass++)
|
for (var resourceClass = 0; resourceClass < ResourceClassCount; resourceClass++)
|
||||||
{
|
{
|
||||||
if (!TryReadUInt64(
|
if (!ctx.TryReadUInt64(
|
||||||
ctx,
|
|
||||||
userDataAddress + 0x08 + (ulong)(resourceClass * sizeof(ulong)),
|
userDataAddress + 0x08 + (ulong)(resourceClass * sizeof(ulong)),
|
||||||
out resourceOffsets[resourceClass]))
|
out resourceOffsets[resourceClass]))
|
||||||
{
|
{
|
||||||
@@ -138,17 +137,4 @@ internal static class Gen5ShaderMetadataReader
|
|||||||
value = BinaryPrimitives.ReadUInt16LittleEndian(bytes);
|
value = BinaryPrimitives.ReadUInt16LittleEndian(bytes);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt64(CpuContext ctx, ulong address, out ulong value)
|
|
||||||
{
|
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(ulong)];
|
|
||||||
if (!ctx.Memory.TryRead(address, bytes))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt64LittleEndian(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using SharpEmu.HLE;
|
using SharpEmu.HLE;
|
||||||
using SharpEmu.Libs.Kernel;
|
using SharpEmu.Libs.Kernel;
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace SharpEmu.Libs.Agc;
|
namespace SharpEmu.Libs.Agc;
|
||||||
@@ -1405,8 +1404,7 @@ internal static class Gen5ShaderScalarEvaluator
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadUInt32(
|
if (!ctx.TryReadUInt32(
|
||||||
ctx,
|
|
||||||
address + (ulong)(index * sizeof(uint)),
|
address + (ulong)(index * sizeof(uint)),
|
||||||
out var value) &&
|
out var value) &&
|
||||||
!TryReadUserDataScalarLoad(
|
!TryReadUserDataScalarLoad(
|
||||||
@@ -1727,16 +1725,4 @@ internal static class Gen5ShaderScalarEvaluator
|
|||||||
opcode.StartsWith("ImageSample", StringComparison.Ordinal) ||
|
opcode.StartsWith("ImageSample", StringComparison.Ordinal) ||
|
||||||
opcode.StartsWith("ImageGather", StringComparison.Ordinal);
|
opcode.StartsWith("ImageGather", StringComparison.Ordinal);
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, bytes))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ internal static class Gen5ShaderTranslator
|
|||||||
var instructionCount = 0;
|
var instructionCount = 0;
|
||||||
for (uint pc = 0; instructionCount < MaxInstructions;)
|
for (uint pc = 0; instructionCount < MaxInstructions;)
|
||||||
{
|
{
|
||||||
if (!TryReadUInt32(ctx, address + pc, out var word))
|
if (!ctx.TryReadUInt32(address + pc, out var word))
|
||||||
{
|
{
|
||||||
error = $"read-failed pc=0x{pc:X}";
|
error = $"read-failed pc=0x{pc:X}";
|
||||||
return false;
|
return false;
|
||||||
@@ -317,7 +317,7 @@ internal static class Gen5ShaderTranslator
|
|||||||
words[0] = word;
|
words[0] = word;
|
||||||
for (uint wordIndex = 1; wordIndex < sizeDwords; wordIndex++)
|
for (uint wordIndex = 1; wordIndex < sizeDwords; wordIndex++)
|
||||||
{
|
{
|
||||||
if (!TryReadUInt32(ctx, address + pc + wordIndex * sizeof(uint), out words[wordIndex]))
|
if (!ctx.TryReadUInt32(address + pc + wordIndex * sizeof(uint), out words[wordIndex]))
|
||||||
{
|
{
|
||||||
error = $"read-failed pc=0x{pc + wordIndex * sizeof(uint):X}";
|
error = $"read-failed pc=0x{pc + wordIndex * sizeof(uint):X}";
|
||||||
return false;
|
return false;
|
||||||
@@ -397,7 +397,7 @@ internal static class Gen5ShaderTranslator
|
|||||||
case 0x34:
|
case 0x34:
|
||||||
case 0x35:
|
case 0x35:
|
||||||
encoding = Gen5ShaderEncoding.Vop3;
|
encoding = Gen5ShaderEncoding.Vop3;
|
||||||
if (!TryReadUInt32(ctx, baseAddress + pc + sizeof(uint), out var vop3Extra))
|
if (!ctx.TryReadUInt32(baseAddress + pc + sizeof(uint), out var vop3Extra))
|
||||||
{
|
{
|
||||||
error = $"vop3-extra-read-failed pc=0x{pc:X}";
|
error = $"vop3-extra-read-failed pc=0x{pc:X}";
|
||||||
return false;
|
return false;
|
||||||
@@ -418,7 +418,7 @@ internal static class Gen5ShaderTranslator
|
|||||||
return DecodeFlat(word, out name, out sizeDwords, out error);
|
return DecodeFlat(word, out name, out sizeDwords, out error);
|
||||||
case 0x38:
|
case 0x38:
|
||||||
encoding = Gen5ShaderEncoding.Mubuf;
|
encoding = Gen5ShaderEncoding.Mubuf;
|
||||||
if (!TryReadUInt32(ctx, baseAddress + pc + sizeof(uint), out var mubufExtra))
|
if (!ctx.TryReadUInt32(baseAddress + pc + sizeof(uint), out var mubufExtra))
|
||||||
{
|
{
|
||||||
error = $"mubuf-extra-read-failed pc=0x{pc:X}";
|
error = $"mubuf-extra-read-failed pc=0x{pc:X}";
|
||||||
return false;
|
return false;
|
||||||
@@ -427,7 +427,7 @@ internal static class Gen5ShaderTranslator
|
|||||||
return DecodeMubuf(word, mubufExtra, out name, out sizeDwords, out error);
|
return DecodeMubuf(word, mubufExtra, out name, out sizeDwords, out error);
|
||||||
case 0x3A:
|
case 0x3A:
|
||||||
encoding = Gen5ShaderEncoding.Mtbuf;
|
encoding = Gen5ShaderEncoding.Mtbuf;
|
||||||
if (!TryReadUInt32(ctx, baseAddress + pc + sizeof(uint), out var mtbufExtra))
|
if (!ctx.TryReadUInt32(baseAddress + pc + sizeof(uint), out var mtbufExtra))
|
||||||
{
|
{
|
||||||
error = $"mtbuf-extra-read-failed pc=0x{pc:X}";
|
error = $"mtbuf-extra-read-failed pc=0x{pc:X}";
|
||||||
return false;
|
return false;
|
||||||
@@ -1741,19 +1741,6 @@ internal static class Gen5ShaderTranslator
|
|||||||
counts[key] = count + 1;
|
counts[key] = count + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, bytes))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly record struct ShaderDecodeInfo(
|
private readonly record struct ShaderDecodeInfo(
|
||||||
int InstructionCount,
|
int InstructionCount,
|
||||||
Dictionary<string, int> Counts,
|
Dictionary<string, int> Counts,
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ public static class AmprExports
|
|||||||
var offset = 0UL;
|
var offset = 0UL;
|
||||||
while (offset < writeOffset)
|
while (offset < writeOffset)
|
||||||
{
|
{
|
||||||
if (!TryReadUInt32(ctx, buffer + offset, out var recordType))
|
if (!ctx.TryReadUInt32(buffer + offset, out var recordType))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -883,19 +883,6 @@ public static class AmprExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void TraceAmpr(CpuContext ctx, string operation, ulong commandBuffer, ulong arg0, ulong arg1)
|
private static void TraceAmpr(CpuContext ctx, string operation, ulong commandBuffer, ulong arg0, ulong arg1)
|
||||||
{
|
{
|
||||||
if (!_traceAmpr)
|
if (!_traceAmpr)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public static class AudioOut2Exports
|
|||||||
}
|
}
|
||||||
|
|
||||||
var handle = (ulong)Interlocked.Increment(ref _nextContextHandle);
|
var handle = (ulong)Interlocked.Increment(ref _nextContextHandle);
|
||||||
return TryWriteUInt64(ctx, outContextAddress, handle)
|
return ctx.TryWriteUInt64(outContextAddress, handle)
|
||||||
? SetReturn(ctx, 0)
|
? SetReturn(ctx, 0)
|
||||||
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ public static class AudioOut2Exports
|
|||||||
|
|
||||||
var portId = unchecked((uint)Interlocked.Increment(ref _nextPortId)) & 0xFF;
|
var portId = unchecked((uint)Interlocked.Increment(ref _nextPortId)) & 0xFF;
|
||||||
var handle = 0x2000_0000UL | ((ulong)(uint)type << 16) | portId;
|
var handle = 0x2000_0000UL | ((ulong)(uint)type << 16) | portId;
|
||||||
return TryWriteUInt64(ctx, outPortAddress, handle)
|
return ctx.TryWriteUInt64(outPortAddress, handle)
|
||||||
? SetReturn(ctx, 0)
|
? SetReturn(ctx, 0)
|
||||||
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -211,18 +211,11 @@ public static class AudioOut2Exports
|
|||||||
}
|
}
|
||||||
|
|
||||||
var handle = (ulong)Interlocked.Increment(ref _nextUserHandle);
|
var handle = (ulong)Interlocked.Increment(ref _nextUserHandle);
|
||||||
return TryWriteUInt64(ctx, outUserAddress, handle)
|
return ctx.TryWriteUInt64(outUserAddress, handle)
|
||||||
? SetReturn(ctx, 0)
|
? SetReturn(ctx, 0)
|
||||||
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryWriteUInt64(CpuContext ctx, ulong address, ulong value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
|
||||||
BinaryPrimitives.WriteUInt64LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int SetReturn(CpuContext ctx, int result)
|
private static int SetReturn(CpuContext ctx, int result)
|
||||||
{
|
{
|
||||||
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public static class FiberExports
|
|||||||
return SetReturn(ctx, FiberErrorAlignment);
|
return SetReturn(ctx, FiberErrorAlignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TryWriteUInt32(ctx, optParam, FiberOptSignature)
|
return ctx.TryWriteUInt32(optParam, FiberOptSignature)
|
||||||
? SetReturn(ctx, 0)
|
? SetReturn(ctx, 0)
|
||||||
: SetReturn(ctx, FiberErrorInvalid);
|
: SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ public static class FiberExports
|
|||||||
return SetReturn(ctx, error);
|
return SetReturn(ctx, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadUInt32(ctx, fiber + FiberStateOffset, out var state))
|
if (!ctx.TryReadUInt32(fiber + FiberStateOffset, out var state))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ public static class FiberExports
|
|||||||
_continuations.TryRemove(fiber, out _);
|
_continuations.TryRemove(fiber, out _);
|
||||||
_returnTargets.TryRemove(fiber, out _);
|
_returnTargets.TryRemove(fiber, out _);
|
||||||
_stackRanges.TryRemove(fiber, out _);
|
_stackRanges.TryRemove(fiber, out _);
|
||||||
_ = TryWriteUInt32(ctx, fiber + FiberStateOffset, FiberStateTerminated);
|
_ = ctx.TryWriteUInt32(fiber + FiberStateOffset, FiberStateTerminated);
|
||||||
return SetReturn(ctx, 0);
|
return SetReturn(ctx, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ public static class FiberExports
|
|||||||
|
|
||||||
var returnArgument = ctx[CpuRegister.Rdi];
|
var returnArgument = ctx[CpuRegister.Rdi];
|
||||||
var argOnRunAddress = ctx[CpuRegister.Rsi];
|
var argOnRunAddress = ctx[CpuRegister.Rsi];
|
||||||
if (argOnRunAddress != 0 && !TryWriteUInt64(ctx, argOnRunAddress, 0))
|
if (argOnRunAddress != 0 && !ctx.TryWriteUInt64(argOnRunAddress, 0))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ public static class FiberExports
|
|||||||
{
|
{
|
||||||
if (!_continuations.TryRemove(previousFiber, out var previousContinuation) ||
|
if (!_continuations.TryRemove(previousFiber, out var previousContinuation) ||
|
||||||
!TryWriteResumeArgument(ctx, previousContinuation, returnArgument) ||
|
!TryWriteResumeArgument(ctx, previousContinuation, returnArgument) ||
|
||||||
!TryWriteUInt32(ctx, previousFiber + FiberStateOffset, FiberStateRun))
|
!ctx.TryWriteUInt32(previousFiber + FiberStateOffset, FiberStateRun))
|
||||||
{
|
{
|
||||||
_continuations.TryRemove(fiberAddress, out _);
|
_continuations.TryRemove(fiberAddress, out _);
|
||||||
return SetReturn(ctx, FiberErrorState);
|
return SetReturn(ctx, FiberErrorState);
|
||||||
@@ -284,7 +284,7 @@ public static class FiberExports
|
|||||||
transferTarget = returnTarget.ThreadContinuation.Value.Context with { Rax = 0 };
|
transferTarget = returnTarget.ThreadContinuation.Value.Context with { Rax = 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryWriteUInt32(ctx, fiberAddress + FiberStateOffset, FiberStateIdle))
|
if (!ctx.TryWriteUInt32(fiberAddress + FiberStateOffset, FiberStateIdle))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -318,7 +318,7 @@ public static class FiberExports
|
|||||||
return SetReturn(ctx, FiberErrorPermission);
|
return SetReturn(ctx, FiberErrorPermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TryWriteUInt64(ctx, outAddress, fiberAddress)
|
return ctx.TryWriteUInt64(outAddress, fiberAddress)
|
||||||
? SetReturn(ctx, 0)
|
? SetReturn(ctx, 0)
|
||||||
: SetReturn(ctx, FiberErrorInvalid);
|
: SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -342,7 +342,7 @@ public static class FiberExports
|
|||||||
return SetReturn(ctx, error);
|
return SetReturn(ctx, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadUInt64(ctx, info, out var size) || size != FiberInfoSize)
|
if (!ctx.TryReadUInt64(info, out var size) || size != FiberInfoSize)
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -352,12 +352,12 @@ public static class FiberExports
|
|||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryWriteUInt64(ctx, info + 8, fields.Entry) ||
|
if (!ctx.TryWriteUInt64(info + 8, fields.Entry) ||
|
||||||
!TryWriteUInt64(ctx, info + 16, fields.ArgOnInitialize) ||
|
!ctx.TryWriteUInt64(info + 16, fields.ArgOnInitialize) ||
|
||||||
!TryWriteUInt64(ctx, info + 24, fields.ContextAddress) ||
|
!ctx.TryWriteUInt64(info + 24, fields.ContextAddress) ||
|
||||||
!TryWriteUInt64(ctx, info + 32, fields.ContextSize) ||
|
!ctx.TryWriteUInt64(info + 32, fields.ContextSize) ||
|
||||||
!TryWriteName(ctx, info + 40, fields.Name) ||
|
!TryWriteName(ctx, info + 40, fields.Name) ||
|
||||||
!TryWriteUInt64(ctx, info + 72, ulong.MaxValue))
|
!ctx.TryWriteUInt64(info + 72, ulong.MaxValue))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,7 @@ public static class FiberExports
|
|||||||
return SetReturn(ctx, FiberErrorNull);
|
return SetReturn(ctx, FiberErrorNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadNullTerminatedUtf8(ctx, nameAddress, MaxNameLength + 1, out var name))
|
if (!ctx.TryReadNullTerminatedUtf8(nameAddress, MaxNameLength + 1, out var name))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -441,7 +441,7 @@ public static class FiberExports
|
|||||||
return SetReturn(ctx, FiberErrorPermission);
|
return SetReturn(ctx, FiberErrorPermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TryWriteUInt64(ctx, outAddress, ctx[CpuRegister.Rbp])
|
return ctx.TryWriteUInt64(outAddress, ctx[CpuRegister.Rbp])
|
||||||
? SetReturn(ctx, 0)
|
? SetReturn(ctx, 0)
|
||||||
: SetReturn(ctx, FiberErrorInvalid);
|
: SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -482,12 +482,12 @@ public static class FiberExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (optParam != 0 &&
|
if (optParam != 0 &&
|
||||||
(!TryReadUInt32(ctx, optParam, out var optMagic) || optMagic != FiberOptSignature))
|
(!ctx.TryReadUInt32(optParam, out var optMagic) || optMagic != FiberOptSignature))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadNullTerminatedUtf8(ctx, nameAddress, MaxNameLength + 1, out var name))
|
if (!ctx.TryReadNullTerminatedUtf8(nameAddress, MaxNameLength + 1, out var name))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -497,25 +497,25 @@ public static class FiberExports
|
|||||||
flags |= FiberFlagContextSizeCheck;
|
flags |= FiberFlagContextSizeCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryWriteUInt32(ctx, fiber + FiberMagicStartOffset, FiberSignature0) ||
|
if (!ctx.TryWriteUInt32(fiber + FiberMagicStartOffset, FiberSignature0) ||
|
||||||
!TryWriteUInt32(ctx, fiber + FiberStateOffset, FiberStateIdle) ||
|
!ctx.TryWriteUInt32(fiber + FiberStateOffset, FiberStateIdle) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberEntryOffset, entry) ||
|
!ctx.TryWriteUInt64(fiber + FiberEntryOffset, entry) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberArgOnInitializeOffset, argOnInitialize) ||
|
!ctx.TryWriteUInt64(fiber + FiberArgOnInitializeOffset, argOnInitialize) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextAddressOffset, contextAddress) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextAddressOffset, contextAddress) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextSizeOffset, contextSize) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextSizeOffset, contextSize) ||
|
||||||
!TryWriteName(ctx, fiber + FiberNameOffset, name) ||
|
!TryWriteName(ctx, fiber + FiberNameOffset, name) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextPointerOffset, 0) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextPointerOffset, 0) ||
|
||||||
!TryWriteUInt32(ctx, fiber + FiberFlagsOffset, flags) ||
|
!ctx.TryWriteUInt32(fiber + FiberFlagsOffset, flags) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextStartOffset, contextAddress) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextStartOffset, contextAddress) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextEndOffset, contextAddress == 0 ? 0 : contextAddress + contextSize) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextEndOffset, contextAddress == 0 ? 0 : contextAddress + contextSize) ||
|
||||||
!TryWriteUInt32(ctx, fiber + FiberMagicEndOffset, FiberSignature1))
|
!ctx.TryWriteUInt32(fiber + FiberMagicEndOffset, FiberSignature1))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contextAddress != 0)
|
if (contextAddress != 0)
|
||||||
{
|
{
|
||||||
if (!TryWriteUInt64(ctx, contextAddress, FiberStackSignature))
|
if (!ctx.TryWriteUInt64(contextAddress, FiberStackSignature))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
}
|
}
|
||||||
@@ -616,9 +616,9 @@ public static class FiberExports
|
|||||||
|
|
||||||
if (previousFiber != 0)
|
if (previousFiber != 0)
|
||||||
{
|
{
|
||||||
if (!TryReadUInt32(ctx, previousFiber + FiberStateOffset, out var previousState) ||
|
if (!ctx.TryReadUInt32(previousFiber + FiberStateOffset, out var previousState) ||
|
||||||
previousState != FiberStateRun ||
|
previousState != FiberStateRun ||
|
||||||
!TryWriteUInt32(ctx, previousFiber + FiberStateOffset, FiberStateIdle))
|
!ctx.TryWriteUInt32(previousFiber + FiberStateOffset, FiberStateIdle))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, FiberErrorState);
|
return SetReturn(ctx, FiberErrorState);
|
||||||
}
|
}
|
||||||
@@ -631,12 +631,12 @@ public static class FiberExports
|
|||||||
_returnTargets[fiber] = new FiberReturnTarget(0, callerContinuation);
|
_returnTargets[fiber] = new FiberReturnTarget(0, callerContinuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryWriteUInt32(ctx, fiber + FiberStateOffset, FiberStateRun))
|
if (!ctx.TryWriteUInt32(fiber + FiberStateOffset, FiberStateRun))
|
||||||
{
|
{
|
||||||
if (previousFiber != 0)
|
if (previousFiber != 0)
|
||||||
{
|
{
|
||||||
_continuations.TryRemove(previousFiber, out _);
|
_continuations.TryRemove(previousFiber, out _);
|
||||||
_ = TryWriteUInt32(ctx, previousFiber + FiberStateOffset, FiberStateRun);
|
_ = ctx.TryWriteUInt32(previousFiber + FiberStateOffset, FiberStateRun);
|
||||||
}
|
}
|
||||||
_returnTargets.TryRemove(fiber, out _);
|
_returnTargets.TryRemove(fiber, out _);
|
||||||
return SetReturn(ctx, FiberErrorInvalid);
|
return SetReturn(ctx, FiberErrorInvalid);
|
||||||
@@ -673,7 +673,7 @@ public static class FiberExports
|
|||||||
|
|
||||||
var stackEnd = fields.ContextAddress + fields.ContextSize;
|
var stackEnd = fields.ContextAddress + fields.ContextSize;
|
||||||
var entryRsp = (stackEnd & ~15UL) - sizeof(ulong);
|
var entryRsp = (stackEnd & ~15UL) - sizeof(ulong);
|
||||||
if (!TryWriteUInt64(ctx, entryRsp, 0))
|
if (!ctx.TryWriteUInt64(entryRsp, 0))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -708,7 +708,7 @@ public static class FiberExports
|
|||||||
FiberContinuation continuation,
|
FiberContinuation continuation,
|
||||||
ulong argument) =>
|
ulong argument) =>
|
||||||
continuation.ArgOnRunAddress == 0 ||
|
continuation.ArgOnRunAddress == 0 ||
|
||||||
TryWriteUInt64(ctx, continuation.ArgOnRunAddress, argument);
|
ctx.TryWriteUInt64(continuation.ArgOnRunAddress, argument);
|
||||||
|
|
||||||
private static GuestCpuContinuation CaptureContinuation(
|
private static GuestCpuContinuation CaptureContinuation(
|
||||||
CpuContext ctx,
|
CpuContext ctx,
|
||||||
@@ -779,11 +779,11 @@ public static class FiberExports
|
|||||||
return FiberErrorInvalid;
|
return FiberErrorInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryWriteUInt64(ctx, fiber + FiberContextAddressOffset, contextAddress) ||
|
if (!ctx.TryWriteUInt64(fiber + FiberContextAddressOffset, contextAddress) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextSizeOffset, contextSize) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextSizeOffset, contextSize) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextStartOffset, contextAddress) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextStartOffset, contextAddress) ||
|
||||||
!TryWriteUInt64(ctx, fiber + FiberContextEndOffset, contextAddress + contextSize) ||
|
!ctx.TryWriteUInt64(fiber + FiberContextEndOffset, contextAddress + contextSize) ||
|
||||||
!TryWriteUInt64(ctx, contextAddress, FiberStackSignature))
|
!ctx.TryWriteUInt64(contextAddress, FiberStackSignature))
|
||||||
{
|
{
|
||||||
return FiberErrorInvalid;
|
return FiberErrorInvalid;
|
||||||
}
|
}
|
||||||
@@ -839,8 +839,8 @@ public static class FiberExports
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadUInt32(ctx, fiber + FiberMagicStartOffset, out var magicStart) ||
|
if (!ctx.TryReadUInt32(fiber + FiberMagicStartOffset, out var magicStart) ||
|
||||||
!TryReadUInt32(ctx, fiber + FiberMagicEndOffset, out var magicEnd) ||
|
!ctx.TryReadUInt32(fiber + FiberMagicEndOffset, out var magicEnd) ||
|
||||||
magicStart != FiberSignature0 ||
|
magicStart != FiberSignature0 ||
|
||||||
magicEnd != FiberSignature1)
|
magicEnd != FiberSignature1)
|
||||||
{
|
{
|
||||||
@@ -855,12 +855,12 @@ public static class FiberExports
|
|||||||
private static bool TryReadFiberFields(CpuContext ctx, ulong fiber, out FiberFields fields)
|
private static bool TryReadFiberFields(CpuContext ctx, ulong fiber, out FiberFields fields)
|
||||||
{
|
{
|
||||||
fields = default;
|
fields = default;
|
||||||
if (!TryReadUInt32(ctx, fiber + FiberStateOffset, out var state) ||
|
if (!ctx.TryReadUInt32(fiber + FiberStateOffset, out var state) ||
|
||||||
!TryReadUInt64(ctx, fiber + FiberEntryOffset, out var entry) ||
|
!ctx.TryReadUInt64(fiber + FiberEntryOffset, out var entry) ||
|
||||||
!TryReadUInt64(ctx, fiber + FiberArgOnInitializeOffset, out var argOnInitialize) ||
|
!ctx.TryReadUInt64(fiber + FiberArgOnInitializeOffset, out var argOnInitialize) ||
|
||||||
!TryReadUInt64(ctx, fiber + FiberContextAddressOffset, out var contextAddress) ||
|
!ctx.TryReadUInt64(fiber + FiberContextAddressOffset, out var contextAddress) ||
|
||||||
!TryReadUInt64(ctx, fiber + FiberContextSizeOffset, out var contextSize) ||
|
!ctx.TryReadUInt64(fiber + FiberContextSizeOffset, out var contextSize) ||
|
||||||
!TryReadUInt32(ctx, fiber + FiberFlagsOffset, out var flags) ||
|
!ctx.TryReadUInt32(fiber + FiberFlagsOffset, out var flags) ||
|
||||||
!TryReadInlineName(ctx, fiber + FiberNameOffset, out var name))
|
!TryReadInlineName(ctx, fiber + FiberNameOffset, out var name))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -898,46 +898,6 @@ public static class FiberExports
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadUInt64(CpuContext ctx, ulong address, out ulong value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt64LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryWriteUInt64(CpuContext ctx, ulong address, ulong value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
|
||||||
BinaryPrimitives.WriteUInt64LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryWriteName(CpuContext ctx, ulong address, string name)
|
private static bool TryWriteName(CpuContext ctx, ulong address, string name)
|
||||||
{
|
{
|
||||||
Span<byte> buffer = stackalloc byte[MaxNameLength + 1];
|
Span<byte> buffer = stackalloc byte[MaxNameLength + 1];
|
||||||
@@ -965,31 +925,6 @@ public static class FiberExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadNullTerminatedUtf8(CpuContext ctx, ulong address, int capacity, out string value)
|
|
||||||
{
|
|
||||||
var bytes = new byte[capacity];
|
|
||||||
for (var index = 0; index < bytes.Length; index++)
|
|
||||||
{
|
|
||||||
Span<byte> current = stackalloc byte[1];
|
|
||||||
if (!ctx.Memory.TryRead(address + (ulong)index, current))
|
|
||||||
{
|
|
||||||
value = string.Empty;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current[0] == 0)
|
|
||||||
{
|
|
||||||
value = Encoding.UTF8.GetString(bytes, 0, index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes[index] = current[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
value = Encoding.UTF8.GetString(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int SetReturn(CpuContext ctx, int result)
|
private static int SetReturn(CpuContext ctx, int result)
|
||||||
{
|
{
|
||||||
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using SharpEmu.HLE;
|
using SharpEmu.HLE;
|
||||||
using SharpEmu.Libs.Ampr;
|
using SharpEmu.Libs.Ampr;
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -50,7 +49,7 @@ public static class KernelAprCompatExports
|
|||||||
return completionResult;
|
return completionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outSubmissionId != 0 && !TryWriteUInt32(ctx, outSubmissionId, submissionId))
|
if (outSubmissionId != 0 && !ctx.TryWriteUInt32(outSubmissionId, submissionId))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -141,7 +140,7 @@ public static class KernelAprCompatExports
|
|||||||
return completionResult;
|
return completionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryWriteUInt32(ctx, outSubmissionId, submissionId))
|
if (!ctx.TryWriteUInt32(outSubmissionId, submissionId))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -178,13 +177,6 @@ public static class KernelAprCompatExports
|
|||||||
return tag is 0x0C or 0x10;
|
return tag is 0x0C or 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void TraceApr(
|
private static void TraceApr(
|
||||||
CpuContext ctx,
|
CpuContext ctx,
|
||||||
string operation,
|
string operation,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using SharpEmu.HLE;
|
using SharpEmu.HLE;
|
||||||
@@ -55,7 +54,7 @@ public static class KernelEventFlagCompatExports
|
|||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadNullTerminatedUtf8(ctx, nameAddress, MaxEventFlagNameLength + 1, out var name))
|
if (!ctx.TryReadNullTerminatedUtf8(nameAddress, MaxEventFlagNameLength + 1, out var name))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -219,7 +218,7 @@ public static class KernelEventFlagCompatExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint timeoutUsec = 0;
|
uint timeoutUsec = 0;
|
||||||
if (timeoutAddress != 0 && !TryReadUInt32(ctx, timeoutAddress, out timeoutUsec))
|
if (timeoutAddress != 0 && !ctx.TryReadUInt32(timeoutAddress, out timeoutUsec))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -234,7 +233,7 @@ public static class KernelEventFlagCompatExports
|
|||||||
|
|
||||||
if (timeoutAddress != 0)
|
if (timeoutAddress != 0)
|
||||||
{
|
{
|
||||||
_ = TryWriteUInt32(ctx, timeoutAddress, 0);
|
_ = ctx.TryWriteUInt32(timeoutAddress, 0);
|
||||||
_ = TryWriteResultPattern(ctx, resultAddress, state.Bits);
|
_ = TryWriteResultPattern(ctx, resultAddress, state.Bits);
|
||||||
TraceEventFlag($"wait-timeout handle=0x{handle:X16} pattern=0x{pattern:X16} timeout={timeoutUsec} ret=0x{returnRip:X16}");
|
TraceEventFlag($"wait-timeout handle=0x{handle:X16} pattern=0x{pattern:X16} timeout={timeoutUsec} ret=0x{returnRip:X16}");
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_TIMED_OUT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_TIMED_OUT);
|
||||||
@@ -340,7 +339,7 @@ public static class KernelEventFlagCompatExports
|
|||||||
lock (state.Gate)
|
lock (state.Gate)
|
||||||
{
|
{
|
||||||
if (waiterCountAddress != 0 &&
|
if (waiterCountAddress != 0 &&
|
||||||
!TryWriteUInt32(ctx, waiterCountAddress, unchecked((uint)state.WaitingThreads)))
|
!ctx.TryWriteUInt32(waiterCountAddress, unchecked((uint)state.WaitingThreads)))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -453,77 +452,6 @@ public static class KernelEventFlagCompatExports
|
|||||||
private static bool TryWriteResultPattern(CpuContext ctx, ulong address, ulong bits) =>
|
private static bool TryWriteResultPattern(CpuContext ctx, ulong address, ulong bits) =>
|
||||||
address == 0 || ctx.TryWriteUInt64(address, bits);
|
address == 0 || ctx.TryWriteUInt64(address, bits);
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadUInt64(CpuContext ctx, ulong address, out ulong value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt64LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadByte(CpuContext ctx, ulong address, out byte value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[1];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = buffer[0];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadNullTerminatedUtf8(CpuContext ctx, ulong address, int capacity, out string value)
|
|
||||||
{
|
|
||||||
var bytes = new byte[capacity];
|
|
||||||
for (var index = 0; index < bytes.Length; index++)
|
|
||||||
{
|
|
||||||
Span<byte> current = stackalloc byte[1];
|
|
||||||
if (!ctx.Memory.TryRead(address + (ulong)index, current))
|
|
||||||
{
|
|
||||||
value = string.Empty;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current[0] == 0)
|
|
||||||
{
|
|
||||||
value = Encoding.UTF8.GetString(bytes, 0, index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes[index] = current[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
value = Encoding.UTF8.GetString(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int SetReturn(CpuContext ctx, OrbisGen2Result result)
|
private static int SetReturn(CpuContext ctx, OrbisGen2Result result)
|
||||||
{
|
{
|
||||||
var value = (int)result;
|
var value = (int)result;
|
||||||
@@ -614,7 +542,7 @@ public static class KernelEventFlagCompatExports
|
|||||||
|
|
||||||
private static void AppendByte(StringBuilder builder, CpuContext ctx, ulong address, string name)
|
private static void AppendByte(StringBuilder builder, CpuContext ctx, ulong address, string name)
|
||||||
{
|
{
|
||||||
if (TryReadByte(ctx, address, out var value))
|
if (ctx.TryReadByte(address, out var value))
|
||||||
{
|
{
|
||||||
builder.Append($" {name}=0x{value:X2}");
|
builder.Append($" {name}=0x{value:X2}");
|
||||||
}
|
}
|
||||||
@@ -622,7 +550,7 @@ public static class KernelEventFlagCompatExports
|
|||||||
|
|
||||||
private static void AppendUInt32(StringBuilder builder, CpuContext ctx, ulong address, string name)
|
private static void AppendUInt32(StringBuilder builder, CpuContext ctx, ulong address, string name)
|
||||||
{
|
{
|
||||||
if (TryReadUInt32(ctx, address, out var value))
|
if (ctx.TryReadUInt32(address, out var value))
|
||||||
{
|
{
|
||||||
builder.Append($" {name}=0x{value:X8}");
|
builder.Append($" {name}=0x{value:X8}");
|
||||||
}
|
}
|
||||||
@@ -630,7 +558,7 @@ public static class KernelEventFlagCompatExports
|
|||||||
|
|
||||||
private static void AppendUInt64(StringBuilder builder, CpuContext ctx, ulong address, string name)
|
private static void AppendUInt64(StringBuilder builder, CpuContext ctx, ulong address, string name)
|
||||||
{
|
{
|
||||||
if (TryReadUInt64(ctx, address, out var value))
|
if (ctx.TryReadUInt64(address, out var value))
|
||||||
{
|
{
|
||||||
builder.Append($" {name}=0x{value:X16}");
|
builder.Append($" {name}=0x{value:X16}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,13 +287,13 @@ public static class KernelEventQueueCompatExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint timeoutUsec = 0;
|
uint timeoutUsec = 0;
|
||||||
if (timeoutAddress != 0 && !TryReadUInt32(ctx, timeoutAddress, out timeoutUsec))
|
if (timeoutAddress != 0 && !ctx.TryReadUInt32(timeoutAddress, out timeoutUsec))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
var deliveredCount = DequeueEvents(ctx, handle, eventsAddress, eventCapacity);
|
var deliveredCount = DequeueEvents(ctx, handle, eventsAddress, eventCapacity);
|
||||||
if (outCountAddress != 0 && !TryWriteUInt32(ctx, outCountAddress, (uint)deliveredCount))
|
if (outCountAddress != 0 && !ctx.TryWriteUInt32(outCountAddress, (uint)deliveredCount))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -336,7 +336,7 @@ public static class KernelEventQueueCompatExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
deliveredCount = DequeueEvents(ctx, handle, eventsAddress, eventCapacity);
|
deliveredCount = DequeueEvents(ctx, handle, eventsAddress, eventCapacity);
|
||||||
if (outCountAddress != 0 && !TryWriteUInt32(ctx, outCountAddress, (uint)deliveredCount))
|
if (outCountAddress != 0 && !ctx.TryWriteUInt32(outCountAddress, (uint)deliveredCount))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -541,7 +541,7 @@ public static class KernelEventQueueCompatExports
|
|||||||
ulong outCountAddress)
|
ulong outCountAddress)
|
||||||
{
|
{
|
||||||
var deliveredCount = DequeueEvents(ctx, handle, eventsAddress, eventCapacity);
|
var deliveredCount = DequeueEvents(ctx, handle, eventsAddress, eventCapacity);
|
||||||
if (outCountAddress != 0 && !TryWriteUInt32(ctx, outCountAddress, (uint)deliveredCount))
|
if (outCountAddress != 0 && !ctx.TryWriteUInt32(outCountAddress, (uint)deliveredCount))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -654,29 +654,8 @@ public static class KernelEventQueueCompatExports
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnRip = 0UL;
|
_ = ctx.TryReadUInt64(ctx[CpuRegister.Rsp], out ulong returnRip);
|
||||||
_ = ctx.TryReadUInt64(ctx[CpuRegister.Rsp], out returnRip);
|
|
||||||
Console.Error.WriteLine(
|
Console.Error.WriteLine(
|
||||||
$"[LOADER][TRACE] equeue.{operation}: handle=0x{handle:X16} rsi=0x{ctx[CpuRegister.Rsi]:X16} rdx=0x{ctx[CpuRegister.Rdx]:X16} ret=0x{returnRip:X16}");
|
$"[LOADER][TRACE] equeue.{operation}: handle=0x{handle:X16} rsi=0x{ctx[CpuRegister.Rsi]:X16} rdx=0x{ctx[CpuRegister.Rdx]:X16} ret=0x{returnRip:X16}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ using System.Buffers;
|
|||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Linq;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace SharpEmu.Libs.Kernel;
|
namespace SharpEmu.Libs.Kernel;
|
||||||
@@ -4527,7 +4525,7 @@ public static class KernelMemoryCompatExports
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<byte> one = stackalloc byte[1];
|
var one = chunk.AsSpan(0, 1);
|
||||||
if (!TryReadCompat(ctx, current, one))
|
if (!TryReadCompat(ctx, current, one))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1018,19 +1018,12 @@ public static class KernelPthreadCompatExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool InitializeMutexObject(CpuContext ctx, ulong address, PthreadMutexState state) =>
|
private static bool InitializeMutexObject(CpuContext ctx, ulong address, PthreadMutexState state) =>
|
||||||
TryWriteUInt32(ctx, address + 0x20, unchecked((uint)state.Type)) &&
|
ctx.TryWriteUInt32(address + 0x20, unchecked((uint)state.Type)) &&
|
||||||
TryWriteUInt32(ctx, address + 0x3C, unchecked((uint)state.Protocol));
|
ctx.TryWriteUInt32(address + 0x3C, unchecked((uint)state.Protocol));
|
||||||
|
|
||||||
private static bool WriteMutexAttrObject(CpuContext ctx, ulong address, PthreadMutexAttrState state) =>
|
private static bool WriteMutexAttrObject(CpuContext ctx, ulong address, PthreadMutexAttrState state) =>
|
||||||
TryWriteUInt32(ctx, address, unchecked((uint)state.Type)) &&
|
ctx.TryWriteUInt32(address, unchecked((uint)state.Type)) &&
|
||||||
TryWriteUInt32(ctx, address + 4, unchecked((uint)state.Protocol));
|
ctx.TryWriteUInt32(address + 4, unchecked((uint)state.Protocol));
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
|
||||||
BitConverter.TryWriteBytes(bytes, value);
|
|
||||||
return ctx.Memory.TryWrite(address, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int PthreadCondInitCore(CpuContext ctx, ulong condAddress)
|
private static int PthreadCondInitCore(CpuContext ctx, ulong condAddress)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Text;
|
|
||||||
using SharpEmu.HLE;
|
using SharpEmu.HLE;
|
||||||
|
|
||||||
namespace SharpEmu.Libs.Kernel;
|
namespace SharpEmu.Libs.Kernel;
|
||||||
@@ -49,7 +47,7 @@ public static class KernelSemaphoreCompatExports
|
|||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadNullTerminatedUtf8(ctx, nameAddress, MaxSemaphoreNameLength, out var name))
|
if (!ctx.TryReadNullTerminatedUtf8(nameAddress, MaxSemaphoreNameLength, out var name))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -68,7 +66,7 @@ public static class KernelSemaphoreCompatExports
|
|||||||
Count = initialCount,
|
Count = initialCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!TryWriteUInt32(ctx, semaphoreAddress, handle))
|
if (!ctx.TryWriteUInt32(semaphoreAddress, handle))
|
||||||
{
|
{
|
||||||
_semaphores.TryRemove(handle, out _);
|
_semaphores.TryRemove(handle, out _);
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
@@ -110,12 +108,12 @@ public static class KernelSemaphoreCompatExports
|
|||||||
|
|
||||||
if (timeoutAddress != 0)
|
if (timeoutAddress != 0)
|
||||||
{
|
{
|
||||||
if (!TryReadUInt32(ctx, timeoutAddress, out _))
|
if (!ctx.TryReadUInt32(timeoutAddress, out _))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = TryWriteUInt32(ctx, timeoutAddress, 0);
|
_ = ctx.TryWriteUInt32(timeoutAddress, 0);
|
||||||
TraceSemaphore($"wait-timeout handle=0x{handle:X8} name='{semaphore.Name}' need={needCount} count={semaphore.Count}");
|
TraceSemaphore($"wait-timeout handle=0x{handle:X8} name='{semaphore.Name}' need={needCount} count={semaphore.Count}");
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_TIMED_OUT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_TIMED_OUT);
|
||||||
}
|
}
|
||||||
@@ -222,7 +220,7 @@ public static class KernelSemaphoreCompatExports
|
|||||||
|
|
||||||
lock (semaphore.Gate)
|
lock (semaphore.Gate)
|
||||||
{
|
{
|
||||||
if (waitingThreadsAddress != 0 && !TryWriteUInt32(ctx, waitingThreadsAddress, unchecked((uint)semaphore.WaitingThreads)))
|
if (waitingThreadsAddress != 0 && !ctx.TryWriteUInt32(waitingThreadsAddress, unchecked((uint)semaphore.WaitingThreads)))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -258,56 +256,6 @@ public static class KernelSemaphoreCompatExports
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadNullTerminatedUtf8(CpuContext ctx, ulong address, int maxLength, out string value)
|
|
||||||
{
|
|
||||||
value = string.Empty;
|
|
||||||
if (address == 0 || maxLength <= 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes = new byte[Math.Min(maxLength, 4096)];
|
|
||||||
for (var i = 0; i < bytes.Length; i++)
|
|
||||||
{
|
|
||||||
Span<byte> current = stackalloc byte[1];
|
|
||||||
if (!ctx.Memory.TryRead(address + (ulong)i, current))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current[0] == 0)
|
|
||||||
{
|
|
||||||
value = Encoding.UTF8.GetString(bytes, 0, i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes[i] = current[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
value = Encoding.UTF8.GetString(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void TraceSemaphore(string message)
|
private static void TraceSemaphore(string message)
|
||||||
{
|
{
|
||||||
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_SEMA"), "1", StringComparison.Ordinal))
|
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_SEMA"), "1", StringComparison.Ordinal))
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ public static class PlayGoExports
|
|||||||
if (outChunkIdList == 0)
|
if (outChunkIdList == 0)
|
||||||
{
|
{
|
||||||
TracePlayGo($"get_chunk_id count_only entries={availableEntries} out_entries=0x{outEntries:X16}");
|
TracePlayGo($"get_chunk_id count_only entries={availableEntries} out_entries=0x{outEntries:X16}");
|
||||||
return TryWriteUInt32(ctx, outEntries, availableEntries)
|
return ctx.TryWriteUInt32(outEntries, availableEntries)
|
||||||
? (int)OrbisGen2Result.ORBIS_GEN2_OK
|
? (int)OrbisGen2Result.ORBIS_GEN2_OK
|
||||||
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ public static class PlayGoExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
TracePlayGo($"get_chunk_id write requested={numberOfEntries} wrote={entriesToWrite} available={availableEntries}");
|
TracePlayGo($"get_chunk_id write requested={numberOfEntries} wrote={entriesToWrite} available={availableEntries}");
|
||||||
return TryWriteUInt32(ctx, outEntries, entriesToWrite)
|
return ctx.TryWriteUInt32(outEntries, entriesToWrite)
|
||||||
? (int)OrbisGen2Result.ORBIS_GEN2_OK
|
? (int)OrbisGen2Result.ORBIS_GEN2_OK
|
||||||
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -503,7 +503,7 @@ public static class PlayGoExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
TracePlayGo($"get_todo requested={numberOfEntries} wrote=0");
|
TracePlayGo($"get_todo requested={numberOfEntries} wrote=0");
|
||||||
return TryWriteUInt32(ctx, outEntries, 0)
|
return ctx.TryWriteUInt32(outEntries, 0)
|
||||||
? (int)OrbisGen2Result.ORBIS_GEN2_OK
|
? (int)OrbisGen2Result.ORBIS_GEN2_OK
|
||||||
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
@@ -748,13 +748,6 @@ public static class PlayGoExports
|
|||||||
return ctx.Memory.TryWrite(address, buffer);
|
return ctx.Memory.TryWrite(address, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
|
|
||||||
return ctx.Memory.TryWrite(address, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryWriteInt32(CpuContext ctx, ulong address, int value)
|
private static bool TryWriteInt32(CpuContext ctx, ulong address, int value)
|
||||||
{
|
{
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(int)];
|
Span<byte> buffer = stackalloc byte[sizeof(int)];
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public static class SaveDataDialogExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
_lastMode = TryReadInt32(ctx, paramAddress, out var mode) ? mode : 0;
|
_lastMode = TryReadInt32(ctx, paramAddress, out var mode) ? mode : 0;
|
||||||
_lastUserData = TryReadUInt64(ctx, paramAddress + 0xC8, out var userData) ? userData : 0;
|
_lastUserData = ctx.TryReadUInt64(paramAddress + 0xC8, out var userData) ? userData : 0;
|
||||||
|
|
||||||
// There is no host save dialog yet. Complete immediately with OK so
|
// There is no host save dialog yet. Complete immediately with OK so
|
||||||
// guest polling sees a finished dialog instead of spinning forever.
|
// guest polling sees a finished dialog instead of spinning forever.
|
||||||
@@ -182,19 +182,6 @@ public static class SaveDataDialogExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt64(CpuContext ctx, ulong address, out ulong value)
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(ulong)];
|
|
||||||
if (!ctx.Memory.TryRead(address, bytes))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt64LittleEndian(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int SetReturn(CpuContext ctx, int result)
|
private static int SetReturn(CpuContext ctx, int result)
|
||||||
{
|
{
|
||||||
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ public static class SaveDataExports
|
|||||||
var setNum = result.DirNamesNum == 0
|
var setNum = result.DirNamesNum == 0
|
||||||
? 0
|
? 0
|
||||||
: Math.Min(result.DirNamesNum, entries.Count);
|
: Math.Min(result.DirNamesNum, entries.Count);
|
||||||
if (!TryWriteUInt32(ctx, resultAddress + ResultHitNumOffset, checked((uint)entries.Count)) ||
|
if (!ctx.TryWriteUInt32(resultAddress + ResultHitNumOffset, checked((uint)entries.Count)) ||
|
||||||
!TryWriteUInt32(ctx, resultAddress + ResultSetNumOffset, checked((uint)setNum)))
|
!ctx.TryWriteUInt32(resultAddress + ResultSetNumOffset, checked((uint)setNum)))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -173,9 +173,9 @@ public static class SaveDataExports
|
|||||||
!ctx.TryReadUInt64(mountAddress + 0x08, out var dirNameAddress) ||
|
!ctx.TryReadUInt64(mountAddress + 0x08, out var dirNameAddress) ||
|
||||||
!ctx.TryReadUInt64(mountAddress + 0x10, out var blocks) ||
|
!ctx.TryReadUInt64(mountAddress + 0x10, out var blocks) ||
|
||||||
!ctx.TryReadUInt64(mountAddress + 0x18, out var systemBlocks) ||
|
!ctx.TryReadUInt64(mountAddress + 0x18, out var systemBlocks) ||
|
||||||
!TryReadUInt32(ctx, mountAddress + 0x20, out var mountMode) ||
|
!ctx.TryReadUInt32(mountAddress + 0x20, out var mountMode) ||
|
||||||
!TryReadUInt32(ctx, mountAddress + 0x24, out var resource) ||
|
!ctx.TryReadUInt32(mountAddress + 0x24, out var resource) ||
|
||||||
!TryReadUInt32(ctx, mountAddress + 0x28, out var mode) ||
|
!ctx.TryReadUInt32(mountAddress + 0x28, out var mode) ||
|
||||||
dirNameAddress == 0 ||
|
dirNameAddress == 0 ||
|
||||||
!TryReadFixedAscii(ctx, dirNameAddress, SaveDataDirNameSize, out var dirName))
|
!TryReadFixedAscii(ctx, dirNameAddress, SaveDataDirNameSize, out var dirName))
|
||||||
{
|
{
|
||||||
@@ -263,7 +263,7 @@ public static class SaveDataExports
|
|||||||
|
|
||||||
var id = (uint)Interlocked.Increment(ref _nextTransactionResource);
|
var id = (uint)Interlocked.Increment(ref _nextTransactionResource);
|
||||||
|
|
||||||
if (!TryWriteUInt32(ctx, resourceAddress, id))
|
if (!ctx.TryWriteUInt32(resourceAddress, id))
|
||||||
{
|
{
|
||||||
return SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
return SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
@@ -280,8 +280,8 @@ public static class SaveDataExports
|
|||||||
if (!TryReadInt32(ctx, address, out var userId) ||
|
if (!TryReadInt32(ctx, address, out var userId) ||
|
||||||
!ctx.TryReadUInt64(address + 0x08, out var titleIdAddress) ||
|
!ctx.TryReadUInt64(address + 0x08, out var titleIdAddress) ||
|
||||||
!ctx.TryReadUInt64(address + 0x10, out var dirNameAddress) ||
|
!ctx.TryReadUInt64(address + 0x10, out var dirNameAddress) ||
|
||||||
!TryReadUInt32(ctx, address + 0x18, out var sortKey) ||
|
!ctx.TryReadUInt32(address + 0x18, out var sortKey) ||
|
||||||
!TryReadUInt32(ctx, address + 0x1C, out var sortOrder))
|
!ctx.TryReadUInt32(address + 0x1C, out var sortOrder))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -304,7 +304,7 @@ public static class SaveDataExports
|
|||||||
{
|
{
|
||||||
result = default;
|
result = default;
|
||||||
if (!ctx.TryReadUInt64(address + ResultDirNamesOffset, out var dirNamesAddress) ||
|
if (!ctx.TryReadUInt64(address + ResultDirNamesOffset, out var dirNamesAddress) ||
|
||||||
!TryReadUInt32(ctx, address + ResultDirNamesNumOffset, out var dirNamesNum) ||
|
!ctx.TryReadUInt32(address + ResultDirNamesNumOffset, out var dirNamesNum) ||
|
||||||
!ctx.TryReadUInt64(address + ResultParamsOffset, out var paramsAddress) ||
|
!ctx.TryReadUInt64(address + ResultParamsOffset, out var paramsAddress) ||
|
||||||
!ctx.TryReadUInt64(address + ResultInfosOffset, out var infosAddress))
|
!ctx.TryReadUInt64(address + ResultInfosOffset, out var infosAddress))
|
||||||
{
|
{
|
||||||
@@ -518,26 +518,6 @@ public static class SaveDataExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, bytes))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(bytes);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryWriteUInt32(CpuContext ctx, ulong address, uint value)
|
|
||||||
{
|
|
||||||
Span<byte> bytes = stackalloc byte[sizeof(uint)];
|
|
||||||
BinaryPrimitives.WriteUInt32LittleEndian(bytes, value);
|
|
||||||
return ctx.Memory.TryWrite(address, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int SetReturn(CpuContext ctx, int result)
|
private static int SetReturn(CpuContext ctx, int result)
|
||||||
{
|
{
|
||||||
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
ctx[CpuRegister.Rax] = unchecked((ulong)result);
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<PackageReference Include="Silk.NET.Windowing" />
|
<PackageReference Include="Silk.NET.Windowing" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -922,9 +922,9 @@ public static class VideoOutExports
|
|||||||
private static bool TryReadBufferAttribute(CpuContext ctx, ulong attributeAddress, bool attribute2, out BufferAttribute attribute)
|
private static bool TryReadBufferAttribute(CpuContext ctx, ulong attributeAddress, bool attribute2, out BufferAttribute attribute)
|
||||||
{
|
{
|
||||||
attribute = default;
|
attribute = default;
|
||||||
if (!TryReadUInt32(ctx, attributeAddress + 0x04, out var tilingMode) ||
|
if (!ctx.TryReadUInt32(attributeAddress + 0x04, out var tilingMode) ||
|
||||||
!TryReadUInt32(ctx, attributeAddress + 0x0C, out var width) ||
|
!ctx.TryReadUInt32(attributeAddress + 0x0C, out var width) ||
|
||||||
!TryReadUInt32(ctx, attributeAddress + 0x10, out var height))
|
!ctx.TryReadUInt32(attributeAddress + 0x10, out var height))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -941,10 +941,10 @@ public static class VideoOutExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryReadUInt32(ctx, attributeAddress + 0x00, out var pixelFormat32) ||
|
if (!ctx.TryReadUInt32(attributeAddress + 0x00, out var pixelFormat32) ||
|
||||||
!TryReadUInt32(ctx, attributeAddress + 0x08, out var aspectRatio) ||
|
!ctx.TryReadUInt32(attributeAddress + 0x08, out var aspectRatio) ||
|
||||||
!TryReadUInt32(ctx, attributeAddress + 0x14, out var pitchInPixel) ||
|
!ctx.TryReadUInt32(attributeAddress + 0x14, out var pitchInPixel) ||
|
||||||
!TryReadUInt32(ctx, attributeAddress + 0x18, out var option32))
|
!ctx.TryReadUInt32(attributeAddress + 0x18, out var option32))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1291,19 +1291,6 @@ public static class VideoOutExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryReadUInt32(CpuContext ctx, ulong address, out uint value)
|
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(uint)];
|
|
||||||
if (!ctx.Memory.TryRead(address, buffer))
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadInt16(CpuContext ctx, ulong address, out short value)
|
private static bool TryReadInt16(CpuContext ctx, ulong address, out short value)
|
||||||
{
|
{
|
||||||
Span<byte> buffer = stackalloc byte[sizeof(short)];
|
Span<byte> buffer = stackalloc byte[sizeof(short)];
|
||||||
|
|||||||
@@ -4,4 +4,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user