Пример #1
0
        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);
        }
Пример #2
0
        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;
            }
        }
Пример #3
0
        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();
        }
Пример #4
0
 // 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
     });
 }
Пример #5
0
        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);
        }
Пример #6
0
        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;
            }
        }
Пример #7
0
        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));
        }
Пример #8
0
        // 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;
        }
Пример #10
0
        /// <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());
                }
            }
        }
Пример #11
0
        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();
        }
Пример #12
0
        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;
            }
        }
Пример #13
0
        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;
            }
        }
Пример #14
0
        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;
            }
        }
Пример #15
0
        public O2Hawk(CoreComm comm, GameInfo game, byte[] rom, O2Settings settings, O2SyncSettings syncSettings)
        {
            var ser = new BasicServiceProvider(this);

            cpu = new I8048
            {
                ReadMemory      = ReadMemory,
                WriteMemory     = WriteMemory,
                PeekMemory      = PeekMemory,
                DummyReadMemory = ReadMemory,
                ReadPort        = ReadPort,
                WritePort       = WritePort,
                OnExecFetch     = ExecFetch,
            };

            _settings     = settings ?? new O2Settings();
            _syncSettings = syncSettings ?? new O2SyncSettings();

            is_G7400 = _syncSettings.G7400_Enable;

            _controllerDeck = new O2HawkControllerDeck("O2 Controller", "O2 Controller", is_G7400);

            _bios = comm.CoreFileProvider.GetFirmwareOrThrow(new("O2", is_G7400 ? "BIOS-G7400" : "BIOS-O2"), "BIOS Not Found, Cannot Load");

            Buffer.BlockCopy(rom, 0x100, header, 0, 0x50);

            Console.WriteLine(MD5Checksum.ComputePrefixedHex(rom));
            Console.WriteLine(SHA1Checksum.ComputePrefixedHex(rom));
            _rom = rom;

            if (game["XROM"])
            {
                is_XROM = true;
            }
            Setup_Mapper();

            _frameHz = 60;

            ser.Register <IVideoProvider>(this);
            ServiceProvider = ser;

            _tracer = new TraceBuffer(cpu.TraceHeader);
            ser.Register(_tracer);
            ser.Register <IStatable>(new StateSerializer(SyncState));
            SetupMemoryDomains();
            cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory);

            // set up differences between PAL and NTSC systems
            if ((game.Region == "US" || game.Region == "EU-US" || game.Region == null) && !is_G7400)
            {
                is_pal     = false;
                pic_height = 240;
                _frameHz   = 60;

                ppu = new NTSC_PPU();
            }
            else
            {
                is_pal     = true;
                pic_height = 240;
                _frameHz   = 50;
                ppu        = new PAL_PPU();
            }

            ppu.Core = this;
            ppu.set_region(is_pal, is_G7400);
            ser.Register <ISoundProvider>(ppu);

            _vidbuffer   = new int[372 * pic_height];
            frame_buffer = new int[320 * pic_height];

            HardReset();
        }
Пример #16
0
        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();
        }
Пример #17
0
        } = 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());
            }
        }
Пример #18
0
        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;
        }
Пример #19
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");
            }
        }
Пример #20
0
        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);
        }
Пример #21
0
        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();
        }