GBHawkLink3x: Initial Commits

This commit is contained in:
alyosha-tas 2019-09-08 16:35:39 -04:00
parent a01c205d62
commit 79c4b1e846
25 changed files with 1485 additions and 3 deletions

View File

@ -111,6 +111,9 @@ namespace BizHawk.Client.ApiHawk
case "ChannelF":
return CoreSystem.ChannelF;
case "GB3x":
return CoreSystem.GB3x;
case "VB":
case "NGP":
case "DNGP":

View File

@ -34,6 +34,7 @@
ZXSpectrum,
AmstradCPC,
GGL,
ChannelF
ChannelF,
GB3x
}
}

View File

@ -136,6 +136,8 @@ namespace BizHawk.Client.Common
return SystemInfo.Saturn;
case "DGB":
return SystemInfo.DualGB;
case "GB3x":
return SystemInfo.GB3x;
case "WSWAN":
return SystemInfo.WonderSwan;
case "Lynx":
@ -148,6 +150,8 @@ namespace BizHawk.Client.Common
return SystemInfo.Libretro;
case "VB":
return SystemInfo.VirtualBoy;
case "VEC":
return SystemInfo.Vectrex;
case "NGP":
return SystemInfo.NeoGeoPocket;
case "ZXSpectrum":

View File

@ -15,6 +15,7 @@ using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
using BizHawk.Emulation.Cores.Nintendo.GBHawkLink;
using BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x;
using BizHawk.Emulation.Cores.Nintendo.SNES;
using BizHawk.Emulation.Cores.PCEngine;
using BizHawk.Emulation.Cores.Sega.GGHawkLink;
@ -659,6 +660,27 @@ namespace BizHawk.Client.Common
}
// other stuff todo
break;
case "GB3x":
var leftBytes3x = xmlGame.Assets.First().Value;
var centerBytes3x = xmlGame.Assets.Skip(1).First().Value;
var rightBytes3x = xmlGame.Assets.Skip(2).First().Value;
var left3x = Database.GetGameInfo(leftBytes3x, "left.gb");
var center3x = Database.GetGameInfo(centerBytes3x, "center.gb");
var right3x = Database.GetGameInfo(rightBytes3x, "right.gb");
nextEmulator = new GBHawkLink3x(
nextComm,
left3x,
leftBytes3x,
center3x,
centerBytes3x,
right3x,
rightBytes3x,
GetCoreSettings<GBHawkLink3x>(),
GetCoreSyncSettings<GBHawkLink3x>());
break;
case "AppleII":
var assets = xmlGame.Assets.Select(a => Database.GetGameInfo(a.Value, a.Key));

View File

@ -73,6 +73,11 @@ namespace BizHawk.Client.Common
/// </summary>
public static SystemInfo Coleco { get; } = new SystemInfo("ColecoVision", CoreSystem.ColecoVision, 1);
/// <summary>
/// Gets the <see cref="SystemInfo"/> instance for Dual Gameboy
/// </summary>
public static SystemInfo GB3x { get; } = new SystemInfo("Game Boy Link 3x", CoreSystem.GB3x, 3, StandardButtons);
/// <summary>
/// Gets the <see cref="SystemInfo"/> instance for Dual Gameboy
/// </summary>

View File

@ -388,6 +388,20 @@ namespace BizHawk.Client.Common
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "Savestates", Path = Path.Combine(".", "State"), Ordinal = 2 },
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
new PathEntry { System = "GB3x", SystemDisplayName = "GB3x", Type = "Base", Path = Path.Combine(".", "GB3x"), Ordinal = 0 },
new PathEntry { System = "GB3x", SystemDisplayName = "GB3x", Type = "ROM", Path = ".", Ordinal = 1 },
new PathEntry { System = "GB3x", SystemDisplayName = "GB3x", Type = "Savestates", Path = Path.Combine(".", "State"), Ordinal = 2 },
new PathEntry { System = "GB3x", SystemDisplayName = "GB3x", Type = "Save RAM", Path = Path.Combine(".", "SaveRAM"), Ordinal = 3 },
new PathEntry { System = "GB3x", SystemDisplayName = "GB3x", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
new PathEntry { System = "GB3x", SystemDisplayName = "GB3x", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
new PathEntry { System = "VEC", SystemDisplayName = "VEC", Type = "Base", Path = Path.Combine(".", "VEC"), Ordinal = 0 },
new PathEntry { System = "VEC", SystemDisplayName = "VEC", Type = "ROM", Path = ".", Ordinal = 1 },
new PathEntry { System = "VEC", SystemDisplayName = "VEC", Type = "Savestates", Path = Path.Combine(".", "State"), Ordinal = 2 },
new PathEntry { System = "VEC", SystemDisplayName = "VEC", Type = "Save RAM", Path = Path.Combine(".", "SaveRAM"), Ordinal = 3 },
new PathEntry { System = "VEC", SystemDisplayName = "VEC", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
new PathEntry { System = "VEC", SystemDisplayName = "VEC", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
};
}
}

View File

@ -338,6 +338,12 @@ namespace BizHawk.Client.Common
{
["Toggle Cable"] = 'L'
},
["GB3x"] = new Dictionary<string, char>
{
["Toggle Cable LC"] = 'L',
["Toggle Cable CR"] = 'C',
["Toggle Cable RL"] = 'R'
},
["Lynx"] = new Dictionary<string, char>
{
["Option 1"] = '1',

View File

@ -215,6 +215,8 @@ namespace BizHawk.Client.DBMan
VB,
UZE,
NGP,
ChannelF
ChannelF,
VEC,
GB3x
}
}

