Skip to content

Commit

Permalink
Wiring up GPGX as core for SMS, GG, and SG (#3902)
Browse files Browse the repository at this point in the history
* Adding GPGX as core for SMS and GG
* Enabling SMS FM selection
* Allow selecting PicoDrive as the preferred core for MD/Genesis

---------

Co-authored-by: James Groom <[email protected]>
Co-authored-by: feos <[email protected]>
  • Loading branch information
3 people authored Apr 28, 2024
1 parent 8a0bf19 commit 9dcb843
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,4 @@
[submodule "waterbox/gpgx/Genesis-Plus-GX"]
path = waterbox/gpgx/Genesis-Plus-GX
url = https://github.com/TASEmulators/Genesis-Plus-GX.git
branch = tasvideos-3
branch = tasvideos-2.1
Binary file modified Assets/dll/gpgx.wbx.zst
Binary file not shown.
4 changes: 4 additions & 0 deletions src/BizHawk.Client.Common/config/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ public class Config
new[] { CoreNames.Gambatte, CoreNames.Sameboy, CoreNames.GbHawk, CoreNames.SubGbHawk }),
(new[] { VSystemID.Raw.GBL },
new[] { CoreNames.GambatteLink, CoreNames.GBHawkLink, CoreNames.GBHawkLink3x, CoreNames.GBHawkLink4x }),
(new[] { VSystemID.Raw.GEN },
new[] { CoreNames.Gpgx, CoreNames.PicoDrive }),
(new[] { VSystemID.Raw.SMS, VSystemID.Raw.GG, VSystemID.Raw.SG },
new[] { CoreNames.Gpgx, CoreNames.SMSHawk }),
(new[] { VSystemID.Raw.PCE, VSystemID.Raw.PCECD, VSystemID.Raw.SGX, VSystemID.Raw.SGXCD },
new[] { CoreNames.TurboNyma, CoreNames.HyperNyma, CoreNames.PceHawk }),
(new[] { VSystemID.Raw.PSX },
Expand Down
2 changes: 1 addition & 1 deletion src/BizHawk.Client.Common/movie/import/GmvImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ protected override void RunImport()
: LibGPGX.INPUT_DEVICE.DEVICE_PAD3B;
}

var controlConverter = new GPGXControlConverter(input, false);
GPGXControlConverter controlConverter = new(input, systemId: VSystemID.Raw.GEN, cdButtons: false);

SimpleController controller = new(controlConverter.ControllerDef);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public bool FrameAdvance(IController controller, bool render, bool renderSound =

public int Frame { get; private set; }

public string SystemId => VSystemID.Raw.GEN;
public string SystemId { get; }

public bool DeterministicEmulation => true;

Expand Down
18 changes: 15 additions & 3 deletions src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ public static bool NeedsReboot(GPGXSettings x, GPGXSettings y)
[CoreSettings]
public class GPGXSyncSettings
{
[DisplayName("Use Six Button Controllers")]
[DisplayName("[Genesis/CD] Use Six Button Controllers")]
[Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")]
[DefaultValue(false)]
public bool UseSixButton { get; set; }
Expand All @@ -263,7 +263,17 @@ public class GPGXSyncSettings
[DefaultValue(LibGPGX.Region.Autodetect)]
public LibGPGX.Region Region { get; set; }

[DisplayName("FM Sound Chip Type")]
[DisplayName("[SMS/GG] Load BIOS")]
[Description("Indicates whether to load the system BIOS rom.")]
[DefaultValue(false)]
public bool loadBIOS { get; set; }

[DisplayName("[SMS] FM Sound Chip Type")]
[Description("Sets the method used to emulate the FM Sound Unit of the Sega Mark III/Master System. 'MAME' is fast and runs full speed on most systems.'Nuked' is cycle accurate, very high quality, and have substantial CPU requirements.")]
[DefaultValue(LibGPGX.InitSettings.SMSFMSoundChipType.YM2413_MAME)]
public LibGPGX.InitSettings.SMSFMSoundChipType SMSFMSoundChip { get; set; }

[DisplayName("[Genesis/CD] FM Sound Chip Type")]
[Description("Sets the method used to emulate the FM synthesizer (main sound generator) of the Mega Drive/Genesis. 'MAME' options are fast, and run full speed on most systems. 'Nuked' options are cycle accurate, very high quality, and have substantial CPU requirements. The 'YM2612' chip is used by the original Model 1 Mega Drive/Genesis. The 'YM3438' is used in later Mega Drive/Genesis revisions.")]
[DefaultValue(LibGPGX.InitSettings.GenesisFMSoundChipType.MAME_YM2612)]
public LibGPGX.InitSettings.GenesisFMSoundChipType GenesisFMSoundChip { get; set; }
Expand Down Expand Up @@ -329,8 +339,10 @@ public LibGPGX.InitSettings GetNativeSettings(GameInfo game)
InputSystemA = SystemForSystem(ControlTypeLeft),
InputSystemB = SystemForSystem(ControlTypeRight),
Region = Region,
loadBIOS = loadBIOS,
ForceSram = game["sram"],
GenesisFMSoundChip = GenesisFMSoundChip,
SMSFMSoundChip = SMSFMSoundChip,
GenesisFMSoundChip = GenesisFMSoundChip,
SpritesAlwaysOnTop = SpritesAlwaysOnTop
};
}
Expand Down
51 changes: 36 additions & 15 deletions src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
using BizHawk.Common;
using BizHawk.Common.StringExtensions;
using BizHawk.Emulation.DiscSystem;
using System.Linq;
using System.IO;

namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{
[PortedCore(CoreNames.Gpgx, "Eke-Eke", "25a90c6", "https://github.com/ekeeke/Genesis-Plus-GX")]
[PortedCore(
name: CoreNames.Gpgx,
author: "Eke-Eke",
portedVersion: "0c45a8a",
portedUrl: "https://github.com/ekeeke/Genesis-Plus-GX")]
public partial class GPGX : IEmulator, IVideoProvider, ISaveRam, IStatable, IRegionable,
IInputPollable, IDebuggable, IDriveLight, ICodeDataLogger, IDisassemblable
{
[CoreConstructor(VSystemID.Raw.GEN)]
[CoreConstructor(VSystemID.Raw.SMS)]
[CoreConstructor(VSystemID.Raw.GG)]
[CoreConstructor(VSystemID.Raw.SG)]
public GPGX(CoreLoadParameters<GPGXSettings, GPGXSyncSettings> lp)
{
LoadCallback = load_archive;
Expand All @@ -26,8 +35,17 @@ public GPGX(CoreLoadParameters<GPGXSettings, GPGXSyncSettings> lp)

ServiceProvider = new BasicServiceProvider(this);
// this can influence some things internally (autodetect romtype, etc)
string romextension = "GEN";

// Determining system ID from the rom. If no rom provided, assume Genesis (Sega CD)
SystemId = VSystemID.Raw.GEN;
var RomExtension = string.Empty;
if (lp.Roms.Count >= 1)
{
SystemId = lp.Roms[0].Game.System;
// We need to pass the exact file extension to GPGX for it to correctly interpret the console
RomExtension = Path.GetExtension(lp.Roms[0].RomPath).RemovePrefix('.');
}

// three or six button?
// http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds

Expand Down Expand Up @@ -82,7 +100,7 @@ public GPGX(CoreLoadParameters<GPGXSettings, GPGXSyncSettings> lp)
LibGPGX.INPUT_SYSTEM system_a = SystemForSystem(_syncSettings.ControlTypeLeft);
LibGPGX.INPUT_SYSTEM system_b = SystemForSystem(_syncSettings.ControlTypeRight);

var initResult = Core.gpgx_init(romextension, LoadCallback, _syncSettings.GetNativeSettings(lp.Game));
var initResult = Core.gpgx_init(RomExtension, LoadCallback, _syncSettings.GetNativeSettings(lp.Game));

if (!initResult)
throw new Exception($"{nameof(Core.gpgx_init)}() failed");
Expand Down Expand Up @@ -228,22 +246,25 @@ private int load_archive(string filename, IntPtr buffer, int maxsize)
{
// use fromtend firmware interface

string firmwareID = null;
switch (filename)
{
case "CD_BIOS_EU": firmwareID = "CD_BIOS_EU"; break;
case "CD_BIOS_JP": firmwareID = "CD_BIOS_JP"; break;
case "CD_BIOS_US": firmwareID = "CD_BIOS_US"; break;
default:
break;
}
FirmwareID? firmwareID = filename switch
{
"CD_BIOS_EU" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_EU"),
"CD_BIOS_JP" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_JP"),
"CD_BIOS_US" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_US"),
"GG_BIOS" => new(system: VSystemID.Raw.SMS, firmware: "Japan"),
"MS_BIOS_EU" => new(system: VSystemID.Raw.SMS, firmware: "Export"),
"MS_BIOS_JP" => new(system: VSystemID.Raw.SMS, firmware: "Japan"),
"MS_BIOS_US" => new(system: VSystemID.Raw.SMS, firmware: "Export"),
_ => null
};

if (firmwareID != null)
{
// this path will be the most common PEBKAC error, so be a bit more vocal about the problem
srcdata = CoreComm.CoreFileProvider.GetFirmware(new("GEN", firmwareID), "GPGX firmwares are usually required.");
srcdata = CoreComm.CoreFileProvider.GetFirmware(firmwareID.Value, "GPGX firmwares are usually required.");
if (srcdata == null)
{
Console.WriteLine("Frontend couldn't satisfy firmware request GEN:{0}", firmwareID);
Console.WriteLine($"Frontend couldn't satisfy firmware request {firmwareID}");
return 0;
}
}
Expand Down Expand Up @@ -365,7 +386,7 @@ private void SetControllerDefinition()
if (!Core.gpgx_get_control(input, inputsize))
throw new Exception($"{nameof(Core.gpgx_get_control)}() failed");

ControlConverter = new GPGXControlConverter(input, _cds != null);
ControlConverter = new(input, systemId: SystemId, cdButtons: _cds is not null);
ControllerDefinition = ControlConverter.ControllerDef;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,27 @@ public CName(string name, LibGPGX.INPUT_KEYS key)
}
}

private static readonly CName[] SMS2B =
{
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
new CName("B1", LibGPGX.INPUT_KEYS.INPUT_BUTTON1),
new CName("B2", LibGPGX.INPUT_KEYS.INPUT_BUTTON2)
};

private static readonly CName[] GameGear =
{
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
new CName("B1", LibGPGX.INPUT_KEYS.INPUT_BUTTON1),
new CName("B2", LibGPGX.INPUT_KEYS.INPUT_BUTTON2),
new CName("Start", LibGPGX.INPUT_KEYS.INPUT_START),
};

private static readonly CName[] Genesis3 =
{
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
Expand Down Expand Up @@ -169,7 +190,7 @@ private void DoXea1PAnalog(int idx, int player)
});
}

public GPGXControlConverter(LibGPGX.InputData input, bool cdButtons)
public GPGXControlConverter(LibGPGX.InputData input, string systemId, bool cdButtons)
{
Console.WriteLine("Genesis Controller report:");
foreach (var e in input.system)
Expand Down Expand Up @@ -215,10 +236,13 @@ public GPGXControlConverter(LibGPGX.InputData input, bool cdButtons)
player++;
break;
case LibGPGX.INPUT_DEVICE.DEVICE_PAD2B:
AddToController(i, player, systemId is VSystemID.Raw.SMS ? SMS2B : GameGear);
player++;
break;
case LibGPGX.INPUT_DEVICE.DEVICE_PADDLE:
case LibGPGX.INPUT_DEVICE.DEVICE_SPORTSPAD:
case LibGPGX.INPUT_DEVICE.DEVICE_TEREBI:
throw new Exception("Master System only device? Something went wrong.");
throw new Exception("Not implemented yet.");
case LibGPGX.INPUT_DEVICE.DEVICE_ACTIVATOR:
AddToController(i, player, Activator);
player++;
Expand Down
9 changes: 9 additions & 0 deletions src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/LibGPGX.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ public enum FilterType : byte
public bool SixButton;
public bool ForceSram;

public enum SMSFMSoundChipType : byte
{
YM2413_DISABLED,
YM2413_MAME,
YM2413_NUKED
}
public SMSFMSoundChipType SMSFMSoundChip;

public enum GenesisFMSoundChipType : byte
{
MAME_YM2612,
Expand All @@ -65,6 +73,7 @@ public enum GenesisFMSoundChipType : byte
public GenesisFMSoundChipType GenesisFMSoundChip;

public bool SpritesAlwaysOnTop;
public bool loadBIOS;
}

[BizImport(CallingConvention.Cdecl)]
Expand Down
2 changes: 1 addition & 1 deletion waterbox/gpgx/Genesis-Plus-GX
24 changes: 15 additions & 9 deletions waterbox/gpgx/cinterface/cinterface.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,10 @@ struct InitSettings
char InputSystemB;
char SixButton;
char ForceSram;
uint8_t SMSFMSoundChip;
uint8_t GenesisFMSoundChip;
uint8_t SpritesAlwaysOnTop;
uint8_t loadBios;
};


Expand Down Expand Up @@ -704,6 +706,8 @@ void bk_cpu_hook(hook_type_t type, int width, unsigned int address, unsigned int

break;
}

default: break;
}
}

