diff --git a/output/dll/pce-fast.wbx.gz b/output/dll/pce-fast.wbx.gz new file mode 100644 index 0000000000..ae9b841923 Binary files /dev/null and b/output/dll/pce-fast.wbx.gz differ diff --git a/src/BizHawk.Client.Common/RomLoader.cs b/src/BizHawk.Client.Common/RomLoader.cs index 1a56e58e66..19299feb18 100644 --- a/src/BizHawk.Client.Common/RomLoader.cs +++ b/src/BizHawk.Client.Common/RomLoader.cs @@ -171,7 +171,12 @@ namespace BizHawk.Client.Common private bool HandleArchiveBinding(HawkFile file) { - var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC", "GBA", "32X", "VEC", "O2" }; + var romExtensions = new[] + { + "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", + "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", + "V64", "N64", "WS", "WSC", "GBA", "32X", "VEC", "O2" + }; // try binding normal rom extensions first if (!file.IsBound) @@ -530,6 +535,9 @@ namespace BizHawk.Client.Common nextEmulator = new TerboGrafix(game, new[] { disc }, nextComm, (Emulation.Cores.Waterbox.NymaCore.NymaSettings)GetCoreSettings(), (Emulation.Cores.Waterbox.NymaCore.NymaSyncSettings)GetCoreSyncSettings(), Deterministic); + // nextEmulator = new TerboGrafixSanic(game, new[] { disc }, nextComm, + // (Emulation.Cores.Waterbox.NymaCore.NymaSettings)GetCoreSettings(), + // (Emulation.Cores.Waterbox.NymaCore.NymaSyncSettings)GetCoreSyncSettings(), Deterministic); } break; diff --git a/src/BizHawk.Emulation.Cores/Consoles/NEC/PCE/TerboGrafixSanic.cs b/src/BizHawk.Emulation.Cores/Consoles/NEC/PCE/TerboGrafixSanic.cs new file mode 100644 index 0000000000..21ea15c075 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/NEC/PCE/TerboGrafixSanic.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.PCEngine; +using BizHawk.Emulation.Cores.Waterbox; +using BizHawk.Emulation.DiscSystem; + +namespace BizHawk.Emulation.Cores.Consoles.NEC.PCE +{ + [Core(CoreNames.TurboTurboNyma, "Mednafen Team", true, true, "1.24.3", "https://mednafen.github.io/releases/", false)] + public class TerboGrafixSanic : NymaCore, IRegionable, IPceGpuView + { + private readonly LibTerboGrafixSanic _terboGrafix; + + [CoreConstructor(new[] { "PCE", "SGX" })] + public TerboGrafixSanic(GameInfo game, byte[] rom, CoreComm comm, string extension, + NymaSettings settings, NymaSyncSettings syncSettings, bool deterministic) + : base(comm, "PCE", "PC Engine Controller", settings, syncSettings) + { + if (game["BRAM"]) + SettingsOverrides["pce.disable_bram_hucard"] = "0"; + _terboGrafix = DoInit(game, rom, null, "pce-fast.wbx", extension, deterministic); + } + public TerboGrafixSanic(GameInfo game, Disc[] discs, CoreComm comm, + NymaSettings settings, NymaSyncSettings syncSettings, bool deterministic) + : base(comm, "PCE", "PC Engine Controller", settings, syncSettings) + { + var firmwares = new Dictionary + { + { "FIRMWARE:syscard3.pce", comm.CoreFileProvider.GetFirmware("PCECD", "Bios", true) }, + }; + _terboGrafix = DoInit(game, null, discs, "pce-fast.wbx", null, deterministic, firmwares); + } + + public override string SystemId => IsSgx ? "SGX" : "PCE"; + + protected override IDictionary SettingsOverrides { get; } = new Dictionary + { + { "pce_fast.correct_aspect", null }, + { "pce_fast.mouse_sensitivity", null }, + { "pce_fast.disable_softreset", null }, + { "pce_fast.cdbios", null }, + { "nyma.rtcinitialtime", null }, + { "nyma.rtcrealtime", null }, + }; + + protected override IDictionary ButtonNameOverrides { get; } = new Dictionary + { + { "RIGHT →", "Right up my arse" }, + }; + + // pce always has two layers, sgx always has 4, and mednafen knows this + public bool IsSgx => SettingsInfo.LayerNames.Count == 4; + + public unsafe void GetGpuData(int vdc, Action callback) + { + using(_exe.EnterExit()) + { + var palScratch = new int[512]; + var v = new PceGpuData(); + _terboGrafix.GetVramInfo(v, vdc); + fixed(int* p = palScratch) + { + for (var i = 0; i < 512; i++) + p[i] = v.PaletteCache[i] | unchecked((int)0xff000000); + v.PaletteCache = p; + callback(v); + } + + } + } + } + + public abstract class LibTerboGrafixSanic : LibNymaCore + { + [BizImport(CallingConvention.Cdecl, Compatibility = true)] + public abstract void GetVramInfo([Out]PceGpuData v, int vdcIndex); + } +} diff --git a/src/BizHawk.Emulation.Cores/CoreNames.cs b/src/BizHawk.Emulation.Cores/CoreNames.cs index e2d4dd57c2..54446f9ae5 100644 --- a/src/BizHawk.Emulation.Cores/CoreNames.cs +++ b/src/BizHawk.Emulation.Cores/CoreNames.cs @@ -23,5 +23,6 @@ namespace BizHawk.Emulation.Cores public const string Gpgx = "Genplus-gx"; public const string PceHawk = "PCEHawk"; public const string TurboNyma = "TurboNyma"; + public const string TurboTurboNyma = "TurboTurboNyma"; } } diff --git a/waterbox/nyma/Interfaces.cpp b/waterbox/nyma/Interfaces.cpp index 862ccea9da..22be56d7fe 100644 --- a/waterbox/nyma/Interfaces.cpp +++ b/waterbox/nyma/Interfaces.cpp @@ -99,8 +99,11 @@ namespace Mednafen va_start(argp, format); vfprintf(t == MDFN_NOTICE_ERROR ? stderr : stdout, format, argp); } + void MDFN_MidSync(EmulateSpecStruct *espec, const unsigned flags) {} + void MDFN_MidLineUpdate(EmulateSpecStruct *espec, int y) + {} bool MDFNSS_StateAction(StateMem *sm, const unsigned load, const bool data_only, const SFORMAT *sf, const char *sname, const bool optional) noexcept { diff --git a/waterbox/nyma/common.mak b/waterbox/nyma/common.mak index 9d9a21d327..08d27e817b 100644 --- a/waterbox/nyma/common.mak +++ b/waterbox/nyma/common.mak @@ -50,3 +50,15 @@ SRCS := \ $(call cppdir,video) \ $(filter-out %generate.cpp,$(call cppdir,sound)) \ Interfaces.cpp NymaCore.cpp + +# Common sources cores with cdroms need for cdrom support +CD_SRCS := \ + mednafen/src/cdrom/CDInterface.cpp \ + mednafen/src/cdrom/scsicd.cpp \ + mednafen/src/cdrom/CDUtility.cpp \ + mednafen/src/cdrom/lec.cpp \ + mednafen/src/cdrom/recover-raw.cpp \ + mednafen/src/cdrom/l-ec.cpp \ + mednafen/src/cdrom/crc32.cpp \ + mednafen/src/cdrom/galois.cpp \ + cdrom.cpp diff --git a/waterbox/nyma/mednafen b/waterbox/nyma/mednafen index 3a6060d100..10cc0a7730 160000 --- a/waterbox/nyma/mednafen +++ b/waterbox/nyma/mednafen @@ -1 +1 @@ -Subproject commit 3a6060d1006a16c913a57495971e2dfe9e6b976d +Subproject commit 10cc0a77301a11b740f6210626b00418bd83e1ee diff --git a/waterbox/nyma/pce-fast.cpp b/waterbox/nyma/pce-fast.cpp new file mode 100644 index 0000000000..db6e483943 --- /dev/null +++ b/waterbox/nyma/pce-fast.cpp @@ -0,0 +1,227 @@ +#include "mednafen/src/types.h" +#include "nyma.h" +#include +#include "mednafen/src/pce_fast/pce.h" +#include +#include "mednafen/src/pce_fast/pcecd.h" +#include "mednafen/src/pce_fast/huc.h" +#include "mednafen/src/pce_fast/vdc.h" +#include "mednafen/src/hw_misc/arcade_card/arcade_card.h" +#include "mednafen/src/pce_fast/huc6280.h" + +using namespace PCE_Fast; + +extern Mednafen::MDFNGI EmulatedPCE_Fast; + +void SetupMDFNGameInfo() +{ + Mednafen::MDFNGameInfo = &EmulatedPCE_Fast; +} + +#define MemoryDomainFunctions(N,R,W)\ +static void Access##N(uint8_t* buffer, int64_t address, int64_t count, bool write)\ +{\ + if (write)\ + {\ + while (count--)\ + W(address++, *buffer++);\ + }\ + else\ + {\ + while (count--)\ + *buffer++ = R(address++);\ + }\ +} +#define MemoryDomainBulkFunctions(N,R,W)\ +static void Access##N(uint8_t* buffer, int64_t address, int64_t count, bool write)\ +{\ + if (write)\ + {\ + W(address, count, buffer);\ + }\ + else\ + {\ + R(address, count, buffer);\ + }\ +} + +namespace PCE_Fast +{ + extern ArcadeCard* arcade_card; + // extern VCE* vce; + uint8 ZZINPUT_Read(unsigned int A); + uint8 INPUT_Read(unsigned int A) + { + LagFlag = false; + if (InputCallback) + InputCallback(); + return ZZINPUT_Read(A); + } +} + +uint8 HucReadVirtual(unsigned int A) +{ + uint8 wmpr = HuCPU.MPR[A >> 13]; + return HuCPU.PCERead[wmpr]((wmpr << 13) | (A & 0x1FFF)); +} +void HucWriteVirtual(unsigned int A, uint8 V) +{ + uint8 wmpr = HuCPU.MPR[A >> 13]; + HuCPU.PCEWrite[wmpr]((wmpr << 13) | (A & 0x1FFF), V); +} +uint8 HucReadActual(unsigned int A) +{ + uint8 wmpr = A >> 13; + return HuCPU.PCERead[wmpr](A); +} +void HucWriteActual(unsigned int A, uint8 V) +{ + uint8 wmpr = A >> 13; + HuCPU.PCEWrite[wmpr](A, V); +} + +MemoryDomainFunctions(ShortBus, HucReadVirtual, HucWriteVirtual); +MemoryDomainFunctions(LongBus, HucReadActual, HucWriteActual); + +ECL_EXPORT void GetMemoryAreas(MemoryArea* m) +{ + CheatArea* c; + int i = 0; + + m[i].Data = (void*)(MemoryFunctionHook)AccessLongBus; + m[i].Name = "System Bus (21 bit)"; + m[i].Size = 1 << 21; + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_FUNCTIONHOOK; + i++; + + m[i].Data = (void*)(MemoryFunctionHook)AccessShortBus; + m[i].Name = "System Bus"; + m[i].Size = 1 << 16; + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_FUNCTIONHOOK; + i++; + + c = FindCheatArea(0xf8 * 8192); + m[i].Data = c->data; + m[i].Name = "Main Memory"; + m[i].Size = c->size; + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_PRIMARY; + i++; + + // TODO: "ROM" + // not that important because we have ROM file domain in the frontend + + c = FindCheatArea(0xf7 * 8192); + if (c) + { + m[i].Data = c->data; + m[i].Name = "Battery RAM"; + m[i].Size = c->size; + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_ONEFILLED | MEMORYAREA_FLAGS_SAVERAMMABLE; + i++; + } + + if (PCE_IsCD) + { + // pce-fast always adds the full 256kiB of turbocd + super system card as a single block + c = FindCheatArea(0x68 * 8192); + m[i].Data = c->data + 0x18 * 8192; + m[i].Name = "TurboCD RAM"; + m[i].Size = 8 * 8192; + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1; + i++; + + // m[i].Data = (void*)(MemoryFunctionHook)AccessADPCM; + // m[i].Name = "ADPCM RAM"; + // m[i].Size = 1 << 16; + // m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_FUNCTIONHOOK; + // i++; + + c = FindCheatArea(0x68 * 8192); + m[i].Data = c->data; + m[i].Name = "Super System Card RAM"; + m[i].Size = 0x18 * 8192; + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1; + i++; + + if (arcade_card) + { + m[i].Data = arcade_card->ACRAM; + m[i].Name = "Arcade Card RAM"; + m[i].Size = sizeof(arcade_card->ACRAM); + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1; + i++; + } + } + + c = FindCheatArea(0x40 * 8192); + if (c) + { + // populous + m[i].Data = c->data; + m[i].Name = "Cart Battery RAM"; + m[i].Size = c->size; + m[i].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1; + i++; + } +} + +struct VramInfo +{ + int32_t BatWidth; + int32_t BatHeight; + const uint32_t* PaletteCache; + const uint8_t* BackgroundCache; + const uint8_t* SpriteCache; + const uint16_t* Vram; +}; + +static uint8_t* SpriteCache; + +static const int bat_width_tab[4] = { 32, 64, 128, 128 }; +static const int bat_height_tab[2] = { 32, 64 }; +ECL_EXPORT void GetVramInfo(VramInfo& v, int vdcIndex) +{ + // pce-fast does have a spr_tile_cache, + // but it's only updated when a particular vram area is actually rendered as a sprite + if (!SpriteCache) + SpriteCache = (uint8_t*)alloc_invisible(0x20000); + auto& vdc = vdc_chips[vdcIndex]; + v.BatWidth = bat_width_tab[(vdc.MWR >> 4) & 3]; + v.BatHeight = bat_height_tab[(vdc.MWR >> 6) & 1]; + v.PaletteCache = vce.color_table_cache; + v.BackgroundCache = (uint8_t*)vdc.bg_tile_cache; + v.SpriteCache = SpriteCache; + v.Vram = vdc.VRAM; + + uint16_t* ssrc = vdc.VRAM; + uint8_t* sdst = SpriteCache; + for (int spriteNum = 0; spriteNum < 512; spriteNum++) + { + auto lsrc = ssrc; + auto ldst = sdst; + for (int line = 0; line < 16; line++) + { + auto a = lsrc[0], b = lsrc[16], c = lsrc[32], d = lsrc[48]; + *ldst++ = a >> 15 & 1 | b >> 14 & 2 | c >> 13 & 4 | d >> 12 & 8; + *ldst++ = a >> 14 & 1 | b >> 13 & 2 | c >> 12 & 4 | d >> 11 & 8; + *ldst++ = a >> 13 & 1 | b >> 12 & 2 | c >> 11 & 4 | d >> 10 & 8; + *ldst++ = a >> 12 & 1 | b >> 11 & 2 | c >> 10 & 4 | d >> 9 & 8; + *ldst++ = a >> 11 & 1 | b >> 10 & 2 | c >> 9 & 4 | d >> 8 & 8; + *ldst++ = a >> 10 & 1 | b >> 9 & 2 | c >> 8 & 4 | d >> 7 & 8; + *ldst++ = a >> 9 & 1 | b >> 8 & 2 | c >> 7 & 4 | d >> 6 & 8; + *ldst++ = a >> 8 & 1 | b >> 7 & 2 | c >> 6 & 4 | d >> 5 & 8; + *ldst++ = a >> 7 & 1 | b >> 6 & 2 | c >> 5 & 4 | d >> 4 & 8; + *ldst++ = a >> 6 & 1 | b >> 5 & 2 | c >> 4 & 4 | d >> 3 & 8; + *ldst++ = a >> 5 & 1 | b >> 4 & 2 | c >> 3 & 4 | d >> 2 & 8; + *ldst++ = a >> 4 & 1 | b >> 3 & 2 | c >> 2 & 4 | d >> 1 & 8; + *ldst++ = a >> 3 & 1 | b >> 2 & 2 | c >> 1 & 4 | d >> 0 & 8; + *ldst++ = a >> 2 & 1 | b >> 1 & 2 | c >> 0 & 4 | d << 1 & 8; + *ldst++ = a >> 1 & 1 | b >> 0 & 2 | c << 1 & 4 | d << 2 & 8; + *ldst++ = a >> 0 & 1 | b << 1 & 2 | c << 2 & 4 | d << 3 & 8; + lsrc += 1; + } + + ssrc += 64; + sdst += 256; + } +} diff --git a/waterbox/nyma/pce-fast.mak b/waterbox/nyma/pce-fast.mak new file mode 100644 index 0000000000..77021cb543 --- /dev/null +++ b/waterbox/nyma/pce-fast.mak @@ -0,0 +1,11 @@ +include common.mak + +SRCS += \ + $(call cppdir,pce_fast) \ + $(call cppdir,hw_misc/arcade_card) \ + $(CD_SRCS) \ + pce-fast.cpp + +PER_FILE_FLAGS_mednafen/src/pce_fast/input.cpp := -DINPUT_Read=ZZINPUT_Read + +include ../common.mak diff --git a/waterbox/nyma/pce.mak b/waterbox/nyma/pce.mak index 462e90ee65..8992b5a484 100644 --- a/waterbox/nyma/pce.mak +++ b/waterbox/nyma/pce.mak @@ -1,24 +1,11 @@ include common.mak -# $(filter-out %CDAFReader_SF.cpp,$(call cppdir,cdrom)) -# $(call cdir,tremor) -# $(call cdir,mpcdec) -# mednafen/src/mthreading/MThreading_POSIX.cpp - SRCS += \ $(filter-out %debug.cpp,$(call cppdir,pce)) \ $(call cppdir,hw_sound/pce_psg) \ $(call cppdir,hw_misc/arcade_card) \ $(call cppdir,hw_video/huc6270) \ - mednafen/src/cdrom/CDInterface.cpp \ - mednafen/src/cdrom/scsicd.cpp \ - mednafen/src/cdrom/CDUtility.cpp \ - mednafen/src/cdrom/lec.cpp \ - mednafen/src/cdrom/recover-raw.cpp \ - mednafen/src/cdrom/l-ec.cpp \ - mednafen/src/cdrom/crc32.cpp \ - mednafen/src/cdrom/galois.cpp \ - cdrom.cpp \ + $(CD_SRCS) \ pce.cpp PER_FILE_FLAGS_mednafen/src/pce/input.cpp := -DINPUT_Read=ZZINPUT_Read