public Sameboy(CoreComm comm, GameInfo game, byte[] file, SameboySettings settings, SameboySyncSettings syncSettings, bool deterministic) { _serviceProvider = new BasicServiceProvider(this); _settings = settings ?? new SameboySettings(); _syncSettings = syncSettings ?? new SameboySyncSettings(); var model = _syncSettings.ConsoleMode; if (model is SameboySyncSettings.GBModel.Auto) { model = game.System == VSystemID.Raw.GBC ? SameboySyncSettings.GBModel.GB_MODEL_CGB_E : SameboySyncSettings.GBModel.GB_MODEL_DMG_B; } IsCgb = model >= SameboySyncSettings.GBModel.GB_MODEL_CGB_0; byte[] bios; if (_syncSettings.EnableBIOS) { FirmwareID fwid = new( IsCgb ? "GBC" : "GB", _syncSettings.ConsoleMode is SameboySyncSettings.GBModel.GB_MODEL_AGB ? "AGB" : "World"); bios = comm.CoreFileProvider.GetFirmwareOrThrow(fwid, "BIOS Not Found, Cannot Load. Change SyncSettings to run without BIOS."); } else { bios = Util.DecompressGzipFile(new MemoryStream(IsCgb ? _syncSettings.ConsoleMode is SameboySyncSettings.GBModel.GB_MODEL_AGB ? Resources.SameboyAgbBoot.Value : Resources.SameboyCgbBoot.Value : Resources.SameboyDmgBoot.Value)); } DeterministicEmulation = false; bool realtime = true; if (!_syncSettings.UseRealTime || deterministic) { realtime = false; DeterministicEmulation = true; } SameboyState = LibSameboy.sameboy_create(file, file.Length, bios, bios.Length, model, realtime); InitMemoryDomains(); InitMemoryCallbacks(); _samplecb = QueueSample; LibSameboy.sameboy_setsamplecallback(SameboyState, _samplecb); _inputcb = InputCallback; LibSameboy.sameboy_setinputcallback(SameboyState, _inputcb); _tracecb = MakeTrace; LibSameboy.sameboy_settracecallback(SameboyState, null); LibSameboy.sameboy_setscanlinecallback(SameboyState, null, 0); LibSameboy.sameboy_setprintercallback(SameboyState, null); const string TRACE_HEADER = "SM83: PC, opcode, registers (A, F, B, C, D, E, H, L, SP, LY, CY)"; Tracer = new TraceBuffer(TRACE_HEADER); _serviceProvider.Register(Tracer); _disassembler = new Gameboy.GBDisassembler(); _serviceProvider.Register <IDisassemblable>(_disassembler); PutSettings(_settings); _stateBuf = new byte[LibSameboy.sameboy_statelen(SameboyState)]; RomDetails = $"{game.Name}\r\n{SHA1Checksum.ComputePrefixedHex(file)}\r\n{MD5Checksum.ComputePrefixedHex(file)}\r\n"; BoardName = MapperName(file); _hasAcc = BoardName is "MBC7 ROM+ACCEL+EEPROM"; ControllerDefinition = Gameboy.Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: _hasAcc); LibSameboy.sameboy_setrtcdivisoroffset(SameboyState, _syncSettings.RTCDivisorOffset); CycleCount = 0; }
public O2Hawk(CoreComm comm, GameInfo game, byte[] rom, O2Settings settings, O2SyncSettings syncSettings) { var ser = new BasicServiceProvider(this); cpu = new I8048 { ReadMemory = ReadMemory, WriteMemory = WriteMemory, PeekMemory = PeekMemory, DummyReadMemory = ReadMemory, ReadPort = ReadPort, WritePort = WritePort, OnExecFetch = ExecFetch, }; _settings = settings ?? new O2Settings(); _syncSettings = syncSettings ?? new O2SyncSettings(); is_G7400 = _syncSettings.G7400_Enable; _controllerDeck = new O2HawkControllerDeck("O2 Controller", "O2 Controller", is_G7400); _bios = comm.CoreFileProvider.GetFirmwareOrThrow(new("O2", is_G7400 ? "BIOS-G7400" : "BIOS-O2"), "BIOS Not Found, Cannot Load"); Buffer.BlockCopy(rom, 0x100, header, 0, 0x50); Console.WriteLine(MD5Checksum.ComputePrefixedHex(rom)); Console.WriteLine(SHA1Checksum.ComputePrefixedHex(rom)); _rom = rom; if (game["XROM"]) { is_XROM = true; } Setup_Mapper(); _frameHz = 60; ser.Register <IVideoProvider>(this); ServiceProvider = ser; _tracer = new TraceBuffer(cpu.TraceHeader); ser.Register(_tracer); ser.Register <IStatable>(new StateSerializer(SyncState)); SetupMemoryDomains(); cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory); // set up differences between PAL and NTSC systems if ((game.Region == "US" || game.Region == "EU-US" || game.Region == null) && !is_G7400) { is_pal = false; pic_height = 240; _frameHz = 60; ppu = new NTSC_PPU(); } else { is_pal = true; pic_height = 240; _frameHz = 50; ppu = new PAL_PPU(); } ppu.Core = this; ppu.set_region(is_pal, is_G7400); ser.Register <ISoundProvider>(ppu); _vidbuffer = new int[372 * pic_height]; frame_buffer = new int[320 * pic_height]; HardReset(); }
public Gameboy(CoreComm comm, GameInfo game, byte[] file, GambatteSettings settings, GambatteSyncSettings syncSettings, bool deterministic) { var ser = new BasicServiceProvider(this); ser.Register <IDisassemblable>(_disassembler); ServiceProvider = ser; const string TRACE_HEADER = "LR35902: PC, opcode, registers (A, F, B, C, D, E, H, L, LY, SP, CY)"; Tracer = new TraceBuffer(TRACE_HEADER); ser.Register <ITraceable>(Tracer); InitMemoryCallbacks(); DeterministicEmulation = deterministic; GambatteState = LibGambatte.gambatte_create(); if (GambatteState == IntPtr.Zero) { throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_create)}() returned null???"); } Console.WriteLine(game.System); try { _syncSettings = syncSettings ?? new GambatteSyncSettings(); LibGambatte.LoadFlags flags = LibGambatte.LoadFlags.READONLY_SAV; switch (_syncSettings.ConsoleMode) { case GambatteSyncSettings.ConsoleModeType.GB: break; case GambatteSyncSettings.ConsoleModeType.GBC: flags |= LibGambatte.LoadFlags.CGB_MODE; break; case GambatteSyncSettings.ConsoleModeType.GBA: flags |= LibGambatte.LoadFlags.CGB_MODE | LibGambatte.LoadFlags.GBA_FLAG; break; default: if (game.System == VSystemID.Raw.GBC) { flags |= LibGambatte.LoadFlags.CGB_MODE; } break; } if (game.System == VSystemID.Raw.SGB) { flags &= ~(LibGambatte.LoadFlags.CGB_MODE | LibGambatte.LoadFlags.GBA_FLAG); flags |= LibGambatte.LoadFlags.SGB_MODE; IsSgb = true; } IsCgb = (flags & LibGambatte.LoadFlags.CGB_MODE) == LibGambatte.LoadFlags.CGB_MODE; if (_syncSettings.EnableBIOS) { FirmwareID fwid = new( IsCgb ? "GBC" : "GB", IsSgb ? "SGB2" : _syncSettings.ConsoleMode is GambatteSyncSettings.ConsoleModeType.GBA ? "AGB" : "World"); var bios = comm.CoreFileProvider.GetFirmwareOrThrow(fwid, "BIOS Not Found, Cannot Load. Change SyncSettings to run without BIOS."); // https://github.com/TASEmulators/BizHawk/issues/2832 tho if (LibGambatte.gambatte_loadbiosbuf(GambatteState, bios, (uint)bios.Length) != 0) { throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_loadbiosbuf)}() returned non-zero (bios error)"); } } else { if (DeterministicEmulation) // throw a warning if a movie is being recorded with the bios disabled { comm.ShowMessage("Detected disabled BIOS during movie recording. It is recommended to use a BIOS for movie recording. Change Sync Settings to run with a BIOS."); } flags |= LibGambatte.LoadFlags.NO_BIOS; } if (LibGambatte.gambatte_loadbuf(GambatteState, file, (uint)file.Length, flags) != 0) { throw new InvalidOperationException($"{nameof(LibGambatte.gambatte_loadbuf)}() returned non-zero (is this not a gb or gbc rom?)"); } if (IsSgb) { ResetStallTicks = 128 * (2 << 14); } else if (_syncSettings.EnableBIOS && (_syncSettings.ConsoleMode is GambatteSyncSettings.ConsoleModeType.GBA)) { ResetStallTicks = 485808; // GBA takes 971616 cycles to switch to CGB mode; CGB CPU is inactive during this time. } else { ResetStallTicks = 0; } // set real default colors (before anyone mucks with them at all) PutSettings(settings ?? new GambatteSettings()); InitSound(); Frame = 0; LagCount = 0; IsLagFrame = false; InputCallback = new LibGambatte.InputGetter(ControllerCallback); LibGambatte.gambatte_setinputgetter(GambatteState, InputCallback, IntPtr.Zero); InitMemoryDomains(); byte[] mbcBuf = new byte[32]; uint rambanks = 0; uint rombanks = 0; uint crc = 0; uint headerchecksumok = 0; LibGambatte.gambatte_pakinfo(GambatteState, mbcBuf, ref rambanks, ref rombanks, ref crc, ref headerchecksumok); byte[] romNameBuf = new byte[32]; LibGambatte.gambatte_romtitle(GambatteState, romNameBuf); string romname = Encoding.ASCII.GetString(romNameBuf); RomDetails = $"{game.Name}\r\n{SHA1Checksum.ComputePrefixedHex(file)}\r\n{MD5Checksum.ComputePrefixedHex(file)}\r\n\r\n"; BoardName = Encoding.ASCII.GetString(mbcBuf); RomDetails += $"Core reported Header Name: {romname}\r\n"; RomDetails += $"Core reported RAM Banks: {rambanks}\r\n"; RomDetails += $"Core reported ROM Banks: {rombanks}\r\n"; RomDetails += $"Core reported CRC32: {crc:X8}\r\n"; RomDetails += $"Core reported Header Checksum Status: {(headerchecksumok != 0 ? "OK" : "BAD")}\r\n"; if (_syncSettings.EnableBIOS && headerchecksumok == 0) { comm.ShowMessage("Core reports the header checksum is bad. This ROM will not boot with the official BIOS.\n" + "Disable BIOS in sync settings to boot this game"); } if (!_syncSettings.EnableBIOS && IsCgb && IsCGBDMGMode()) // without a bios, we need to set the palette for cgbdmg ourselves { int[] cgbDmgColors = new int[] { 0xFFFFFF, 0x7BFF31, 0x0063C5, 0x000000, 0xFFFFFF, 0xFF8484, 0x943A3A, 0x000000, 0xFFFFFF, 0xFF8484, 0x943A3A, 0x000000 }; if (file[0x14B] == 0x01 || (file[0x14B] == 0x33 && file[0x144] == '0' && file[0x145] == '1')) // Nintendo licencees get special palettes { cgbDmgColors = ColorsFromTitleHash(file); } ChangeDMGColors(cgbDmgColors); } if (!DeterministicEmulation && _syncSettings.RealTimeRTC) { LibGambatte.gambatte_settimemode(GambatteState, false); } if (DeterministicEmulation) { ulong dividers = _syncSettings.InitialTime * (0x400000UL + (ulong)_syncSettings.RTCDivisorOffset) / 2UL; LibGambatte.gambatte_settime(GambatteState, dividers); } LibGambatte.gambatte_setrtcdivisoroffset(GambatteState, _syncSettings.RTCDivisorOffset); LibGambatte.gambatte_setcartbuspulluptime(GambatteState, (uint)_syncSettings.CartBusPullUpTime); _cdCallback = new LibGambatte.CDCallback(CDCallbackProc); ControllerDefinition = CreateControllerDefinition(sgb: IsSgb, sub: _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames, tilt: false); NewSaveCoreSetBuff(); } catch { Dispose(); throw; } }
public A7800Hawk(CoreComm comm, byte[] rom, A7800Hawk.A7800Settings settings, A7800Hawk.A7800SyncSettings syncSettings) { var ser = new BasicServiceProvider(this); maria = new Maria(); tia = new TIA(); m6532 = new M6532(); pokey = new Pokey(); cpu = new MOS6502X <CpuLink>(new CpuLink(this)); maria = new Maria { ReadMemory = ReadMemory }; _blip.SetRates(1789773, 44100); _settings = (A7800Settings)settings ?? new A7800Settings(); _syncSettings = (A7800SyncSettings)syncSettings ?? new A7800SyncSettings(); _controllerDeck = new A7800HawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2); var highscoreBios = comm.CoreFileProvider.GetFirmware(new("A78", "Bios_HSC"), "Some functions may not work without the high score BIOS."); var palBios = comm.CoreFileProvider.GetFirmware(new("A78", "Bios_PAL"), "The game will not run if the correct region BIOS is not available."); var ntscBios = comm.CoreFileProvider.GetFirmware(new("A78", "Bios_NTSC"), "The game will not run if the correct region BIOS is not available."); byte[] header = new byte[128]; bool is_header = false; if (rom.Length % 1024 == 128) { Console.WriteLine("128 byte header detected"); byte[] newrom = new byte[rom.Length - 128]; is_header = true; Buffer.BlockCopy(rom, 0, header, 0, 128); Buffer.BlockCopy(rom, 128, newrom, 0, newrom.Length); rom = newrom; } _isPAL = false; // look up hash in gamedb to see what mapper to use // if none found default is zero // also check for PAL region s_mapper = null; var hash_md5 = MD5Checksum.ComputePrefixedHex(rom); var gi = Database.CheckDatabase(hash_md5); if (gi != null) { var dict = gi.GetOptions(); if (dict.ContainsKey("PAL")) { _isPAL = true; } if (!dict.TryGetValue("board", out s_mapper)) { throw new Exception("No Board selected for this game"); } // check if the game uses pokey or RAM if (dict.TryGetValue("RAM", out var cartRAMStr)) { int.TryParse(cartRAMStr, out cart_RAM); } if (dict.TryGetValue("Pokey", out var pokeyStr)) { bool.TryParse(pokeyStr, out is_pokey); } if (dict.TryGetValue("Pokey_450", out var pokey450Str)) { bool.TryParse(pokey450Str, out is_pokey_450); } // some games will not function with the high score bios // if such a game is being played, tell the user and disable it if (dict.TryGetValue("No_HS", out var noHSStr)) { bool.TryParse(noHSStr, out var no_hs); if (no_hs) { Console.WriteLine("This game is incompatible with the High Score BIOS, disabling it"); highscoreBios = null; } } } else if (is_header) { Console.WriteLine("ROM not in DB, inferring mapper info from header"); byte cart_1 = header[0x35]; byte cart_2 = header[0x36]; _isPAL = (header[0x39] > 0); if (cart_2.Bit(1)) { if (cart_2.Bit(3)) { s_mapper = "2"; } else { s_mapper = "1"; } if (cart_2.Bit(2)) { cart_RAM = 8; // the homebrew game serpentine requires extra RAM, but in the alternative style if (hash_md5 == RomChecksums.Serpentine) { cart_RAM = 16; } } } else { s_mapper = "0"; } if (cart_2.Bit(0)) { is_pokey = true; } // the homebrew game serpentine requires the pokey chip to be available at the alternative location 0x450 if (cart_2.Bit(6)) { is_pokey_450 = true; } } else { throw new Exception("ROM not in gamedb and has no header"); } // some games that use the Super Game mapper only have 4 banks, so let's set a flag to limit bank size if (rom.Length < 0x14000) { small_flag = true; // additionally, PAL Karateka has bank 6 (actually 2) at 0x4000 if (hash_md5 == RomChecksums.KaratekaPAL) { PAL_Kara = true; } } _rom = rom; Reset_Mapper(s_mapper); _hsbios = highscoreBios; _bios = _isPAL ? palBios : ntscBios; if (_bios == null) { throw new MissingFirmwareException("The BIOS corresponding to the region of the game you loaded is required to run Atari 7800 games."); } // set up palette and frame rate if (_isPAL) { _frameHz = 50; _screen_width = 320; _screen_height = 313; _vblanklines = 20; maria._palette = PALPalette; } else { _frameHz = 60; _screen_width = 320; _screen_height = 263; _vblanklines = 20; maria._palette = NTSCPalette; } maria.Core = this; m6532.Core = this; tia.Core = this; pokey.Core = this; ser.Register <IVideoProvider>(this); ser.Register <ISoundProvider>(this); ServiceProvider = ser; _tracer = new TraceBuffer(cpu.TraceHeader); ser.Register <ITraceable>(_tracer); ser.Register <IStatable>(new StateSerializer(SyncState)); SetupMemoryDomains(); ser.Register <IDisassemblable>(cpu); HardReset(); }
public C64(CoreLoadParameters <C64Settings, C64SyncSettings> lp) { PutSyncSettings((C64SyncSettings)lp.SyncSettings ?? new C64SyncSettings()); PutSettings((C64Settings)lp.Settings ?? new C64Settings()); var ser = new BasicServiceProvider(this); ServiceProvider = ser; CoreComm = lp.Comm; _roms = lp.Roms.Select(r => r.RomData).ToList(); _currentDisk = 0; RomSanityCheck(); Init(SyncSettings.VicType, Settings.BorderType, SyncSettings.SidType, SyncSettings.TapeDriveType, SyncSettings.DiskDriveType); _cyclesPerFrame = _board.Vic.CyclesPerFrame; _memoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); InitMedia(_roms[_currentDisk]); HardReset(); switch (SyncSettings.VicType) { case VicType.Ntsc: case VicType.Drean: case VicType.NtscOld: Region = DisplayType.NTSC; break; case VicType.Pal: Region = DisplayType.PAL; break; } if (_board.Sid != null) { _soundProvider = new DCFilter(_board.Sid, 512); ser.Register <ISoundProvider>(_soundProvider); } ser.Register <IVideoProvider>(_board.Vic); ser.Register <IDriveLight>(this); _tracer = new TraceBuffer(_board.Cpu.TraceHeader); ser.Register <ITraceable>(_tracer); ser.Register <IStatable>(new StateSerializer(SyncState)); if (_board.CartPort.IsConnected) { var first = _roms[0]; // There are no multi-cart cart games, so just hardcode first RomDetails = $"{lp.Game.Name}\r\n{SHA1Checksum.ComputePrefixedHex(first)}\r\n{MD5Checksum.ComputePrefixedHex(first)}\r\nMapper Impl \"{_board.CartPort.CartridgeType}\""; } SetupMemoryDomains(); }