Skip to content

Commit 8833c7d

Browse files
committed
Waterbox: Give function hook memory domain multi-byte peek/poke implementations, letting the hooked function decide how to handle them.
1 parent 0029689 commit 8833c7d

6 files changed

Lines changed: 120 additions & 6 deletions

File tree

src/BizHawk.Client.Common/Api/Classes/MemoryApi.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ public IReadOnlyList<byte> ReadByteRange(long addr, int length, string domain =
264264
return newBytes;
265265
}
266266

267-
public void WriteByteRange(long addr, IReadOnlyList<byte> memoryblock, string domain = null)
267+
public void WriteByteRange(long addr, byte[] memoryblock, string domain = null)
268268
{
269269
var d = NamedDomainOrCurrent(domain);
270270
if (!d.Writable)
@@ -273,13 +273,15 @@ public void WriteByteRange(long addr, IReadOnlyList<byte> memoryblock, string do
273273
return;
274274
}
275275
if (addr < 0) LogCallback($"Warning: Attempted writes on addresses {addr}..-1 outside range of domain {d.Name} in {nameof(WriteByteRange)}()");
276-
var lastReqAddr = addr + memoryblock.Count - 1;
276+
var lastReqAddr = addr + memoryblock.Length - 1;
277277
var indexAfterLast = Math.Min(Math.Max(-1L, lastReqAddr), d.Size - 1L) + 1L;
278278
var iDst = Math.Min(Math.Max(0L, addr), d.Size);
279279
var iSrc = checked((int) (iDst - addr));
280280
using (d.EnterExit())
281281
{
282-
while (iDst < indexAfterLast) d.PokeByte(iDst++, memoryblock[iSrc++]);
282+
var writeLength = indexAfterLast - iDst;
283+
if (writeLength == memoryblock.Length) d.BulkPokeByte(iDst, memoryblock);
284+
else if (writeLength > 0) d.BulkPokeByte(iDst, memoryblock.Skip(iSrc).Take((int)writeLength).ToArray());
283285
}
284286
if (lastReqAddr >= d.Size) LogCallback($"Warning: Attempted writes on addresses {d.Size}..{lastReqAddr} outside range of domain {d.Name} in {nameof(WriteByteRange)}()");
285287
}

src/BizHawk.Client.Common/Api/Interfaces/IMemoryApi.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public interface IMemoryApi : IExternalApi
3030
uint ReadU32(long addr, string domain = null);
3131

3232
void WriteByte(long addr, uint value, string domain = null);
33-
void WriteByteRange(long addr, IReadOnlyList<byte> memoryblock, string domain = null);
33+
void WriteByteRange(long addr, byte[] memoryblock, string domain = null);
3434
void WriteFloat(long addr, float value, string domain = null);
3535

3636
void WriteS8(long addr, int value, string domain = null);

src/BizHawk.Client.Common/lua/CommonLibs/MemoryLuaLibrary.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public void WriteByteRange(LuaTable memoryblock, string domain = null)
117117
[LuaMethodExample("memory.write_bytes_as_array(0x100, { 0xAB, 0x12, 0xCD, 0x34 });")]
118118
[LuaMethod("write_bytes_as_array", "Writes sequential bytes starting at addr.")]
119119
public void WriteBytesAsArray(long addr, LuaTable bytes, string domain = null)
120-
=> APIs.Memory.WriteByteRange(addr, _th.EnumerateValues<long>(bytes).Select(l => (byte) l).ToList(), domain);
120+
=> APIs.Memory.WriteByteRange(addr, _th.EnumerateValues<long>(bytes).Select(l => (byte) l).ToArray(), domain);
121121

122122
[LuaMethodExample("memory.write_bytes_as_dict({ [0x100] = 0xAB, [0x104] = 0xCD, [0x106] = 0x12, [0x107] = 0x34, [0x108] = 0xEF });")]
123123
[LuaMethod("write_bytes_as_dict", "Writes bytes at arbitrary addresses (the keys of the given table are the addresses, relative to the start of the domain).")]

src/BizHawk.Client.Common/lua/LuaHelperLibs/MainMemoryLuaLibrary.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public void WriteByteRange(LuaTable memoryblock)
117117
[LuaMethodExample("mainmemory.write_bytes_as_array(0x100, { 0xAB, 0x12, 0xCD, 0x34 });")]
118118
[LuaMethod("write_bytes_as_array", "Writes sequential bytes starting at addr.")]
119119
public void WriteBytesAsArray(long addr, LuaTable bytes)
120-
=> APIs.Memory.WriteByteRange(addr, _th.EnumerateValues<long>(bytes).Select(l => (byte) l).ToList(), MainMemName);
120+
=> APIs.Memory.WriteByteRange(addr, _th.EnumerateValues<long>(bytes).Select(l => (byte) l).ToArray(), MainMemName);
121121

122122
[LuaMethodExample("mainmemory.write_bytes_as_dict({ [0x100] = 0xAB, [0x104] = 0xCD, [0x106] = 0x12, [0x107] = 0x34, [0x108] = 0xEF });")]
123123
[LuaMethod("write_bytes_as_dict", "Writes bytes at arbitrary addresses (the keys of the given table are the addresses, relative to the start of the main memory).")]

src/BizHawk.Emulation.Common/Base Implementations/MemoryDomain.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ public virtual void BulkPeekUint(Range<long> addresses, bool bigEndian, uint[] v
152152
}
153153
}
154154

155+
public virtual void BulkPokeByte(long addr, byte[] memoryblock)
156+
{
157+
if (!Writable)
158+
{
159+
return;
160+
}
161+
if (addr < 0) return;
162+
long lastReqAddr = addr + memoryblock.Length - 1;
163+
if (lastReqAddr >= Size) return;
164+
long iSrc = 0;
165+
using (this.EnterExit())
166+
{
167+
while (addr <= lastReqAddr) PokeByte(addr++, memoryblock[iSrc++]);
168+
}
169+
}
170+
155171
public virtual void SendCheatToCore(int addr, byte value, int compare, int compare_type) { }
156172

157173
/// <summary>

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

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Buffers.Binary;
12
using System.Runtime.InteropServices;
23

34
using BizHawk.BizInvoke;
@@ -189,6 +190,72 @@ public override void PokeByte(long addr, byte val)
189190
}
190191
}
191192

193+
public override ushort PeekUshort(long addr, bool bigEndian)
194+
{
195+
if ((ulong)addr < (ulong)Size - 1)
196+
{
197+
byte[] bytes = new byte[2];
198+
BulkPeekByte(addr.RangeTo(addr+1), bytes);
199+
if (bigEndian) return BinaryPrimitives.ReadUInt16BigEndian(bytes);
200+
else return BinaryPrimitives.ReadUInt16LittleEndian(bytes);
201+
}
202+
else
203+
{
204+
throw new ArgumentOutOfRangeException(nameof(addr));
205+
}
206+
}
207+
208+
public override void PokeUshort(long addr, ushort val, bool bigEndian)
209+
{
210+
if (Writable)
211+
{
212+
if ((ulong)addr < (ulong)Size - 1)
213+
{
214+
Span<byte> bytes = stackalloc byte[2];
215+
if (bigEndian) BinaryPrimitives.WriteUInt16BigEndian(bytes, val);
216+
else BinaryPrimitives.WriteUInt16LittleEndian(bytes, val);
217+
BulkPokeByte(addr, bytes);
218+
}
219+
else
220+
{
221+
throw new ArgumentOutOfRangeException(nameof(addr));
222+
}
223+
}
224+
}
225+
226+
public override uint PeekUint(long addr, bool bigEndian)
227+
{
228+
if ((ulong)addr < (ulong)Size - 3)
229+
{
230+
byte[] bytes = new byte[4];
231+
BulkPeekByte(addr.RangeTo(addr+3), bytes);
232+
if (bigEndian) return BinaryPrimitives.ReadUInt32BigEndian(bytes);
233+
else return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
234+
}
235+
else
236+
{
237+
throw new ArgumentOutOfRangeException(nameof(addr));
238+
}
239+
}
240+
241+
public override void PokeUint(long addr, uint val, bool bigEndian)
242+
{
243+
if (Writable)
244+
{
245+
if ((ulong)addr < (ulong)Size - 3)
246+
{
247+
Span<byte> bytes = stackalloc byte[4];
248+
if (bigEndian) BinaryPrimitives.WriteUInt32BigEndian(bytes, val);
249+
else BinaryPrimitives.WriteUInt32LittleEndian(bytes, val);
250+
BulkPokeByte(addr, bytes);
251+
}
252+
else
253+
{
254+
throw new ArgumentOutOfRangeException(nameof(addr));
255+
}
256+
}
257+
}
258+
192259
public override void BulkPeekByte(Range<long> addresses, byte[] values)
193260
{
194261
var start = (ulong)addresses.Start;
@@ -204,5 +271,34 @@ public override void BulkPeekByte(Range<long> addresses, byte[] values)
204271
throw new ArgumentOutOfRangeException(nameof(addresses));
205272
}
206273
}
274+
275+
public override void BulkPokeByte(long addr, byte[] memoryblock)
276+
{
277+
var count = memoryblock.Length;
278+
279+
if (addr < Size && ((ulong)addr + (ulong)count) <= (ulong)Size)
280+
{
281+
fixed(byte* p = memoryblock)
282+
_access.Access((IntPtr)p, addr, count, true);
283+
}
284+
else
285+
{
286+
throw new ArgumentOutOfRangeException(nameof(addr));
287+
}
288+
}
289+
290+
private void BulkPokeByte(long addr, Span<byte> memoryblock)
291+
{
292+
long count = memoryblock.Length;
293+
if (addr < Size && ((ulong)addr + (ulong)count) <= (ulong)Size)
294+
{
295+
fixed(byte* p = memoryblock)
296+
_access.Access((IntPtr)p, addr, count, true);
297+
}
298+
else
299+
{
300+
throw new ArgumentOutOfRangeException(nameof(addr));
301+
}
302+
}
207303
}
208304
}

0 commit comments

Comments
 (0)