public int Parse(byte[] rom) { // Combine every two bytes into a word. int index = 0; while (index + 1 < rom.Length) { Data[(index / 2)] = (ushort)((rom[index++] << 8) | rom[index++]); } // look up hash in gamedb to see what mapper to use string s_mapper = null; var gi = Database.CheckDatabase(SHA1Checksum.ComputePrefixedHex(rom)); if (gi != null && !gi.GetOptions().TryGetValue("board", out s_mapper)) { throw new Exception("INTV gamedb entries must have a board identifier!"); } if (gi == null && (rom.Length % 1024) != 0) { throw new Exception("Game is of unusual size but no header entry present and hash not in game db."); } _mapper = 0; int.TryParse(s_mapper, out _mapper); return(rom.Length); }
private void ComputeBootGod() { // inefficient, sloppy, etc etc var chrrom = _memoryDomains["CHR VROM"]; var prgrom = _memoryDomains["PRG ROM"] !; var ms = new MemoryStream(); for (int i = 0; i < prgrom.Size; i++) { ms.WriteByte(prgrom.PeekByte(i)); } if (chrrom != null) { for (int i = 0; i < chrrom.Size; i++) { ms.WriteByte(chrrom.PeekByte(i)); } } var sha1 = SHA1Checksum.ComputeDigestHex(ms.ToArray()); Console.WriteLine("Hash for BootGod: {0}", sha1); // Bail out on ROM's known to not be playable by this core if (HashBlackList.Contains(sha1)) { throw new UnsupportedGameException("Game known to not be playable in this core"); } sha1 = "sha1:" + sha1; // huh? var carts = BootGodDb.Identify(sha1); if (carts.Count > 0) { Console.WriteLine("BootGod entry found: {0}", carts[0].Name); switch (carts[0].System) { case "NES-PAL": case "NES-PAL-A": case "NES-PAL-B": case "Dendy": Console.WriteLine("Bad region {0}! Failing over...", carts[0].System); throw new UnsupportedGameException("Unsupported region!"); } BootGodStatus = RomStatus.GoodDump; BootGodName = carts[0].Name; } else { Console.WriteLine("No BootGod entry found."); BootGodStatus = null; BootGodName = null; } }
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(); }
// ICreateGameDBEntries public CompactGameInfo GenerateGameDbEntry() { return(new CompactGameInfo { Name = _game.Name, System = VSystemID.Raw.A26, MetaData = "m=" + _mapper.GetType().ToString().Split('.').Last(), Hash = SHA1Checksum.ComputeDigestHex(Rom), Region = _game.Region, Status = RomStatus.Unknown }); }
private FileInfo GetConfigFile(Type plugin) { string fileName = String.Format("{0}-{1}.xml", plugin.Name, SHA1Checksum.Generate(plugin.GetType().FullName)); string path = Path.Combine( this.storageDirectory.FullName, fileName); FileInfo fi = new FileInfo(path); return(fi); }
private void RebootCore() { // Regenerate mapper here to make sure its state is entirely clean _mapper = CreateMapper(this, _game.GetOptions()["m"], Rom.Length); _lagCount = 0; Cpu = new MOS6502X <CpuLink>(new CpuLink(this)); if (_game["PAL"]) { _pal = true; } else if (_game["NTSC"]) { _pal = false; } else { _pal = DetectPal(_game, Rom); } // dcfilter coefficent is from real observed hardware behavior: a latched "1" will fully decay by ~170 or so tia sound cycles _tia = new TIA(this, _pal, Settings.SECAMColors); _dcfilter = new DCFilter(_tia, 256); _m6532 = new M6532(this); HardReset(); RomDetails = $"{_game.Name}\r\n{SHA1Checksum.ComputePrefixedHex(Rom)}\r\n{MD5Checksum.ComputePrefixedHex(Rom)}\r\nMapper Impl \"{_mapper.GetType()}\""; // Some games (ex. 3D tic tac toe), turn off the screen for extended periods, so we need to allow for this here. if (_game.GetOptions().TryGetValue("SP_FRAME", out var spFrameStr) && spFrameStr == "true") { SP_FRAME = true; } // Some games wait for reset to be unpressed before turning the screen back on, hack unset it if needed if (_game.GetOptions().TryGetValue("SP_RESET", out var spResetStr) && spResetStr == "true") { SP_RESET = true; } // Ditto select (ex. Karate) if (_game.GetOptions().TryGetValue("SP_SELECT", out var spSelectStr) && spSelectStr == "true") { SP_SELECT = true; } }
public Atari2600(GameInfo game, byte[] rom, Atari2600.A2600Settings settings, Atari2600.A2600SyncSettings syncSettings) { var ser = new BasicServiceProvider(this); ServiceProvider = ser; _ram = new byte[128]; Settings = (A2600Settings)settings ?? new A2600Settings(); SyncSettings = (A2600SyncSettings)syncSettings ?? new A2600SyncSettings(); _controllerDeck = new Atari2600ControllerDeck(SyncSettings.Port1, SyncSettings.Port2); _leftDifficultySwitchPressed = SyncSettings.LeftDifficulty; _rightDifficultySwitchPressed = SyncSettings.RightDifficulty; Rom = rom; _game = game; if (!game.GetOptions().ContainsKey("m")) { game.AddOption("m", DetectMapper(rom)); } var romHashSHA1 = SHA1Checksum.ComputePrefixedHex(Rom); if (romHashSHA1 is RomChecksums.CongoBongo or RomChecksums.Tapper or RomChecksums.KangarooNotInGameDB) { game.RemoveOption("m"); game.AddOption("m", "F8_sega"); } Console.WriteLine("Game uses mapper " + game.GetOptions()["m"]); Console.WriteLine(romHashSHA1); RebootCore(); SetupMemoryDomains(); Tracer = new TraceBuffer(Cpu.TraceHeader); ser.Register <IDisassemblable>(Cpu); ser.Register <ITraceable>(Tracer); ser.Register <IVideoProvider>(_tia); ser.Register <ISoundProvider>(_dcfilter); ser.Register <IStatable>(new StateSerializer(SyncState)); }
// Fix some incorrect ines header entries that QuickNES uses to load games. // we need to do this from the raw file since QuickNES hasn't had time to process it yet. private byte[] FixInesHeader(byte[] file) { var sha1 = SHA1Checksum.ComputeDigestHex(file); bool didSomething = false; Console.WriteLine(sha1); if (sha1 == "93010514AA1300499ABC8F145D6ABCDBF3084090") // Ms. Pac Man (Tengen) [!] { file[6] &= 0xFE; didSomething = true; } if (didSomething) { Console.WriteLine("iNES header error detected, adjusting settings..."); Console.WriteLine(sha1); } return(file); }
public bool GetObject(StreamDataParserTask task, out object value) { if (task.StreamType == typeof(MD5Checksum)) { // 128 bits value = new MD5Checksum(task.Stream.ReadBytes(16)); return true; } if (task.StreamType == typeof(SHA1Checksum)) { // 160 bits value = new SHA1Checksum(task.Stream.ReadBytes(20)); return true; } if (task.StreamType == typeof(SHA256Checksum)) { // 256 bits value = new SHA256Checksum(task.Stream.ReadBytes(32)); return true; } if (task.StreamType == typeof(SHA384Checksum)) { // 384 bits value = new SHA256Checksum(task.Stream.ReadBytes(48)); return true; } if (task.StreamType == typeof(SHA512Checksum)) { // 512 bits value = new SHA512Checksum(task.Stream.ReadBytes(64)); return true; } value = null; return false; }
/// <exception cref="Exception"><paramref name="file"/> does not exist</exception> public RomGame(HawkFile file, string patch) { if (!file.Exists) { throw new Exception("The file needs to exist, yo."); } Extension = file.Extension.ToUpperInvariant(); var stream = file.GetStream(); int fileLength = (int)stream.Length; // read the entire contents of the file into memory. // unfortunate in the case of large files, but that's what we've got to work with for now. // if we're offset exactly 512 bytes from a 1024-byte boundary, // assume we have a header of that size. Otherwise, assume it's just all rom. // Other 'recognized' header sizes may need to be added. int headerOffset = fileLength % BankSize; if (headerOffset.In(0, 128, 512) == false) { Console.WriteLine("ROM was not a multiple of 1024 bytes, and not a recognized header size: {0}. Assume it's purely ROM data.", headerOffset); headerOffset = 0; } else if (headerOffset > 0) { Console.WriteLine("Assuming header of {0} bytes.", headerOffset); } // read the entire file into FileData. FileData = new byte[fileLength]; stream.Position = 0; stream.Read(FileData, 0, fileLength); string SHA1_check = SHA1Checksum.ComputePrefixedHex(FileData); // if there was no header offset, RomData is equivalent to FileData // (except in cases where the original interleaved file data is necessary.. in that case we'll have problems.. // but this whole architecture is not going to withstand every peculiarity and be fast as well. if (headerOffset == 0) { RomData = FileData; } else if (file.Extension == ".dsk" || file.Extension == ".tap" || file.Extension == ".tzx" || file.Extension == ".pzx" || file.Extension == ".csw" || file.Extension == ".wav" || file.Extension == ".cdt") { // these are not roms. unfortunately if treated as such there are certain edge-cases // where a header offset is detected. This should mitigate this issue until a cleaner solution is found // (-Asnivor) RomData = FileData; } else if (SHA1_check == Flappy_Bird_INTV || SHA1_check == Minehunter_INTV) { // several INTV games have sizes that are multiples of 512 bytes Console.WriteLine("False positive detected in Header Check, using entire file."); RomData = FileData; } else { // if there was a header offset, read the whole file into FileData and then copy it into RomData (this is unfortunate, in case RomData isn't needed) int romLength = fileLength - headerOffset; RomData = new byte[romLength]; Buffer.BlockCopy(FileData, headerOffset, RomData, 0, romLength); } if (file.Extension == ".smd") { RomData = DeInterleaveSMD(RomData); } if (file.Extension == ".z64" || file.Extension == ".n64" || file.Extension == ".v64") { // Use a simple magic number to detect N64 rom format, then byteswap the ROM to ensure a consistent endianness/order RomData = RomData[0] switch { 0x37 => EndiannessUtils.ByteSwap16(RomData), // V64 format (byte swapped) 0x40 => EndiannessUtils.ByteSwap32(RomData), // N64 format (word swapped) _ => RomData // Z64 format (no swap), or something unexpected; in either case do nothing }; } // note: this will be taking several hashes, of a potentially large amount of data.. yikes! GameInfo = Database.GetGameInfo(RomData, file.Name); if (GameInfo.NotInDatabase && headerOffset == 128 && file.Extension == ".a78") { // if the game is not in the DB, add the header back in so the core can use it // for now only .A78 games, but probably should be for other systems as well RomData = FileData; } CheckForPatchOptions(); if (patch != null) { using var patchFile = new HawkFile(patch); patchFile.BindFirstOf(".ips"); if (patchFile.IsBound) { RomData = IPS.Patch(RomData, patchFile.GetStream()); } } }
public LibsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm, LibsnesCore.SnesSettings settings, LibsnesCore.SnesSyncSettings syncSettings) { _baseRomPath = baseRomPath; var ser = new BasicServiceProvider(this); ServiceProvider = ser; const string TRACE_HEADER = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, DB, flags (NVMXDIZC), V, H)"; _tracer = new TraceBuffer(TRACE_HEADER); ser.Register <IDisassemblable>(new W65816_DisassemblerService()); _game = game; CoreComm = comm; byte[] sgbRomData = null; if (game.System == VSystemID.Raw.SGB) { if ((romData[0x143] & 0xc0) == 0xc0) { throw new CGBNotSupportedException(); } sgbRomData = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB"), "SGB Rom is required for SGB emulation."); game.FirmwareHash = SHA1Checksum.ComputeDigestHex(sgbRomData); } _settings = (SnesSettings)settings ?? new SnesSettings(); _syncSettings = (SnesSyncSettings)syncSettings ?? new SnesSyncSettings(); _videocb = snes_video_refresh; _inputpollcb = snes_input_poll; _inputstatecb = snes_input_state; _inputnotifycb = snes_input_notify; _scanlineStartCb = snes_scanlineStart; _tracecb = snes_trace; _soundcb = snes_audio_sample; _pathrequestcb = snes_path_request; // TODO: pass profile here Api = new LibsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, new Delegate[] { _videocb, _inputpollcb, _inputstatecb, _inputnotifycb, _scanlineStartCb, _tracecb, _soundcb, _pathrequestcb }) { ReadHook = ReadHook, ExecHook = ExecHook, WriteHook = WriteHook, ReadHook_SMP = ReadHook_SMP, ExecHook_SMP = ExecHook_SMP, WriteHook_SMP = WriteHook_SMP, }; ScanlineHookManager = new MyScanlineHookManager(this); _controllerDeck = new LibsnesControllerDeck(_syncSettings); _controllerDeck.NativeInit(Api); Api.CMD_init(_syncSettings.RandomizedInitialState); Api.QUERY_set_path_request(_pathrequestcb); // start up audio resampler InitAudio(); ser.Register <ISoundProvider>(_resampler); // strip header if ((romData?.Length & 0x7FFF) == 512) { var newData = new byte[romData.Length - 512]; Array.Copy(romData, 512, newData, 0, newData.Length); romData = newData; } if (game.System == VSystemID.Raw.SGB) { IsSGB = true; SystemId = VSystemID.Raw.SNES; ser.Register <IBoardInfo>(new SGBBoardInfo()); _currLoadParams = new LoadParams { type = LoadParamType.SuperGameBoy, rom_xml = null, rom_data = sgbRomData, rom_size = (uint)sgbRomData.Length, dmg_data = romData, }; if (!LoadCurrent()) { throw new Exception("snes_load_cartridge_normal() failed"); } } 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 :/ 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 = VSystemID.Raw.SNES; _currLoadParams = new LoadParams { type = LoadParamType.Normal, xml_data = xmlData, rom_data = romData }; if (!LoadCurrent()) { throw new Exception("snes_load_cartridge_normal() failed"); } } if (_region == LibsnesApi.SNES_REGION.NTSC) { // similar to what aviout reports from snes9x and seems logical from bsnes first principles. bsnes uses that numerator (ntsc master clockrate) for sure. VsyncNumerator = 21477272; VsyncDenominator = 4 * 341 * 262; } else { // http://forums.nesdev.com/viewtopic.php?t=5367&start=19 VsyncNumerator = 21281370; VsyncDenominator = 4 * 341 * 312; } Api.CMD_power(); SetupMemoryDomains(romData, sgbRomData); if (CurrentProfile == "Compatibility") { ser.Register <ITraceable>(_tracer); } Api.QUERY_set_path_request(null); Api.QUERY_set_video_refresh(_videocb); Api.QUERY_set_input_poll(_inputpollcb); Api.QUERY_set_input_state(_inputstatecb); Api.QUERY_set_input_notify(_inputnotifycb); Api.QUERY_set_audio_sample(_soundcb); Api.Seal(); RefreshPalette(); }
public Unif(Stream s) { var br = new BinaryReader(s, Encoding.ASCII); if (!Encoding.ASCII.GetBytes("UNIF") .SequenceEqual(br.ReadBytes(4))) { throw new Exception("Missing \"UNIF\" header mark!"); } int ver = br.ReadInt32(); Console.WriteLine("Processing Version {0} UNIF...", ver); br.ReadBytes(32 - 4 - 4); while (br.PeekChar() > 0) { string chunkId = Encoding.ASCII.GetString(br.ReadBytes(4)); int length = br.ReadInt32(); byte[] chunkData = br.ReadBytes(length); Chunks.Add(chunkId, chunkData); } var prgs = new MemoryStream(); var chrs = new MemoryStream(); for (int i = 0; i < 16; i++) { TryAdd(prgs, $"PRG{i:X1}"); TryAdd(chrs, $"CHR{i:X1}"); } prgs.Close(); chrs.Close(); Prg = prgs.ToArray(); Chr = chrs.ToArray(); Cart.PrgSize = (short)(Prg.Length / 1024); Cart.ChrSize = (short)(Chr.Length / 1024); if (Chunks.TryGetValue("MIRR", out var tmp)) { switch (tmp[0]) { case 0: // h mirror Cart.PadH = 0; Cart.PadV = 1; break; case 1: // v mirror Cart.PadH = 1; Cart.PadV = 0; break; } } if (Chunks.TryGetValue("MAPR", out tmp)) { Cart.BoardType = new BinaryReader(new MemoryStream(tmp)).ReadStringUtf8NullTerminated(); } Cart.BoardType = Cart.BoardType.TrimEnd('\0'); Cart.BoardType = "UNIF_" + Cart.BoardType; if (Chunks.TryGetValue("BATR", out _)) { // apparently, this chunk just existing means battery is yes Cart.WramBattery = true; } Cart.Sha1 = SHA1Checksum.ComputeConcat(Prg, Chr).BytesToHexString(); // other code will expect this if (Chr.Length == 0) { Chr = null; } }
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 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(); ThrowExceptionForBadRom(file); BoardName = MapperName(file); 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; } if (_syncSettings.MulticartCompat) { flags |= LibGambatte.LoadFlags.MULTICART_COMPAT; } 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((GambatteSettings)settings ?? new GambatteSettings()); InitSound(); Frame = 0; LagCount = 0; IsLagFrame = false; InputCallback = new LibGambatte.InputGetter(ControllerCallback); LibGambatte.gambatte_setinputgetter(GambatteState, InputCallback); InitMemoryDomains(); RomDetails = $"{game.Name}\r\n{SHA1Checksum.ComputePrefixedHex(file)}\r\n{MD5Checksum.ComputePrefixedHex(file)}\r\n"; byte[] buff = new byte[32]; LibGambatte.gambatte_romtitle(GambatteState, buff); string romname = System.Text.Encoding.ASCII.GetString(buff); Console.WriteLine("Core reported rom name: {0}", romname); 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) { int[] rtcRegs = new int[11]; rtcRegs[(int)LibGambatte.RtcRegIndices.Dh] = 0; if (_syncSettings.InternalRTCOverflow) { rtcRegs[(int)LibGambatte.RtcRegIndices.Dh] |= 0x80; } if (_syncSettings.InternalRTCHalt) { rtcRegs[(int)LibGambatte.RtcRegIndices.Dh] |= 0x40; } rtcRegs[(int)LibGambatte.RtcRegIndices.Dh] |= _syncSettings.InternalRTCDays >> 8; rtcRegs[(int)LibGambatte.RtcRegIndices.Dl] = _syncSettings.InternalRTCDays & 0xFF; rtcRegs[(int)LibGambatte.RtcRegIndices.H] = (_syncSettings.InternalRTCHours < 0) ? (_syncSettings.InternalRTCHours + 0x20) : _syncSettings.InternalRTCHours; rtcRegs[(int)LibGambatte.RtcRegIndices.M] = (_syncSettings.InternalRTCMinutes < 0) ? (_syncSettings.InternalRTCMinutes + 0x40) : _syncSettings.InternalRTCMinutes; rtcRegs[(int)LibGambatte.RtcRegIndices.S] = (_syncSettings.InternalRTCSeconds < 0) ? (_syncSettings.InternalRTCSeconds + 0x40) : _syncSettings.InternalRTCSeconds; rtcRegs[(int)LibGambatte.RtcRegIndices.C] = _syncSettings.InternalRTCCycles; rtcRegs[(int)LibGambatte.RtcRegIndices.Dh_L] = 0; if (_syncSettings.LatchedRTCOverflow) { rtcRegs[(int)LibGambatte.RtcRegIndices.Dh_L] |= 0x80; } if (_syncSettings.LatchedRTCHalt) { rtcRegs[(int)LibGambatte.RtcRegIndices.Dh_L] |= 0x40; } rtcRegs[(int)LibGambatte.RtcRegIndices.Dh_L] |= _syncSettings.LatchedRTCDays >> 8; rtcRegs[(int)LibGambatte.RtcRegIndices.Dl_L] = _syncSettings.LatchedRTCDays & 0xFF; rtcRegs[(int)LibGambatte.RtcRegIndices.H_L] = _syncSettings.LatchedRTCHours; rtcRegs[(int)LibGambatte.RtcRegIndices.M_L] = _syncSettings.LatchedRTCMinutes; rtcRegs[(int)LibGambatte.RtcRegIndices.S_L] = _syncSettings.LatchedRTCSeconds; LibGambatte.gambatte_setrtcregs(GambatteState, rtcRegs); } LibGambatte.gambatte_setrtcdivisoroffset(GambatteState, _syncSettings.RTCDivisorOffset); LibGambatte.gambatte_setcartbuspulluptime(GambatteState, (uint)_syncSettings.CartBusPullUpTime); _cdCallback = new LibGambatte.CDCallback(CDCallbackProc); ControllerDefinition = CreateControllerDefinition(IsSgb, _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames); NewSaveCoreSetBuff(); } catch { Dispose(); throw; } }
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 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; _settings = settings ?? new SnesSettings(); _syncSettings = syncSettings ?? new SnesSyncSettings(); if (game.System == VSystemID.Raw.SGB) { if ((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."); 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 }; 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 == VSystemID.Raw.SGB) { IsSGB = true; SystemId = VSystemID.Raw.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 = VSystemID.Raw.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(); 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(); }
} = new List <string>(); // TODO: Hack work around, to avoid having to refactor Assets into a object array, should be refactored! /// <exception cref="InvalidOperationException">internal error</exception> public static XmlGame Create(HawkFile f) { try { var x = new XmlDocument(); x.Load(f.GetStream()); var y = x.SelectSingleNode("./BizHawk-XMLGame"); if (y == null) { return(null); } var ret = new XmlGame { GI = { System = y.Attributes["System"].Value, Name = y.Attributes["Name"].Value, Status = RomStatus.Unknown }, Xml = x }; string fullPath = ""; var n = y.SelectSingleNode("./LoadAssets"); if (n != null) { var hashStream = new MemoryStream(); int?originalIndex = null; foreach (XmlNode a in n.ChildNodes) { string filename = a.Attributes["FileName"].Value; byte[] data; if (filename[0] == '|') { // in same archive var ai = f.FindArchiveMember(filename.Substring(1)); if (ai != null) { originalIndex ??= f.BoundIndex; f.Unbind(); f.BindArchiveMember(ai.Value); data = f.GetStream().ReadAllBytes(); } else { throw new Exception($"Couldn't load XMLGame Asset \"{filename}\""); } } else { // relative path fullPath = Path.GetDirectoryName(f.CanonicalFullPath.Split('|').First()) ?? ""; fullPath = Path.Combine(fullPath, filename.Split('|').First()); try { using var hf = new HawkFile(fullPath); if (hf.IsArchive) { var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.Split('|').Skip(1).First()); hf.Unbind(); hf.BindArchiveMember(archiveItem); data = hf.GetStream().ReadAllBytes(); filename = filename.Split('|').Skip(1).First(); } else { data = File.ReadAllBytes(fullPath.Split('|').First()); } } catch { throw new Exception($"Couldn't load XMLGame LoadAsset \"{filename}\""); } } ret.Assets.Add(new KeyValuePair <string, byte[]>(filename, data)); ret.AssetFullPaths.Add(fullPath); var sha1 = SHA1Checksum.Compute(data); hashStream.Write(sha1, 0, sha1.Length); } ret.GI.Hash = SHA1Checksum.ComputeDigestHex(hashStream.GetBufferAsSpan()); hashStream.Close(); if (originalIndex != null) { f.Unbind(); f.BindArchiveMember((int)originalIndex); } } else { ret.GI.Hash = SHA1Checksum.Zero; } return(ret); } catch (Exception ex) { throw new InvalidOperationException(ex.ToString()); } }
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 PCEngine(CoreLoadParameters <PCESettings, PCESyncSettings> lp) { if (lp.Discs.Count == 1 && lp.Roms.Count == 0) { SystemId = VSystemID.Raw.PCECD; Type = NecSystemType.TurboCD; this.disc = lp.Discs[0].DiscData; Settings = (PCESettings)lp.Settings ?? new PCESettings(); _syncSettings = (PCESyncSettings)lp.SyncSettings ?? new PCESyncSettings(); var(rom, biosInfo) = lp.Comm.CoreFileProvider.GetFirmwareWithGameInfoOrThrow( new("PCECD", "Bios"), "PCE-CD System Card not found. Please check the BIOS settings in Config->Firmwares."); if (biosInfo.Status == RomStatus.BadDump) { lp.Comm.ShowMessage( "The PCE-CD System Card you have selected is known to be a bad dump. This may cause problems playing PCE-CD games.\n\n" + "It is recommended that you find a good dump of the system card. Sorry to be the bearer of bad news!"); } else if (biosInfo.NotInDatabase) { lp.Comm.ShowMessage( "The PCE-CD System Card you have selected is not recognized in our database. That might mean it's a bad dump, or isn't the correct rom."); } else if (biosInfo["BIOS"] == false) { // zeromus says: someone please write a note about how this could possibly happen. // it seems like this is a relic of using gameDB for storing whether something is a bios? firmwareDB should be handling it now. lp.Comm.ShowMessage( "The PCE-CD System Card you have selected is not a BIOS image. You may have selected the wrong rom. FYI-Please report this to developers, I don't think this error message should happen."); } if (biosInfo["SuperSysCard"]) { lp.Game.AddOption("SuperSysCard", ""); } if (lp.Game["NeedSuperSysCard"] && lp.Game["SuperSysCard"] == false) { lp.Comm.ShowMessage( "This game requires a version 3.0 System card and won't run with the system card you've selected. Try selecting a 3.0 System Card in the firmware configuration."); throw new Exception(); } lp.Game.FirmwareHash = SHA1Checksum.ComputeDigestHex(rom); Init(lp.Game, rom); // the default RomStatusDetails don't do anything with Disc RomDetails = $"{lp.Game.Name}\r\nDisk partial hash:{new DiscHasher(disc).OldHash()}"; _controllerDeck = new PceControllerDeck( _syncSettings.Port1, _syncSettings.Port2, _syncSettings.Port3, _syncSettings.Port4, _syncSettings.Port5); } else if (lp.Discs.Count == 0 && lp.Roms.Count == 1) { switch (SystemId = lp.Game.System) { default: case VSystemID.Raw.PCE: Type = NecSystemType.TurboGrafx; break; case VSystemID.Raw.SGX: Type = NecSystemType.SuperGrafx; break; } Settings = (PCESettings)lp.Settings ?? new PCESettings(); _syncSettings = (PCESyncSettings)lp.SyncSettings ?? new PCESyncSettings(); Init(lp.Game, lp.Roms[0].RomData); _controllerDeck = new PceControllerDeck( _syncSettings.Port1, _syncSettings.Port2, _syncSettings.Port3, _syncSettings.Port4, _syncSettings.Port5); } else { throw new InvalidOperationException("PCEHawk can only load exactly one CD or exactly one ROM"); } }
public VectrexHawk(CoreComm comm, byte[] rom, VectrexHawk.VectrexSyncSettings syncSettings) { var ser = new BasicServiceProvider(this); cpu = new MC6809 { ReadMemory = ReadMemory, WriteMemory = WriteMemory, PeekMemory = PeekMemory, DummyReadMemory = ReadMemory, OnExecFetch = ExecFetch, }; audio = new Audio(); ppu = new PPU(); serialport = new SerialPort(); _settings = new object(); // TODO: wtf is this _syncSettings = (VectrexSyncSettings)syncSettings ?? new VectrexSyncSettings(); _controllerDeck = new VectrexHawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2); /*var Bios =*/ _bios = comm.CoreFileProvider.GetFirmwareOrThrow(new("VEC", "Bios"), "BIOS Not Found, Cannot Load"); /*var Mine =*/ minestorm = comm.CoreFileProvider.GetFirmwareOrThrow(new("VEC", "Minestorm"), "Minestorm Not Found, Cannot Load"); var romHashSHA1 = SHA1Checksum.ComputePrefixedHex(rom); Console.WriteLine(romHashSHA1); _rom = rom; // If the game is minstorm, then no cartridge is inserted, retun 0xFF if (romHashSHA1 == RomChecksums.Minestorm) { _rom = new byte[0x8000]; for (int i = 0; i < 0x8000; i++) { _rom[i] = 0xFF; } } // mirror games that are too small if (_rom.Length < 0x8000) { _rom = new byte[0x8000]; for (int i = 0; i < 0x8000 / rom.Length; i++) { for (int j = 0; j < rom.Length; j++) { _rom[j + i * rom.Length] = rom[j]; } } } // RAM appears to power up to either random values or 0xFF, otherwise all the asteroids in minestorm are on the same side if RAM[0x7E]=0 for (int i = 0; i < RAM.Length; i++) { RAM[i] = 0xFF; } Setup_Mapper(); _frameHz = 50; audio.Core = this; ppu.Core = this; serialport.Core = this; ser.Register <IVideoProvider>(this); ser.Register <ISoundProvider>(audio); ServiceProvider = ser; _settings = new object(); // TODO: wtf is this _syncSettings = (VectrexSyncSettings)syncSettings ?? new VectrexSyncSettings(); _tracer = new TraceBuffer(cpu.TraceHeader); ser.Register <ITraceable>(_tracer); ser.Register <IStatable>(new StateSerializer(SyncState)); SetupMemoryDomains(); HardReset(); cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory); }
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(); }