Expand Down Expand Up @@ -755,8 +759,7 @@ GPGX_EX int gpgx_init(const char* feromextension,

// Selecting FM Sound chip to use for SMS / GG emulation. Using a default for now, until we also
// accept this core for SMS/GG emulation in BizHawk
int smsFMChipType = YM2413_NUKED;
switch (smsFMChipType)
switch (settings->SMSFMSoundChip)
{
case YM2413_DISABLED:
config.opll = 0;
Expand All @@ -770,7 +773,7 @@ GPGX_EX int gpgx_init(const char* feromextension,

case YM2413_NUKED:
config.opll = 1;
config.ym2413 = 0;
config.ym2413 = 1;
break;
}

Expand Down Expand Up @@ -810,7 +813,7 @@ GPGX_EX int gpgx_init(const char* feromextension,
config.master_clock = 0; /* = AUTO (1 = NTSC, 2 = PAL) */
config.force_dtack = 0;
config.addr_error = 1;
config.bios = 0;
config.bios = settings->loadBios;
config.lock_on = 0; /* = OFF (or TYPE_SK, TYPE_GG & TYPE_AR) */
config.add_on = 0; /* = HW_ADDON_AUTO (or HW_ADDON_MEGACD, HW_ADDON_MEGASD & HW_ADDON_ONE) */
config.cd_latency = 1;
Expand All @@ -836,13 +839,16 @@ GPGX_EX int gpgx_init(const char* feromextension,

cinterface_custom_backdrop_color = settings->BackdropColor;

// Default: Genesis
// apparently, the only part of config.input used is the padtype identifier,
// and that's used only for choosing pad type when system_md
{
int i;
for (i = 0; i < MAX_INPUTS; i++)
config.input[i].padtype = settings->SixButton ? DEVICE_PAD6B : DEVICE_PAD3B;
}
for (int i = 0; i < MAX_INPUTS; i++)
config.input[i].padtype = settings->SixButton ? DEVICE_PAD6B : DEVICE_PAD3B;

// Hacky but effective. Setting the correct controller type here if this is sms or GG
if (system_hw == SYSTEM_SMS || system_hw == SYSTEM_SMS2 || system_hw == SYSTEM_GG || system_hw == SYSTEM_SG)
for (int i = 0; i < MAX_INPUTS; i++)
config.input[i].padtype = DEVICE_PAD2B;

// first try to load our main CD
if (!load_rom("PRIMARY_CD"))
Expand Down
1 change: 1 addition & 0 deletions waterbox/gpgx/util/osd.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,4 @@ extern char MS_BIOS_JP[256];

extern void osd_input_update(void);
extern int load_archive(const char *filename, unsigned char *buffer, int maxsize, char *extension);
extern void real_input_callback(void);

0 comments on commit 9dcb843

Please sign in to comment.