Skip to content

Commit

Permalink
[Encore]
Browse files Browse the repository at this point in the history
Remove GetVideoVirtualDimensions (no longer used)
Add System Bus domain
Fix deterministic time functionality using timezones when they should not
  • Loading branch information
CasualPokePlayer committed Jan 14, 2025
1 parent 20d7355 commit 1a1de0f
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 4 deletions.
Binary file modified Assets/dll/encore.dll
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Runtime.InteropServices;

using BizHawk.Common;
using BizHawk.Emulation.Common;

namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
Expand Down Expand Up @@ -28,6 +31,9 @@ private void InitMemoryDomains()
domains.Add(_n3dsExRam);
}

// extra domain for virtual memory (important for dealing with pointers!)
domains.Add(new EncoreMMU(_context));

_memoryDomains = new MemoryDomainList(domains);
_serviceProvider.Register(_memoryDomains);
WireMemoryDomains();
Expand All @@ -47,5 +53,223 @@ void WireDomain(LibEncore.MemoryRegion region, MemoryDomainIntPtr domain)
WireDomain(LibEncore.MemoryRegion.DSP, _dspRam);
WireDomain(LibEncore.MemoryRegion.N3DS, _n3dsExRam);
}

private class EncoreMMU : MemoryDomain
{
private const uint ENCORE_PAGE_SIZE = 0x1000;
private const uint ENCORE_PAGE_MASK = ENCORE_PAGE_SIZE - 1;

private readonly IntPtr _context;

public EncoreMMU(IntPtr context)
{
Name = "System Bus";
Size = 1L << 32;
WordSize = 4;
EndianType = Endian.Little;
Writable = true;
_context = context;
}

private Span<byte> GetPage(uint addr)
{
var pagePointer = _core.Encore_GetPagePointer(_context, addr);
return pagePointer == IntPtr.Zero ? [ ] : Util.UnsafeSpanFromPointer(pagePointer, (int)(ENCORE_PAGE_SIZE - (addr & ENCORE_PAGE_MASK)));
}

public override byte PeekByte(long addr)
{
var page = GetPage((uint)addr);
return page.IsEmpty ? (byte)0 : page[0];
}

public override ushort PeekUshort(long addr, bool bigEndian)
{
// if we cross a page boundary, we need to read multiple pages
if ((addr & ENCORE_PAGE_MASK) > ENCORE_PAGE_MASK - 1)
{
return base.PeekUshort(addr, bigEndian);
}

var page = GetPage((uint)addr);
if (page.IsEmpty)
{
return 0;
}

return bigEndian
? BinaryPrimitives.ReadUInt16BigEndian(page)
: BinaryPrimitives.ReadUInt16LittleEndian(page);
}

public override uint PeekUint(long addr, bool bigEndian)
{
// if we cross a page boundary, we need to read multiple pages
if ((addr & ENCORE_PAGE_MASK) > ENCORE_PAGE_MASK - 3)
{
return base.PeekUint(addr, bigEndian);
}

var page = GetPage((uint)addr);
if (page.IsEmpty)
{
return 0;
}

return bigEndian
? BinaryPrimitives.ReadUInt32BigEndian(page)
: BinaryPrimitives.ReadUInt32LittleEndian(page);
}

public override void PokeByte(long addr, byte val)
{
var page = GetPage((uint)addr);
if (page.IsEmpty)
{
return;
}

page[0] = val;
}

public override void PokeUshort(long addr, ushort val, bool bigEndian)
{
// if we cross a page boundary, we need to write to multiple pages
if ((addr & ENCORE_PAGE_MASK) > ENCORE_PAGE_MASK - 1)
{
base.PokeUshort(addr, val, bigEndian);
return;
}

var page = GetPage((uint)addr);
if (page.IsEmpty)
{
return;
}

if (bigEndian)
{
BinaryPrimitives.WriteUInt16BigEndian(page, val);
}
else
{
BinaryPrimitives.WriteUInt16LittleEndian(page, val);
}
}

public override void PokeUint(long addr, uint val, bool bigEndian)
{
// if we cross a page boundary, we need to write to multiple pages
if ((addr & ENCORE_PAGE_MASK) > ENCORE_PAGE_MASK - 3)
{
base.PokeUint(addr, val, bigEndian);
return;
}

var page = GetPage((uint)addr);
if (page.IsEmpty)
{
return;
}

if (bigEndian)
{
BinaryPrimitives.WriteUInt32BigEndian(page, val);
}
else
{
BinaryPrimitives.WriteUInt32LittleEndian(page, val);
}
}

private void BulkPeekByte(uint startAddr, Span<byte> values)
{
while (!values.IsEmpty)
{
var page = GetPage(startAddr);
var numBytes = Math.Min(values.Length, (int)(ENCORE_PAGE_SIZE - (startAddr & ENCORE_PAGE_MASK)));
if (page.IsEmpty)
{
values[..numBytes].Clear();
}
else
{
page[..numBytes].CopyTo(values);
}

values = values[numBytes..];
startAddr += (uint)numBytes;
}
}

public override void BulkPeekByte(Range<long> addresses, byte[] values)
{
if (addresses is null) throw new ArgumentNullException(paramName: nameof(addresses));
if (values is null) throw new ArgumentNullException(paramName: nameof(values));

if ((long)addresses.Count() != values.Length)
{
throw new InvalidOperationException("Invalid length of values array");
}

BulkPeekByte((uint)addresses.Start, values);
}

public override void BulkPeekUshort(Range<long> addresses, bool bigEndian, ushort[] values)
{
if (addresses is null) throw new ArgumentNullException(paramName: nameof(addresses));
if (values is null) throw new ArgumentNullException(paramName: nameof(values));

var start = addresses.Start;
var end = addresses.EndInclusive + 1;

if ((start & 1) != 0 || (end & 1) != 0)
throw new InvalidOperationException("The API contract doesn't define what to do for unaligned reads and writes!");

if (values.LongLength * 2 != end - start)
{
// a longer array could be valid, but nothing needs that so don't support it for now
throw new InvalidOperationException("Invalid length of values array");
}

BulkPeekByte((uint)addresses.Start, MemoryMarshal.AsBytes(values.AsSpan()));

if (!bigEndian)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = BinaryPrimitives.ReverseEndianness(values[i]);
}
}
}

public override void BulkPeekUint(Range<long> addresses, bool bigEndian, uint[] values)
{
if (addresses is null) throw new ArgumentNullException(paramName: nameof(addresses));
if (values is null) throw new ArgumentNullException(paramName: nameof(values));

var start = addresses.Start;
var end = addresses.EndInclusive + 1;

if ((start & 3) != 0 || (end & 3) != 0)
throw new InvalidOperationException("The API contract doesn't define what to do for unaligned reads and writes!");

if (values.LongLength * 4 != end - start)
{
// a longer array could be valid, but nothing needs that so don't support it for now
throw new InvalidOperationException("Invalid length of values array");
}

BulkPeekByte((uint)addresses.Start, MemoryMarshal.AsBytes(values.AsSpan()));

if (!bigEndian)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = BinaryPrimitives.ReverseEndianness(values[i]);
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ public abstract IntPtr Encore_CreateContext(
[BizImport(cc)]
public abstract void Encore_Reset(IntPtr context);

[BizImport(cc)]
public abstract void Encore_GetVideoVirtualDimensions(IntPtr context, out int width, out int height);

[BizImport(cc)]
public abstract void Encore_GetVideoBufferDimensions(IntPtr context, out int width, out int height);

Expand Down Expand Up @@ -158,6 +155,9 @@ public enum MemoryRegion
[BizImport(cc)]
public abstract void Encore_GetMemoryRegion(IntPtr context, MemoryRegion region, out IntPtr ptr, out int size);

[BizImport(cc)]
public abstract IntPtr Encore_GetPagePointer(IntPtr context, uint addr);

[BizImport(cc)]
public abstract void Encore_GetTouchScreenLayout(IntPtr context, out int x, out int y, out int width, out int height, out bool rotated, out bool enabled);
}
Expand Down

0 comments on commit 1a1de0f

Please sign in to comment.