View File

@ -355,6 +355,8 @@
this.DGBsettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.DGBHawkSubMenu = new System.Windows.Forms.ToolStripMenuItem();
this.DGBHawksettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.GB3xSubMenu = new System.Windows.Forms.ToolStripMenuItem();
this.GB3xsettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.GGLSubMenu = new System.Windows.Forms.ToolStripMenuItem();
this.GGLsettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.VectrexSubMenu = new System.Windows.Forms.ToolStripMenuItem();
@ -512,7 +514,8 @@
this.SaturnSubMenu,
this.DGBSubMenu,
this.DGBHawkSubMenu,
this.GGLSubMenu,
this.GB3xSubMenu,
this.GGLSubMenu,
this.GenesisSubMenu,
this.wonderSwanToolStripMenuItem,
this.AppleSubMenu,
@ -3218,6 +3221,21 @@
this.DGBHawksettingsToolStripMenuItem.Text = "Settings...";
this.DGBHawksettingsToolStripMenuItem.Click += new System.EventHandler(this.DgbHawkSettingsMenuItem_Click);
//
// GB3xSubMenu
//
this.GB3xSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.GB3xsettingsToolStripMenuItem});
this.GB3xSubMenu.Name = "GB3xSubMenu";
this.GB3xSubMenu.Size = new System.Drawing.Size(59, 19);
this.GB3xSubMenu.Text = "&GB Link 3x";
//
// GB3xsettingsToolStripMenuItem
//
this.GB3xsettingsToolStripMenuItem.Name = "GB3xsettingsToolStripMenuItem";
this.GB3xsettingsToolStripMenuItem.Size = new System.Drawing.Size(125, 22);
this.GB3xsettingsToolStripMenuItem.Text = "Settings...";
this.GB3xsettingsToolStripMenuItem.Click += new System.EventHandler(this.GB3xSettingsMenuItem_Click);
//
// GGLSubMenu
//
this.GGLSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -4577,6 +4595,8 @@
private System.Windows.Forms.ToolStripMenuItem DGBsettingsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem DGBHawkSubMenu;
private System.Windows.Forms.ToolStripMenuItem DGBHawksettingsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem GB3xSubMenu;
private System.Windows.Forms.ToolStripMenuItem GB3xsettingsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem GGLSubMenu;
private System.Windows.Forms.ToolStripMenuItem GGLsettingsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem VectrexSubMenu;

View File

@ -2386,6 +2386,15 @@ namespace BizHawk.Client.EmuHawk
#endregion
#region GB3x
private void GB3xSettingsMenuItem_Click(object sender, EventArgs e)
{
GenericCoreConfig.DoDialog(this, "Gameboy Settings");
}
#endregion
#region GGL
private void GGLSettingsMenuItem_Click(object sender, EventArgs e)

View File

@ -1729,6 +1729,7 @@ namespace BizHawk.Client.EmuHawk
SaturnSubMenu.Visible = false;
DGBSubMenu.Visible = false;
DGBHawkSubMenu.Visible = false;
GB3xSubMenu.Visible = false;
GGLSubMenu.Visible = false;
GenesisSubMenu.Visible = false;
wonderSwanToolStripMenuItem.Visible = false;
@ -1860,6 +1861,9 @@ namespace BizHawk.Client.EmuHawk
case "VEC":
VectrexSubMenu.Visible = true;
break;
case "GB3x":
GB3xSubMenu.Visible = true;
break;
}
}

View File

@ -141,6 +141,7 @@
"AppleII",
"C64",
"GB",
"GB3x",
"PCFX",
"PSX",
"SAT",

View File

@ -839,6 +839,31 @@
<DependentUpon>VBANext.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBA\VBARegisterHelper.cs" />
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.cs" />
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.ICodeDataLog.cs" />
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.IDebuggable.cs">
<DependentUpon>GBHawkLink3x.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.IEmulator.cs">
<DependentUpon>GBHawkLink3x.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.IInputPollable.cs">
<DependentUpon>GBHawkLink3x.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.IMemoryDomains.cs">
<DependentUpon>GBHawkLink3x.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.ISaveRam.cs">
<DependentUpon>GBHawkLink3x.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.ISettable.cs">
<DependentUpon>GBHawkLink3x.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3x.IStatable.cs">
<DependentUpon>GBHawkLink3x.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3xControllerDeck.cs" />
<Compile Include="Consoles\Nintendo\GBHawkLink3x\GBHawkLink3xControllers.cs" />
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.cs" />
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.ICodeDataLog.cs" />
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.IDebuggable.cs">

View File

