Skip to content

Commit

Permalink
Add SameBoy as a GB/C core (#3009)
Browse files Browse the repository at this point in the history
* basics for sameboy

* lol

* bleh

* lol

* push this in

* push this in

* settings, and also update sameboy bootroms

* bleh

* build linux

* remove some debugging shiz

* fix the order of this

* debug stuff also do gpu palettes right

* use new key mask API

* push shit in

* bleh

* add in replacement impl for joypad, use until opposing directions are allowed upstream

* update

* finally get this working without needing GB_INTERNAL

* hook up acc controls

* oops

* oops x2

* oh right this doesn't use this

* finish this up

* also mark this as released

* cleanups

* Nitpicks

Co-authored-by: YoshiRulz <OSSYoshiRulz@gmail.com>
  • Loading branch information
CasualPokePlayer and YoshiRulz authored Jan 27, 2022
1 parent 69d51ab commit 2348e28
Show file tree
Hide file tree
Showing 30 changed files with 1,707 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@
[submodule "submodules/libfwunpack"]
path = submodules/libfwunpack
url = https://github.com/TASEmulators/fwunpack
[submodule "submodules/sameboy/libsameboy"]
path = submodules/sameboy/libsameboy
url = https://github.com/LIJI32/SameBoy
Binary file added Assets/dll/libsameboy.dll
Binary file not shown.
Binary file added Assets/dll/libsameboy.so
Binary file not shown.
2 changes: 1 addition & 1 deletion src/BizHawk.Client.Common/config/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class Config
(new[] { VSystemID.Raw.SGB },
new[] { CoreNames.Gambatte, CoreNames.Bsnes, CoreNames.Bsnes115}),
(new[] { VSystemID.Raw.GB, VSystemID.Raw.GBC },
new[] { CoreNames.Gambatte, CoreNames.GbHawk, CoreNames.SubGbHawk }),
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.PCE, VSystemID.Raw.PCECD, VSystemID.Raw.SGX },
Expand Down
7 changes: 7 additions & 0 deletions src/BizHawk.Client.Common/movie/MovieSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
using BizHawk.Emulation.Cores.Nintendo.SubNESHawk;
using BizHawk.Emulation.Cores.Nintendo.SubGBHawk;

Expand Down Expand Up @@ -363,6 +364,12 @@ private void HandlePlaybackEnd()
coreValue = ((Gameboy)Movie.Emulator).CycleCount;
movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.CycleCount, out movieValueStr);
}
else if (Movie.Core == CoreNames.Sameboy)
{
valueName = "cycle";
coreValue = ((Sameboy)Movie.Emulator).CycleCount;
movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.CycleCount, out movieValueStr);
}
else if (Movie.Core == CoreNames.SubGbHawk)
{
valueName = "cycle";
Expand Down
4 changes: 4 additions & 0 deletions src/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ private void SetCycleValues()
{
Header[HeaderKeys.CycleCount] = gameboy.CycleCount.ToString();
}
else if (Emulator is Emulation.Cores.Nintendo.Sameboy.Sameboy sameboy)
{
Header[HeaderKeys.CycleCount] = sameboy.CycleCount.ToString();
}
else if (Emulator is Emulation.Cores.Nintendo.SubGBHawk.SubGBHawk subGb)
{
Header[HeaderKeys.CycleCount] = subGb.CycleCount.ToString();
Expand Down
13 changes: 13 additions & 0 deletions src/BizHawk.Client.EmuHawk/MainForm.Debug.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Nintendo.GBA;
using BizHawk.Emulation.Cores.Nintendo.N64;
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
using BizHawk.WinForms.Controls;

namespace BizHawk.Client.EmuHawk
Expand Down Expand Up @@ -186,6 +187,18 @@ private void AddDebugMenu()
Text = "Firmware",
},
new ToolStripSeparatorEx(),
new DebugVSystemMenuItem("GB")
{
DropDownItems =
{
new DebugVSystemChildItem(
"Debug SameBoy States",
() => ((Sameboy) Emulator).DebugSameBoyState())
{
RequiresCore = CoreNames.Sameboy,
},
},
},
new DebugVSystemMenuItem("GBA")
{
DropDownItems =
Expand Down
1 change: 1 addition & 0 deletions src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<Compile Update="Consoles/Nintendo/NDS/MelonDS.*.cs" DependentUpon="MelonDS.cs" />
<Compile Update="Consoles/Nintendo/SubNESHawk/SubNESHawk.*.cs" DependentUpon="SubNESHawk.cs" />
<Compile Update="Consoles/Nintendo/QuickNES/QuickNES.*.cs" DependentUpon="QuickNES.cs" />
<Compile Update="Consoles/Nintendo/Sameboy/SameBoy.*.cs" DependentUpon="SameBoy.cs" />
<Compile Update="Consoles/Nintendo/SNES/LibsnesCore.*.cs" DependentUpon="LibsnesCore.cs" />
<Compile Update="Consoles/PC Engine/PCEngine.*.cs" DependentUpon="PCEngine.cs" />
<Compile Update="Consoles/Sega/GGHawkLink/GGHawkLink.*.cs" DependentUpon="GGHawkLink.cs" />
Expand Down
16 changes: 11 additions & 5 deletions src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public Gameboy(CoreComm comm, GameInfo game, byte[] file, GambatteSettings setti

_cdCallback = new LibGambatte.CDCallback(CDCallbackProc);

ControllerDefinition = CreateControllerDefinition(IsSgb, _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames);
ControllerDefinition = CreateControllerDefinition(sgb: IsSgb, sub: _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames, tilt: false);

NewSaveCoreSetBuff();
}
Expand Down Expand Up @@ -263,11 +263,17 @@ public Gameboy(CoreComm comm, GameInfo game, byte[] file, GambatteSettings setti
public long CycleCount => (long)_cycleCount;
public double ClockRate => TICKSPERSECOND;

public static ControllerDefinition CreateControllerDefinition(bool sgb, bool sub)
public static ControllerDefinition CreateControllerDefinition(bool sgb, bool sub, bool tilt)
{
var ret = sub
? new ControllerDefinition("Subframe Gameboy Controller").AddAxis("Input Length", 0.RangeTo(35112), 35112)
: new ControllerDefinition("Gameboy Controller");
var ret = new ControllerDefinition((sub ? "Subframe " : "") + "Gameboy Controller" + (tilt ? " + Tilt" : ""));
if (sub)
{
ret.AddAxis("Input Length", 0.RangeTo(35112), 35112);
}
if (tilt)
{
ret.AddXYPair($"Tilt {{0}}", AxisPairOrientation.RightAndUp, (-90).RangeTo(90), 0);
}
if (sgb)
{
for (int i = 0; i < 4; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public GambatteLink(CoreLoadParameters<GambatteLinkSettings, GambatteLinkSyncSet
_linkedCores[i] = new Gameboy(lp.Comm, lp.Roms[i].Game, lp.Roms[i].RomData, _settings._linkedSettings[i], _syncSettings._linkedSyncSettings[i], lp.DeterministicEmulationRequested);
_linkedCores[i].ConnectInputCallbackSystem(_inputCallbacks);
_linkedCores[i].ConnectMemoryCallbackSystem(_memoryCallbacks, i);
_linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(false, false));
_linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: false));
_linkedBlips[i] = new BlipBuffer(1024);
_linkedBlips[i].SetRates(2097152 * 2, 44100);
_linkedOverflow[i] = 0;
Expand Down
152 changes: 152 additions & 0 deletions src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/LibSameBoy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System;
using System.Runtime.InteropServices;

using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;

namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
{
/// <summary>
/// static bindings into libsameboy.dll
/// </summary>
public static class LibSameboy
{
[Flags]
public enum Buttons : uint
{
RIGHT = 0x01,
LEFT = 0x02,
UP = 0x04,
DOWN = 0x08,
A = 0x10,
B = 0x20,
SELECT = 0x40,
START = 0x80,
}

// mirror of GB_direct_access_t
public enum MemoryAreas : uint
{
ROM,
RAM,
CART_RAM,
VRAM,
HRAM,
IO,
BOOTROM,
OAM,
BGP,
OBP,
IE,
BGPRGB,
OBPRGB,
}

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr sameboy_create(byte[] romdata, int romlength, byte[] biosdata, int bioslength, Sameboy.SameboySyncSettings.GBModel model, bool realtime);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_destroy(IntPtr core);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SampleCallback(IntPtr core, IntPtr sample);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setsamplecallback(IntPtr core, SampleCallback callback);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void InputCallback();

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setinputcallback(IntPtr core, InputCallback callback);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_frameadvance(IntPtr core, Buttons buttons, ushort x, ushort y, int[] videobuf, bool render, bool border);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_reset(IntPtr core);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool sameboy_iscgbdmg(IntPtr core);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_savesram(IntPtr core, byte[] dest);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_loadsram(IntPtr core, byte[] data, int len);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern int sameboy_sramlen(IntPtr core);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_savestate(IntPtr core, byte[] data);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool sameboy_loadstate(IntPtr core, byte[] data, int len);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern int sameboy_statelen(IntPtr core);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern bool sameboy_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref int length);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern byte sameboy_cpuread(IntPtr core, ushort addr);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_cpuwrite(IntPtr core, ushort addr, byte val);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern long sameboy_getcyclecount(IntPtr core);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setcyclecount(IntPtr core, long newcc);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TraceCallback(ushort pc);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_settracecallback(IntPtr core, TraceCallback callback);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_getregs(IntPtr core, int[] buf);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setreg(IntPtr core, int which, int value);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MemoryCallback(ushort address);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setmemorycallback(IntPtr core, int which, MemoryCallback callback);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setprintercallback(IntPtr core, PrinterCallback callback);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setscanlinecallback(IntPtr core, ScanlineCallback callback, int sl);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setpalette(IntPtr core, Sameboy.SameboySettings.GBPaletteType which);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setcolorcorrection(IntPtr core, Sameboy.SameboySettings.ColorCorrectionMode which);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setlighttemperature(IntPtr core, int temperature);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_sethighpassfilter(IntPtr core, Sameboy.SameboySettings.HighPassFilterMode which);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setinterferencevolume(IntPtr core, int volume);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setrtcdivisoroffset(IntPtr core, int offset);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setbgwinenabled(IntPtr core, bool enabled);

[DllImport("libsameboy", CallingConvention = CallingConvention.Cdecl)]
public static extern void sameboy_setobjenabled(IntPtr core, bool enabled);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;

using BizHawk.Emulation.Common;

namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
{
public partial class Sameboy : IDebuggable
{
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
{
int[] data = new int[10];
LibSameboy.sameboy_getregs(SameboyState, data);

return new Dictionary<string, RegisterValue>
{
["PC"] = (ushort)(data[0] & 0xFFFF),
["A"] = (byte)(data[1] & 0xFF),
["F"] = (byte)(data[2] & 0xFF),
["B"] = (byte)(data[3] & 0xFF),
["C"] = (byte)(data[4] & 0xFF),
["D"] = (byte)(data[5] & 0xFF),
["E"] = (byte)(data[6] & 0xFF),
["H"] = (byte)(data[7] & 0xFF),
["L"] = (byte)(data[8] & 0xFF),
["SP"] = (ushort)(data[9] & 0xFFFF),
};
}

public void SetCpuRegister(string register, int value)
{
LibSameboy.sameboy_setreg(SameboyState, register.ToUpper() switch
{
"PC" => 0,
"A" => 1,
"F" => 2,
"B" => 3,
"C" => 4,
"D" => 5,
"E" => 6,
"H" => 7,
"L" => 8,
"SP" => 9,
_ => throw new InvalidOperationException("Invalid Register?"),
},
value);
}

public bool CanStep(StepType type) => false;

[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();

public long TotalExecutedCycles => CycleCount;

private const string systemBusScope = "System Bus";

private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { systemBusScope });

public IMemoryCallbackSystem MemoryCallbacks => _memorycallbacks;

private LibSameboy.MemoryCallback _readcb;
private LibSameboy.MemoryCallback _writecb;
private LibSameboy.MemoryCallback _execcb;

private void InitMemoryCallbacks()
{
LibSameboy.MemoryCallback CreateCallback(MemoryCallbackFlags flags, Func<bool> getHasCBOfType)
{
var rawFlags = (uint)flags;
return (address) =>
{
if (getHasCBOfType())
{
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, systemBusScope);
}
};
}

_readcb = CreateCallback(MemoryCallbackFlags.AccessRead, () => MemoryCallbacks.HasReads);
_writecb = CreateCallback(MemoryCallbackFlags.AccessWrite, () => MemoryCallbacks.HasWrites);
_execcb = CreateCallback(MemoryCallbackFlags.AccessExecute, () => MemoryCallbacks.HasExecutes);

_memorycallbacks.ActiveChanged += SetMemoryCallbacks;
}

private void SetMemoryCallbacks()
{
LibSameboy.sameboy_setmemorycallback(SameboyState, 0, MemoryCallbacks.HasReads ? _readcb : null);
LibSameboy.sameboy_setmemorycallback(SameboyState, 1, MemoryCallbacks.HasWrites ? _writecb : null);
LibSameboy.sameboy_setmemorycallback(SameboyState, 2, MemoryCallbacks.HasExecutes ? _execcb : null);
}
}
}
Loading

0 comments on commit 2348e28

Please sign in to comment.