public NDS(CoreLoadParameters <NDSSettings, NDSSyncSettings> lp) : base(lp.Comm, new Configuration { DefaultWidth = 256, DefaultHeight = 384, MaxWidth = 256, MaxHeight = 384, MaxSamples = 1024, DefaultFpsNumerator = 33513982, DefaultFpsDenominator = 560190, SystemId = VSystemID.Raw.NDS, }) { var roms = lp.Roms.Select(r => r.RomData).ToList(); if (roms.Count > 3) { throw new InvalidOperationException("Wrong number of ROMs!"); } bool gbacartpresent = roms.Count > 1; bool gbasrampresent = roms.Count == 3; _tracecb = MakeTrace; _core = PreInit <LibMelonDS>(new WaterboxOptions { Filename = "melonDS.wbx", SbrkHeapSizeKB = 2 * 1024, SealedHeapSizeKB = 4, InvisibleHeapSizeKB = 4, PlainHeapSizeKB = 4, MmapHeapSizeKB = 1024 * 1024, SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }, new Delegate[] { _tracecb }); _syncSettings = lp.SyncSettings ?? new NDSSyncSettings(); _settings = lp.Settings ?? new NDSSettings(); var bios7 = _syncSettings.UseRealBIOS ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "bios7")) : null; var bios9 = _syncSettings.UseRealBIOS ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "bios9")) : null; var fw = CoreComm.CoreFileProvider.GetFirmware(new("NDS", "firmware")); bool skipfw = _syncSettings.SkipFirmware || !_syncSettings.UseRealBIOS || fw == null; LibMelonDS.LoadFlags flags = LibMelonDS.LoadFlags.NONE; if (_syncSettings.UseRealBIOS) { flags |= LibMelonDS.LoadFlags.USE_REAL_BIOS; } if (skipfw) { flags |= LibMelonDS.LoadFlags.SKIP_FIRMWARE; } if (gbacartpresent) { flags |= LibMelonDS.LoadFlags.GBA_CART_PRESENT; } if (_settings.AccurateAudioBitrate) { flags |= LibMelonDS.LoadFlags.ACCURATE_AUDIO_BITRATE; } if (_syncSettings.FirmwareOverride || lp.DeterministicEmulationRequested) { flags |= LibMelonDS.LoadFlags.FIRMWARE_OVERRIDE; } var fwSettings = new LibMelonDS.FirmwareSettings(); var name = Encoding.UTF8.GetBytes(_syncSettings.FirmwareUsername); fwSettings.FirmwareUsernameLength = name.Length; fwSettings.FirmwareLanguage = _syncSettings.FirmwareLanguage; if (_syncSettings.FirmwareStartUp == NDSSyncSettings.StartUp.AutoBoot) { fwSettings.FirmwareLanguage |= (NDSSyncSettings.Language) 0x40; } fwSettings.FirmwareBirthdayMonth = _syncSettings.FirmwareBirthdayMonth; fwSettings.FirmwareBirthdayDay = _syncSettings.FirmwareBirthdayDay; fwSettings.FirmwareFavouriteColour = _syncSettings.FirmwareFavouriteColour; var message = _syncSettings.FirmwareMessage.Length != 0 ? Encoding.UTF8.GetBytes(_syncSettings.FirmwareMessage) : new byte[1] { 0 }; fwSettings.FirmwareMessageLength = message.Length; _exe.AddReadonlyFile(roms[0], "game.rom"); if (gbacartpresent) { _exe.AddReadonlyFile(roms[1], "gba.rom"); if (gbasrampresent) { _exe.AddReadonlyFile(roms[2], "gba.ram"); } } if (_syncSettings.UseRealBIOS) { _exe.AddReadonlyFile(bios7, "bios7.rom"); _exe.AddReadonlyFile(bios9, "bios9.rom"); } if (fw != null) { if (NDSFirmware.MaybeWarnIfBadFw(fw, CoreComm)) { if (_syncSettings.FirmwareOverride || lp.DeterministicEmulationRequested) { NDSFirmware.SanitizeFw(fw); } } _exe.AddReadonlyFile(fw, "firmware.bin"); } unsafe { fixed(byte *namePtr = &name[0], messagePtr = &message[0]) { fwSettings.FirmwareUsername = (IntPtr)namePtr; fwSettings.FirmwareMessage = (IntPtr)messagePtr; if (!_core.Init(flags, fwSettings)) { throw new InvalidOperationException("Init returned false!"); } } } _exe.RemoveReadonlyFile("game.rom"); if (gbacartpresent) { _exe.RemoveReadonlyFile("gba.rom"); if (gbasrampresent) { _exe.RemoveReadonlyFile("gba.ram"); } } if (_syncSettings.UseRealBIOS) { _exe.RemoveReadonlyFile("bios7.rom"); _exe.RemoveReadonlyFile("bios9.rom"); } if (fw != null) { _exe.RemoveReadonlyFile("firmware.bin"); } PostInit(); ((MemoryDomainList)this.AsMemoryDomains()).SystemBus = new NDSSystemBus(this.AsMemoryDomains()["ARM9 System Bus"], this.AsMemoryDomains()["ARM7 System Bus"]); DeterministicEmulation = lp.DeterministicEmulationRequested || (!_syncSettings.UseRealTime); InitializeRtc(_syncSettings.InitialTime); _resampler = new SpeexResampler(SpeexResampler.Quality.QUALITY_DEFAULT, 32768, 44100, 32768, 44100, null, this); _serviceProvider.Register <ISoundProvider>(_resampler); _disassembler = new NDSDisassembler(); _serviceProvider.Register <IDisassemblable>(_disassembler); const string TRACE_HEADER = "ARM9+ARM7: PC, opcode, registers (r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, Cy, CpuMode)"; Tracer = new TraceBuffer(TRACE_HEADER); _serviceProvider.Register <ITraceable>(Tracer); }
public NDS(CoreLoadParameters <NDSSettings, NDSSyncSettings> lp) : base(lp.Comm, new Configuration { DefaultWidth = 256, DefaultHeight = 384, MaxWidth = 256, MaxHeight = 384, MaxSamples = 1024, DefaultFpsNumerator = 33513982, DefaultFpsDenominator = 560190, SystemId = VSystemID.Raw.NDS, }) { _syncSettings = lp.SyncSettings ?? new NDSSyncSettings(); _settings = lp.Settings ?? new NDSSettings(); IsDSi = _syncSettings.UseDSi; var roms = lp.Roms.Select(r => r.RomData).ToList(); if (roms.Count > (IsDSi ? 1 : 3)) { throw new InvalidOperationException("Wrong number of ROMs!"); } IsDSiWare = IsDSi && RomIsWare(roms[0]); bool gbacartpresent = roms.Count > 1; bool gbasrampresent = roms.Count == 3; InitMemoryCallbacks(); _tracecb = MakeTrace; _threadstartcb = ThreadStartCallback; _core = PreInit <LibMelonDS>(new WaterboxOptions { Filename = "melonDS.wbx", SbrkHeapSizeKB = 2 * 1024, SealedHeapSizeKB = 4, InvisibleHeapSizeKB = 4 * 1024, PlainHeapSizeKB = 4, MmapHeapSizeKB = 1024 * 1024, SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck), SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck), }, new Delegate[] { _readcb, _writecb, _execcb, _tracecb, _threadstartcb }); var bios7 = IsDSi || _syncSettings.UseRealBIOS ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "bios7")) : null; var bios9 = IsDSi || _syncSettings.UseRealBIOS ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "bios9")) : null; var bios7i = IsDSi ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "bios7i")) : null; var bios9i = IsDSi ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "bios9i")) : null; var nand = IsDSi ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "nand")) : null; var fw = IsDSi ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "firmwarei")) : CoreComm.CoreFileProvider.GetFirmware(new("NDS", "firmware")); var tmd = IsDSi && IsDSiWare ? GetTMDData(roms[0]) : null; bool skipfw = _syncSettings.SkipFirmware || !_syncSettings.UseRealBIOS || fw == null; LibMelonDS.LoadFlags loadFlags = LibMelonDS.LoadFlags.NONE; if (_syncSettings.UseRealBIOS || IsDSi) { loadFlags |= LibMelonDS.LoadFlags.USE_REAL_BIOS; } if (skipfw && !IsDSi) { loadFlags |= LibMelonDS.LoadFlags.SKIP_FIRMWARE; } if (gbacartpresent) { loadFlags |= LibMelonDS.LoadFlags.GBA_CART_PRESENT; } if (_syncSettings.FirmwareOverride || lp.DeterministicEmulationRequested) { loadFlags |= LibMelonDS.LoadFlags.FIRMWARE_OVERRIDE; } if (IsDSi) { loadFlags |= LibMelonDS.LoadFlags.IS_DSI; } if (IsDSi && IsDSiWare) { loadFlags |= LibMelonDS.LoadFlags.LOAD_DSIWARE; } if (_syncSettings.ThreadedRendering) { loadFlags |= LibMelonDS.LoadFlags.THREADED_RENDERING; } var fwSettings = new LibMelonDS.FirmwareSettings(); var name = Encoding.UTF8.GetBytes(_syncSettings.FirmwareUsername); fwSettings.FirmwareUsernameLength = name.Length; fwSettings.FirmwareLanguage = _syncSettings.FirmwareLanguage; if (!IsDSi && _syncSettings.FirmwareStartUp == NDSSyncSettings.StartUp.AutoBoot) { fwSettings.FirmwareLanguage |= (NDSSyncSettings.Language) 0x40; } fwSettings.FirmwareBirthdayMonth = _syncSettings.FirmwareBirthdayMonth; fwSettings.FirmwareBirthdayDay = _syncSettings.FirmwareBirthdayDay; fwSettings.FirmwareFavouriteColour = _syncSettings.FirmwareFavouriteColour; var message = _syncSettings.FirmwareMessage.Length != 0 ? Encoding.UTF8.GetBytes(_syncSettings.FirmwareMessage) : new byte[1] { 0 }; fwSettings.FirmwareMessageLength = message.Length; var loadData = new LibMelonDS.LoadData { DsRomLength = roms[0].Length, GbaRomLength = gbacartpresent ? roms[1].Length : 0, GbaRamLength = gbasrampresent ? roms[2].Length : 0, NandLength = nand?.Length ?? 0, AudioBitrate = _settings.AudioBitrate, }; if (_syncSettings.UseRealBIOS || IsDSi) { _exe.AddReadonlyFile(bios7, "bios7.rom"); _exe.AddReadonlyFile(bios9, "bios9.rom"); } if (IsDSi) { _exe.AddReadonlyFile(bios7i, "bios7i.rom"); _exe.AddReadonlyFile(bios9i, "bios9i.rom"); if (IsDSiWare) { _exe.AddReadonlyFile(roms[0], "dsiware.rom"); } } if (fw != null) { if (IsDSi || NDSFirmware.MaybeWarnIfBadFw(fw, CoreComm)) // fw checks dont work on dsi firmware, don't bother { if (_syncSettings.FirmwareOverride || lp.DeterministicEmulationRequested) { NDSFirmware.SanitizeFw(fw); } } _exe.AddReadonlyFile(fw, IsDSi ? "firmwarei.bin" : "firmware.bin"); } unsafe { fixed(byte * dsRomPtr = roms[0], gbaRomPtr = gbacartpresent?roms[1] : null, gbaRamPtr = gbasrampresent?roms[2] : null, nandPtr = nand, tmdPtr = tmd, namePtr = name, messagePtr = message) { loadData.DsRomData = (IntPtr)dsRomPtr; loadData.GbaRomData = (IntPtr)gbaRomPtr; loadData.GbaRamData = (IntPtr)gbaRamPtr; loadData.NandData = (IntPtr)nandPtr; loadData.TmdData = (IntPtr)tmdPtr; fwSettings.FirmwareUsername = (IntPtr)namePtr; fwSettings.FirmwareMessage = (IntPtr)messagePtr; if (!_core.Init(loadFlags, ref loadData, ref fwSettings)) { throw new InvalidOperationException("Init returned false!"); } } } if (fw != null) { _exe.RemoveReadonlyFile(IsDSi ? "firmwarei.bin" : "firmware.bin"); } if (IsDSi && IsDSiWare) { _exe.RemoveReadonlyFile("dsiware.rom"); } PostInit(); ((MemoryDomainList)this.AsMemoryDomains()).SystemBus = new NDSSystemBus(this.AsMemoryDomains()["ARM9 System Bus"], this.AsMemoryDomains()["ARM7 System Bus"]); DeterministicEmulation = lp.DeterministicEmulationRequested || (!_syncSettings.UseRealTime); InitializeRtc(_syncSettings.InitialTime); _frameThreadPtr = _core.GetFrameThreadProc(); if (_frameThreadPtr != IntPtr.Zero) { Console.WriteLine($"Setting up waterbox thread for 0x{_frameThreadPtr:X16}"); _frameThreadStart = CallingConventionAdapters.GetWaterboxUnsafeUnwrapped().GetDelegateForFunctionPointer <Action>(_frameThreadPtr); _core.SetThreadStartCallback(_threadstartcb); } _resampler = new SpeexResampler(SpeexResampler.Quality.QUALITY_DEFAULT, 32768, 44100, 32768, 44100, null, this); _serviceProvider.Register <ISoundProvider>(_resampler); _disassembler = new NDSDisassembler(); _serviceProvider.Register <IDisassemblable>(_disassembler); const string TRACE_HEADER = "ARM9+ARM7: PC, opcode, registers (r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, Cy, CpuMode)"; Tracer = new TraceBuffer(TRACE_HEADER); _serviceProvider.Register(Tracer); }