Skip to content

Commit c5ab05e

Browse files
committed
Code changes for melonDS sized access.
1 parent 06b975e commit c5ab05e

4 files changed

Lines changed: 292 additions & 55 deletions

File tree

src/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ public enum MemoryDomainFlags : long
9292
/// If true, Data is a function to call and not a pointer
9393
/// </summary>
9494
FunctionHook = 1024,
95+
/// <summary>
96+
/// If true, Data is a list of functions; function(s) may be null
97+
/// </summary>
98+
SizedFunctionHooks = 2048,
9599
}
96100

97101
[StructLayout(LayoutKind.Sequential)]

src/BizHawk.Emulation.Cores/Waterbox/WaterboxMemoryDomain.cs

Lines changed: 175 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ public abstract class WaterboxMemoryDomain : MemoryDomain
1818

1919
public static WaterboxMemoryDomain Create(MemoryArea m, WaterboxHost monitor)
2020
{
21-
return m.Flags.HasFlag(MemoryDomainFlags.FunctionHook)
22-
? new WaterboxMemoryDomainFunc(m, monitor)
23-
: new WaterboxMemoryDomainPointer(m, monitor);
21+
if (m.Flags.HasFlag(MemoryDomainFlags.FunctionHook))
22+
return new WaterboxMemoryDomainFunc(m, monitor);
23+
else if (m.Flags.HasFlag(MemoryDomainFlags.SizedFunctionHooks))
24+
return new WaterboxMemoryDomainSizedFuncs(m, monitor);
25+
else
26+
return new WaterboxMemoryDomainPointer(m, monitor);
2427
}
2528

2629
protected WaterboxMemoryDomain(MemoryArea m, IMonitor monitor)
@@ -149,6 +152,33 @@ public static MemoryDomainAccessStub Create(IntPtr p, WaterboxHost host)
149152
new StubResolver(p), host, CallingConventionAdapters.MakeWaterboxDepartureOnly(host));
150153
}
151154
}
155+
public abstract class MemoryDomainSizedAccessStub
156+
{
157+
[BizImport(CallingConvention.Cdecl)]
158+
public abstract void Access(IntPtr buffer, long address, long count);
159+
160+
private class StubResolver : IImportResolver
161+
{
162+
private readonly IntPtr _p;
163+
164+
public StubResolver(IntPtr p)
165+
{
166+
_p = p;
167+
}
168+
169+
public IntPtr GetProcAddrOrThrow(string entryPoint) => _p;
170+
public IntPtr GetProcAddrOrZero(string entryPoint) => _p;
171+
}
172+
173+
public static MemoryDomainSizedAccessStub Create(IntPtr p, WaterboxHost host)
174+
{
175+
return BizInvoker.GetInvoker<MemoryDomainSizedAccessStub>(
176+
new StubResolver(p),
177+
host,
178+
CallingConventionAdapters.MakeWaterboxDepartureOnly(host));
179+
}
180+
}
181+
152182