@ -0,0 +1,185 @@
using System;
using System.IO;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components.LR35902;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x : ICodeDataLogger
{
private ICodeDataLog _cdl;
public void SetCDL(ICodeDataLog cdl)
{
_cdl = cdl;
if (cdl == null)
this.L.cpu.CDLCallback = null;
else this.L.cpu.CDLCallback = CDLCpuCallback;
}
public void NewCDL(ICodeDataLog cdl)
{
cdl["ROM"] = new byte[MemoryDomains["ROM L"].Size];
cdl["HRAM"] = new byte[MemoryDomains["Zero Page RAM L"].Size];
cdl["WRAM"] = new byte[MemoryDomains["Main RAM L"].Size];
if (MemoryDomains.Has("Cart RAM L"))
{
cdl["CartRAM"] = new byte[MemoryDomains["Cart RAM L"].Size];
}
cdl.SubType = "GB";
cdl.SubVer = 0;
}
[FeatureNotImplemented]
void ICodeDataLogger.DisassembleCDL(Stream s, ICodeDataLog cdl)
{
}
public void SetCDL(LR35902.eCDLogMemFlags flags, string type, int cdladdr)
{
if (type == null) return;
byte val = (byte)flags;
_cdl[type][cdladdr] |= (byte)flags;
}
void CDLCpuCallback(ushort addr, LR35902.eCDLogMemFlags flags)
{
if (addr < 0x8000)
{
//don't record writes to the ROM, it's just noisy
//NOTE: in principle a mapper could mount a useful resource here, but I doubt it)
if ((flags & LR35902.eCDLogMemFlags.Write) != 0) return;
}
if (L.ppu.DMA_start)
{
// some of gekkio's tests require these to be accessible during DMA
if (addr < 0x8000)
{
if (L.ppu.DMA_addr < 0x80)
{
return;
}
else
{
L.mapper.MapCDL(addr, flags);
return;
}
}
else if ((addr >= 0xE000) && (addr < 0xF000))
{
SetCDL(flags, "WRAM", addr - 0xE000);
}
else if ((addr >= 0xF000) && (addr < 0xFE00))
{
SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xF000));
}
else if ((addr >= 0xFE00) && (addr < 0xFEA0) && L.ppu.DMA_OAM_access)
{
return;
}
else if ((addr >= 0xFF00) && (addr < 0xFF80)) // The game GOAL! Requires Hardware Regs to be accessible
{
return;
}
else if ((addr >= 0xFF80))
{
SetCDL(flags, "HRAM", addr - 0xFF80);
}
}
if (addr < 0x900)
{
if (addr < 0x100)
{
// return Either BIOS ROM or Game ROM
if ((L.GB_bios_register & 0x1) == 0)
{
return;
}
else
{
L.mapper.MapCDL(addr, flags);
return;
}
}
else if (addr >= 0x200)
{
// return Either BIOS ROM or Game ROM
if (((L.GB_bios_register & 0x1) == 0) && L.is_GBC)
{
return;
}
else
{
L.mapper.MapCDL(addr, flags);
return;
}
}
else
{
L.mapper.MapCDL(addr, flags);
return;
}
}
else if (addr < 0x8000)
{
L.mapper.MapCDL(addr, flags);
return;
}
else if (addr < 0xA000)
{
return;
}
else if (addr < 0xC000)
{
L.mapper.MapCDL(addr, flags);
return;
}
else if (addr < 0xD000)
{
return;
}
else if (addr < 0xE000)
{
SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xD000));
}
else if (addr < 0xF000)
{
SetCDL(flags, "WRAM", addr - 0xE000);
}
else if (addr < 0xFE00)
{
SetCDL(flags, "WRAM", (L.RAM_Bank * 0x1000) + (addr - 0xF000));
}
else if (addr < 0xFEA0)
{
return;
}
else if (addr < 0xFF00)
{
return;
}
else if (addr < 0xFF80)
{
return;
}
else if (addr < 0xFFFF)
{
SetCDL(flags, "HRAM", addr - 0xFF80);
}
else
{
return;
}
}
}
}

View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x : IDebuggable
{
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
{
return new Dictionary<string, RegisterValue>
{
/*
["A"] = cpu.A,
["X"] = cpu.X,
["Y"] = cpu.Y,
["S"] = cpu.S,
["PC"] = cpu.PC,
["Flag C"] = cpu.FlagC,
["Flag Z"] = cpu.FlagZ,
["Flag I"] = cpu.FlagI,
["Flag D"] = cpu.FlagD,
["Flag B"] = cpu.FlagB,
["Flag V"] = cpu.FlagV,
["Flag N"] = cpu.FlagN,
["Flag T"] = cpu.FlagT
*/
};
}
public void SetCpuRegister(string register, int value)
{
switch (register)
{
default:
throw new InvalidOperationException();
case "A":
//cpu.A = (byte)value;
break;
case "X":
//cpu.X = (byte)value;
break;
case "Y":
//cpu.Y = (byte)value;
break;
case "S":
//cpu.S = (byte)value;
break;
case "PC":
//cpu.PC = (ushort)value;
break;
case "Flag I":
//cpu.FlagI = value > 0;
break;
}
}
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" });
public bool CanStep(StepType type)
{
return false;
}
[FeatureNotImplemented]
public void Step(StepType type)
{
throw new NotImplementedException();
}
public long TotalExecutedCycles
{
get { return (long)L.cpu.TotalExecutedCycles; }
}
}
}

View File

@ -0,0 +1,325 @@
using System;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x : IEmulator, IVideoProvider, ISoundProvider
{
public IEmulatorServiceProvider ServiceProvider { get; }
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
public bool FrameAdvance(IController controller, bool render, bool rendersound)
{
//Console.WriteLine("-----------------------FRAME-----------------------");
//Update the color palette if a setting changed
if (Link3xSettings.Palette_L == GBHawk.GBHawk.GBSettings.PaletteType.BW)
{
L.color_palette[0] = color_palette_BW[0];
L.color_palette[1] = color_palette_BW[1];
L.color_palette[2] = color_palette_BW[2];
L.color_palette[3] = color_palette_BW[3];
}
else
{
L.color_palette[0] = color_palette_Gr[0];
L.color_palette[1] = color_palette_Gr[1];
L.color_palette[2] = color_palette_Gr[2];
L.color_palette[3] = color_palette_Gr[3];
}
if (Link3xSettings.Palette_C == GBHawk.GBHawk.GBSettings.PaletteType.BW)
{
C.color_palette[0] = color_palette_BW[0];
C.color_palette[1] = color_palette_BW[1];
C.color_palette[2] = color_palette_BW[2];
C.color_palette[3] = color_palette_BW[3];
}
else
{
C.color_palette[0] = color_palette_Gr[0];
C.color_palette[1] = color_palette_Gr[1];
C.color_palette[2] = color_palette_Gr[2];
C.color_palette[3] = color_palette_Gr[3];
}
if (Link3xSettings.Palette_R == GBHawk.GBHawk.GBSettings.PaletteType.BW)
{
R.color_palette[0] = color_palette_BW[0];
R.color_palette[1] = color_palette_BW[1];
R.color_palette[2] = color_palette_BW[2];
R.color_palette[3] = color_palette_BW[3];
}
else
{
R.color_palette[0] = color_palette_Gr[0];
R.color_palette[1] = color_palette_Gr[1];
R.color_palette[2] = color_palette_Gr[2];
R.color_palette[3] = color_palette_Gr[3];
}
if (_tracer.Enabled)
{
L.cpu.TraceCallback = s => _tracer.Put(s);
}
else
{
L.cpu.TraceCallback = null;
}
_frame++;
if (controller.IsPressed("Power"))
{
HardReset();
}
bool cablediscosignalNew = controller.IsPressed("Toggle Cable");
if (cablediscosignalNew && !_cablediscosignal)
{
_cableconnected ^= true;
Console.WriteLine("Cable connect status to {0}", _cableconnected);
}
_cablediscosignal = cablediscosignalNew;
_islag = true;
GetControllerState(controller);
do_frame();
_islag = L._islag;
if (_islag)
{
_lagcount++;
}
return true;
}
public void do_frame()
{
L.do_controller_check();
C.do_controller_check();
R.do_controller_check();
// advance one full frame
for (int i = 0; i < 70224; i++)
{
L.do_single_step();
C.do_single_step();
R.do_single_step();
// the signal to shift out a bit is when serial_clock = 1
if (((L.serialport.serial_clock == 1) || (L.serialport.serial_clock == 2)) && !do_r_next)
{
if (_cableconnected)
{
L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80));
if ((R.serialport.clk_rate == -1) && R.serialport.serial_start)
{
R.serialport.serial_clock = L.serialport.serial_clock;
R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80));
R.serialport.coming_in = L.serialport.going_out;
}
L.serialport.coming_in = R.serialport.going_out;
}
}
else if ((R.serialport.serial_clock == 1) || (R.serialport.serial_clock == 2))
{
do_r_next = false;
if (_cableconnected)
{
R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80));
if ((L.serialport.clk_rate == -1) && L.serialport.serial_start)
{
L.serialport.serial_clock = R.serialport.serial_clock;
L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80));
L.serialport.coming_in = R.serialport.going_out;
}
R.serialport.coming_in = L.serialport.going_out;
}
if (R.serialport.serial_clock == 2) { do_r_next = true; }
}
else
{
do_r_next = false;
}
// if we hit a frame boundary, update video
if (L.vblank_rise)
{
buff_L = L.GetVideoBuffer();
L.vblank_rise = false;
FillVideoBuffer();
}
if (C.vblank_rise)
{
buff_C = C.GetVideoBuffer();
C.vblank_rise = false;
FillVideoBuffer();
}
if (R.vblank_rise)
{
buff_R = R.GetVideoBuffer();
R.vblank_rise = false;
FillVideoBuffer();
}
}
}
public void GetControllerState(IController controller)
{
InputCallbacks.Call();
L.controller_state = _controllerDeck.ReadPort1(controller);
C.controller_state = _controllerDeck.ReadPort2(controller);
R.controller_state = _controllerDeck.ReadPort3(controller);
}
public int Frame => _frame;
public string SystemId => "GB3x";
public bool DeterministicEmulation { get; set; }
public void ResetCounters()
{
_frame = 0;
_lagcount = 0;
_islag = false;
}
public CoreComm CoreComm { get; }
public void Dispose()
{
L.Dispose();
C.Dispose();
R.Dispose();
}
#region Video provider
public int _frameHz = 60;
public int[] _vidbuffer = new int[160 * 2 * 144 * 2];
public int[] buff_L = new int[160 * 144];
public int[] buff_C = new int[160 * 144];
public int[] buff_R = new int[160 * 144];
public int[] GetVideoBuffer()
{
return _vidbuffer;
}
public void FillVideoBuffer()
{
// combine the 2 video buffers from the instances
for (int i = 0; i < 144; i++)
{
for (int j = 0; j < 160; j++)
{
_vidbuffer[i * 320 + j] = buff_L[i * 160 + j];
_vidbuffer[(i + 144) * 320 + j + 80] = buff_C[i * 160 + j];
_vidbuffer[i * 320 + j + 160] = buff_R[i * 160 + j];
}
}
}
public int VirtualWidth => 160 * 2;
public int VirtualHeight => 144 * 2;
public int BufferWidth => 160 * 2;
public int BufferHeight => 144 * 2;
public int BackgroundColor => unchecked((int)0xFF000000);
public int VsyncNumerator => _frameHz;
public int VsyncDenominator => 1;
public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 };
public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 };
public uint[] color_palette = new uint[4];
#endregion
#region audio
public bool CanProvideAsync => false;
public void SetSyncMode(SyncSoundMode mode)
{
if (mode != SyncSoundMode.Sync)
{
throw new InvalidOperationException("Only Sync mode is supported_");
}
}
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
public void GetSamplesSync(out short[] samples, out int nsamp)
{
short[] temp_samp_L;
short[] temp_samp_C;
short[] temp_samp_R;
int nsamp_L;
int nsamp_C;
int nsamp_R;
L.audio.GetSamplesSync(out temp_samp_L, out nsamp_L);
C.audio.GetSamplesSync(out temp_samp_C, out nsamp_C);
R.audio.GetSamplesSync(out temp_samp_R, out nsamp_R);
if (Link3xSettings.AudioSet == GBLink3xSettings.AudioSrc.Left)
{
samples = temp_samp_L;
nsamp = nsamp_L;
}
else if (Link3xSettings.AudioSet == GBLink3xSettings.AudioSrc.Right)
{
samples = temp_samp_R;
nsamp = nsamp_R;
}
else
{
samples = new short[0];
nsamp = 0;
}
}
public void GetSamplesAsync(short[] samples)
{
throw new NotSupportedException("Async is not available");
}
public void DiscardSamples()
{
L.audio.DiscardSamples();
C.audio.DiscardSamples();
R.audio.DiscardSamples();
}
private void GetSamples(short[] samples)
{
}
public void DisposeSound()
{
L.audio.DisposeSound();
C.audio.DisposeSound();
R.audio.DisposeSound();
}
#endregion
}
}

