Example #1
0
        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);
        }
Example #2
0
        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);
        }