public BsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm, SnesSettings settings, SnesSyncSettings syncSettings) { _baseRomPath = baseRomPath; var ser = new BasicServiceProvider(this); ServiceProvider = ser; CoreComm = comm; byte[] sgbRomData = null; if (game.System == "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(); } _settings = settings ?? new SnesSettings(); _syncSettings = syncSettings ?? new SnesSyncSettings(); BsnesApi.SnesCallbacks callbacks = new() { inputPollCb = snes_input_poll, inputStateCb = snes_input_state, noLagCb = snes_no_lag, videoFrameCb = snes_video_refresh, audioSampleCb = snes_audio_sample, pathRequestCb = snes_path_request, snesTraceCb = snes_trace }; Api = new BsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, callbacks.AllDelegatesInMemoryOrder()); _controllers = new BsnesControllers(_syncSettings); generate_palette(); // TODO: massive random hack till waterboxhost gets fixed to support 5+ args ushort mergedBools = (ushort)((_syncSettings.Hotfixes ? 1 << 8 : 0) | (_syncSettings.FastPPU ? 1 : 0)); Api.core.snes_init(_syncSettings.Entropy, _syncSettings.LeftPort, _syncSettings.RightPort, mergedBools); Api.SetCallbacks(callbacks); // start up audio resampler InitAudio(); ser.Register <ISoundProvider>(_resampler); if (game.System == "SGB") { IsSGB = true; SystemId = "SNES"; ser.Register <IBoardInfo>(new SGBBoardInfo()); _currLoadParams = new LoadParams { type = LoadParamType.SuperGameBoy, baseRomPath = baseRomPath, romData = sgbRomData, sgbRomData = romData }; } else { // we may need to get some information out of the cart, even during the following bootup/load process if (xmlData != null) { _romxml = new 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 :/ // TODO: uhh i have no idea what the xml is or whether this below code is needed if (_romxml["cartridge"]?["rom"] != null) { romData = File.ReadAllBytes(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, baseRomPath = baseRomPath, romData = romData }; } LoadCurrent(); if (_region == BsnesApi.SNES_REGION.NTSC) { // taken from bsnes source VsyncNumerator = 21477272; VsyncDenominator = 357366; } else { // http://forums.nesdev.com/viewtopic.php?t=5367&start=19 VsyncNumerator = 21281370; VsyncDenominator = 4 * 341 * 312; } SetMemoryDomains(); _tracer = new TraceBuffer { Header = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, B, flags (NVMXDIZC), V, H)" }; ser.Register <IDisassemblable>(new W65816_DisassemblerService()); ser.Register(_tracer); Api.Seal(); }
public BsnesCore(CoreLoadParameters <SnesSettings, SnesSyncSettings> loadParameters) { var ser = new BasicServiceProvider(this); ServiceProvider = ser; this._romPath = Path.Combine(loadParameters.Roms[0].RomDirectory, loadParameters.Game.Name); CoreComm = loadParameters.Comm; _settings = loadParameters.Settings ?? new SnesSettings(); _syncSettings = loadParameters.SyncSettings ?? new SnesSyncSettings(); IsSGB = loadParameters.Game.System == VSystemID.Raw.SGB; byte[] sgbRomData = null; if (IsSGB) { if ((loadParameters.Roms[0].RomData[0x143] & 0xc0) == 0xc0) { throw new CGBNotSupportedException(); } sgbRomData = _syncSettings.UseSGB2 ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB2"), "SGB2 Rom is required for SGB2 emulation.") : CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB"), "SGB1 Rom is required for SGB1 emulation."); loadParameters.Game.FirmwareHash = SHA1Checksum.ComputeDigestHex(sgbRomData); } BsnesApi.SnesCallbacks callbacks = new() { inputPollCb = snes_input_poll, noLagCb = snes_no_lag, controllerLatchCb = snes_controller_latch, videoFrameCb = snes_video_refresh, audioSampleCb = snes_audio_sample, pathRequestCb = snes_path_request, traceCb = snes_trace, readHookCb = ReadHook, writeHookCb = WriteHook, execHookCb = ExecHook, msuOpenCb = msu_open, msuSeekCb = msu_seek, msuReadCb = msu_read, msuEndCb = msu_end }; Api = new BsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, callbacks.AllDelegatesInMemoryOrder()); _controllers = new BsnesControllers(_syncSettings); generate_palette(); BsnesApi.SnesInitData snesInitData = new() { entropy = _syncSettings.Entropy, left_port = _syncSettings.LeftPort, right_port = _syncSettings.RightPort, hotfixes = _syncSettings.Hotfixes, fast_ppu = _syncSettings.FastPPU, fast_dsp = _syncSettings.FastDSP, fast_coprocessors = _syncSettings.FastCoprocessors, region_override = _syncSettings.RegionOverride, }; Api.core.snes_init(ref snesInitData); Api.SetCallbacks(callbacks); // start up audio resampler InitAudio(); ser.Register <ISoundProvider>(_resampler); if (IsSGB) { ser.Register <IBoardInfo>(new SGBBoardInfo()); Api.core.snes_load_cartridge_super_gameboy(sgbRomData, loadParameters.Roms[0].RomData, sgbRomData !.Length, loadParameters.Roms[0].RomData.Length); } else { Api.core.snes_load_cartridge_normal(loadParameters.Roms[0].RomData, loadParameters.Roms[0].RomData.Length); } _region = Api.core.snes_get_region(); if (_region == BsnesApi.SNES_REGION.NTSC) { // taken from bsnes source VsyncNumerator = 21477272; VsyncDenominator = 357366; } else { // http://forums.nesdev.com/viewtopic.php?t=5367&start=19 VsyncNumerator = 21281370; VsyncDenominator = 4 * 341 * 312; } SetMemoryDomains(); const string TRACE_HEADER = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, B, flags (NVMXDIZC), V, H)"; _tracer = new TraceBuffer(TRACE_HEADER); ser.Register <IDisassemblable>(new W65816_DisassemblerService()); ser.Register(_tracer); Api.Seal(); }