View File

@ -0,0 +1,24 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x : IInputPollable
{
public int LagCount
{
get { return _lagcount; }
set { _lagcount = value; }
}
public bool IsLagFrame
{
get { return _islag; }
set { _islag = value; }
}
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
public bool _islag = true;
private int _lagcount;
}
}

View File

@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x
{
private IMemoryDomains MemoryDomains;
public void SetupMemoryDomains()
{
var domains = new List<MemoryDomain>
{
new MemoryDomainDelegate(
"Main RAM L",
L.RAM.Length,
MemoryDomain.Endian.Little,
addr => L.RAM[addr],
(addr, value) => L.RAM[addr] = value,
1),
new MemoryDomainDelegate(
"Main RAM R",
R.RAM.Length,
MemoryDomain.Endian.Little,
addr => R.RAM[addr],
(addr, value) => R.RAM[addr] = value,
1),
new MemoryDomainDelegate(
"Zero Page RAM L",
L.ZP_RAM.Length,
MemoryDomain.Endian.Little,
addr => L.ZP_RAM[addr],
(addr, value) => L.ZP_RAM[addr] = value,
1),
new MemoryDomainDelegate(
"Zero Page RAM R",
R.ZP_RAM.Length,
MemoryDomain.Endian.Little,
addr => R.ZP_RAM[addr],
(addr, value) => R.ZP_RAM[addr] = value,
1),
new MemoryDomainDelegate(
"System Bus L",
0X10000,
MemoryDomain.Endian.Little,
addr => PeekSystemBusL(addr),
(addr, value) => PokeSystemBusL(addr, value),
1),
new MemoryDomainDelegate(
"System Bus R",
0X10000,
MemoryDomain.Endian.Little,
addr => PeekSystemBusR(addr),
(addr, value) => PokeSystemBusR(addr, value),
1),
new MemoryDomainDelegate(
"ROM L",
L._rom.Length,
MemoryDomain.Endian.Little,
addr => L._rom[addr],
(addr, value) => L._rom[addr] = value,
1),
new MemoryDomainDelegate(
"ROM R",
R._rom.Length,
MemoryDomain.Endian.Little,
addr => R._rom[addr],
(addr, value) => R._rom[addr] = value,
1),
new MemoryDomainDelegate(
"VRAM L",
L.VRAM.Length,
MemoryDomain.Endian.Little,
addr => L.VRAM[addr],
(addr, value) => L.VRAM[addr] = value,
1),
new MemoryDomainDelegate(
"VRAM R",
R.VRAM.Length,
MemoryDomain.Endian.Little,
addr => R.VRAM[addr],
(addr, value) => R.VRAM[addr] = value,
1)
};
if (L.cart_RAM != null)
{
var CartRamL = new MemoryDomainByteArray("Cart RAM L", MemoryDomain.Endian.Little, L.cart_RAM, true, 1);
domains.Add(CartRamL);
}
if (R.cart_RAM != null)
{
var CartRamR = new MemoryDomainByteArray("Cart RAM R", MemoryDomain.Endian.Little, R.cart_RAM, true, 1);
domains.Add(CartRamR);
}
MemoryDomains = new MemoryDomainList(domains);
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
}
private byte PeekSystemBusL(long addr)
{
ushort addr2 = (ushort)(addr & 0xFFFF);
return L.PeekMemory(addr2);
}
private byte PeekSystemBusR(long addr)
{
ushort addr2 = (ushort)(addr & 0xFFFF);
return R.PeekMemory(addr2);
}
private void PokeSystemBusL(long addr, byte value)
{
ushort addr2 = (ushort)(addr & 0xFFFF);
L.WriteMemory(addr2, value);
}
private void PokeSystemBusR(long addr, byte value)
{
ushort addr2 = (ushort)(addr & 0xFFFF);
R.WriteMemory(addr2, value);
}
}
}

View File

@ -0,0 +1,81 @@
using System;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x : ISaveRam
{
public byte[] CloneSaveRam()
{
if ((L.cart_RAM != null) || (R.cart_RAM != null))
{
int Len1 = 0;
int Len2 = 0;
int index = 0;
if (L.cart_RAM != null)
{
Len1 = L.cart_RAM.Length;
}
if (R.cart_RAM != null)
{
Len2 = R.cart_RAM.Length;
}
byte[] temp = new byte[Len1 + Len2];
if (L.cart_RAM != null)
{
for (int i = 0; i < L.cart_RAM.Length; i++)
{
temp[index] = L.cart_RAM[i];
index++;
}
}
if (R.cart_RAM != null)
{
for (int i = 0; i < L.cart_RAM.Length; i++)
{
temp[index] = R.cart_RAM[i];
index++;
}
}
return temp;
}
else
{
return null;
}
}
public void StoreSaveRam(byte[] data)
{
if ((L.cart_RAM != null) && (R.cart_RAM == null))
{
Buffer.BlockCopy(data, 0, L.cart_RAM, 0, L.cart_RAM.Length);
}
else if ((R.cart_RAM != null) && (L.cart_RAM == null))
{
Buffer.BlockCopy(data, 0, R.cart_RAM, 0, R.cart_RAM.Length);
}
else if ((R.cart_RAM != null) && (L.cart_RAM != null))
{
Buffer.BlockCopy(data, 0, L.cart_RAM, 0, L.cart_RAM.Length);
Buffer.BlockCopy(data, L.cart_RAM.Length, R.cart_RAM, 0, R.cart_RAM.Length);
}
Console.WriteLine("loading SRAM here");
}
public bool SaveRamModified
{
get
{
return (L.has_bat || R.has_bat) & Link3xSyncSettings.Use_SRAM;
}
}
}
}

View File

@ -0,0 +1,176 @@
using System;
using System.ComponentModel;
using Newtonsoft.Json;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x : IEmulator, IStatable, ISettable<GBHawkLink3x.GBLink3xSettings, GBHawkLink3x.GBLink3xSyncSettings>
{
public GBLink3xSettings GetSettings()
{
return Link3xSettings.Clone();
}
public GBLink3xSyncSettings GetSyncSettings()
{
return Link3xSyncSettings.Clone();
}
public bool PutSettings(GBLink3xSettings o)
{
Link3xSettings = o;
return false;
}
public bool PutSyncSettings(GBLink3xSyncSettings o)
{
bool ret = GBLink3xSyncSettings.NeedsReboot(Link3xSyncSettings, o);
Link3xSyncSettings = o;
return ret;
}
private GBLink3xSettings Link3xSettings = new GBLink3xSettings();
public GBLink3xSyncSettings Link3xSyncSettings = new GBLink3xSyncSettings();
public class GBLink3xSettings
{
[DisplayName("Color Mode")]
[Description("Pick Between Green scale and Grey scale colors")]
[DefaultValue(GBHawk.GBHawk.GBSettings.PaletteType.BW)]
public GBHawk.GBHawk.GBSettings.PaletteType Palette_L { get; set; }
[DisplayName("Color Mode")]
[Description("Pick Between Green scale and Grey scale colors")]
[DefaultValue(GBHawk.GBHawk.GBSettings.PaletteType.BW)]
public GBHawk.GBHawk.GBSettings.PaletteType Palette_C { get; set; }
[DisplayName("Color Mode")]
[Description("Pick Between Green scale and Grey scale colors")]
[DefaultValue(GBHawk.GBHawk.GBSettings.PaletteType.BW)]
public GBHawk.GBHawk.GBSettings.PaletteType Palette_R { get; set; }
public enum AudioSrc
{
Left,
Right,
Both
}
[DisplayName("Audio Selection")]
[Description("Choose Audio Source. Both will produce Stereo sound.")]
[DefaultValue(AudioSrc.Left)]
public AudioSrc AudioSet { get; set; }
public GBLink3xSettings Clone()
{
return (GBLink3xSettings)MemberwiseClone();
}
}
public class GBLink3xSyncSettings
{
[DisplayName("Console Mode L")]
[Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")]
[DefaultValue(GBHawk.GBHawk.GBSyncSettings.ConsoleModeType.Auto)]
public GBHawk.GBHawk.GBSyncSettings.ConsoleModeType ConsoleMode_L { get; set; }
[DisplayName("Console Mode C")]
[Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")]
[DefaultValue(GBHawk.GBHawk.GBSyncSettings.ConsoleModeType.Auto)]
public GBHawk.GBHawk.GBSyncSettings.ConsoleModeType ConsoleMode_C { get; set; }
[DisplayName("Console Mode R")]
[Description("Pick which console to run, 'Auto' chooses from ROM extension, 'GB' and 'GBC' chooses the respective system")]
[DefaultValue(GBHawk.GBHawk.GBSyncSettings.ConsoleModeType.Auto)]
public GBHawk.GBHawk.GBSyncSettings.ConsoleModeType ConsoleMode_R { get; set; }
[DisplayName("CGB in GBA")]
[Description("Emulate GBA hardware running a CGB game, instead of CGB hardware. Relevant only for titles that detect the presense of a GBA, such as Shantae.")]
[DefaultValue(false)]
public bool GBACGB { get; set; }
[DisplayName("RTC Initial Time L")]
[Description("Set the initial RTC time in terms of elapsed seconds.")]
[DefaultValue(0)]
public int RTCInitialTime_L
{
get { return _RTCInitialTime_L; }
set { _RTCInitialTime_L = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); }
}
[DisplayName("RTC Initial Time C")]
[Description("Set the initial RTC time in terms of elapsed seconds.")]
[DefaultValue(0)]
public int RTCInitialTime_C
{
get { return _RTCInitialTime_C; }
set { _RTCInitialTime_C = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); }
}
[DisplayName("RTC Initial Time R")]
[Description("Set the initial RTC time in terms of elapsed seconds.")]
[DefaultValue(0)]
public int RTCInitialTime_R
{
get { return _RTCInitialTime_R; }
set { _RTCInitialTime_R = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); }
}
[DisplayName("Timer Div Initial Time L")]
[Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")]
[DefaultValue(8)]
public int DivInitialTime_L
{
get { return _DivInitialTime_L; }
set { _DivInitialTime_L = Math.Min((ushort)65535, (ushort)value); }
}
[DisplayName("Timer Div Initial Time C")]
[Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")]
[DefaultValue(8)]
public int DivInitialTime_C
{
get { return _DivInitialTime_C; }
set { _DivInitialTime_C = Math.Min((ushort)65535, (ushort)value); }
}
[DisplayName("Timer Div Initial Time R")]
[Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")]
[DefaultValue(8)]
public int DivInitialTime_R
{
get { return _DivInitialTime_R; }
set { _DivInitialTime_R = Math.Min((ushort)65535, (ushort)value); }
}
[DisplayName("Use Existing SaveRAM")]
[Description("When true, existing SaveRAM will be loaded at boot up")]
[DefaultValue(false)]
public bool Use_SRAM { get; set; }
[JsonIgnore]
private int _RTCInitialTime_L;
private int _RTCInitialTime_C;
private int _RTCInitialTime_R;
[JsonIgnore]
public ushort _DivInitialTime_L = 8;
public ushort _DivInitialTime_C = 8;
public ushort _DivInitialTime_R = 8;
public GBLink3xSyncSettings Clone()
{
return (GBLink3xSyncSettings)MemberwiseClone();
}
public static bool NeedsReboot(GBLink3xSyncSettings x, GBLink3xSyncSettings y)
{
return !DeepEquality.DeepEquals(x, y);
}
}
}
}

View File

@ -0,0 +1,66 @@
using System.IO;
using Newtonsoft.Json;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public partial class GBHawkLink3x : IStatable
{
public bool BinarySaveStatesPreferred => true;
public void SaveStateText(TextWriter writer)
{
L.SaveStateText(writer);
R.SaveStateText(writer);
SyncState(new Serializer(writer));
}
public void LoadStateText(TextReader reader)
{
L.LoadStateText(reader);
R.LoadStateText(reader);
SyncState(new Serializer(reader));
}
public void SaveStateBinary(BinaryWriter bw)
{
L.SaveStateBinary(bw);
R.SaveStateBinary(bw);
// other variables
SyncState(new Serializer(bw));
}
public void LoadStateBinary(BinaryReader br)
{
L.LoadStateBinary(br);
R.LoadStateBinary(br);
// other variables
SyncState(new Serializer(br));
}
public byte[] SaveStateBinary()
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
return ms.ToArray();
}
//private JsonSerializer ser = new JsonSerializer { Formatting = Formatting.Indented };
private void SyncState(Serializer ser)
{
ser.Sync("Lag", ref _lagcount);
ser.Sync("Frame", ref _frame);
ser.Sync("IsLag", ref _islag);
ser.Sync(nameof(_cableconnected), ref _cableconnected);
ser.Sync(nameof(_cablediscosignal), ref _cablediscosignal);
ser.Sync(nameof(do_r_next), ref do_r_next);
_controllerDeck.SyncState(ser);
}
}
}

