LibsnesCore.cs - move ScnalineHookManager to the button of the file, and the constructor of LibsnesCore to the top of the object, so it isn't so annoying to find it
This commit is contained in:
parent
315316210d
commit
21dad476a8
|
@ -21,43 +21,6 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||
{
|
||||
public class ScanlineHookManager
|
||||
{
|
||||
public void Register(object tag, Action<int> callback)
|
||||
{
|
||||
var rr = new RegistrationRecord();
|
||||
rr.tag = tag;
|
||||
rr.callback = callback;
|
||||
|
||||
Unregister(tag);
|
||||
records.Add(rr);
|
||||
OnHooksChanged();
|
||||
}
|
||||
|
||||
public int HookCount { get { return records.Count; } }
|
||||
|
||||
public virtual void OnHooksChanged() { }
|
||||
|
||||
public void Unregister(object tag)
|
||||
{
|
||||
records.RemoveAll((r) => r.tag == tag);
|
||||
}
|
||||
|
||||
public void HandleScanline(int scanline)
|
||||
{
|
||||
foreach (var rr in records) rr.callback(scanline);
|
||||
}
|
||||
|
||||
List<RegistrationRecord> records = new List<RegistrationRecord>();
|
||||
|
||||
class RegistrationRecord
|
||||
{
|
||||
public object tag;
|
||||
public int scanline = 0;
|
||||
public Action<int> callback;
|
||||
}
|
||||
}
|
||||
|
||||
[CoreAttributes(
|
||||
"BSNES",
|
||||
"byuu",
|
||||
|
@ -69,6 +32,138 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|||
public unsafe class LibsnesCore : IEmulator, IVideoProvider, IMemoryDomains,
|
||||
IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>
|
||||
{
|
||||
public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings)
|
||||
{
|
||||
CoreComm = comm;
|
||||
byte[] sgbRomData = null;
|
||||
if (game["SGB"])
|
||||
{
|
||||
if ((romData[0x143] & 0xc0) == 0xc0)
|
||||
throw new CGBNotSupportedException();
|
||||
sgbRomData = CoreComm.CoreFileProvider.GetFirmware("SNES", "Rom_SGB", true, "SGB Rom is required for SGB emulation.");
|
||||
game.FirmwareHash = sgbRomData.HashSHA1();
|
||||
}
|
||||
|
||||
this.Settings = (SnesSettings)Settings ?? new SnesSettings();
|
||||
this.SyncSettings = (SnesSyncSettings)SyncSettings ?? new SnesSyncSettings();
|
||||
|
||||
api = new LibsnesApi(GetExePath());
|
||||
api.CMD_init();
|
||||
api.ReadHook = ReadHook;
|
||||
api.ExecHook = ExecHook;
|
||||
api.WriteHook = WriteHook;
|
||||
|
||||
ScanlineHookManager = new MyScanlineHookManager(this);
|
||||
|
||||
api.CMD_init();
|
||||
|
||||
api.QUERY_set_video_refresh(snes_video_refresh);
|
||||
api.QUERY_set_input_poll(snes_input_poll);
|
||||
api.QUERY_set_input_state(snes_input_state);
|
||||
api.QUERY_set_input_notify(snes_input_notify);
|
||||
api.QUERY_set_path_request(snes_path_request);
|
||||
|
||||
scanlineStart_cb = new LibsnesApi.snes_scanlineStart_t(snes_scanlineStart);
|
||||
tracecb = new LibsnesApi.snes_trace_t(snes_trace);
|
||||
|
||||
soundcb = new LibsnesApi.snes_audio_sample_t(snes_audio_sample);
|
||||
api.QUERY_set_audio_sample(soundcb);
|
||||
|
||||
RefreshPalette();
|
||||
|
||||
// start up audio resampler
|
||||
InitAudio();
|
||||
|
||||
//strip header
|
||||
if (romData != null)
|
||||
if ((romData.Length & 0x7FFF) == 512)
|
||||
{
|
||||
var newData = new byte[romData.Length - 512];
|
||||
Array.Copy(romData, 512, newData, 0, newData.Length);
|
||||
romData = newData;
|
||||
}
|
||||
|
||||
if (game["SGB"])
|
||||
{
|
||||
IsSGB = true;
|
||||
SystemId = "SNES";
|
||||
BoardName = "SGB";
|
||||
|
||||
CurrLoadParams = new LoadParams()
|
||||
{
|
||||
type = LoadParamType.SuperGameBoy,
|
||||
rom_xml = null,
|
||||
rom_data = sgbRomData,
|
||||
rom_size = (uint)sgbRomData.Length,
|
||||
dmg_xml = null,
|
||||
dmg_data = romData,
|
||||
dmg_size = (uint)romData.Length
|
||||
};
|
||||
|
||||
if (!LoadCurrent())
|
||||
throw new Exception("snes_load_cartridge_normal() failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
//we may need to get some information out of the cart, even during the following bootup/load process
|
||||
if (xmlData != null)
|
||||
{
|
||||
romxml = new System.Xml.XmlDocument();
|
||||
romxml.Load(new MemoryStream(xmlData));
|
||||
|
||||
//bsnes wont inspect the xml to load the necessary sfc file.
|
||||
//so, we have to do that here and pass it in as the romData :/
|
||||
if (romxml["cartridge"] != null && romxml["cartridge"]["rom"] != null)
|
||||
romData = File.ReadAllBytes(CoreComm.CoreFileProvider.PathSubfile(romxml["cartridge"]["rom"].Attributes["name"].Value));
|
||||
else
|
||||
throw new Exception("Could not find rom file specification in xml file. Please check the integrity of your xml file");
|
||||
}
|
||||
|
||||
SystemId = "SNES";
|
||||
CurrLoadParams = new LoadParams()
|
||||
{
|
||||
type = LoadParamType.Normal,
|
||||
xml_data = xmlData,
|
||||
rom_data = romData
|
||||
};
|
||||
|
||||
if (!LoadCurrent())
|
||||
throw new Exception("snes_load_cartridge_normal() failed");
|
||||
}
|
||||
|
||||
if (api.QUERY_get_region() == LibsnesApi.SNES_REGION.NTSC)
|
||||
{
|
||||
//similar to what aviout reports from snes9x and seems logical from bsnes first principles. bsnes uses that numerator (ntsc master clockrate) for sure.
|
||||
CoreComm.VsyncNum = 21477272;
|
||||
CoreComm.VsyncDen = 4 * 341 * 262;
|
||||
}
|
||||
else
|
||||
{
|
||||
//http://forums.nesdev.com/viewtopic.php?t=5367&start=19
|
||||
CoreComm.VsyncNum = 21281370;
|
||||
CoreComm.VsyncDen = 4 * 341 * 312;
|
||||
}
|
||||
|
||||
CoreComm.CpuTraceAvailable = true;
|
||||
|
||||
api.CMD_power();
|
||||
|
||||
SetupMemoryDomains(romData, sgbRomData);
|
||||
|
||||
DeterministicEmulation = deterministicEmulation;
|
||||
if (DeterministicEmulation) // save frame-0 savestate now
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
bw.Write(CoreSaveState());
|
||||
bw.Write(true); // framezero, so no controller follows and don't frameadvance on load
|
||||
// hack: write fake dummy controller info
|
||||
bw.Write(new byte[536]);
|
||||
bw.Close();
|
||||
savestatebuff = ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSGB { get; private set; }
|
||||
|
||||
/// <summary>disable all external callbacks. the front end should not even know the core is frame advancing</summary>
|
||||
|
@ -315,138 +410,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|||
else return api.CMD_load_cartridge_super_game_boy(CurrLoadParams.rom_xml, CurrLoadParams.rom_data, CurrLoadParams.rom_size, CurrLoadParams.dmg_xml, CurrLoadParams.dmg_data, CurrLoadParams.dmg_size);
|
||||
}
|
||||
|
||||
public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings)
|
||||
{
|
||||
CoreComm = comm;
|
||||
byte[] sgbRomData = null;
|
||||
if (game["SGB"])
|
||||
{
|
||||
if ((romData[0x143] & 0xc0) == 0xc0)
|
||||
throw new CGBNotSupportedException();
|
||||
sgbRomData = CoreComm.CoreFileProvider.GetFirmware("SNES", "Rom_SGB", true, "SGB Rom is required for SGB emulation.");
|
||||
game.FirmwareHash = sgbRomData.HashSHA1();
|
||||
}
|
||||
|
||||
this.Settings = (SnesSettings)Settings ?? new SnesSettings();
|
||||
this.SyncSettings = (SnesSyncSettings)SyncSettings ?? new SnesSyncSettings();
|
||||
|
||||
api = new LibsnesApi(GetExePath());
|
||||
api.CMD_init();
|
||||
api.ReadHook = ReadHook;
|
||||
api.ExecHook = ExecHook;
|
||||
api.WriteHook = WriteHook;
|
||||
|
||||
ScanlineHookManager = new MyScanlineHookManager(this);
|
||||
|
||||
api.CMD_init();
|
||||
|
||||
api.QUERY_set_video_refresh(snes_video_refresh);
|
||||
api.QUERY_set_input_poll(snes_input_poll);
|
||||
api.QUERY_set_input_state(snes_input_state);
|
||||
api.QUERY_set_input_notify(snes_input_notify);
|
||||
api.QUERY_set_path_request(snes_path_request);
|
||||
|
||||
scanlineStart_cb = new LibsnesApi.snes_scanlineStart_t(snes_scanlineStart);
|
||||
tracecb = new LibsnesApi.snes_trace_t(snes_trace);
|
||||
|
||||
soundcb = new LibsnesApi.snes_audio_sample_t(snes_audio_sample);
|
||||
api.QUERY_set_audio_sample(soundcb);
|
||||
|
||||
RefreshPalette();
|
||||
|
||||
// start up audio resampler
|
||||
InitAudio();
|
||||
|
||||
//strip header
|
||||
if(romData != null)
|
||||
if ((romData.Length & 0x7FFF) == 512)
|
||||
{
|
||||
var newData = new byte[romData.Length - 512];
|
||||
Array.Copy(romData, 512, newData, 0, newData.Length);
|
||||
romData = newData;
|
||||
}
|
||||
|
||||
if (game["SGB"])
|
||||
{
|
||||
IsSGB = true;
|
||||
SystemId = "SNES";
|
||||
BoardName = "SGB";
|
||||
|
||||
CurrLoadParams = new LoadParams()
|
||||
{
|
||||
type = LoadParamType.SuperGameBoy,
|
||||
rom_xml = null,
|
||||
rom_data = sgbRomData,
|
||||
rom_size = (uint)sgbRomData.Length,
|
||||
dmg_xml = null,
|
||||
dmg_data = romData,
|
||||
dmg_size = (uint)romData.Length
|
||||
};
|
||||
|
||||
if (!LoadCurrent())
|
||||
throw new Exception("snes_load_cartridge_normal() failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
//we may need to get some information out of the cart, even during the following bootup/load process
|
||||
if (xmlData != null)
|
||||
{
|
||||
romxml = new System.Xml.XmlDocument();
|
||||
romxml.Load(new MemoryStream(xmlData));
|
||||
|
||||
//bsnes wont inspect the xml to load the necessary sfc file.
|
||||
//so, we have to do that here and pass it in as the romData :/
|
||||
if (romxml["cartridge"] != null && romxml["cartridge"]["rom"] != null)
|
||||
romData = File.ReadAllBytes(CoreComm.CoreFileProvider.PathSubfile(romxml["cartridge"]["rom"].Attributes["name"].Value));
|
||||
else
|
||||
throw new Exception("Could not find rom file specification in xml file. Please check the integrity of your xml file");
|
||||
}
|
||||
|
||||
SystemId = "SNES";
|
||||
CurrLoadParams = new LoadParams()
|
||||
{
|
||||
type = LoadParamType.Normal,
|
||||
xml_data = xmlData,
|
||||
rom_data = romData
|
||||
};
|
||||
|
||||
if(!LoadCurrent())
|
||||
throw new Exception("snes_load_cartridge_normal() failed");
|
||||
}
|
||||
|
||||
if (api.QUERY_get_region() == LibsnesApi.SNES_REGION.NTSC)
|
||||
{
|
||||
//similar to what aviout reports from snes9x and seems logical from bsnes first principles. bsnes uses that numerator (ntsc master clockrate) for sure.
|
||||
CoreComm.VsyncNum = 21477272;
|
||||
CoreComm.VsyncDen = 4 * 341 * 262;
|
||||
}
|
||||
else
|
||||
{
|
||||
//http://forums.nesdev.com/viewtopic.php?t=5367&start=19
|
||||
CoreComm.VsyncNum = 21281370;
|
||||
CoreComm.VsyncDen = 4 * 341 * 312;
|
||||
}
|
||||
|
||||
CoreComm.CpuTraceAvailable = true;
|
||||
|
||||
api.CMD_power();
|
||||
|
||||
SetupMemoryDomains(romData,sgbRomData);
|
||||
|
||||
DeterministicEmulation = deterministicEmulation;
|
||||
if (DeterministicEmulation) // save frame-0 savestate now
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
bw.Write(CoreSaveState());
|
||||
bw.Write(true); // framezero, so no controller follows and don't frameadvance on load
|
||||
// hack: write fake dummy controller info
|
||||
bw.Write(new byte[536]);
|
||||
bw.Close();
|
||||
savestatebuff = ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -1236,4 +1199,41 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ScanlineHookManager
|
||||
{
|
||||
public void Register(object tag, Action<int> callback)
|
||||
{
|
||||
var rr = new RegistrationRecord();
|
||||
rr.tag = tag;
|
||||
rr.callback = callback;
|
||||
|
||||
Unregister(tag);
|
||||
records.Add(rr);
|
||||
OnHooksChanged();
|
||||
}
|
||||
|
||||
public int HookCount { get { return records.Count; } }
|
||||
|
||||
public virtual void OnHooksChanged() { }
|
||||
|
||||
public void Unregister(object tag)
|
||||
{
|
||||
records.RemoveAll((r) => r.tag == tag);
|
||||
}
|
||||
|
||||
public void HandleScanline(int scanline)
|
||||
{
|
||||
foreach (var rr in records) rr.callback(scanline);
|
||||
}
|
||||
|
||||
List<RegistrationRecord> records = new List<RegistrationRecord>();
|
||||
|
||||
class RegistrationRecord
|
||||
{
|
||||
public object tag;
|
||||
public int scanline = 0;
|
||||
public Action<int> callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue