GBHawkLink3x: Initial Commits
This commit is contained in:
parent
a01c205d62
commit
79c4b1e846
|
@ -111,6 +111,9 @@ namespace BizHawk.Client.ApiHawk
|
|||
case "ChannelF":
|
||||
return CoreSystem.ChannelF;
|
||||
|
||||
case "GB3x":
|
||||
return CoreSystem.GB3x;
|
||||
|
||||
case "VB":
|
||||
case "NGP":
|
||||
case "DNGP":
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
ZXSpectrum,
|
||||
AmstradCPC,
|
||||
GGL,
|
||||
ChannelF
|
||||
ChannelF,
|
||||
GB3x
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -215,6 +215,8 @@ namespace BizHawk.Client.DBMan
|
|||
VB,
|
||||
UZE,
|
||||
NGP,
|
||||
ChannelF
|
||||
ChannelF,
|
||||
VEC,
|
||||
GB3x
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
"AppleII",
|
||||
"C64",
|
||||
"GB",
|
||||
"GB3x",
|
||||
"PCFX",
|
||||
"PSX",
|
||||
"SAT",
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
TODO:
|
Loading…
Reference in New Issue