View File

@ -0,0 +1,105 @@
using System;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
[Core(
"GBHawkLink3x",
"",
isPorted: false,
isReleased: true)]
[ServiceNotApplicable(typeof(IDriveLight))]
public partial class GBHawkLink3x : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable,
ISettable<GBHawkLink3x.GBLink3xSettings, GBHawkLink3x.GBLink3xSyncSettings>
{
// we want to create two GBHawk instances that we will run concurrently
// maybe up to 4 eventually?
public GBHawk.GBHawk L;
public GBHawk.GBHawk C;
public GBHawk.GBHawk R;
// if true, the link cable is currently connected
private bool _cableconnected = true;
// if true, the link cable toggle signal is currently asserted
private bool _cablediscosignal = false;
private bool do_r_next = false;
//[CoreConstructor("GB", "GBC")]
public GBHawkLink3x(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_C, byte[] rom_C, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings)
{
var ser = new BasicServiceProvider(this);
Link3xSettings = (GBLink3xSettings)settings ?? new GBLink3xSettings();
Link3xSyncSettings = (GBLink3xSyncSettings)syncSettings ?? new GBLink3xSyncSettings();
_controllerDeck = new GBHawkLink3xControllerDeck(GBHawkLink3xControllerDeck.DefaultControllerName, GBHawkLink3xControllerDeck.DefaultControllerName, GBHawkLink3xControllerDeck.DefaultControllerName);
CoreComm = comm;
var temp_set_L = new GBHawk.GBHawk.GBSettings();
var temp_set_C = new GBHawk.GBHawk.GBSettings();
var temp_set_R = new GBHawk.GBHawk.GBSettings();
var temp_sync_L = new GBHawk.GBHawk.GBSyncSettings();
var temp_sync_C = new GBHawk.GBHawk.GBSyncSettings();
var temp_sync_R = new GBHawk.GBHawk.GBSyncSettings();
temp_sync_L.ConsoleMode = Link3xSyncSettings.ConsoleMode_L;
temp_sync_C.ConsoleMode = Link3xSyncSettings.ConsoleMode_C;
temp_sync_R.ConsoleMode = Link3xSyncSettings.ConsoleMode_R;
temp_sync_L.DivInitialTime = Link3xSyncSettings.DivInitialTime_L;
temp_sync_C.DivInitialTime = Link3xSyncSettings.DivInitialTime_C;
temp_sync_R.DivInitialTime = Link3xSyncSettings.DivInitialTime_R;
temp_sync_L.RTCInitialTime = Link3xSyncSettings.RTCInitialTime_L;
temp_sync_C.RTCInitialTime = Link3xSyncSettings.RTCInitialTime_C;
temp_sync_R.RTCInitialTime = Link3xSyncSettings.RTCInitialTime_R;
L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider },
game_L, rom_L, temp_set_L, temp_sync_L);
C = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider },
game_C, rom_C, temp_set_C, temp_sync_C);
R = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider },
game_R, rom_R, temp_set_R, temp_sync_R);
ser.Register<IVideoProvider>(this);
ser.Register<ISoundProvider>(this);
_tracer = new TraceBuffer { Header = L.cpu.TraceHeader };
ser.Register<ITraceable>(_tracer);
ServiceProvider = ser;
SetupMemoryDomains();
HardReset();
}
public void HardReset()
{
L.HardReset();
C.HardReset();
R.HardReset();
}
public DisplayType Region => DisplayType.NTSC;
public int _frame = 0;
private readonly GBHawkLink3xControllerDeck _controllerDeck;
private readonly ITraceable _tracer;
private void ExecFetch(ushort addr)
{
uint flags = (uint)(MemoryCallbackFlags.AccessExecute);
MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus");
}
}
}

