GBHawk: Start link support
This commit is contained in:
parent
2b7014f8b8
commit
f47c2d1558
|
@ -14,6 +14,7 @@ using BizHawk.Emulation.Cores.Computers.Commodore64;
|
||||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
|
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
|
||||||
|
using BizHawk.Emulation.Cores.Nintendo.GBHawkLink;
|
||||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||||
using BizHawk.Emulation.Cores.PCEngine;
|
using BizHawk.Emulation.Cores.PCEngine;
|
||||||
using BizHawk.Emulation.Cores.Sega.Saturn;
|
using BizHawk.Emulation.Cores.Sega.Saturn;
|
||||||
|
@ -630,7 +631,20 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
var left = Database.GetGameInfo(leftBytes, "left.gb");
|
var left = Database.GetGameInfo(leftBytes, "left.gb");
|
||||||
var right = Database.GetGameInfo(rightBytes, "right.gb");
|
var right = Database.GetGameInfo(rightBytes, "right.gb");
|
||||||
nextEmulator = new GambatteLink(
|
if (Global.Config.GB_UseGBHawk)
|
||||||
|
{
|
||||||
|
nextEmulator = new GBHawkLink(
|
||||||
|
nextComm,
|
||||||
|
left,
|
||||||
|
leftBytes,
|
||||||
|
right,
|
||||||
|
rightBytes,
|
||||||
|
GetCoreSettings<GBHawkLink>(),
|
||||||
|
GetCoreSyncSettings<GBHawkLink>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextEmulator = new GambatteLink(
|
||||||
nextComm,
|
nextComm,
|
||||||
left,
|
left,
|
||||||
leftBytes,
|
leftBytes,
|
||||||
|
@ -639,7 +653,8 @@ namespace BizHawk.Client.Common
|
||||||
GetCoreSettings<GambatteLink>(),
|
GetCoreSettings<GambatteLink>(),
|
||||||
GetCoreSyncSettings<GambatteLink>(),
|
GetCoreSyncSettings<GambatteLink>(),
|
||||||
Deterministic);
|
Deterministic);
|
||||||
|
}
|
||||||
|
|
||||||
// other stuff todo
|
// other stuff todo
|
||||||
break;
|
break;
|
||||||
case "AppleII":
|
case "AppleII":
|
||||||
|
|
|
@ -789,6 +789,31 @@
|
||||||
<DependentUpon>VBANext.cs</DependentUpon>
|
<DependentUpon>VBANext.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Consoles\Nintendo\GBA\VBARegisterHelper.cs" />
|
<Compile Include="Consoles\Nintendo\GBA\VBARegisterHelper.cs" />
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.cs" />
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.ICodeDataLog.cs" />
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.IDebuggable.cs">
|
||||||
|
<DependentUpon>GBHawkLink.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.IEmulator.cs">
|
||||||
|
<DependentUpon>GBHawkLink.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.IInputPollable.cs">
|
||||||
|
<DependentUpon>GBHawkLink.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.IMemoryDomains.cs">
|
||||||
|
<DependentUpon>GBHawkLink.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.ISaveRam.cs">
|
||||||
|
<DependentUpon>GBHawkLink.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.ISettable.cs">
|
||||||
|
<DependentUpon>GBHawkLink.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLink.IStatable.cs">
|
||||||
|
<DependentUpon>GBHawkLink.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLinkControllerDeck.cs" />
|
||||||
|
<Compile Include="Consoles\Nintendo\GBHawkLink\GBHawkLinkControllers.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\GBHawk\Audio.cs" />
|
<Compile Include="Consoles\Nintendo\GBHawk\Audio.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.ICodeDataLog.cs" />
|
<Compile Include="Consoles\Nintendo\GBHawk\GBHawk.ICodeDataLog.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_WisdomTree.cs" />
|
<Compile Include="Consoles\Nintendo\GBHawk\Mappers\Mapper_WisdomTree.cs" />
|
||||||
|
|
|
@ -159,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker++;
|
ticker++;
|
||||||
//if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); }
|
// if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); }
|
||||||
|
|
||||||
in_vblank_old = in_vblank;
|
in_vblank_old = in_vblank;
|
||||||
REG_FF0F_OLD = REG_FF0F;
|
REG_FF0F_OLD = REG_FF0F;
|
||||||
|
|
|
@ -107,9 +107,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||||
ser.Sync("cart_RAM", ref cart_RAM, false);
|
ser.Sync("cart_RAM", ref cart_RAM, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ser.EndSection();
|
||||||
|
|
||||||
ser.EndSection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
using BizHawk.Common.BufferExtensions;
|
using BizHawk.Common.BufferExtensions;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Common.Components.LR35902;
|
using BizHawk.Emulation.Common.Components.LR35902;
|
||||||
using BizHawk.Common.NumberExtensions;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@ -275,7 +274,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
||||||
|
|
||||||
private readonly GBHawkControllerDeck _controllerDeck;
|
private readonly GBHawkControllerDeck _controllerDeck;
|
||||||
|
|
||||||
private void HardReset()
|
public void HardReset()
|
||||||
{
|
{
|
||||||
GB_bios_register = 0; // bios enable
|
GB_bios_register = 0; // bios enable
|
||||||
GBC_compat = is_GBC;
|
GBC_compat = is_GBC;
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components.LR35902;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink : 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink : 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
using BizHawk.Common.NumberExtensions;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink : IEmulator, IVideoProvider
|
||||||
|
{
|
||||||
|
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
|
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
|
||||||
|
|
||||||
|
public byte controller_state;
|
||||||
|
public bool in_vblank_old;
|
||||||
|
public bool in_vblank;
|
||||||
|
public bool vblank_rise;
|
||||||
|
|
||||||
|
public void FrameAdvance(IController controller, bool render, bool rendersound)
|
||||||
|
{
|
||||||
|
//Console.WriteLine("-----------------------FRAME-----------------------");
|
||||||
|
if (_tracer.Enabled)
|
||||||
|
{
|
||||||
|
L.cpu.TraceCallback = s => _tracer.Put(s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
L.cpu.TraceCallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_frame++;
|
||||||
|
|
||||||
|
if (controller.IsPressed("Power"))
|
||||||
|
{
|
||||||
|
HardReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
_islag = true;
|
||||||
|
|
||||||
|
GetControllerState(controller);
|
||||||
|
|
||||||
|
do_frame();
|
||||||
|
|
||||||
|
_islag = L._islag;
|
||||||
|
|
||||||
|
if (_islag)
|
||||||
|
{
|
||||||
|
_lagcount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void do_frame()
|
||||||
|
{
|
||||||
|
L.do_frame();
|
||||||
|
R.do_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetControllerState(IController controller)
|
||||||
|
{
|
||||||
|
InputCallbacks.Call();
|
||||||
|
L.controller_state = _controllerDeck.ReadPort1(controller);
|
||||||
|
R.controller_state = _controllerDeck.ReadPort2(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Frame => _frame;
|
||||||
|
|
||||||
|
public string SystemId => "GB";
|
||||||
|
|
||||||
|
public bool DeterministicEmulation { get; set; }
|
||||||
|
|
||||||
|
public void ResetCounters()
|
||||||
|
{
|
||||||
|
_frame = 0;
|
||||||
|
_lagcount = 0;
|
||||||
|
_islag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoreComm CoreComm { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
L.Dispose();
|
||||||
|
R.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Video provider
|
||||||
|
|
||||||
|
public int _frameHz = 60;
|
||||||
|
|
||||||
|
public int[] _vidbuffer = new int[160 * 2 * 144];
|
||||||
|
public int[] buff_L;
|
||||||
|
public int[] buff_R;
|
||||||
|
|
||||||
|
public int[] GetVideoBuffer()
|
||||||
|
{
|
||||||
|
// combine the 2 video buffers from the instances
|
||||||
|
buff_L = L.GetVideoBuffer();
|
||||||
|
buff_R = R.GetVideoBuffer();
|
||||||
|
|
||||||
|
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 * 320 + j + 160] = buff_R[i * 160 + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _vidbuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int VirtualWidth => 160 * 2;
|
||||||
|
public int VirtualHeight => 144;
|
||||||
|
public int BufferWidth => 160 * 2;
|
||||||
|
public int BufferHeight => 144;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink : 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink : ISaveRam
|
||||||
|
{
|
||||||
|
public byte[] CloneSaveRam()
|
||||||
|
{
|
||||||
|
if (L.cart_RAM != null)
|
||||||
|
{
|
||||||
|
return (byte[])L.cart_RAM.Clone();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StoreSaveRam(byte[] data)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(data, 0, L.cart_RAM, 0, data.Length);
|
||||||
|
Console.WriteLine("loading SRAM here");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SaveRamModified
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return L.has_bat & _syncSettings.L.Use_SRAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
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.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink : IEmulator, IStatable, ISettable<GBHawkLink.GBLinkSettings, GBHawkLink.GBLinkSyncSettings>
|
||||||
|
{
|
||||||
|
public GBLinkSettings GetSettings()
|
||||||
|
{
|
||||||
|
return new GBLinkSettings
|
||||||
|
(
|
||||||
|
L.GetSettings(),
|
||||||
|
R.GetSettings()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GBLinkSyncSettings GetSyncSettings()
|
||||||
|
{
|
||||||
|
return new GBLinkSyncSettings
|
||||||
|
(
|
||||||
|
L.GetSyncSettings(),
|
||||||
|
R.GetSyncSettings()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PutSettings(GBLinkSettings o)
|
||||||
|
{
|
||||||
|
return L.PutSettings(o.L) || R.PutSettings(o.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PutSyncSettings(GBLinkSyncSettings o)
|
||||||
|
{
|
||||||
|
return L.PutSyncSettings(o.L) || R.PutSyncSettings(o.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GBLinkSettings _settings = new GBLinkSettings();
|
||||||
|
public GBLinkSyncSettings _syncSettings = new GBLinkSyncSettings();
|
||||||
|
|
||||||
|
public class GBLinkSettings
|
||||||
|
{
|
||||||
|
public GBHawk.GBHawk.GBSettings L;
|
||||||
|
public GBHawk.GBHawk.GBSettings R;
|
||||||
|
|
||||||
|
public GBLinkSettings()
|
||||||
|
{
|
||||||
|
L = new GBHawk.GBHawk.GBSettings();
|
||||||
|
R = new GBHawk.GBHawk.GBSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GBLinkSettings(GBHawk.GBHawk.GBSettings L, GBHawk.GBHawk.GBSettings R)
|
||||||
|
{
|
||||||
|
this.L = L;
|
||||||
|
this.R = R;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GBLinkSettings Clone()
|
||||||
|
{
|
||||||
|
return new GBLinkSettings(L.Clone(), R.Clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GBLinkSyncSettings
|
||||||
|
{
|
||||||
|
public GBHawk.GBHawk.GBSyncSettings L;
|
||||||
|
public GBHawk.GBHawk.GBSyncSettings R;
|
||||||
|
|
||||||
|
public GBLinkSyncSettings()
|
||||||
|
{
|
||||||
|
L = new GBHawk.GBHawk.GBSyncSettings();
|
||||||
|
R = new GBHawk.GBHawk.GBSyncSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GBLinkSyncSettings(GBHawk.GBHawk.GBSyncSettings L, GBHawk.GBHawk.GBSyncSettings R)
|
||||||
|
{
|
||||||
|
this.L = L;
|
||||||
|
this.R = R;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GBLinkSyncSettings Clone()
|
||||||
|
{
|
||||||
|
return new GBLinkSyncSettings(L.Clone(), R.Clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
public partial class GBHawkLink : 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);
|
||||||
|
_controllerDeck.SyncState(ser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using BizHawk.Common.BufferExtensions;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
using BizHawk.Emulation.Common.Components.LR35902;
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||||
|
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
|
||||||
|
{
|
||||||
|
[Core(
|
||||||
|
"GBHawkLink",
|
||||||
|
"",
|
||||||
|
isPorted: false,
|
||||||
|
isReleased: true)]
|
||||||
|
[ServiceNotApplicable(typeof(IDriveLight))]
|
||||||
|
public partial class GBHawkLink : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ILinkable,
|
||||||
|
ISettable<GBHawkLink.GBLinkSettings, GBHawkLink.GBLinkSyncSettings>
|
||||||
|
{
|
||||||
|
// we want to create two GBHawk instances that we will run concurrently
|
||||||
|
// maybe up to 4 eventually?
|
||||||
|
public GBHawk.GBHawk L;
|
||||||
|
public GBHawk.GBHawk R;
|
||||||
|
|
||||||
|
//[CoreConstructor("GB", "GBC")]
|
||||||
|
public GBHawkLink(CoreComm comm, GameInfo game_L, byte[] rom_L, GameInfo game_R, byte[] rom_R, /*string gameDbFn,*/ object settings, object syncSettings)
|
||||||
|
{
|
||||||
|
var ser = new BasicServiceProvider(this);
|
||||||
|
|
||||||
|
GBLinkSettings linkSettings = (GBLinkSettings)settings ?? new GBLinkSettings();
|
||||||
|
GBLinkSyncSettings linkSyncSettings = (GBLinkSyncSettings)syncSettings ?? new GBLinkSyncSettings();
|
||||||
|
_controllerDeck = new GBHawkLinkControllerDeck(GBHawkControllerDeck.DefaultControllerName, GBHawkControllerDeck.DefaultControllerName);
|
||||||
|
|
||||||
|
CoreComm = comm;
|
||||||
|
|
||||||
|
L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider },
|
||||||
|
game_L, rom_L, linkSettings.L, linkSyncSettings.L);
|
||||||
|
|
||||||
|
R = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider },
|
||||||
|
game_R, rom_R, linkSettings.R, linkSyncSettings.R);
|
||||||
|
|
||||||
|
ser.Register<IVideoProvider>(this);
|
||||||
|
ser.Register<ISoundProvider>(L.audio);
|
||||||
|
|
||||||
|
_tracer = new TraceBuffer { Header = L.cpu.TraceHeader };
|
||||||
|
ser.Register<ITraceable>(_tracer);
|
||||||
|
|
||||||
|
ServiceProvider = ser;
|
||||||
|
|
||||||
|
SetupMemoryDomains();
|
||||||
|
|
||||||
|
HardReset();
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HardReset()
|
||||||
|
{
|
||||||
|
L.HardReset();
|
||||||
|
R.HardReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayType Region => DisplayType.NTSC;
|
||||||
|
|
||||||
|
public int _frame = 0;
|
||||||
|
|
||||||
|
private readonly GBHawkLinkControllerDeck _controllerDeck;
|
||||||
|
|
||||||
|
private readonly ITraceable _tracer;
|
||||||
|
|
||||||
|
bool ILinkable.LinkConnected { get; }
|
||||||
|
|
||||||
|
private void ExecFetch(ushort addr)
|
||||||
|
{
|
||||||
|
MemoryCallbacks.CallExecutes(addr, "System Bus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
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.GBHawkLink
|
||||||
|
{
|
||||||
|
public class GBHawkLinkControllerDeck
|
||||||
|
{
|
||||||
|
public GBHawkLinkControllerDeck(string controller1Name, string controller2Name)
|
||||||
|
{
|
||||||
|
if (!ValidControllerTypes.ContainsKey(controller1Name))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid controller type: " + controller1Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ValidControllerTypes.ContainsKey(controller2Name))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid controller type: " + controller2Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1);
|
||||||
|
Port2 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller2Name], 2);
|
||||||
|
|
||||||
|
Definition = new ControllerDefinition
|
||||||
|
{
|
||||||
|
Name = Port1.Definition.Name,
|
||||||
|
BoolButtons = Port1.Definition.BoolButtons
|
||||||
|
.Concat(Port2.Definition.BoolButtons)
|
||||||
|
.ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadPort1(IController c)
|
||||||
|
{
|
||||||
|
return Port1.Read(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadPort2(IController c)
|
||||||
|
{
|
||||||
|
return Port2.Read(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControllerDefinition Definition { get; }
|
||||||
|
|
||||||
|
public void SyncState(Serializer ser)
|
||||||
|
{
|
||||||
|
ser.BeginSection("Port1");
|
||||||
|
Port1.SyncState(ser);
|
||||||
|
ser.EndSection();
|
||||||
|
|
||||||
|
ser.BeginSection("Port2");
|
||||||
|
Port2.SyncState(ser);
|
||||||
|
ser.EndSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IPort Port1;
|
||||||
|
private readonly IPort Port2;
|
||||||
|
|
||||||
|
private static Dictionary<string, Type> _controllerTypes;
|
||||||
|
|
||||||
|
public static Dictionary<string, Type> ValidControllerTypes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_controllerTypes == null)
|
||||||
|
{
|
||||||
|
_controllerTypes = typeof(GBHawkLinkControllerDeck).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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.GBHawkLink
|
||||||
|
{
|
||||||
|
/// <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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
TODO:
|
Loading…
Reference in New Issue