diff --git a/Assets/dll/bsnes.wbx.zst b/Assets/dll/bsnes.wbx.zst index bd84674734..214479c198 100644 Binary files a/Assets/dll/bsnes.wbx.zst and b/Assets/dll/bsnes.wbx.zst differ diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs index 8c75ef3fe0..9059d11631 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi.cs @@ -46,6 +46,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES [BizImport(CallingConvention.Cdecl)] public abstract void snes_bus_write(uint address, byte value); [BizImport(CallingConvention.Cdecl)] + public abstract byte snes_read_oam(ushort address); + [BizImport(CallingConvention.Cdecl)] + public abstract void snes_write_oam(ushort address, byte value); + [BizImport(CallingConvention.Cdecl)] public abstract IntPtr snes_get_sgb_memory_region(int id, out int size); [BizImport(CallingConvention.Cdecl)] public abstract byte snes_sgb_bus_read(ushort address); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs index 12a89b168d..61a9c7bdbb 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs @@ -102,7 +102,7 @@ WRAM, APURAM, VRAM, - OBJECTS, + OAM, CGRAM, } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IMemoryDomains.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IMemoryDomains.cs index 363fa9b1d9..32c5a8cc04 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IMemoryDomains.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.IMemoryDomains.cs @@ -14,6 +14,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES foreach (int i in Enum.GetValues(typeof(BsnesApi.SNES_MEMORY))) { var data = Api.core.snes_get_memory_region(i, out var size, out var wordSize); + if (i == (int)BsnesApi.SNES_MEMORY.OAM) + { + mm.Add(new MemoryDomainDelegate("OAM", size, MemoryDomain.Endian.Little, + address => Api.core.snes_read_oam((ushort)address), + (address, value) => Api.core.snes_write_oam((ushort)address, value), wordSize)); + continue; + } if (data == IntPtr.Zero) continue; if (i == (int) BsnesApi.SNES_MEMORY.CARTRAM) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/SNESGraphicsDecoder.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/SNESGraphicsDecoder.cs index 2eec906e1d..a94cb2c68b 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/SNESGraphicsDecoder.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/SNESGraphicsDecoder.cs @@ -1,6 +1,5 @@ using System; using System.Drawing; -using System.Runtime.InteropServices; using BizHawk.Emulation.Cores.Nintendo.SNES; using static BizHawk.Emulation.Cores.Nintendo.BSNES.BsnesApi.SNES_REGISTER; using static BizHawk.Emulation.Cores.Nintendo.SNES.SNESGraphicsDecoder; @@ -9,23 +8,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES { public sealed unsafe class SNESGraphicsDecoder : ISNESGraphicsDecoder { - [StructLayout(LayoutKind.Sequential)] - public struct Object // size: 10 bytes; equivalent to the c++ version - { - public readonly ushort x; - public readonly byte y; - public readonly byte character; - public readonly bool nameSelect; - public readonly bool vflip; - public readonly bool hflip; - public readonly byte priority; - public readonly byte palette; - public readonly bool size; - } - private readonly BsnesApi _api; private readonly byte* vram; // waterbox pointer, ALWAYS access with EnterExit() - private readonly Object* objects; // waterbox pointer, ALWAYS access with EnterExit() private readonly ushort* cgram; // waterbox pointer, ALWAYS access with EnterExit() private readonly byte[][] cachedTiles = new byte[5][]; private readonly int[] bppArrayIndex = { 0, 0, 0, 0, 1, 0, 0, 0, 2 }; @@ -66,7 +50,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES { _api = api; vram = (byte*)api.core.snes_get_memory_region((int)BsnesApi.SNES_MEMORY.VRAM, out _, out _); - objects = (Object*)api.core.snes_get_memory_region((int)BsnesApi.SNES_MEMORY.OBJECTS, out _, out _); cgram = (ushort*)api.core.snes_get_memory_region((int)BsnesApi.SNES_MEMORY.CGRAM, out _, out _); generate_palette(); generate_directColorTable(); @@ -131,7 +114,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES cachedTiles[3] ??= new byte[pixelCount]; for (int i = 0; i < pixelCount; i++) - cachedTiles[3][i] = vram[2*i + 1]; + cachedTiles[3][i] = vram[2 * i + 1]; } private void CacheTilesMode7ExtBg() @@ -157,7 +140,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES } } - public ISNESGraphicsDecoder.OAMInfo CreateOAMInfo(ScreenInfo si, int num) => new OAMInfo(objects, si, num); + public ISNESGraphicsDecoder.OAMInfo CreateOAMInfo(ScreenInfo si, int num) => new OAMInfo(_api.core.snes_read_oam, si, num); public void DecodeBG( int* screen, @@ -255,7 +238,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES public TileEntry[] FetchMode7Tilemap() { - var buf = new TileEntry[128*128]; + var buf = new TileEntry[128 * 128]; for (int tidx = 0; tidx < 128 * 128; tidx++) { buf[tidx].address = tidx * 2; @@ -270,7 +253,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES Dimensions blockDimensions = SizeInBlocksForBGSize(size); int realWidth = blockDimensions.Width * 32; int realHeight = blockDimensions.Height * 32; - TileEntry[] buf = new TileEntry[realWidth*realHeight]; + TileEntry[] buf = new TileEntry[realWidth * realHeight]; for (int by = 0; by < blockDimensions.Height; by++) for (int bx = 0; bx < blockDimensions.Width; bx++) @@ -343,38 +326,38 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES int destx, int desty, ScreenInfo si, int spritenum, - ISNESGraphicsDecoder.OAMInfo oam, + ISNESGraphicsDecoder.OAMInfo oamInfo, int xlimit, int ylimit, byte[,] spriteMap) { - oam ??= new OAMInfo(objects, si, spritenum); - Size dim = ObjSizes[si.OBSEL_Size, oam.Size ? 1 : 0]; + oamInfo ??= new OAMInfo(_api.core.snes_read_oam, si, spritenum); + Size dim = ObjSizes[si.OBSEL_Size, oamInfo.Size ? 1 : 0]; byte[] cachedTileBuffer = cachedTiles[bppArrayIndex[4]]; - int baseaddr = oam.Table ? si.OBJTable1Addr : si.OBJTable0Addr; + int baseaddr = oamInfo.Table ? si.OBJTable1Addr : si.OBJTable0Addr; //TODO - flips of 'undocumented' rectangular oam settings are wrong. probably easy to do right, but we need a test - int bcol = oam.Tile & 0xF; - int brow = (oam.Tile >> 4) & 0xF; - for(int oy=0;oy> 4) & 0xF; + for (int oy = 0; oy < dim.Height; oy++) for (int ox = 0; ox < dim.Width; ox++) { int dy, dx; - if (oam.HFlip) + if (oamInfo.HFlip) dx = dim.Width - 1 - ox; else dx = ox; - if (oam.VFlip) + if (oamInfo.VFlip) dy = dim.Height - 1 - oy; else dy = oy; dx += destx; dy += desty; - if(dx>=xlimit || dy>=ylimit || dx<0 || dy<0) + if (dx >= xlimit || dy >= ylimit || dx < 0 || dy < 0) continue; int col = (bcol + (ox >> 3)) & 0xF; @@ -382,10 +365,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES int sx = ox & 0x7; int sy = oy & 0x7; - int addr = baseaddr*2 + (row * 16 + col) * 64; + int addr = baseaddr * 2 + (row * 16 + col) * 64; addr += sy * 8 + sx; - int dofs = stride*dy+dx; + int dofs = stride * dy + dx; int color = cachedTileBuffer[addr]; if (spriteMap != null && color == 0) { @@ -394,7 +377,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES else { screen[dofs] = color; - Paletteize(screen, dofs, oam.Palette * 16 + 128, 1); + Paletteize(screen, dofs, oamInfo.Palette * 16 + 128, 1); Colorize(screen, dofs, 1); if (spriteMap != null) spriteMap[dx, dy] = (byte)spritenum; } @@ -473,7 +456,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES M7SEL_VFLIP = _api.core.snes_peek_logical_register(M7SEL_VFLIP) == 1 }; - screenInfo.ObjSizeBounds = ObjSizes[screenInfo.OBSEL_Size,1]; + screenInfo.ObjSizeBounds = ObjSizes[screenInfo.OBSEL_Size, 1]; int square = Math.Max(screenInfo.ObjSizeBounds.Width, screenInfo.ObjSizeBounds.Height); screenInfo.ObjSizeBoundsSquare = new Size(square, square); @@ -623,17 +606,26 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES public bool Size { get; } public int Address { get; } - public unsafe OAMInfo(SNESGraphicsDecoder.Object* objects, ScreenInfo si, int index) + public OAMInfo(Func readOam, ScreenInfo si, int index) { - X = objects[index].x; - Y = objects[index].y; - Table = objects[index].nameSelect; - Palette = objects[index].palette; - Priority = objects[index].priority; - HFlip = objects[index].hflip; - VFlip = objects[index].vflip; - Size = objects[index].size; - byte character = objects[index].character; + ushort lowaddr = (ushort)(index * 4); + X = readOam(lowaddr++); + Y = readOam(lowaddr++); + byte character = readOam(lowaddr++); + Table = (readOam(lowaddr) & 1) == 1; + Palette = (readOam(lowaddr) >> 1) & 7; + Priority = (byte)((readOam(lowaddr) >> 4) & 3); + HFlip = ((readOam(lowaddr) >> 6) & 1) == 1; + VFlip = ((readOam(lowaddr) >> 7) & 1) == 1; + + int highaddr = index / 4; + int shift = (index % 4) * 2; + byte high = readOam((ushort)(512 + highaddr)); + + bool highX = (high & (1 << shift++)) != 0; + Size = (high & (1 << shift)) != 0; + if (highX) X += 256; + Tile = character + (Table ? 256 : 0); Address = character * 32 + (Table ? si.OBJTable1Addr : si.OBJTable0Addr); Address &= 0xFFFF; diff --git a/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp b/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp index 04eb848628..7d07650078 100644 --- a/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp +++ b/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.cpp @@ -405,11 +405,11 @@ EXPORT void* snes_get_memory_region(int id, int* size, int* word_size) *size = sizeof(ppufast.vram); *word_size = sizeof(*ppufast.vram); return ppufast.vram; - case SNES_MEMORY::OBJECTS: // returns a pointer to an array of "objects", not raw OAM memory + case SNES_MEMORY::OAM: if (!fast_ppu) break; - *size = sizeof(ppufast.objects); - *word_size = sizeof(*ppufast.objects); - return (void*) ppufast.objects; + *size = (128 * 32 + 128 * 2) / 8; + *word_size = 1; + return nullptr; // needs read_oam / write_oam functions below case SNES_MEMORY::CGRAM: if (!fast_ppu) break; *size = sizeof(ppufast.cgram); @@ -430,6 +430,20 @@ EXPORT void snes_bus_write(unsigned addr, uint8_t value) bus.write(addr, value); } +EXPORT uint8_t snes_read_oam(uint16_t addr) +{ + if (!SuperFamicom::system.fastPPU()) return 0; + + return ppufast.readObject(addr); +} + +EXPORT void snes_write_oam(uint16_t addr, uint8_t value) +{ + if (!SuperFamicom::system.fastPPU()) return; + + return ppufast.writeObject(addr, value); +} + EXPORT void* snes_get_sgb_memory_region(int id, int* size) { if(!emulator->loaded()) return nullptr; diff --git a/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.hpp b/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.hpp index d3476a32e5..277c36fa09 100644 --- a/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.hpp +++ b/waterbox/bsnescore/bsnes/target-bsnescore/bsnescore.hpp @@ -21,7 +21,7 @@ enum SNES_MEMORY { WRAM, APURAM, VRAM, - OBJECTS, + OAM, CGRAM };