Ejemplo n.º 1
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;
        }
Ejemplo n.º 2
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();
        }
Ejemplo n.º 3
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;
            }
        }
Ejemplo n.º 4
0
        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();
        }
Ejemplo n.º 5
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();
        }