private void MakeTrace(ushort pc) { int[] s = new int[10]; LibSameboy.sameboy_getregs(SameboyState, s); Tracer.Put(new( disassembly: LR35902.Disassemble( pc, addr => LibSameboy.sameboy_cpuread(SameboyState, addr), _settings.UseRGBDSSyntax, out _).PadRight(36), registerInfo: string.Format( "A:{0:x2} F:{1:x2} B:{2:x2} C:{3:x2} D:{4:x2} E:{5:x2} H:{6:x2} L:{7:x2} SP:{8:x4} LY:{9:x2} Cy:{10}", s[1] & 0xFF, s[2] & 0xFF, s[3] & 0xFF, s[4] & 0xFF, s[5] & 0xFF, s[6] & 0xFF, s[7] & 0xFF, s[8] & 0xFF, s[9] & 0xFFFF, LibSameboy.sameboy_cpuread(SameboyState, 0xFF44), CycleCount ))); }
public void LoadStateBinary(BinaryReader reader) { int length = reader.ReadInt32(); if (length != _stateBuf.Length) { throw new InvalidOperationException("Savestate buffer size mismatch!"); } reader.Read(_stateBuf, 0, _stateBuf.Length); if (LibSameboy.sameboy_loadstate(SameboyState, _stateBuf, _stateBuf.Length)) { throw new Exception($"{nameof(LibSameboy.sameboy_loadstate)}() returned true"); } // other variables IsLagFrame = reader.ReadBoolean(); LagCount = reader.ReadInt32(); Frame = reader.ReadInt32(); IsCgb = reader.ReadBoolean(); CycleCount = reader.ReadInt64(); theta = reader.ReadDouble(); phi = reader.ReadDouble(); theta_prev = reader.ReadDouble(); phi_prev = reader.ReadDouble(); phi_prev_2 = reader.ReadDouble(); }
static Sameboy() { var resolver = new DynamicLibraryImportResolver( OSTailoredCode.IsUnixHost ? "libsameboy.so" : "libsameboy.dll", hasLimitedLifetime: false); LibSameboy = BizInvoker.GetInvoker <LibSameboy>(resolver, CallingConventionAdapters.Native); }
public void Dispose() { if (SameboyState != IntPtr.Zero) { LibSameboy.sameboy_destroy(SameboyState); SameboyState = IntPtr.Zero; } }
public void StoreSaveRam(byte[] data) { int expected = LibSameboy.sameboy_sramlen(SameboyState); if (data.Length - expected != 0) { throw new ArgumentException("Size of saveram data does not match expected!"); } LibSameboy.sameboy_loadsram(SameboyState, data, data.Length); }
public byte[] CloneSaveRam() { int length = LibSameboy.sameboy_sramlen(SameboyState); if (length > 0) { byte[] ret = new byte[length]; LibSameboy.sameboy_savesram(SameboyState, ret); return(ret); } return(null); }
public PutSettingsDirtyBits PutSettings(SameboySettings o) { LibSameboy.sameboy_setpalette(SameboyState, o.GBPalette, o.GetCustomPalette()); LibSameboy.sameboy_setcolorcorrection(SameboyState, o.ColorCorrection); LibSameboy.sameboy_setlighttemperature(SameboyState, o.LightTemperature); LibSameboy.sameboy_sethighpassfilter(SameboyState, o.HighPassFilter); LibSameboy.sameboy_setinterferencevolume(SameboyState, o.InterferenceVolume); LibSameboy.sameboy_setbgwinenabled(SameboyState, o.EnableBGWIN); LibSameboy.sameboy_setobjenabled(SameboyState, o.EnableOBJ); _disassembler.UseRGBDSSyntax = o.UseRGBDSSyntax; _settings = o; return(PutSettingsDirtyBits.None); }
private void FrameAdvancePost() { if (IsLagFrame) { LagCount++; } Frame++; if (_scanlinecbline == -1) { _scanlinecb?.Invoke(LibSameboy.sameboy_cpuread(SameboyState, 0xFF40)); } }
public bool FrameAdvance(IController controller, bool render, bool rendersound) { var buttons = FrameAdvancePrep(controller); LibSameboy.sameboy_frameadvance(SameboyState, buttons, GetAccX(controller), GetAccY(), VideoBuffer, render, _settings.ShowBorder); if (!rendersound) { DiscardSamples(); } FrameAdvancePost(); return(true); }
private void CreateMemoryDomain(LibSameboy.MemoryAreas which, string name) { IntPtr data = IntPtr.Zero; int length = 0; if (!LibSameboy.sameboy_getmemoryarea(SameboyState, which, ref data, ref length)) { throw new Exception($"{nameof(LibSameboy.sameboy_getmemoryarea)}() failed!"); } // if length == 0, it's an empty block; (usually rambank on some carts); that's ok if (data != IntPtr.Zero && length > 0) { _memoryDomains.Add(new MemoryDomainIntPtr(name, MemoryDomain.Endian.Little, data, length, true, 1)); } }
public void SetCpuRegister(string register, int value) { LibSameboy.sameboy_setreg(SameboyState, register.ToUpper() switch { "PC" => 0, "A" => 1, "F" => 2, "B" => 3, "C" => 4, "D" => 5, "E" => 6, "H" => 7, "L" => 8, "SP" => 9, _ => throw new InvalidOperationException("Invalid Register?"), },
public IDictionary <string, RegisterValue> GetCpuFlagsAndRegisters() { int[] data = new int[10]; LibSameboy.sameboy_getregs(SameboyState, data); return(new Dictionary <string, RegisterValue> { ["PC"] = (ushort)(data[0] & 0xFFFF), ["A"] = (byte)(data[1] & 0xFF), ["F"] = (byte)(data[2] & 0xFF), ["B"] = (byte)(data[3] & 0xFF), ["C"] = (byte)(data[4] & 0xFF), ["D"] = (byte)(data[5] & 0xFF), ["E"] = (byte)(data[6] & 0xFF), ["H"] = (byte)(data[7] & 0xFF), ["L"] = (byte)(data[8] & 0xFF), ["SP"] = (ushort)(data[9] & 0xFFFF), }); }
public void SaveStateBinary(BinaryWriter writer) { LibSameboy.sameboy_savestate(SameboyState, _stateBuf); writer.Write(_stateBuf.Length); writer.Write(_stateBuf); // other variables writer.Write(IsLagFrame); writer.Write(LagCount); writer.Write(Frame); writer.Write(IsCgb); writer.Write(CycleCount); writer.Write(theta); writer.Write(phi); writer.Write(theta_prev); writer.Write(phi_prev); writer.Write(phi_prev_2); }
private void InitMemoryDomains() { CreateMemoryDomain(LibSameboy.MemoryAreas.ROM, "ROM"); CreateMemoryDomain(LibSameboy.MemoryAreas.RAM, "WRAM"); CreateMemoryDomain(LibSameboy.MemoryAreas.CART_RAM, "CartRAM"); CreateMemoryDomain(LibSameboy.MemoryAreas.VRAM, "VRAM"); CreateMemoryDomain(LibSameboy.MemoryAreas.HRAM, "HRAM"); CreateMemoryDomain(LibSameboy.MemoryAreas.IO, "MMIO"); CreateMemoryDomain(LibSameboy.MemoryAreas.BOOTROM, "BIOS"); CreateMemoryDomain(LibSameboy.MemoryAreas.OAM, "OAM"); CreateMemoryDomain(LibSameboy.MemoryAreas.BGP, "BGP"); CreateMemoryDomain(LibSameboy.MemoryAreas.OBP, "OBP"); CreateMemoryDomain(LibSameboy.MemoryAreas.IE, "IE"); // also add a special memory domain for the system bus, where calls get sent directly to the core each time _memoryDomains.Add(new MemoryDomainDelegate("System Bus", 65536, MemoryDomain.Endian.Little, delegate(long addr) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } return(LibSameboy.sameboy_cpuread(SameboyState, (ushort)addr)); }, delegate(long addr, byte val) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } LibSameboy.sameboy_cpuwrite(SameboyState, (ushort)addr, val); }, 1)); MemoryDomains = new MemoryDomainList(_memoryDomains); _serviceProvider.Register(MemoryDomains); }
private LibSameboy.Buttons FrameAdvancePrep(IController controller) { uint b = 0; for (var i = 0; i < 8; i++) { b <<= 1; if (controller.IsPressed(GB_BUTTON_ORDER_IN_BITMASK[i])) { b |= 1; } } if (controller.IsPressed("Power")) { LibSameboy.sameboy_reset(SameboyState); } IsLagFrame = true; LibSameboy.sameboy_settracecallback(SameboyState, Tracer.IsEnabled() ? _tracecb : null); return((LibSameboy.Buttons)b); }
public void DebugSameBoyState() { LibSameboy.sameboy_savestate(SameboyState, _stateBuf); Directory.CreateDirectory("sameboy_debug"); File.WriteAllBytes($"sameboy_debug/debug_state{Frame}.bin", _stateBuf); }
public bool IsCGBDMGMode() => LibSameboy.sameboy_iscgbdmg(SameboyState);
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; }