rough in some stuff for game boy link cable recording. none of it is finished yet
This commit is contained in:
parent
cc73cdb6f9
commit
63f9752ea2
|
@ -168,6 +168,7 @@
|
||||||
<Compile Include="Consoles\Intellivision\PSG.cs" />
|
<Compile Include="Consoles\Intellivision\PSG.cs" />
|
||||||
<Compile Include="Consoles\Intellivision\STIC.cs" />
|
<Compile Include="Consoles\Intellivision\STIC.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\Gameboy\Gambatte.cs" />
|
<Compile Include="Consoles\Nintendo\Gameboy\Gambatte.cs" />
|
||||||
|
<Compile Include="Consoles\Nintendo\Gameboy\GambatteLink.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\Gameboy\GBColors.cs" />
|
<Compile Include="Consoles\Nintendo\Gameboy\GBColors.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" />
|
<Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" />
|
||||||
<Compile Include="Consoles\Nintendo\GBA\LibMeteor.cs" />
|
<Compile Include="Consoles\Nintendo\GBA\LibMeteor.cs" />
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// internal gambatte state
|
/// internal gambatte state
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IntPtr GambatteState = IntPtr.Zero;
|
internal IntPtr GambatteState = IntPtr.Zero;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// keep a copy of the input callback delegate so it doesn't get GCed
|
/// keep a copy of the input callback delegate so it doesn't get GCed
|
||||||
|
|
|
@ -0,0 +1,276 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Consoles.GB
|
||||||
|
{
|
||||||
|
public class GambatteLink : IEmulator, IVideoProvider, ISyncSoundProvider
|
||||||
|
{
|
||||||
|
class ControlSplitter : IController
|
||||||
|
{
|
||||||
|
public ControllerDefinition Type
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool this[string button]
|
||||||
|
{
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPressed(string button)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetFloat(string name)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateControls(int frame)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Gameboy L;
|
||||||
|
Gameboy R;
|
||||||
|
|
||||||
|
Consoles.Nintendo.SNES.LibsnesCore.SnesSaveController LCont = new Nintendo.SNES.LibsnesCore.SnesSaveController(Gameboy.GbController);
|
||||||
|
Consoles.Nintendo.SNES.LibsnesCore.SnesSaveController RCont = new Nintendo.SNES.LibsnesCore.SnesSaveController(Gameboy.GbController);
|
||||||
|
|
||||||
|
public GambatteLink(CoreComm comm, GameInfo leftinfo, byte[] leftrom, GameInfo rightinfo, byte[] rightrom)
|
||||||
|
{
|
||||||
|
CoreComm = comm;
|
||||||
|
L = new Gameboy(new CoreComm(), leftinfo, leftrom);
|
||||||
|
R = new Gameboy(new CoreComm(), rightinfo, rightrom);
|
||||||
|
|
||||||
|
L.Controller = LCont;
|
||||||
|
R.Controller = RCont;
|
||||||
|
|
||||||
|
comm.VsyncNum = L.CoreComm.VsyncNum;
|
||||||
|
comm.VsyncDen = L.CoreComm.VsyncDen;
|
||||||
|
comm.RomStatusAnnotation = null;
|
||||||
|
comm.RomStatusDetails = "LEFT:\r\n" + L.CoreComm.RomStatusDetails + "RIGHT:\r\n" + R.CoreComm.RomStatusDetails;
|
||||||
|
comm.CpuTraceAvailable = false; // TODO
|
||||||
|
comm.NominalWidth = L.CoreComm.NominalWidth + R.CoreComm.NominalWidth;
|
||||||
|
comm.NominalHeight = L.CoreComm.NominalHeight;
|
||||||
|
|
||||||
|
Frame = 0;
|
||||||
|
LagCount = 0;
|
||||||
|
IsLagFrame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IVideoProvider VideoProvider { get { return this; } }
|
||||||
|
public ISoundProvider SoundProvider { get { return null; } }
|
||||||
|
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
|
||||||
|
public bool StartAsyncSound() { return false; }
|
||||||
|
public void EndAsyncSound() { }
|
||||||
|
|
||||||
|
public static readonly ControllerDefinition DualGbController = new ControllerDefinition
|
||||||
|
{
|
||||||
|
Name = "Dual Gameboy Controller",
|
||||||
|
BoolButtons =
|
||||||
|
{
|
||||||
|
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 A", "P1 B", "P1 Select", "P1 Start", "P1 Power",
|
||||||
|
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 A", "P2 B", "P2 Select", "P2 Start", "P2 Power",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public ControllerDefinition ControllerDefinition { get { return DualGbController; } }
|
||||||
|
public IController Controller { get; set; }
|
||||||
|
|
||||||
|
public void FrameAdvance(bool render, bool rendersound = true)
|
||||||
|
{
|
||||||
|
LCont.Clear();
|
||||||
|
RCont.Clear();
|
||||||
|
|
||||||
|
foreach (var s in DualGbController.BoolButtons)
|
||||||
|
{
|
||||||
|
if (Controller[s])
|
||||||
|
{
|
||||||
|
if (s.Contains("P1 "))
|
||||||
|
LCont.Set(s.Replace("P1 ", ""));
|
||||||
|
else if (s.Contains("P2 "))
|
||||||
|
RCont.Set(s.Replace("P2 ", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame++;
|
||||||
|
L.FrameAdvance(render, rendersound);
|
||||||
|
R.FrameAdvance(render, rendersound);
|
||||||
|
IsLagFrame = L.IsLagFrame && R.IsLagFrame;
|
||||||
|
if (IsLagFrame)
|
||||||
|
LagCount++;
|
||||||
|
BlitFrameBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Frame { get; private set; }
|
||||||
|
public int LagCount { get; set; }
|
||||||
|
public bool IsLagFrame { get; private set; }
|
||||||
|
public string SystemId { get { return "DGB"; } }
|
||||||
|
public bool DeterministicEmulation { get { return true; } }
|
||||||
|
|
||||||
|
#region saveram
|
||||||
|
|
||||||
|
public byte[] ReadSaveRam()
|
||||||
|
{
|
||||||
|
byte[] lb = L.ReadSaveRam();
|
||||||
|
byte[] rb = R.ReadSaveRam();
|
||||||
|
byte[] ret = new byte[lb.Length + rb.Length];
|
||||||
|
Buffer.BlockCopy(lb, 0, ret, 0, lb.Length);
|
||||||
|
Buffer.BlockCopy(rb, 0, ret, lb.Length, rb.Length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StoreSaveRam(byte[] data)
|
||||||
|
{
|
||||||
|
byte[] lb = new byte[L.ReadSaveRam().Length];
|
||||||
|
byte[] rb = new byte[R.ReadSaveRam().Length];
|
||||||
|
Buffer.BlockCopy(data, 0, lb, 0, lb.Length);
|
||||||
|
Buffer.BlockCopy(data, lb.Length, rb, 0, rb.Length);
|
||||||
|
L.StoreSaveRam(lb);
|
||||||
|
R.StoreSaveRam(rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearSaveRam()
|
||||||
|
{
|
||||||
|
L.ClearSaveRam();
|
||||||
|
R.ClearSaveRam();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SaveRamModified
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return L.SaveRamModified || R.SaveRamModified;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public void ResetFrameCounter()
|
||||||
|
{
|
||||||
|
Frame = 0;
|
||||||
|
LagCount = 0;
|
||||||
|
IsLagFrame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region savestates
|
||||||
|
|
||||||
|
public void SaveStateText(TextWriter writer)
|
||||||
|
{
|
||||||
|
var temp = SaveStateBinary();
|
||||||
|
temp.SaveAsHex(writer);
|
||||||
|
// write extra copy of stuff we don't use
|
||||||
|
writer.WriteLine("Frame {0}", Frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadStateText(TextReader reader)
|
||||||
|
{
|
||||||
|
string hex = reader.ReadLine();
|
||||||
|
byte[] state = new byte[hex.Length / 2];
|
||||||
|
state.ReadFromHex(hex);
|
||||||
|
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStateBinary(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
L.SaveStateBinary(writer);
|
||||||
|
R.SaveStateBinary(writer);
|
||||||
|
// other variables
|
||||||
|
writer.Write(IsLagFrame);
|
||||||
|
writer.Write(LagCount);
|
||||||
|
writer.Write(Frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadStateBinary(BinaryReader reader)
|
||||||
|
{
|
||||||
|
L.LoadStateBinary(reader);
|
||||||
|
R.LoadStateBinary(reader);
|
||||||
|
// other variables
|
||||||
|
IsLagFrame = reader.ReadBoolean();
|
||||||
|
LagCount = reader.ReadInt32();
|
||||||
|
Frame = reader.ReadInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] SaveStateBinary()
|
||||||
|
{
|
||||||
|
MemoryStream ms = new MemoryStream();
|
||||||
|
BinaryWriter bw = new BinaryWriter(ms);
|
||||||
|
SaveStateBinary(bw);
|
||||||
|
bw.Flush();
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public CoreComm CoreComm { get; private set; }
|
||||||
|
|
||||||
|
public IList<MemoryDomain> MemoryDomains
|
||||||
|
{
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemoryDomain MainMemory
|
||||||
|
{
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (L != null)
|
||||||
|
{
|
||||||
|
L.Dispose();
|
||||||
|
L = null;
|
||||||
|
}
|
||||||
|
if (R != null)
|
||||||
|
{
|
||||||
|
R.Dispose();
|
||||||
|
R = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] VideoBuffer = new int[160 * 2 * 144];
|
||||||
|
public int[] GetVideoBuffer() { return VideoBuffer; }
|
||||||
|
public int VirtualWidth { get { return 320; } }
|
||||||
|
public int BufferWidth { get { return 320; } }
|
||||||
|
public int BufferHeight { get { return 144; } }
|
||||||
|
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
|
||||||
|
|
||||||
|
void BlitFrameBuffer()
|
||||||
|
{
|
||||||
|
var lb = L.GetVideoBuffer();
|
||||||
|
var rb = R.GetVideoBuffer();
|
||||||
|
int destpos = 0;
|
||||||
|
for (int y = 0; y < 144; y++)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(lb, 160 * 4 * y, VideoBuffer, destpos, 160 * 4);
|
||||||
|
destpos += 160 * 4;
|
||||||
|
Buffer.BlockCopy(rb, 160 * 4 * y, VideoBuffer, destpos, 160 * 4);
|
||||||
|
destpos += 160 * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void GetSamples(out short[] samples, out int nsamp)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
samples = new short[735 * 2];
|
||||||
|
nsamp = 735;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DiscardSamples()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -377,5 +377,14 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
/// <param name="val">byte to write</param>
|
/// <param name="val">byte to write</param>
|
||||||
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void gambatte_cpuwrite(IntPtr core, ushort addr, byte val);
|
public static extern void gambatte_cpuwrite(IntPtr core, ushort addr, byte val);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// link cable stuff; never touch for normal operation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">opaque state pointe</param>
|
||||||
|
/// <param name="which">todo</param>
|
||||||
|
/// <returns>todo</returns>
|
||||||
|
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int gambatte_linkstatus(IntPtr core, int which);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,7 +509,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// can freeze a copy of a controller input set and serialize\deserialize it
|
/// can freeze a copy of a controller input set and serialize\deserialize it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class SnesSaveController : IController
|
public class SnesSaveController : IController
|
||||||
{
|
{
|
||||||
// this is all rather general, so perhaps should be moved out of LibsnesCore
|
// this is all rather general, so perhaps should be moved out of LibsnesCore
|
||||||
|
|
||||||
|
@ -579,6 +579,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
buttons.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(string button)
|
||||||
|
{
|
||||||
|
buttons[button] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
public bool this[string button]
|
public bool this[string button]
|
||||||
{
|
{
|
||||||
get { return buttons[button] != 0; }
|
get { return buttons[button] != 0; }
|
||||||
|
@ -596,7 +606,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
||||||
|
|
||||||
public void UpdateControls(int frame)
|
public void UpdateControls(int frame)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1952,65 +1952,77 @@ namespace BizHawk.MultiClient
|
||||||
break;
|
break;
|
||||||
case "GB":
|
case "GB":
|
||||||
case "GBC":
|
case "GBC":
|
||||||
if (!Global.Config.GB_AsSGB)
|
if (false) // DEBUG
|
||||||
{
|
{
|
||||||
if (Global.Config.GB_ForceDMG) game.AddOption("ForceDMG");
|
if (Global.Config.GB_ForceDMG) game.AddOption("ForceDMG");
|
||||||
if (Global.Config.GB_GBACGB) game.AddOption("GBACGB");
|
if (Global.Config.GB_GBACGB) game.AddOption("GBACGB");
|
||||||
if (Global.Config.GB_MulticartCompat) game.AddOption("MulitcartCompat");
|
if (Global.Config.GB_MulticartCompat) game.AddOption("MulitcartCompat");
|
||||||
Emulation.Consoles.GB.Gameboy gb = new Emulation.Consoles.GB.Gameboy(nextComm, game, rom.FileData);
|
GambatteLink gbl = new GambatteLink(nextComm, game, rom.FileData, game, rom.FileData);
|
||||||
nextEmulator = gb;
|
nextEmulator = gbl;
|
||||||
if (gb.IsCGBMode())
|
// other stuff todo
|
||||||
{
|
|
||||||
gb.SetCGBColors(Global.Config.CGBColors);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (StreamReader f = new StreamReader(Global.Config.GB_PaletteFile))
|
|
||||||
{
|
|
||||||
int[] colors = GBtools.ColorChooserForm.LoadPalFile(f);
|
|
||||||
if (colors != null)
|
|
||||||
gb.ChangeDMGColors(colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// todo: get these bioses into a gamedb?? then we could demand different filenames for different regions?
|
if (!Global.Config.GB_AsSGB)
|
||||||
string sgbromPath = Path.Combine(Global.Config.FirmwaresPath, "sgb.sfc"); //Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathSNESFirmwares, "SNES"), "sgb.sfc");
|
|
||||||
byte[] sgbrom = null;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (File.Exists(sgbromPath))
|
if (Global.Config.GB_ForceDMG) game.AddOption("ForceDMG");
|
||||||
|
if (Global.Config.GB_GBACGB) game.AddOption("GBACGB");
|
||||||
|
if (Global.Config.GB_MulticartCompat) game.AddOption("MulitcartCompat");
|
||||||
|
Emulation.Consoles.GB.Gameboy gb = new Emulation.Consoles.GB.Gameboy(nextComm, game, rom.FileData);
|
||||||
|
nextEmulator = gb;
|
||||||
|
if (gb.IsCGBMode())
|
||||||
{
|
{
|
||||||
sgbrom = File.ReadAllBytes(sgbromPath);
|
gb.SetCGBColors(Global.Config.CGBColors);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MessageBox.Show("Couldn't open sgb.sfc from the configured SNES firmwares path, which is:\n\n" + sgbromPath + "\n\nPlease make sure it is available and try again.\n\nWe're going to disable SGB for now; please re-enable it when you've set up the file.");
|
try
|
||||||
Global.Config.GB_AsSGB = false;
|
{
|
||||||
game.System = "GB";
|
using (StreamReader f = new StreamReader(Global.Config.GB_PaletteFile))
|
||||||
goto RETRY;
|
{
|
||||||
|
int[] colors = GBtools.ColorChooserForm.LoadPalFile(f);
|
||||||
|
if (colors != null)
|
||||||
|
gb.ChangeDMGColors(colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
else
|
||||||
{
|
{
|
||||||
// failed to load SGB bios. to avoid catch-22, disable SGB mode
|
// todo: get these bioses into a gamedb?? then we could demand different filenames for different regions?
|
||||||
Global.Config.GB_AsSGB = false;
|
string sgbromPath = Path.Combine(Global.Config.FirmwaresPath, "sgb.sfc"); //Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathSNESFirmwares, "SNES"), "sgb.sfc");
|
||||||
throw;
|
byte[] sgbrom = null;
|
||||||
}
|
try
|
||||||
if (sgbrom != null)
|
{
|
||||||
{
|
if (File.Exists(sgbromPath))
|
||||||
game.System = "SNES";
|
{
|
||||||
game.AddOption("SGB");
|
sgbrom = File.ReadAllBytes(sgbromPath);
|
||||||
nextComm.SNES_ExePath = SNES_Prepare(Global.Config.SNESProfile);
|
}
|
||||||
var snes = new LibsnesCore(nextComm);
|
else
|
||||||
nextEmulator = snes;
|
{
|
||||||
game.FirmwareHash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(sgbrom));
|
MessageBox.Show("Couldn't open sgb.sfc from the configured SNES firmwares path, which is:\n\n" + sgbromPath + "\n\nPlease make sure it is available and try again.\n\nWe're going to disable SGB for now; please re-enable it when you've set up the file.");
|
||||||
snes.Load(game, rom.FileData, sgbrom, deterministicemulation);
|
Global.Config.GB_AsSGB = false;
|
||||||
|
game.System = "GB";
|
||||||
|
goto RETRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// failed to load SGB bios. to avoid catch-22, disable SGB mode
|
||||||
|
Global.Config.GB_AsSGB = false;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
if (sgbrom != null)
|
||||||
|
{
|
||||||
|
game.System = "SNES";
|
||||||
|
game.AddOption("SGB");
|
||||||
|
nextComm.SNES_ExePath = SNES_Prepare(Global.Config.SNESProfile);
|
||||||
|
var snes = new LibsnesCore(nextComm);
|
||||||
|
nextEmulator = snes;
|
||||||
|
game.FirmwareHash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(sgbrom));
|
||||||
|
snes.Load(game, rom.FileData, sgbrom, deterministicemulation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -492,6 +492,10 @@ namespace BizHawk.MultiClient
|
||||||
{
|
{
|
||||||
return GetGBAControllersAsMnemonic();
|
return GetGBAControllersAsMnemonic();
|
||||||
}
|
}
|
||||||
|
else if (ControlType == "Dual Gameboy Controller")
|
||||||
|
{
|
||||||
|
return "|.|"; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder input = new StringBuilder("|");
|
StringBuilder input = new StringBuilder("|");
|
||||||
|
|
||||||
|
@ -907,6 +911,10 @@ namespace BizHawk.MultiClient
|
||||||
SetAtari7800AsMnemonic(mnemonic);
|
SetAtari7800AsMnemonic(mnemonic);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (ControlType == "Dual Gameboy Controller")
|
||||||
|
{
|
||||||
|
return; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
MnemonicChecker c = new MnemonicChecker(mnemonic);
|
MnemonicChecker c = new MnemonicChecker(mnemonic);
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,8 @@ public:
|
||||||
unsigned char ExternalRead(unsigned short addr);
|
unsigned char ExternalRead(unsigned short addr);
|
||||||
void ExternalWrite(unsigned short addr, unsigned char val);
|
void ExternalWrite(unsigned short addr, unsigned char val);
|
||||||
|
|
||||||
|
int LinkStatus(int which);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Priv;
|
struct Priv;
|
||||||
Priv *const p_;
|
Priv *const p_;
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||||
|
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
@ -67,6 +68,7 @@
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>include;src;src\common</AdditionalIncludeDirectories>
|
||||||
|
<DisableSpecificWarnings>4244;4373;4800;4804</DisableSpecificWarnings>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
|
|
@ -234,3 +234,9 @@ __declspec(dllexport) void gambatte_cpuwrite(void *core, unsigned short addr, un
|
||||||
GB *g = (GB *) core;
|
GB *g = (GB *) core;
|
||||||
g->ExternalWrite(addr, val);
|
g->ExternalWrite(addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__declspec(dllexport) int gambatte_linkstatus(void *core, int which)
|
||||||
|
{
|
||||||
|
GB *g = (GB *) core;
|
||||||
|
return g->LinkStatus(which);
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,9 @@ extern "C"
|
||||||
__declspec(dllexport) unsigned char gambatte_cpuread(void *core, unsigned short addr);
|
__declspec(dllexport) unsigned char gambatte_cpuread(void *core, unsigned short addr);
|
||||||
|
|
||||||
__declspec(dllexport) void gambatte_cpuwrite(void *core, unsigned short addr, unsigned char val);
|
__declspec(dllexport) void gambatte_cpuwrite(void *core, unsigned short addr, unsigned char val);
|
||||||
|
|
||||||
|
__declspec(dllexport) int gambatte_linkstatus(void *core, int which);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,7 @@ public:
|
||||||
unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); }
|
unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); }
|
||||||
void ExternalWrite(unsigned short addr, unsigned char val) { memory.write(addr, val, cycleCounter_); }
|
void ExternalWrite(unsigned short addr, unsigned char val) { memory.write(addr, val, cycleCounter_); }
|
||||||
|
|
||||||
|
int LinkStatus(int which) { return memory.LinkStatus(which); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,4 +260,8 @@ void GB::setGameShark(const std::string &codes) {
|
||||||
p_->cpu.setGameShark(codes);
|
p_->cpu.setGameShark(codes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GB::LinkStatus(int which) {
|
||||||
|
return p_->cpu.LinkStatus(which);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,9 @@ Memory::Memory(const Interrupter &interrupter_in)
|
||||||
dmaDestination(0),
|
dmaDestination(0),
|
||||||
oamDmaPos(0xFE),
|
oamDmaPos(0xFE),
|
||||||
serialCnt(0),
|
serialCnt(0),
|
||||||
blanklcd(false)
|
blanklcd(false),
|
||||||
|
LINKCABLE(false),
|
||||||
|
linkClockTrigger(false)
|
||||||
{
|
{
|
||||||
intreq.setEventTime<BLIT>(144*456ul);
|
intreq.setEventTime<BLIT>(144*456ul);
|
||||||
intreq.setEventTime<END>(0);
|
intreq.setEventTime<END>(0);
|
||||||
|
@ -123,16 +125,26 @@ void Memory::setEndtime(const unsigned long cycleCounter, const unsigned long in
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memory::updateSerial(const unsigned long cc) {
|
void Memory::updateSerial(const unsigned long cc) {
|
||||||
if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
|
if (!LINKCABLE) {
|
||||||
if (intreq.eventTime(SERIAL) <= cc) {
|
if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
|
||||||
ioamhram[0x101] = (((ioamhram[0x101] + 1) << serialCnt) - 1) & 0xFF;
|
if (intreq.eventTime(SERIAL) <= cc) {
|
||||||
ioamhram[0x102] &= 0x7F;
|
ioamhram[0x101] = (((ioamhram[0x101] + 1) << serialCnt) - 1) & 0xFF;
|
||||||
intreq.setEventTime<SERIAL>(DISABLED_TIME);
|
ioamhram[0x102] &= 0x7F;
|
||||||
intreq.flagIrq(8);
|
intreq.setEventTime<SERIAL>(DISABLED_TIME);
|
||||||
} else {
|
intreq.flagIrq(8);
|
||||||
const int targetCnt = serialCntFrom(intreq.eventTime(SERIAL) - cc, ioamhram[0x102] & isCgb() * 2);
|
} else {
|
||||||
ioamhram[0x101] = (((ioamhram[0x101] + 1) << (serialCnt - targetCnt)) - 1) & 0xFF;
|
const int targetCnt = serialCntFrom(intreq.eventTime(SERIAL) - cc, ioamhram[0x102] & isCgb() * 2);
|
||||||
serialCnt = targetCnt;
|
ioamhram[0x101] = (((ioamhram[0x101] + 1) << (serialCnt - targetCnt)) - 1) & 0xFF;
|
||||||
|
serialCnt = targetCnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
|
||||||
|
if (intreq.eventTime(SERIAL) <= cc) {
|
||||||
|
linkClockTrigger = true;
|
||||||
|
intreq.setEventTime<SERIAL>(DISABLED_TIME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1062,5 +1074,31 @@ bool Memory::getMemoryArea(int which, unsigned char **data, int *length) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Memory::LinkStatus(int which)
|
||||||
|
{
|
||||||
|
switch (which)
|
||||||
|
{
|
||||||
|
case 256: // ClockSignaled
|
||||||
|
return linkClockTrigger;
|
||||||
|
case 257: // AckClockSignal
|
||||||
|
linkClockTrigger = false;
|
||||||
|
return 0;
|
||||||
|
case 258: // GetOut
|
||||||
|
return ioamhram[0x101] & 0xff;
|
||||||
|
case 259: // connect link cable
|
||||||
|
LINKCABLE = true;
|
||||||
|
return 0;
|
||||||
|
default: // ShiftIn
|
||||||
|
if (ioamhram[0x102] & 0x80) // was enabled
|
||||||
|
{
|
||||||
|
ioamhram[0x101] = which;
|
||||||
|
ioamhram[0x102] &= 0x7F;
|
||||||
|
intreq.flagIrq(8);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,9 @@ class Memory {
|
||||||
unsigned char serialCnt;
|
unsigned char serialCnt;
|
||||||
bool blanklcd;
|
bool blanklcd;
|
||||||
|
|
||||||
|
bool LINKCABLE;
|
||||||
|
bool linkClockTrigger;
|
||||||
|
|
||||||
void updateInput();
|
void updateInput();
|
||||||
void decEventCycles(MemEventId eventId, unsigned long dec);
|
void decEventCycles(MemEventId eventId, unsigned long dec);
|
||||||
|
|
||||||
|
@ -176,6 +179,8 @@ public:
|
||||||
void setCgbPalette(unsigned *lut);
|
void setCgbPalette(unsigned *lut);
|
||||||
void setGameGenie(const std::string &codes) { cart.setGameGenie(codes); }
|
void setGameGenie(const std::string &codes) { cart.setGameGenie(codes); }
|
||||||
void setGameShark(const std::string &codes) { interrupter.setGameShark(codes); }
|
void setGameShark(const std::string &codes) { interrupter.setGameShark(codes); }
|
||||||
|
|
||||||
|
int LinkStatus(int which);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue