예제 #1
0
        protected T PreInit <T>(WaterboxOptions options, IEnumerable <Delegate> allExtraDelegates = null)
            where T : LibWaterboxCore
        {
            options.Path ??= CoreComm.CoreFileProvider.DllPath();
            _exe = new WaterboxHost(options);
            var delegates = new Delegate[] { _inputCallback }.AsEnumerable();

            if (allExtraDelegates != null)
            {
                delegates = delegates.Concat(allExtraDelegates);
            }
            using (_exe.EnterExit())
            {
                var ret = BizInvoker.GetInvoker <T>(_exe, _exe, CallingConventionAdapters.MakeWaterbox(delegates, _exe));
                _core = ret;
                return(ret);
            }
        }
예제 #2
0
파일: LibsnesApi.cs 프로젝트: zcatt/BizHawk
 public LibsnesApi(string dllPath, CoreComm comm, IEnumerable <Delegate> allCallbacks)
 {
     _exe = new WaterboxHost(new WaterboxOptions
     {
         Filename                   = "libsnes.wbx",
         Path                       = dllPath,
         SbrkHeapSizeKB             = 4 * 1024,
         InvisibleHeapSizeKB        = 8 * 1024,
         MmapHeapSizeKB             = 32 * 1024,     // TODO: see if we can safely make libco stacks smaller
         PlainHeapSizeKB            = 2 * 1024,      // TODO: wasn't there more in here?
         SealedHeapSizeKB           = 128 * 1024,
         SkipCoreConsistencyCheck   = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
         SkipMemoryConsistencyCheck = comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
     });
     using (_exe.EnterExit())
     {
         // Marshal checks that function pointers passed to GetDelegateForFunctionPointer are
         // _currently_ valid when created, even though they don't need to be valid until
         // the delegate is later invoked.  so GetInvoker needs to be acquired within a lock.
         _core = BizInvoker.GetInvoker <CoreImpl>(_exe, _exe, CallingConventionAdapters.MakeWaterbox(allCallbacks, _exe));
         _comm = (CommStruct *)_core.DllInit().ToPointer();
     }
 }
예제 #3
0
        public GPGX(CoreLoadParameters <GPGXSettings, GPGXSyncSettings> lp)
        {
            LoadCallback   = new LibGPGX.load_archive_cb(load_archive);
            _inputCallback = new LibGPGX.input_cb(input_callback);
            InitMemCallbacks();             // ExecCallback, ReadCallback, WriteCallback
            CDCallback         = new LibGPGX.CDCallback(CDCallbackProc);
            cd_callback_handle = new LibGPGX.cd_read_cb(CDRead);

            ServiceProvider = new BasicServiceProvider(this);
            // this can influence some things internally (autodetect romtype, etc)
            string romextension = "GEN";

            // three or six button?
            // http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds

            //hack, don't use
            if (lp.Roms.FirstOrDefault()?.RomData.Length > 32 * 1024 * 1024)
            {
                throw new InvalidOperationException("ROM too big!  Did you try to load a CD as a ROM?");
            }

            _elf = new WaterboxHost(new WaterboxOptions
            {
                Path                       = lp.Comm.CoreFileProvider.DllPath(),
                Filename                   = "gpgx.wbx",
                SbrkHeapSizeKB             = 512,
                SealedHeapSizeKB           = 4 * 1024,
                InvisibleHeapSizeKB        = 4 * 1024,
                PlainHeapSizeKB            = 34 * 1024,
                MmapHeapSizeKB             = 1 * 1024,
                SkipCoreConsistencyCheck   = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
                SkipMemoryConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
            });

            var callingConventionAdapter = CallingConventionAdapters.MakeWaterbox(new Delegate[]
            {
                LoadCallback, _inputCallback, ExecCallback, ReadCallback, WriteCallback,
                CDCallback, cd_callback_handle,
            }, _elf);

            using (_elf.EnterExit())
            {
                Core          = BizInvoker.GetInvoker <LibGPGX>(_elf, _elf, callingConventionAdapter);
                _syncSettings = lp.SyncSettings ?? new GPGXSyncSettings();
                _settings     = lp.Settings ?? new GPGXSettings();

                CoreComm = lp.Comm;

                _romfile = lp.Roms.FirstOrDefault()?.RomData;

                if (lp.Discs.Count > 0)
                {
                    _cds       = lp.Discs.Select(d => d.DiscData).ToArray();
                    _cdReaders = _cds.Select(c => new DiscSectorReader(c)).ToArray();
                    Core.gpgx_set_cdd_callback(cd_callback_handle);
                    DriveLightEnabled = true;
                }

                LibGPGX.INPUT_SYSTEM system_a = SystemForSystem(_syncSettings.ControlTypeLeft);
                LibGPGX.INPUT_SYSTEM system_b = SystemForSystem(_syncSettings.ControlTypeRight);

                var initResult = Core.gpgx_init(romextension, LoadCallback, _syncSettings.GetNativeSettings(lp.Game));

                if (!initResult)
                {
                    throw new Exception($"{nameof(Core.gpgx_init)}() failed");
                }

                {
                    int fpsnum = 60;
                    int fpsden = 1;
                    Core.gpgx_get_fps(ref fpsnum, ref fpsden);
                    VsyncNumerator   = fpsnum;
                    VsyncDenominator = fpsden;
                    Region           = VsyncNumerator / VsyncDenominator > 55 ? DisplayType.NTSC : DisplayType.PAL;
                }

                // when we call Seal, ANY pointer passed from managed code must be 0.
                // this is so the initial state is clean
                // the only two pointers set so far are LoadCallback, which the core zeroed itself,
                // and CdCallback
                Core.gpgx_set_cdd_callback(null);
                _elf.Seal();
                Core.gpgx_set_cdd_callback(cd_callback_handle);

                SetControllerDefinition();

                // pull the default video size from the core
                UpdateVideo();

                SetMemoryDomains();

                Core.gpgx_set_input_callback(_inputCallback);

                // process the non-init settings now
                PutSettings(_settings);

                KillMemCallbacks();

                _tracer = new GPGXTraceBuffer(this, _memoryDomains, this);
                (ServiceProvider as BasicServiceProvider).Register <ITraceable>(_tracer);
            }

            _romfile = null;
        }
예제 #4
0
        protected T DoInit <T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension, bool deterministic,
                               IDictionary <string, FirmwareID> firmwares = null)
            where T : LibNymaCore
        {
            _settingsQueryDelegate = SettingsQuery;
            _cdTocCallback         = CDTOCCallback;
            _cdSectorCallback      = CDSectorCallback;

            var filesToRemove = new List <string>();

            var firmwareDelegate = new LibNymaCore.FrontendFirmwareNotify((name) =>
            {
                if (firmwares != null && firmwares.TryGetValue(name, out var id))
                {
                    var data = CoreComm.CoreFileProvider.GetFirmwareOrThrow(id, "Firmware files are usually required and may stop your game from loading");
                    _exe.AddReadonlyFile(data, name);
                    filesToRemove.Add(name);
                }
                else
                {
                    throw new InvalidOperationException($"Core asked for firmware `{name}`, but that was not understood by the system");
                }
            });

            var t = PreInit <T>(new WaterboxOptions
            {
                Filename = wbxFilename,
                // WaterboxHost only saves parts of memory that have changed, so not much to be gained by making these precisely sized
                SbrkHeapSizeKB             = 1024 * 16,
                SealedHeapSizeKB           = 1024 * 48,
                InvisibleHeapSizeKB        = 1024 * 48,
                PlainHeapSizeKB            = 1024 * 48,
                MmapHeapSizeKB             = 1024 * 48,
                SkipCoreConsistencyCheck   = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
                SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
            }, new Delegate[] { _settingsQueryDelegate, _cdTocCallback, _cdSectorCallback, firmwareDelegate });

            _nyma = t;

            using (_exe.EnterExit())
            {
                _nyma.PreInit();
                _nyma.SetFrontendFirmwareNotify(firmwareDelegate);
                var portData = GetInputPortsData();
                InitAllSettingsInfo(portData);
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);

                if (discs?.Length > 0)
                {
                    _disks       = discs;
                    _diskReaders = _disks.Select(d => new DiscSectorReader(d)
                    {
                        Policy = _diskPolicy
                    }).ToArray();
                    _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                    var didInit = _nyma.InitCd(_disks.Length);
                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the CDs!");
                    }
                }
                else
                {
                    var fn = game.FilesystemSafeName();
                    _exe.AddReadonlyFile(rom, fn);

                    var didInit = _nyma.InitRom(new LibNymaCore.InitData
                    {
                        // TODO: Set these as some cores need them
                        FileNameBase = "",
                        FileNameExt  = extension.Trim('.').ToLowerInvariant(),
                        FileNameFull = fn
                    });

                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the rom!");
                    }

                    _exe.RemoveReadonlyFile(fn);
                }

                foreach (var s in filesToRemove)
                {
                    _exe.RemoveReadonlyFile(s);
                }
                // any later attempts to request a firmware will crash
                _nyma.SetFrontendFirmwareNotify(null);

                var info = *_nyma.GetSystemInfo();
                _videoBuffer       = new int[Math.Max(info.MaxWidth * info.MaxHeight, info.LcmWidth * info.LcmHeight)];
                BufferWidth        = info.NominalWidth;
                BufferHeight       = info.NominalHeight;
                _mdfnNominalWidth  = info.NominalWidth;
                _mdfnNominalHeight = info.NominalHeight;
                switch (info.VideoSystem)
                {
                // TODO: There seriously isn't any region besides these?
                case LibNymaCore.VideoSystem.PAL:
                case LibNymaCore.VideoSystem.SECAM:
                    Region = DisplayType.PAL;
                    break;

                case LibNymaCore.VideoSystem.PAL_M:
                    Region = DisplayType.Dendy;                             // sort of...
                    break;

                default:
                    Region = DisplayType.NTSC;
                    break;
                }
                VsyncNumerator   = info.FpsFixed;
                VsyncDenominator = 1 << 24;
                _soundBuffer     = new short[22050 * 2];

                InitControls(portData, discs?.Length > 0, ref info);
                PostInit();
                SettingsInfo.LayerNames = GetLayerData();
                _settings.Normalize(SettingsInfo);
                _syncSettings.Normalize(SettingsInfo);
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
                if (_disks != null)
                {
                    _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                }
                PutSettings(_settings);
                DateTime RtcStart = DateTime.Parse("2010-01-01");
                try
                {
                    RtcStart = DateTime.Parse(SettingsQuery("nyma.rtcinitialtime"));
                }
                catch
                {
                    Console.Error.WriteLine($"Couldn't parse DateTime \"{SettingsQuery("nyma.rtcinitialtime")}\"");
                }
                // Don't optimistically set deterministic, as some cores like faust can change this
                DeterministicEmulation = deterministic;                 // || SettingsQuery("nyma.rtcrealtime") == "0";
                InitializeRtc(RtcStart);
                _frameThreadPtr = _nyma.GetFrameThreadProc();
                if (_frameThreadPtr != IntPtr.Zero)
                {
                    // This will probably be fine, right?  TODO: Revisit
                    // if (deterministic)
                    //  throw new InvalidOperationException("Internal error: Core set a frame thread proc in deterministic mode");
                    Console.WriteLine($"Setting up waterbox thread for {_frameThreadPtr}");
                    _frameThreadStart = CallingConventionAdapters.GetWaterboxUnsafeUnwrapped().GetDelegateForFunctionPointer <Action>(_frameThreadPtr);
                }
            }

            return(t);
        }
 public static MemoryDomainAccessStub Create(IntPtr p, WaterboxHost host)
 {
     return(BizInvoker.GetInvoker <MemoryDomainAccessStub>(
                new StubResolver(p), host, CallingConventionAdapters.MakeWaterboxDepartureOnly(host)));
 }
예제 #6
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);
        }