mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
[VideoOut] Initialize output options storage (#315)
* [VideoOut] Initialize output options storage * [VideoOut] Keep output options size local
This commit is contained in:
@@ -381,7 +381,18 @@ public static class VideoOutExports
|
|||||||
LibraryName = "libSceVideoOut")]
|
LibraryName = "libSceVideoOut")]
|
||||||
public static int VideoOutInitializeOutputOptions(CpuContext ctx)
|
public static int VideoOutInitializeOutputOptions(CpuContext ctx)
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
const int outputOptionsSize = 0x40;
|
||||||
|
var optionsAddress = ctx[CpuRegister.Rdi];
|
||||||
|
if (optionsAddress == 0)
|
||||||
|
{
|
||||||
|
return OrbisVideoOutErrorInvalidAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> options = stackalloc byte[outputOptionsSize];
|
||||||
|
options.Clear();
|
||||||
|
return ctx.Memory.TryWrite(optionsAddress, options)
|
||||||
|
? (int)OrbisGen2Result.ORBIS_GEN2_OK
|
||||||
|
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
using SharpEmu.HLE;
|
||||||
|
using SharpEmu.Libs.VideoOut;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace SharpEmu.Libs.Tests.VideoOut;
|
||||||
|
|
||||||
|
public sealed class VideoOutOutputOptionsTests
|
||||||
|
{
|
||||||
|
private const ulong MemoryBase = 0x1_0000_0000;
|
||||||
|
private const ulong OptionsAddress = MemoryBase + 0x40;
|
||||||
|
private const int OptionsSize = 0x40;
|
||||||
|
private const int InvalidAddress = unchecked((int)0x80290002);
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(Generation.Gen4)]
|
||||||
|
[InlineData(Generation.Gen5)]
|
||||||
|
public void InitializeOutputOptions_ClearsExactlyOneStructure(Generation generation)
|
||||||
|
{
|
||||||
|
var memory = new FakeCpuMemory(MemoryBase, 0x1000);
|
||||||
|
var context = new CpuContext(memory, generation);
|
||||||
|
var sentinel = new byte[OptionsSize + 1];
|
||||||
|
Array.Fill(sentinel, (byte)0xCC);
|
||||||
|
Assert.True(memory.TryWrite(OptionsAddress, sentinel));
|
||||||
|
context[CpuRegister.Rdi] = OptionsAddress;
|
||||||
|
|
||||||
|
Assert.Equal(0, VideoOutExports.VideoOutInitializeOutputOptions(context));
|
||||||
|
|
||||||
|
var result = new byte[OptionsSize + 1];
|
||||||
|
Assert.True(memory.TryRead(OptionsAddress, result));
|
||||||
|
Assert.All(result.AsSpan(0, OptionsSize).ToArray(), value => Assert.Equal(0, value));
|
||||||
|
Assert.Equal(0xCC, result[OptionsSize]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InitializeOutputOptions_NullAddressReturnsInvalidAddress()
|
||||||
|
{
|
||||||
|
var context = new CpuContext(new FakeCpuMemory(MemoryBase, 0x100), Generation.Gen5);
|
||||||
|
context[CpuRegister.Rdi] = 0;
|
||||||
|
|
||||||
|
Assert.Equal(InvalidAddress, VideoOutExports.VideoOutInitializeOutputOptions(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InitializeOutputOptions_UnwritableStructureReturnsMemoryFault()
|
||||||
|
{
|
||||||
|
var context = new CpuContext(new FakeCpuMemory(MemoryBase, 0x100), Generation.Gen5);
|
||||||
|
context[CpuRegister.Rdi] = MemoryBase + 0xC1;
|
||||||
|
|
||||||
|
Assert.Equal(
|
||||||
|
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT,
|
||||||
|
VideoOutExports.VideoOutInitializeOutputOptions(context));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user