153183
public unsafe class WaterboxMemoryDomainFunc : WaterboxMemoryDomain
154184
{
@@ -202,7 +232,7 @@ public override void BulkPeekByte(Range<long> addresses, byte[] values)
202232

203233
if (start < (ulong)Size && (start + count) <= (ulong)Size)
204234
{
205-
fixed(byte* p = values)
235+
fixed (byte* p = values)
206236
_access.Access((IntPtr)p, (long)start, (long)count, false);
207237
}
208238
else
@@ -211,4 +241,145 @@ public override void BulkPeekByte(Range<long> addresses, byte[] values)
211241
}
212242
}
213243
}
244+
245+
/// <summary>
246+
/// A memory domain for things like a system bus, where the size of the read/write may affect the result.
247+
/// Endianness is ignored; we are writing numbers not multi-byte representations of numbers.
248+
/// </summary>
249+
public unsafe class WaterboxMemoryDomainSizedFuncs : WaterboxMemoryDomain
250+
{
251+
private readonly MemoryDomainSizedAccessStub _read8 = null;
252+
private readonly MemoryDomainSizedAccessStub _write8 = null;
253+
private readonly MemoryDomainSizedAccessStub _read16 = null;
254+
private readonly MemoryDomainSizedAccessStub _write16 = null;
255+
private readonly MemoryDomainSizedAccessStub _read32 = null;
256+
private readonly MemoryDomainSizedAccessStub _write32 = null;
257+
258+
private string AddressRangeError => string.Format("Address must be in the range [0, 0x{0:x}]", Size - 1);
259+
260+
internal WaterboxMemoryDomainSizedFuncs(MemoryArea m, WaterboxHost monitor)
261+
: base(m, monitor)
262+
{
263+
if (!m.Flags.HasFlag(MemoryDomainFlags.SizedFunctionHooks))
264+
throw new InvalidOperationException();
265+
266+
using (monitor.EnterExit())
267+
{
268+
IntPtr* functionPointers = (IntPtr*)m.Data;
269+
for (int i = 0; i < 6; i++)
270+
{
271+
if (functionPointers[i] == IntPtr.Zero) throw new Exception("All access functions must have implementations.");
272+
}
273+
_read8 = MemoryDomainSizedAccessStub.Create(functionPointers[0], monitor);
274+
_write8 = MemoryDomainSizedAccessStub.Create(functionPointers[1], monitor);
275+
276+
_read16 = MemoryDomainSizedAccessStub.Create(functionPointers[2], monitor);
277+
_write16 = MemoryDomainSizedAccessStub.Create(functionPointers[3], monitor);
278+
279+
_read32 = MemoryDomainSizedAccessStub.Create(functionPointers[4], monitor);
280+
_write32 = MemoryDomainSizedAccessStub.Create(functionPointers[5], monitor);
281+
}
282+
}
283+
284+
public override byte PeekByte(long addr)
285+
{
286+
if ((ulong)addr >= (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
287+
288+
byte ret = 0;
289+
_read8.Access((IntPtr)(&ret), addr, 1);
290+
return ret;
291+
}
292+
293+
public override void PokeByte(long addr, byte val)
294+
{
295+
if ((ulong)addr >= (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
296+
297+
_write8.Access((IntPtr)(&val), addr, 1);
298+
}
299+
300+
public override ushort PeekUshort(long addr, bool bigEndian)
301+
{
302+
if ((ulong)addr + 1 >= (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
303+
304+
ushort ret = 0;
305+
_read16.Access((IntPtr)(&ret), addr, 1);
306+
return ret;
307+
}
308+
309+
public override void PokeUshort(long addr, ushort val, bool bigEndian)
310+
{
311+
if ((ulong)addr + 1 >= (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
312+
313+
_write16.Access((IntPtr)(&val), addr, 1);
314+
}
315+
316+
public override uint PeekUint(long addr, bool bigEndian)
317+
{
318+
if ((ulong)addr + 3 >= (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
319+
320+
uint ret = 0;
321+
_read32.Access((IntPtr)(&ret), addr, 1);
322+
return ret;
323+
}
324+
325+
public override void PokeUint(long addr, uint val, bool bigEndian)
326+
{
327+
if ((ulong)addr + 3 >= (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
328+
329+
_write32.Access((IntPtr)(&val), addr, 1);
330+
}
331+
332+
public override void BulkPeekByte(Range<long> addresses, byte[] values)
333+
{
334+
if ((ulong)addresses.Start + addresses.Count() > (ulong)Size || addresses.Start < 0) throw new ArgumentOutOfRangeException(nameof(addresses), message: AddressRangeError);
335+
if (addresses.Count() > (uint)values.Length) throw new ArgumentException(message: $"Length of {nameof(values)} must be at least {nameof(addresses)} count.", nameof(values));
336+
337+
fixed (byte* p = values)
338+
_read8.Access((IntPtr)p, addresses.Start, (long)addresses.Count());
339+
}
340+
341+
public void BulkPokeByte(long addr, Span<byte> values)
342+
{
343+
if ((ulong)addr + (ulong)values.Length > (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
344+
345+
fixed (byte* p = values)
346+
_write8.Access((IntPtr)p, addr, values.Length);
347+
}
348+
349+
public override void BulkPeekUshort(Range<long> addresses, bool bigEndian, ushort[] values)
350+
{
351+
if ((ulong)addresses.Start + addresses.Count() > (ulong)Size || addresses.Start < 0) throw new ArgumentOutOfRangeException(nameof(addresses), message: AddressRangeError);
352+
if (addresses.Count() > (uint)values.Length * sizeof(ushort)) throw new ArgumentException(message: $"Length of {nameof(values)} must be at least {nameof(addresses)} count.", nameof(values));
353+
if ((addresses.Count() & 1) != 0) throw new ArgumentOutOfRangeException(nameof(addresses), "Requested byte count must be divisible by 2."); // TODO: The caller should be specifying the count of ushorts, not the count of bytes!
354+
355+
fixed (ushort* p = values)
356+
_read16.Access((IntPtr)p, addresses.Start, (long)addresses.Count() / sizeof(ushort));
357+
}
358+
359+
public void BulkPokeUshort(long addr, Span<ushort> values)
360+
{
361+
if ((ulong)addr + (ulong)values.Length * sizeof(ushort) > (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
362+
363+
fixed (ushort* p = values)
364+
_write16.Access((IntPtr)p, addr, values.Length);
365+
}
366+
367+
public override void BulkPeekUint(Range<long> addresses, bool bigEndian, uint[] values)
368+
{
369+
if ((ulong)addresses.Start + addresses.Count() > (ulong)Size || addresses.Start < 0) throw new ArgumentOutOfRangeException(nameof(addresses), message: AddressRangeError);
370+
if (addresses.Count() > (uint)values.Length * sizeof(uint)) throw new ArgumentException(message: $"Length of {nameof(values)} must be at least {nameof(addresses)} count.", nameof(values));
371+
if ((addresses.Count() & 3) != 0) throw new ArgumentOutOfRangeException(nameof(addresses), "Requested byte count must be divisible by 4."); // TODO: The caller should be specifying the count of uints, not the count of bytes!
372+
373+
fixed (uint* p = values)
374+
_read32.Access((IntPtr)p, addresses.Start, (long)addresses.Count() / sizeof(uint));
375+
}
376+
377+
public void BulkPokeUint(long addr, Span<uint> values)
378+
{
379+
if ((ulong)addr + (ulong)values.Length * sizeof(uint) > (ulong)Size || addr < 0) throw new ArgumentOutOfRangeException(nameof(addr), message: AddressRangeError);
380+
381+
fixed (uint* p = values)
382+
_write32.Access((IntPtr)p, addr, values.Length);
383+
}
384+
}
214385
}

waterbox/emulibc/waterboxcore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef void (*MemoryFunctionHook)(uint8_t* buffer, int64_t address, int64_t cou
3838
#define MEMORYAREA_FLAGS_WORDSIZE8 256
3939
#define MEMORYAREA_FLAGS_SWAPPED 512
4040
#define MEMORYAREA_FLAGS_FUNCTIONHOOK 1024
41+
#define MEMORYAREA_FLAGS_SIZEDFUNCTIONHOOKS 2048
4142

4243
#ifdef __cplusplus
4344
}

0 commit comments

Comments
 (0)