private void HardReset() { _ram = new byte[128]; _mapper.HardReset(); Cpu = new MOS6502X { ReadMemory = ReadMemory, WriteMemory = WriteMemory, PeekMemory = PeekMemory, DummyReadMemory = ReadMemory, OnExecFetch = ExecFetch }; _tia.Reset(); _m6532 = new M6532(this); Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 // executing a reset sequence at power on, but it's needed so let's hard code it for now Cpu.S = 0xFD; SetupMemoryDomains(); }
private void MakeTrace(IntPtr data) { int[] s = new int[7]; Marshal.Copy(data, s, 0, 7); byte a = (byte)s[0]; byte x = (byte)s[1]; byte y = (byte)s[2]; ushort sp = (ushort)s[3]; ushort pc = (ushort)s[4]; byte p = (byte)s[5]; byte opcode = (byte)s[6]; int notused = 0; string opcodeStr = MOS6502X.Disassemble(pc, out notused, (address) => _memoryDomains.SystemBus.PeekByte(address)); Tracer.Put(new TraceInfo { Disassembly = string.Format("{0:X4} {1}", pc, opcodeStr).PadRight(26), RegisterInfo = string.Format( "SP:{0:X2} A:{1:X2} P:{2:X2} X:{3:X2} Y:{4:X2}", sp, a, p, x, y) }); }
private void MakeTrace(IntPtr data) { int[] s = new int[7]; Marshal.Copy(data, s, 0, 7); byte a = (byte)s[0]; byte x = (byte)s[1]; byte y = (byte)s[2]; ushort sp = (ushort)s[3]; ushort pc = (ushort)s[4]; byte p = (byte)s[5]; byte opcode = (byte)s[6]; int notused = 0; string opcodeStr = MOS6502X.Disassemble(pc, out notused, (address) => _memoryDomains.SystemBus.PeekByte(address)); Tracer.Put(new TraceInfo { Disassembly = $"{pc:X4}: {opcodeStr}".PadRight(26), RegisterInfo = string.Join(" ", $"A:{a:X2}", $"X:{x:X2}", $"Y:{y:X2}", $"P:{p:X2}", $"SP:{sp:X2}") }); }
public Chip6510() { // configure cpu r/w _cpu = new MOS6502X <CpuLink>(new CpuLink(this)); // perform hard reset HardReset(); }
public Cpu() { processor = new MOS6502X(); processor.DummyReadMemory = CoreReadMemory; processor.ReadMemory = CoreReadMemory; processor.WriteMemory = CoreWriteMemory; Reset(); }
// ------------------------------------ public MOS6510() { cpu = new MOS6502X(); // configure cpu r/w cpu.DummyReadMemory = Read; cpu.ReadMemory = Read; cpu.WriteMemory = Write; // perform hard reset HardReset(); }
private void HardReset() { _ram = new byte[128]; _mapper.HardReset(); Cpu = new MOS6502X <CpuLink>(new CpuLink(this)); _tia.Reset(); _m6532 = new M6532(this); SetupMemoryDomains(); cyc_counter = 0; }
// ------------------------------------ public Chip6510() { // configure cpu r/w _cpu = new MOS6502X { DummyReadMemory = CpuRead, ReadMemory = CpuRead, WriteMemory = CpuWrite, PeekMemory = CpuPeek }; // perform hard reset HardReset(); }
public Drive1541(int clockNum, int clockDen) { DriveRom = new Chip23128(); _cpu = new MOS6502X <CpuLink>(new CpuLink(this)) { NMI = false }; _ram = new int[0x800]; Via0 = Chip6522.Create(ViaReadClock, ViaReadData, ViaReadAtn, 8); Via1 = Chip6522.Create(ReadVia1PrA, ReadVia1PrB); _cpuClockNum = clockNum; _driveCpuClockNum = clockDen * 16000000; // 16mhz }
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; } }
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\nSHA1:{Rom.HashSHA1()}\r\nMD5:{Rom.HashMD5()}\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().ContainsKey("SP_FRAME")) { if (_game.GetOptions()["SP_FRAME"] == "true") { SP_FRAME = true; } } if (_game.GetOptions().ContainsKey("SP_RESET")) { if (_game.GetOptions()["SP_RESET"] == "true") { SP_RESET = true; } } }
private void HardReset() { _ram = new byte[128]; _mapper.HardReset(); Cpu = new MOS6502X { ReadMemory = ReadMemory, WriteMemory = WriteMemory, PeekMemory = PeekMemory, DummyReadMemory = ReadMemory, OnExecFetch = ExecFetch }; _tia.Reset(); _m6532 = new M6532(this); SetupMemoryDomains(); cyc_counter = 0; }
public Drive1541(int clockNum, int clockDen) { DriveRom = new Chip23128(); _cpu = new MOS6502X { ReadMemory = CpuRead, WriteMemory = CpuWrite, DummyReadMemory = CpuRead, PeekMemory = CpuPeek, NMI = false }; _ram = new int[0x800]; Via0 = Chip6522.Create(ViaReadClock, ViaReadData, ViaReadAtn, 8); Via1 = Chip6522.Create(ReadVia1PrA, ReadVia1PrB); _cpuClockNum = clockNum; _driveCpuClockNum = clockDen * 16000000; // 16mhz }
public void HardReset() { Ram = new byte[128]; _mapper.HardReset(); Cpu = new MOS6502X { ReadMemory = this.ReadMemory, WriteMemory = this.WriteMemory, PeekMemory = this.PeekMemory, DummyReadMemory = this.ReadMemory, OnExecFetch = this.ExecFetch }; _tia.Reset(); M6532 = new M6532(this); Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC }
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(); }
private void RebootCore() { // Regenerate mapper here to make sure its state is entirely clean switch (_game.GetOptionsDict()["m"]) { case "2IN1": _mapper = SetMultiCartMapper(Rom.Length, 2); break; case "4IN1": _mapper = SetMultiCartMapper(Rom.Length, 4); break; case "8IN1": _mapper = SetMultiCartMapper(Rom.Length, 8); break; case "16IN1": _mapper = SetMultiCartMapper(Rom.Length, 16); break; case "32IN1": _mapper = SetMultiCartMapper(Rom.Length, 32); break; case "AR": _mapper = new mAR(this); // This mapper has to set up configurations in the contructor. break; case "4K": _mapper = new m4K(); break; case "2K": _mapper = new m2K(); break; case "CM": _mapper = new mCM(); break; case "CV": _mapper = new mCV(); break; case "DPC": _mapper = new mDPC(); break; case "DPC+": _mapper = new mDPCPlus(); break; case "F8": _mapper = new mF8(); break; case "F8SC": _mapper = new mF8SC(); break; case "F6": _mapper = new mF6(); break; case "F6SC": _mapper = new mF6SC(); break; case "F4": _mapper = new mF4(); break; case "F4SC": _mapper = new mF4SC(); break; case "FE": _mapper = new mFE(); break; case "E0": _mapper = new mE0(); break; case "3F": _mapper = new m3F(); break; case "FA": _mapper = new mFA(); break; case "FA2": _mapper = new mFA2(); break; case "E7": _mapper = new mE7(); break; case "F0": _mapper = new mF0(); break; case "UA": _mapper = new mUA(); break; // Special Sega Mapper which has swapped banks case "F8_sega": _mapper = new mF8_sega(); break; // Homebrew mappers case "3E": _mapper = new m3E(); break; case "0840": _mapper = new m0840(); break; case "MC": _mapper = new mMC(); break; case "EF": _mapper = new mEF(); break; case "EFSC": _mapper = new mEFSC(); break; case "X07": _mapper = new mX07(); break; case "4A50": _mapper = new m4A50(); break; case "SB": _mapper = new mSB(); break; default: throw new InvalidOperationException("mapper not supported: " + _game.GetOptionsDict()["m"]); } _mapper.Core = this; _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(); // Show mapper class on romstatusdetails CoreComm.RomStatusDetails = $"{this._game.Name}\r\nSHA1:{Rom.HashSHA1()}\r\nMD5:{Rom.HashMD5()}\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.GetOptionsDict().ContainsKey("SP_FRAME")) { if (_game.GetOptionsDict()["SP_FRAME"] == "true") { SP_FRAME = true; } } if (_game.GetOptionsDict().ContainsKey("SP_RESET")) { if (_game.GetOptionsDict()["SP_RESET"] == "true") { SP_RESET = true; } } }
public void HardReset() { cpu = new MOS6502X(); cpu.SetCallbacks(ReadMemory, ReadMemory, PeekMemory, WriteMemory); cpu.BCD_Enabled = false; cpu.OnExecFetch = ExecFetch; ppu = new PPU(this); ram = new byte[0x800]; CIRAM = new byte[0x800]; // wire controllers // todo: allow changing this ControllerDeck = ControllerSettings.Instantiate(ppu.LightGunCallback); // set controller definition first time only if (ControllerDefinition == null) { ControllerDefinition = new ControllerDefinition(ControllerDeck.GetDefinition()); ControllerDefinition.Name = "NES Controller"; // controls other than the deck ControllerDefinition.BoolButtons.Add("Power"); ControllerDefinition.BoolButtons.Add("Reset"); if (Board is FDS) { var b = Board as FDS; ControllerDefinition.BoolButtons.Add("FDS Eject"); for (int i = 0; i < b.NumSides; i++) { ControllerDefinition.BoolButtons.Add("FDS Insert " + i); } } if (_isVS) { ControllerDefinition.BoolButtons.Add("Insert Coin P1"); ControllerDefinition.BoolButtons.Add("Insert Coin P2"); ControllerDefinition.BoolButtons.Add("Service Switch"); } } // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); // set up region switch (_display_type) { case Common.DisplayType.PAL: apu = new APU(this, apu, true); ppu.region = PPU.Region.PAL; CoreComm.VsyncNum = 50; CoreComm.VsyncDen = 1; cpuclockrate = 1662607; cpu_sequence = cpu_sequence_PAL; _display_type = DisplayType.PAL; break; case Common.DisplayType.NTSC: apu = new APU(this, apu, false); ppu.region = PPU.Region.NTSC; CoreComm.VsyncNum = 39375000; CoreComm.VsyncDen = 655171; cpuclockrate = 1789773; cpu_sequence = cpu_sequence_NTSC; break; // this is in bootgod, but not used at all case Common.DisplayType.DENDY: apu = new APU(this, apu, false); ppu.region = PPU.Region.Dendy; CoreComm.VsyncNum = 50; CoreComm.VsyncDen = 1; cpuclockrate = 1773448; cpu_sequence = cpu_sequence_NTSC; _display_type = DisplayType.DENDY; break; default: throw new Exception("Unknown displaytype!"); } if (magicSoundProvider == null) { magicSoundProvider = new MagicSoundProvider(this, (uint)cpuclockrate); } BoardSystemHardReset(); // apu has some specific power up bahaviour that we will emulate here apu.NESHardReset(); if (SyncSettings.InitialWRamStatePattern != null && SyncSettings.InitialWRamStatePattern.Any()) { for (int i = 0; i < 0x800; i++) { ram[i] = SyncSettings.InitialWRamStatePattern[i % SyncSettings.InitialWRamStatePattern.Count]; } } else { // check fceux's PowerNES and FCEU_MemoryRand function for more information: // relevant games: Cybernoid; Minna no Taabou no Nakayoshi Daisakusen; Huang Di; and maybe mechanized attack for (int i = 0; i < 0x800; i++) { if ((i & 4) != 0) { ram[i] = 0xFF; } else { ram[i] = 0x00; } } } SetupMemoryDomains(); // some boards cannot have specific values in RAM upon initialization // Let's hard code those cases here // these will be defined through the gameDB exclusively for now. if (cart.DB_GameInfo != null) { if (cart.DB_GameInfo.Hash == "60FC5FA5B5ACCAF3AEFEBA73FC8BFFD3C4DAE558" || // Camerica Golden 5 cart.DB_GameInfo.Hash == "BAD382331C30B22A908DA4BFF2759C25113CC26A" || // Camerica Golden 5 cart.DB_GameInfo.Hash == "40409FEC8249EFDB772E6FFB2DCD41860C6CCA23" // Camerica Pegasus 4-in-1 ) { ram[0x701] = 0xFF; } } }
public void RebootCore() { // Regenerate mapper here to make sure its state is entirely clean switch (_game.GetOptionsDict()["m"]) { case "2IN1": _mapper = SetMultiCartMapper(Rom.Length, 2); break; case "4IN1": _mapper = SetMultiCartMapper(Rom.Length, 4); break; case "8IN1": _mapper = SetMultiCartMapper(Rom.Length, 8); break; case "16IN1": _mapper = SetMultiCartMapper(Rom.Length, 16); break; case "32IN1": _mapper = SetMultiCartMapper(Rom.Length, 32); break; case "AR": _mapper = new mAR(this); // This mapper has to set up configurations in the contructor. break; case "4K": _mapper = new m4K(); break; case "2K": _mapper = new m2K(); break; case "CM": _mapper = new mCM(); break; case "CV": _mapper = new mCV(); break; case "DPC": _mapper = new mDPC(); break; case "DPC+": _mapper = new mDPCPlus(); break; case "F8": _mapper = new mF8(); break; case "F8SC": _mapper = new mF8SC(); break; case "F6": _mapper = new mF6(); break; case "F6SC": _mapper = new mF6SC(); break; case "F4": _mapper = new mF4(); break; case "F4SC": _mapper = new mF4SC(); break; case "FE": _mapper = new mFE(); break; case "E0": _mapper = new mE0(); break; case "3F": _mapper = new m3F(); break; case "FA": _mapper = new mFA(); break; case "FA2": _mapper = new mFA2(); break; case "E7": _mapper = new mE7(); break; case "F0": _mapper = new mF0(); break; case "UA": _mapper = new mUA(); break; // Homebrew mappers case "3E": _mapper = new m3E(); break; case "0840": _mapper = new m0840(); break; case "MC": _mapper = new mMC(); break; case "EF": _mapper = new mEF(); break; case "EFSC": _mapper = new mEFSC(); break; case "X07": _mapper = new mX07(); break; case "4A50": _mapper = new m4A50(); break; case "SB": _mapper = new mSB(); break; default: throw new InvalidOperationException("mapper not supported: " + _game.GetOptionsDict()["m"]); } _mapper.Core = this; _lagcount = 0; Cpu = new MOS6502X { ReadMemory = this.ReadMemory, WriteMemory = this.WriteMemory, PeekMemory = this.PeekMemory, DummyReadMemory = this.ReadMemory, OnExecFetch = this.ExecFetch }; if (_game["PAL"]) { _pal = true; } else if (_game["NTSC"]) { _pal = false; } else { _pal = DetectPal(_game, Rom); } _tia = new TIA(this, _pal, Settings.SECAMColors); _tia.GetFrameRate(out CoreComm.VsyncNum, out CoreComm.VsyncDen); // dcfilter coefficent is from real observed hardware behavior: a latched "1" will fully decay by ~170 or so tia sound cycles _dcfilter = DCFilter.AsISoundProvider(_tia, 256); M6532 = new M6532(this); // Set up the system state here. for instance.. // Read from the reset vector for where to start Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC // Show mapper class on romstatusdetails CoreComm.RomStatusDetails = string.Format( "{0}\r\nSHA1:{1}\r\nMD5:{2}\r\nMapper Impl \"{3}\"", this._game.Name, Rom.HashSHA1(), Rom.HashMD5(), _mapper.GetType()); }
private void RebootCore() { // Regenerate mapper here to make sure its state is entirely clean switch (_game.GetOptionsDict()["m"]) { case "2IN1": _mapper = SetMultiCartMapper(Rom.Length, 2); break; case "4IN1": _mapper = SetMultiCartMapper(Rom.Length, 4); break; case "8IN1": _mapper = SetMultiCartMapper(Rom.Length, 8); break; case "16IN1": _mapper = SetMultiCartMapper(Rom.Length, 16); break; case "32IN1": _mapper = SetMultiCartMapper(Rom.Length, 32); break; case "AR": _mapper = new mAR(this); // This mapper has to set up configurations in the contructor. break; case "4K": _mapper = new m4K(); break; case "2K": _mapper = new m2K(); break; case "CM": _mapper = new mCM(); break; case "CV": _mapper = new mCV(); break; case "DPC": _mapper = new mDPC(); break; case "DPC+": _mapper = new mDPCPlus(); break; case "F8": _mapper = new mF8(); break; case "F8SC": _mapper = new mF8SC(); break; case "F6": _mapper = new mF6(); break; case "F6SC": _mapper = new mF6SC(); break; case "F4": _mapper = new mF4(); break; case "F4SC": _mapper = new mF4SC(); break; case "FE": _mapper = new mFE(); break; case "E0": _mapper = new mE0(); break; case "3F": _mapper = new m3F(); break; case "FA": _mapper = new mFA(); break; case "FA2": _mapper = new mFA2(); break; case "E7": _mapper = new mE7(); break; case "F0": _mapper = new mF0(); break; case "UA": _mapper = new mUA(); break; // Special Sega Mapper which has swapped banks case "F8_sega": _mapper = new mF8_sega(); break; // Homebrew mappers case "3E": _mapper = new m3E(); break; case "0840": _mapper = new m0840(); break; case "MC": _mapper = new mMC(); break; case "EF": _mapper = new mEF(); break; case "EFSC": _mapper = new mEFSC(); break; case "X07": _mapper = new mX07(); break; case "4A50": _mapper = new m4A50(); break; case "SB": _mapper = new mSB(); break; default: throw new InvalidOperationException("mapper not supported: " + _game.GetOptionsDict()["m"]); } _mapper.Core = this; _lagcount = 0; Cpu = new MOS6502X { ReadMemory = this.ReadMemory, WriteMemory = this.WriteMemory, PeekMemory = this.PeekMemory, DummyReadMemory = this.ReadMemory, OnExecFetch = this.ExecFetch }; 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, CoreComm.VsyncRate > 55.0 ? 735 : 882); _tia.GetFrameRate(out CoreComm.VsyncNum, out CoreComm.VsyncDen); _dcfilter = new DCFilter(_tia, 256); M6532 = new M6532(this); // Set up the system state here. for instance.. // Read from the reset vector for where to start Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC // Show mapper class on romstatusdetails CoreComm.RomStatusDetails = string.Format( "{0}\r\nSHA1:{1}\r\nMD5:{2}\r\nMapper Impl \"{3}\"", this._game.Name, Rom.HashSHA1(), Rom.HashMD5(), _mapper.GetType()); // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 // executing a reset sequence at power on, but it's needed so let's hard code it for now Cpu.S = 0xFD; }
public void HardReset() { cpu = new MOS6502X <CpuLink>(new CpuLink(this)) { BCD_Enabled = false }; ppu = new PPU(this); ram = new byte[0x800]; CIRAM = new byte[0x800]; // wire controllers // todo: allow changing this ControllerDeck = ControllerSettings.Instantiate(ppu.LightGunCallback); // set controller definition first time only if (ControllerDefinition == null) { ControllerDefinition = new ControllerDefinition(ControllerDeck.GetDefinition()); ControllerDefinition.Name = "NES Controller"; // controls other than the deck ControllerDefinition.BoolButtons.Add("Power"); ControllerDefinition.BoolButtons.Add("Reset"); if (Board is FDS) { var b = Board as FDS; ControllerDefinition.BoolButtons.Add("FDS Eject"); for (int i = 0; i < b.NumSides; i++) { ControllerDefinition.BoolButtons.Add("FDS Insert " + i); } } if (_isVS) { ControllerDefinition.BoolButtons.Add("Insert Coin P1"); ControllerDefinition.BoolButtons.Add("Insert Coin P2"); ControllerDefinition.BoolButtons.Add("Service Switch"); } } // Add in the reset timing float control for subneshawk if (using_reset_timing && (ControllerDefinition.FloatControls.Count() == 0)) { ControllerDefinition.FloatControls.Add("Reset Cycle"); ControllerDefinition.FloatRanges.Add(new ControllerDefinition.FloatRange(0, 0, 500000)); } // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); // set up region switch (_display_type) { case Common.DisplayType.PAL: apu = new APU(this, apu, true); ppu.region = PPU.Region.PAL; VsyncNum = 50; VsyncDen = 1; cpuclockrate = 1662607; cpu_sequence = cpu_sequence_PAL; _display_type = DisplayType.PAL; ClockRate = 5320342.5; break; case Common.DisplayType.NTSC: apu = new APU(this, apu, false); ppu.region = PPU.Region.NTSC; VsyncNum = 39375000; VsyncDen = 655171; cpuclockrate = 1789773; cpu_sequence = cpu_sequence_NTSC; ClockRate = 5369318.1818181818181818181818182; break; // this is in bootgod, but not used at all case Common.DisplayType.Dendy: apu = new APU(this, apu, false); ppu.region = PPU.Region.Dendy; VsyncNum = 50; VsyncDen = 1; cpuclockrate = 1773448; cpu_sequence = cpu_sequence_NTSC; _display_type = DisplayType.Dendy; ClockRate = 5320342.5; break; default: throw new Exception("Unknown displaytype!"); } blip.SetRates((uint)cpuclockrate, 44100); BoardSystemHardReset(); // apu has some specific power up bahaviour that we will emulate here apu.NESHardReset(); if (SyncSettings.InitialWRamStatePattern != null && SyncSettings.InitialWRamStatePattern.Any()) { for (int i = 0; i < 0x800; i++) { ram[i] = SyncSettings.InitialWRamStatePattern[i % SyncSettings.InitialWRamStatePattern.Count]; } } else { // check fceux's PowerNES and FCEU_MemoryRand function for more information: // relevant games: Cybernoid; Minna no Taabou no Nakayoshi Daisakusen; Huang Di; and maybe mechanized attack for (int i = 0; i < 0x800; i++) { if ((i & 4) != 0) { ram[i] = 0xFF; } else { ram[i] = 0x00; } } } SetupMemoryDomains(); // some boards cannot have specific values in RAM upon initialization // Let's hard code those cases here // these will be defined through the gameDB exclusively for now. if (cart.DB_GameInfo != null) { if (cart.DB_GameInfo.Hash == "60FC5FA5B5ACCAF3AEFEBA73FC8BFFD3C4DAE558" || // Camerica Golden 5 cart.DB_GameInfo.Hash == "BAD382331C30B22A908DA4BFF2759C25113CC26A" || // Camerica Golden 5 cart.DB_GameInfo.Hash == "40409FEC8249EFDB772E6FFB2DCD41860C6CCA23" // Camerica Pegasus 4-in-1 ) { ram[0x701] = 0xFF; } if (cart.DB_GameInfo.Hash == "68ABE1E49C9E9CCEA978A48232432C252E5912C0") // Dancing Blocks { ram[0xEC] = 0; ram[0xED] = 0; } if (cart.DB_GameInfo.Hash == "00C50062A2DECE99580063777590F26A253AAB6B") // Silva Saga { for (int i = 0; i < Board.WRAM.Length; i++) { Board.WRAM[i] = 0xFF; } } } }
public void HardReset() { cpu = new MOS6502X(); cpu.SetCallbacks(ReadMemory, ReadMemory, PeekMemory, WriteMemory); cpu.BCD_Enabled = false; cpu.OnExecFetch = ExecFetch; ppu = new PPU(this); ram = new byte[0x800]; CIRAM = new byte[0x800]; // wire controllers // todo: allow changing this ControllerDeck = ControllerSettings.Instantiate(ppu.LightGunCallback); // set controller definition first time only if (ControllerDefinition == null) { ControllerDefinition = new ControllerDefinition(ControllerDeck.GetDefinition()); ControllerDefinition.Name = "NES Controller"; // controls other than the deck ControllerDefinition.BoolButtons.Add("Power"); ControllerDefinition.BoolButtons.Add("Reset"); if (board is FDS) { var b = board as FDS; ControllerDefinition.BoolButtons.Add("FDS Eject"); for (int i = 0; i < b.NumSides; i++) { ControllerDefinition.BoolButtons.Add("FDS Insert " + i); } } } // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); // set up region switch (_display_type) { case Common.DisplayType.PAL: apu = new APU(this, apu, true); ppu.region = PPU.Region.PAL; CoreComm.VsyncNum = 50; CoreComm.VsyncDen = 1; cpuclockrate = 1662607; cpu_sequence = cpu_sequence_PAL; _display_type = DisplayType.PAL; break; case Common.DisplayType.NTSC: apu = new APU(this, apu, false); ppu.region = PPU.Region.NTSC; CoreComm.VsyncNum = 39375000; CoreComm.VsyncDen = 655171; cpuclockrate = 1789773; cpu_sequence = cpu_sequence_NTSC; break; // this is in bootgod, but not used at all case Common.DisplayType.DENDY: apu = new APU(this, apu, false); ppu.region = PPU.Region.Dendy; CoreComm.VsyncNum = 50; CoreComm.VsyncDen = 1; cpuclockrate = 1773448; cpu_sequence = cpu_sequence_NTSC; _display_type = DisplayType.DENDY; break; default: throw new Exception("Unknown displaytype!"); } if (magicSoundProvider == null) { magicSoundProvider = new MagicSoundProvider(this, (uint)cpuclockrate); } BoardSystemHardReset(); //check fceux's PowerNES and FCEU_MemoryRand function for more information: //relevant games: Cybernoid; Minna no Taabou no Nakayoshi Daisakusen; Huang Di; and maybe mechanized attack for (int i = 0; i < 0x800; i++) { if ((i & 4) != 0) { ram[i] = 0xFF; } else { ram[i] = 0x00; } } SetupMemoryDomains(); //in this emulator, reset takes place instantaneously cpu.PC = (ushort)(ReadMemory(0xFFFC) | (ReadMemory(0xFFFD) << 8)); cpu.P = 0x34; cpu.S = 0xFD; }
public VIC1541Motherboard(Region initRegion, byte[] initRom) { cpu = new MOS6502X(); pla = new VIC1541PLA(); ram = new byte[0x800]; rom = initRom; serPort = new SerialPort(); via0 = new MOS6522(); via1 = new MOS6522(); cpu.DummyReadMemory = pla.Read; cpu.ReadMemory = pla.Read; cpu.WriteMemory = pla.Write; pla.PeekRam = ((int addr) => { return(ram[addr & 0x07FF]); }); pla.PeekRom = ((int addr) => { return(rom[addr & 0x3FFF]); }); pla.PeekVia0 = via0.Peek; pla.PeekVia1 = via1.Peek; pla.PokeRam = ((int addr, byte val) => { ram[addr & 0x07FF] = val; }); pla.PokeRom = ((int addr, byte val) => { }); pla.PokeVia0 = via0.Poke; pla.PokeVia1 = via1.Poke; pla.ReadRam = ((ushort addr) => { return(ram[addr & 0x07FF]); }); pla.ReadRom = ((ushort addr) => { return(rom[addr & 0x3FFF]); }); pla.ReadVia0 = via0.Read; pla.ReadVia1 = via1.Read; pla.WriteRam = ((ushort addr, byte val) => { ram[addr & 0x07FF] = val; }); pla.WriteRom = ((ushort addr, byte val) => { }); pla.WriteVia0 = via0.Write; pla.WriteVia1 = via1.Write; via0CA0 = false; via0CA1 = false; via0CB0 = false; via0CB1 = false; via0DirA = 0x00; via0DirB = 0x00; via0DataA = 0xFF; via0DataB = 0xFF; via1CA0 = false; via1CA1 = false; via1CB0 = false; via1CB1 = false; via1DirA = 0x00; via1DirB = 0x00; via1DataA = 0xFF; via1DataB = 0xFF; via0.ReadCA0 = (() => { return(via0CA0); }); via0.ReadCA1 = (() => { return(via0CA1); }); via0.ReadCB0 = (() => { return(via0CB0); }); via0.ReadCB1 = (() => { return(via0CB1); }); via0.ReadDirA = (() => { return(via0DirA); }); via0.ReadDirB = (() => { return(via0DirB); }); via0.ReadPortA = (() => { return(via0DataA); }); via0.ReadPortB = (() => { return(via0DataB); }); via0.WriteCA0 = ((bool val) => { via0CA0 = val; }); via0.WriteCA1 = ((bool val) => { via0CA1 = val; }); via0.WriteCB0 = ((bool val) => { via0CB0 = val; }); via0.WriteCB1 = ((bool val) => { via0CB1 = val; }); via0.WriteDirA = ((byte val) => { via0DirA = val; }); via0.WriteDirB = ((byte val) => { via0DirB = val; }); via0.WritePortA = ((byte val) => { via0DataA = Port.CPUWrite(via0DataA, val, via0DirA); }); via0.WritePortB = ((byte val) => { via0DataB = Port.CPUWrite(via0DataB, val, via0DirB); serPort.DeviceWriteAtn((via0DataB & 0x80) != 0); serPort.DeviceWriteClock((via0DataB & 0x08) != 0); serPort.DeviceWriteData((via0DataB & 0x02) != 0); }); via1.ReadCA0 = (() => { return(via1CA0); }); via1.ReadCA1 = (() => { return(via1CA1); }); via1.ReadCB0 = (() => { return(via1CB0); }); via1.ReadCB1 = (() => { return(via1CB1); }); via1.ReadDirA = (() => { return(via1DirA); }); via1.ReadDirB = (() => { return(via1DirB); }); via1.ReadPortA = (() => { return(via1DataA); }); via1.ReadPortB = (() => { return(via1DataB); }); via1.WriteCA0 = ((bool val) => { via1CA0 = val; }); via1.WriteCA1 = ((bool val) => { via1CA1 = val; }); via1.WriteCB0 = ((bool val) => { via1CB0 = val; }); via1.WriteCB1 = ((bool val) => { via1CB1 = val; }); via1.WriteDirA = ((byte val) => { via1DirA = val; }); via1.WriteDirB = ((byte val) => { via1DirB = val; }); via1.WritePortA = ((byte val) => { via1DataA = Port.CPUWrite(via1DataA, val, via1DirA); }); via1.WritePortB = ((byte val) => { via1DataB = Port.CPUWrite(via1DataB, val, via1DirB); }); }
public void HardReset() { cpu = new MOS6502X <CpuLink>(new CpuLink(this)) { BCD_Enabled = false }; ppu = new PPU(this); ram = new byte[0x800]; CIRAM = new byte[0x800]; // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); // set up region switch (_display_type) { case DisplayType.PAL: apu = new APU(this, apu, true); ppu.region = PPU.Region.PAL; cpuclockrate = 1662607; VsyncNum = cpuclockrate * 2; VsyncDen = 66495; cpu_sequence = cpu_sequence_PAL; _display_type = DisplayType.PAL; ClockRate = 5320342.5; break; case DisplayType.NTSC: apu = new APU(this, apu, false); ppu.region = PPU.Region.NTSC; cpuclockrate = 1789773; VsyncNum = cpuclockrate * 2; VsyncDen = 59561; cpu_sequence = cpu_sequence_NTSC; ClockRate = 5369318.1818181818181818181818182; break; // this is in bootgod, but not used at all case DisplayType.Dendy: apu = new APU(this, apu, false); ppu.region = PPU.Region.Dendy; cpuclockrate = 1773448; VsyncNum = cpuclockrate; VsyncDen = 35464; cpu_sequence = cpu_sequence_NTSC; _display_type = DisplayType.Dendy; ClockRate = 5320342.5; break; default: throw new Exception("Unknown displaytype!"); } blip.SetRates((uint)cpuclockrate, 44100); BoardSystemHardReset(); // apu has some specific power up bahaviour that we will emulate here apu.NESHardReset(); if (SyncSettings.InitialWRamStatePattern != null && SyncSettings.InitialWRamStatePattern.Any()) { for (int i = 0; i < 0x800; i++) { ram[i] = SyncSettings.InitialWRamStatePattern[i % SyncSettings.InitialWRamStatePattern.Count]; } } else { // check fceux's PowerNES and FCEU_MemoryRand function for more information: // relevant games: Cybernoid; Minna no Taabou no Nakayoshi Daisakusen; Huang Di; and maybe mechanized attack for (int i = 0; i < 0x800; i++) { if ((i & 4) != 0) { ram[i] = 0xFF; } else { ram[i] = 0x00; } } } SetupMemoryDomains(); // some boards cannot have specific values in RAM upon initialization // Let's hard code those cases here // these will be defined through the gameDB exclusively for now. var hash = cart.GameInfo?.Hash; // SHA1 or MD5 (see NES.IdentifyFromGameDB) if (hash is null) { // short-circuit } else if (hash is RomChecksums.CamericaGolden5 or RomChecksums.CamericaGolden5Overdump or RomChecksums.CamericaPegasus4in1) { ram[0x701] = 0xFF; }
public string Disassemble(MemoryDomain m, uint addr, out int length) { return(MOS6502X.Disassemble((ushort)addr, out length, a => unchecked ((byte)Peek(a)))); }
public void HardReset() { cpu = new MOS6502X <CpuLink>(new CpuLink(this)) { BCD_Enabled = false }; ppu = new PPU(this); ram = new byte[0x800]; CIRAM = new byte[0x800]; // wire controllers // todo: allow changing this ControllerDeck = ControllerSettings.Instantiate(ppu.LightGunCallback); // set controller definition first time only if (ControllerDefinition == null) { ControllerDefinition = new ControllerDefinition(ControllerDeck.GetDefinition()) { Name = "NES Controller" }; // controls other than the deck ControllerDefinition.BoolButtons.Add("Power"); ControllerDefinition.BoolButtons.Add("Reset"); if (Board is FDS b) { ControllerDefinition.BoolButtons.Add("FDS Eject"); for (int i = 0; i < b.NumSides; i++) { ControllerDefinition.BoolButtons.Add("FDS Insert " + i); } } if (_isVS) { ControllerDefinition.BoolButtons.Add("Insert Coin P1"); ControllerDefinition.BoolButtons.Add("Insert Coin P2"); ControllerDefinition.BoolButtons.Add("Service Switch"); } } // Add in the reset timing axis for subneshawk if (using_reset_timing && ControllerDefinition.Axes.Count == 0) { ControllerDefinition.AddAxis("Reset Cycle", 0.RangeTo(500000), 0); } // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); // set up region switch (_display_type) { case DisplayType.PAL: apu = new APU(this, apu, true); ppu.region = PPU.Region.PAL; cpuclockrate = 1662607; VsyncNum = cpuclockrate * 2; VsyncDen = 66495; cpu_sequence = cpu_sequence_PAL; _display_type = DisplayType.PAL; ClockRate = 5320342.5; break; case DisplayType.NTSC: apu = new APU(this, apu, false); ppu.region = PPU.Region.NTSC; cpuclockrate = 1789773; VsyncNum = cpuclockrate * 2; VsyncDen = 59561; cpu_sequence = cpu_sequence_NTSC; ClockRate = 5369318.1818181818181818181818182; break; // this is in bootgod, but not used at all case DisplayType.Dendy: apu = new APU(this, apu, false); ppu.region = PPU.Region.Dendy; cpuclockrate = 1773448; VsyncNum = cpuclockrate; VsyncDen = 35464; cpu_sequence = cpu_sequence_NTSC; _display_type = DisplayType.Dendy; ClockRate = 5320342.5; break; default: throw new Exception("Unknown displaytype!"); } blip.SetRates((uint)cpuclockrate, 44100); BoardSystemHardReset(); // apu has some specific power up bahaviour that we will emulate here apu.NESHardReset(); if (SyncSettings.InitialWRamStatePattern != null && SyncSettings.InitialWRamStatePattern.Any()) { for (int i = 0; i < 0x800; i++) { ram[i] = SyncSettings.InitialWRamStatePattern[i % SyncSettings.InitialWRamStatePattern.Count]; } } else { // check fceux's PowerNES and FCEU_MemoryRand function for more information: // relevant games: Cybernoid; Minna no Taabou no Nakayoshi Daisakusen; Huang Di; and maybe mechanized attack for (int i = 0; i < 0x800; i++) { if ((i & 4) != 0) { ram[i] = 0xFF; } else { ram[i] = 0x00; } } } SetupMemoryDomains(); // some boards cannot have specific values in RAM upon initialization // Let's hard code those cases here // these will be defined through the gameDB exclusively for now. if (cart.GameInfo != null) { if (cart.GameInfo.Hash is RomChecksums.CamericaGolden5 or RomChecksums.CamericaGolden5Overdump or RomChecksums.CamericaPegasus4in1) { ram[0x701] = 0xFF; } else if (cart.GameInfo.Hash == RomChecksums.DancingBlocks) { ram[0xEC] = 0; ram[0xED] = 0; } else if (cart.GameInfo.Hash == RomChecksums.SilvaSaga) { for (int i = 0; i < Board.Wram.Length; i++) { Board.Wram[i] = 0xFF; } } }
public string Disassemble(MemoryDomain m, uint addr, out int length) { return(MOS6502X.Disassemble((ushort)addr, out length, CpuPeek)); }
public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn) { var ser = new BasicServiceProvider(this); maria = new Maria(); tia = new TIA(); m6532 = new M6532(); cpu = new MOS6502X { ReadMemory = ReadMemory, WriteMemory = WriteMemory, PeekMemory = ReadMemory, DummyReadMemory = ReadMemory, OnExecFetch = ExecFetch }; maria = new Maria { ReadMemory = ReadMemory }; CoreComm = comm; _controllerDeck = new A7800HawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2); byte[] highscoreBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS."); byte[] palBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available."); byte[] ntscBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_NTSC", false, "The game will not run if the correct region BIOS is not available."); if (rom.Length % 1024 == 128) { Console.WriteLine("Trimming 128 byte .a78 header..."); byte[] newrom = new byte[rom.Length - 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 string hash_md5 = null; s_mapper = null; hash_md5 = "md5:" + rom.HashMD5(0, rom.Length); var gi = Database.CheckDatabase(hash_md5); if (gi != null) { var dict = gi.GetOptionsDict(); if (dict.ContainsKey("PAL")) { _isPAL = true; } if (dict.ContainsKey("board")) { s_mapper = dict["board"]; } else { throw new Exception("No Board selected for this game"); } } else { throw new Exception("ROM not in gamedb"); } Reset_Mapper(s_mapper); _rom = rom; _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) { maria._frameHz = 50; maria._screen_width = 320; maria._screen_height = 313; maria._palette = PALPalette; } else { maria._frameHz = 60; maria._screen_width = 320; maria._screen_height = 263; maria._palette = NTSCPalette; } maria.Core = this; m6532.Core = this; tia.Core = this; ser.Register <IVideoProvider>(maria); ser.Register <ISoundProvider>(tia); ServiceProvider = ser; _tracer = new TraceBuffer { Header = cpu.TraceHeader }; ser.Register <ITraceable>(_tracer); SetupMemoryDomains(); HardReset(); }
public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn, object settings, object 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 }; CoreComm = comm; _blip.SetRates(1789773, 44100); _settings = (A7800Settings)settings ?? new A7800Settings(); _syncSettings = (A7800SyncSettings)syncSettings ?? new A7800SyncSettings(); _controllerDeck = new A7800HawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2); byte[] highscoreBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS."); byte[] palBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available."); byte[] ntscBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_NTSC", false, "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 string hash_md5 = null; s_mapper = null; hash_md5 = "md5:" + rom.HashMD5(0, rom.Length); var gi = Database.CheckDatabase(hash_md5); if (gi != null) { var dict = gi.GetOptionsDict(); if (dict.ContainsKey("PAL")) { _isPAL = true; } if (dict.ContainsKey("board")) { s_mapper = dict["board"]; } else { throw new Exception("No Board selected for this game"); } // check if the game uses pokey or RAM if (dict.ContainsKey("RAM")) { int.TryParse(dict["RAM"], out cart_RAM); Console.WriteLine(cart_RAM); } if (dict.ContainsKey("Pokey")) { bool.TryParse(dict["Pokey"], out is_pokey); } // 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.ContainsKey("No_HS")) { bool no_hs; bool.TryParse(dict["No_HS"], out 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; } } else { s_mapper = "0"; } if (cart_2.Bit(0)) { is_pokey = 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 (rom.HashMD5() == "5E0A1E832BBCEA6FACB832FDE23A440A") { 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 { Header = cpu.TraceHeader }; ser.Register <ITraceable>(_tracer); SetupMemoryDomains(); ser.Register <IDisassemblable>(cpu); HardReset(); }
public string Disassemble(MemoryDomain m, uint addr, out int length) { return(MOS6502X.Disassemble((ushort)addr, out length, (a) => m.PeekByte(a))); }