View File

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Common.ReflectionExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
public class GBHawkLink3xControllerDeck
{
public GBHawkLink3xControllerDeck(string controller1Name, string controller2Name, string controller3Name)
{
if (!ValidControllerTypes.ContainsKey(controller1Name))
{
throw new InvalidOperationException("Invalid controller type: " + controller1Name);
}
if (!ValidControllerTypes.ContainsKey(controller2Name))
{
throw new InvalidOperationException("Invalid controller type: " + controller2Name);
}
if (!ValidControllerTypes.ContainsKey(controller3Name))
{
throw new InvalidOperationException("Invalid controller type: " + controller3Name);
}
Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1);
Port2 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller2Name], 2);
Port3 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller3Name], 3);
Definition = new ControllerDefinition
{
Name = Port1.Definition.Name,
BoolButtons = Port1.Definition.BoolButtons
.Concat(Port2.Definition.BoolButtons)
.Concat(Port3.Definition.BoolButtons)
.Concat(new[] { "Toggle Cable LC" } )
.Concat(new[] { "Toggle Cable CR" } )
.Concat(new[] { "Toggle Cable RL" } )
.ToList()
};
}
public byte ReadPort1(IController c)
{
return Port1.Read(c);
}
public byte ReadPort2(IController c)
{
return Port2.Read(c);
}
public byte ReadPort3(IController c)
{
return Port3.Read(c);
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser)
{
ser.BeginSection(nameof(Port1));
Port1.SyncState(ser);
ser.EndSection();
ser.BeginSection(nameof(Port2));
Port2.SyncState(ser);
ser.EndSection();
ser.BeginSection(nameof(Port3));
Port3.SyncState(ser);
ser.EndSection();
}
private readonly IPort Port1;
private readonly IPort Port2;
private readonly IPort Port3;
private static Dictionary<string, Type> _controllerTypes;
public static Dictionary<string, Type> ValidControllerTypes
{
get
{
if (_controllerTypes == null)
{
_controllerTypes = typeof(GBHawkLink3xControllerDeck).Assembly
.GetTypes()
.Where(t => typeof(IPort).IsAssignableFrom(t))
.Where(t => !t.IsAbstract && !t.IsInterface)
.ToDictionary(tkey => tkey.DisplayName());
}
return _controllerTypes;
}
}
public static string DefaultControllerName => typeof(StandardControls).DisplayName();
}
}

View File

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
{
/// <summary>
/// Represents a GB add on
/// </summary>
public interface IPort
{
byte Read(IController c);
ControllerDefinition Definition { get; }
void SyncState(Serializer ser);
int PortNum { get; }
}
[DisplayName("Gameboy Controller")]
public class StandardControls : IPort
{
public StandardControls(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition
{
Name = "Gameboy Controller H",
BoolButtons = BaseDefinition
.Select(b => "P" + PortNum + " " + b)
.ToList()
};
}
public int PortNum { get; }
public ControllerDefinition Definition { get; }
public byte Read(IController c)
{
byte result = 0xFF;
if (c.IsPressed(Definition.BoolButtons[0]))
{
result -= 4;
}
if (c.IsPressed(Definition.BoolButtons[1]))
{
result -= 8;
}
if (c.IsPressed(Definition.BoolButtons[2]))
{
result -= 2;
}
if (c.IsPressed(Definition.BoolButtons[3]))
{
result -= 1;
}
if (c.IsPressed(Definition.BoolButtons[4]))
{
result -= 128;
}
if (c.IsPressed(Definition.BoolButtons[5]))
{
result -= 64;
}
if (c.IsPressed(Definition.BoolButtons[6]))
{
result -= 32;
}
if (c.IsPressed(Definition.BoolButtons[7]))
{
result -= 16;
}
return result;
}
private static readonly string[] BaseDefinition =
{
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
};
public void SyncState(Serializer ser)
{
//nothing
}
}
}

View File

@ -0,0 +1 @@
TODO: