void WireMemoryDomainPointers() { var s = new LibmGBA.MemoryAreas(); LibmGBA.BizGetMemoryAreas(core, s); _iwram.Data = s.iwram; _ewram.Data = s.wram; _bios.Data = s.bios; _palram.Data = s.palram; _vram.Data = s.vram; _oam.Data = s.oam; _rom.Data = s.rom; _sram.Data = s.sram; _sram.SetSize(s.sram_size); // special combined ram memory domain _cwram.Peek = delegate(long addr) { LibmGBA.BizGetMemoryAreas(core, s); if (addr < 0 || addr >= (256 + 32) * 1024) { throw new IndexOutOfRangeException(); } if (addr >= 256 * 1024) { return(PeekWRAM(s.iwram, addr & 32767)); } else { return(PeekWRAM(s.wram, addr)); } }; _cwram.Poke = delegate(long addr, byte val) { if (addr < 0 || addr >= (256 + 32) * 1024) { throw new IndexOutOfRangeException(); } if (addr >= 256 * 1024) { PokeWRAM(s.iwram, addr & 32767, val); } else { PokeWRAM(s.wram, addr, val); } }; _gpumem = new GBAGPUMemoryAreas { mmio = s.mmio, oam = s.oam, palram = s.palram, vram = s.vram }; }
public void FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; if (controller.IsPressed("Power")) { LibmGBA.BizReset(_core); // BizReset caused memorydomain pointers to change. WireMemoryDomainPointers(); } IsLagFrame = LibmGBA.BizAdvance( _core, VBANext.GetButtons(controller), _videobuff, ref _nsamp, _soundbuff, RTCTime(), (short)controller.GetFloat("Tilt X"), (short)controller.GetFloat("Tilt Y"), (short)controller.GetFloat("Tilt Z"), (byte)(255 - controller.GetFloat("Light Sensor"))); if (IsLagFrame) { LagCount++; } // this should be called in hblank on the appropriate line, but until we implement that, just do it here _scanlinecb?.Invoke(); }
private MemoryDomainList CreateMemoryDomains(int romsize) { var s = new LibmGBA.MemoryAreas(); var mm = new List <MemoryDomain>(); LibmGBA.BizGetMemoryAreas(core, s); var l = MemoryDomain.Endian.Little; mm.Add(MemoryDomain.FromIntPtr("IWRAM", 32 * 1024, l, s.iwram, true, 4)); mm.Add(MemoryDomain.FromIntPtr("EWRAM", 256 * 1024, l, s.wram, true, 4)); mm.Add(MemoryDomain.FromIntPtr("BIOS", 16 * 1024, l, s.bios, false, 4)); mm.Add(MemoryDomain.FromIntPtr("PALRAM", 1024, l, s.palram, false, 4)); mm.Add(MemoryDomain.FromIntPtr("VRAM", 96 * 1024, l, s.vram, true, 4)); mm.Add(MemoryDomain.FromIntPtr("OAM", 1024, l, s.oam, false, 4)); mm.Add(MemoryDomain.FromIntPtr("ROM", romsize, l, s.rom, false, 4)); _gpumem = new GBAGPUMemoryAreas { mmio = s.mmio, oam = s.oam, palram = s.palram, vram = s.vram }; return(new MemoryDomainList(mm)); }
public MGBAHawk(byte[] file, CoreComm comm, SyncSettings syncSettings, Settings settings, bool deterministic) { _syncSettings = syncSettings ?? new SyncSettings(); _settings = settings ?? new Settings(); DeterministicEmulation = deterministic; byte[] bios = comm.CoreFileProvider.GetFirmware("GBA", "Bios", false); DeterministicEmulation &= bios != null; if (DeterministicEmulation != deterministic) { throw new InvalidOperationException("A BIOS is required for deterministic recordings!"); } if (!DeterministicEmulation && bios != null && !_syncSettings.RTCUseRealTime && !_syncSettings.SkipBios) { // in these situations, this core is deterministic even though it wasn't asked to be DeterministicEmulation = true; } if (bios != null && bios.Length != 16384) { throw new InvalidOperationException("BIOS must be exactly 16384 bytes!"); } core = LibmGBA.BizCreate(bios); if (core == IntPtr.Zero) { throw new InvalidOperationException("BizCreate() returned NULL! Bad BIOS?"); } try { if (!LibmGBA.BizLoad(core, file, file.Length)) { throw new InvalidOperationException("BizLoad() returned FALSE! Bad ROM?"); } if (!DeterministicEmulation && _syncSettings.SkipBios) { LibmGBA.BizSkipBios(core); } var ser = new BasicServiceProvider(this); ser.Register <IDisassemblable>(new ArmV4Disassembler()); ser.Register <IMemoryDomains>(CreateMemoryDomains(file.Length)); ServiceProvider = ser; CoreComm = comm; CoreComm.VsyncNum = 262144; CoreComm.VsyncDen = 4389; CoreComm.NominalWidth = 240; CoreComm.NominalHeight = 160; InitStates(); } catch { LibmGBA.BizDestroy(core); throw; } }
public bool FrameAdvance(IController controller, bool render, bool renderSound = true) { Frame++; if (controller.IsPressed("Power")) { LibmGBA.BizReset(Core); // BizReset caused memorydomain pointers to change. WireMemoryDomainPointers(); } LibmGBA.BizSetTraceCallback(Tracer.Enabled ? _tracecb : null); IsLagFrame = LibmGBA.BizAdvance( Core, LibmGBA.GetButtons(controller), render ? _videobuff : _dummyvideobuff, ref _nsamp, renderSound ? _soundbuff : _dummysoundbuff, RTCTime(), (short)controller.AxisValue("Tilt X"), (short)controller.AxisValue("Tilt Y"), (short)controller.AxisValue("Tilt Z"), (byte)(255 - controller.AxisValue("Light Sensor"))); if (IsLagFrame) { LagCount++; } // this should be called in hblank on the appropriate line, but until we implement that, just do it here _scanlinecb?.Invoke(); return(true); }
public void StoreSaveRam(byte[] data) { if (data.Take(8).SequenceEqual(Encoding.ASCII.GetBytes("GBABATT\0"))) { data = LegacyFix(data); } int len = LibmGBA.BizGetSaveRamSize(core); if (len > data.Length) { byte[] _tmp = new byte[len]; Array.Copy(data, _tmp, data.Length); for (int i = data.Length; i < len; i++) { _tmp[i] = 0xff; } data = _tmp; } else if (len < data.Length) { // we could continue from this, but we don't expect it throw new InvalidOperationException("Saveram will be truncated!"); } LibmGBA.BizPutSaveRam(core, data); }
public void SetCpuRegister(string register, int value) { int index = register?.ToUpper() switch { "R0" => 0, "R1" => 1, "R2" => 2, "R3" => 3, "R4" => 4, "R5" => 5, "R6" => 6, "R7" => 7, "R8" => 8, "R9" => 9, "R10" => 10, "R11" => 11, "R12" => 12, "R13" => 13, "R14" => 14, "R15" => 15, "CPSR" => 16, "SPSR" => 17, _ => - 1 }; if (index != -1) { LibmGBA.BizSetRegister(Core, index, value); } }
public bool PutSettings(Settings o) { LibmGBA.Layers mask = 0; if (o.DisplayBG0) { mask |= LibmGBA.Layers.BG0; } if (o.DisplayBG1) { mask |= LibmGBA.Layers.BG1; } if (o.DisplayBG2) { mask |= LibmGBA.Layers.BG2; } if (o.DisplayBG3) { mask |= LibmGBA.Layers.BG3; } if (o.DisplayOBJ) { mask |= LibmGBA.Layers.OBJ; } LibmGBA.BizSetLayerMask(core, mask); _settings = o; return(false); }
static MGBAHawk() { var resolver = new DynamicLibraryImportResolver( OSTailoredCode.IsUnixHost ? "libmgba.dll.so" : "mgba.dll", hasLimitedLifetime: false); LibmGBA = BizInvoker.GetInvoker <LibmGBA>(resolver, CallingConventionAdapters.Native); }
public void Add(IMemoryCallback callback) { if (!AvailableScopes.Contains(callback.Scope)) { throw new InvalidOperationException($"{callback.Scope} is not currently supported for callbacks"); } if (!callback.Address.HasValue) { throw new NotImplementedException("Wildcard callbacks (no address specified) not currently implemented."); } var container = new CallbackContainer(callback); if (container.Callback.Type == MemoryCallbackType.Execute) { _executeCallback = RunExecCallback; _execPcs[callback.Address.Value] = callback; LibmGBA.BizSetExecCallback(_executeCallback); } else { LibmGBA.BizSetMemCallback(container.CallDelegate); container.ID = LibmGBA.BizSetWatchpoint(_mgba.Core, callback.Address.Value, container.WatchPointType); } _callbacks.Add(container); }
public void SaveStateBinary(BinaryWriter writer) { IntPtr p = IntPtr.Zero; int size = 0; if (!LibmGBA.BizStartGetState(Core, ref p, ref size)) { throw new InvalidOperationException("Core failed to save!"); } if (size != _savebuff.Length) { _savebuff = new byte[size]; } LibmGBA.BizFinishGetState(p, _savebuff, size); writer.Write(_savebuff.Length); writer.Write(_savebuff, 0, _savebuff.Length); // other variables writer.Write(IsLagFrame); writer.Write(LagCount); writer.Write(Frame); }
public void FrameAdvance(bool render, bool rendersound = true) { Frame++; if (Controller["Power"]) { LibmGBA.BizReset(core); } IsLagFrame = LibmGBA.BizAdvance(core, VBANext.GetButtons(Controller), videobuff, ref nsamp, soundbuff, RTCTime(), (short)Controller.GetFloat("Tilt X"), (short)Controller.GetFloat("Tilt Y"), (short)Controller.GetFloat("Tilt Z"), (byte)(255 - Controller.GetFloat("Light Sensor"))); if (IsLagFrame) { LagCount++; } // this should be called in hblank on the appropriate line, but until we implement that, just do it here if (_scanlinecb != null) { _scanlinecb(); } }
public MGBAHawk(byte[] file, CoreComm comm, SyncSettings syncSettings, Settings settings, bool deterministic, GameInfo game) { _syncSettings = syncSettings ?? new SyncSettings(); _settings = settings ?? new Settings(); DeterministicEmulation = deterministic; byte[] bios = comm.CoreFileProvider.GetFirmware("GBA", "Bios", false); DeterministicEmulation &= bios != null; if (DeterministicEmulation != deterministic) { throw new InvalidOperationException("A BIOS is required for deterministic recordings!"); } if (!DeterministicEmulation && bios != null && !_syncSettings.RTCUseRealTime && !_syncSettings.SkipBios) { // in these situations, this core is deterministic even though it wasn't asked to be DeterministicEmulation = true; } if (bios != null && bios.Length != 16384) { throw new InvalidOperationException("BIOS must be exactly 16384 bytes!"); } var skipBios = !DeterministicEmulation && _syncSettings.SkipBios; _core = LibmGBA.BizCreate(bios, file, file.Length, GetOverrideInfo(game), skipBios); if (_core == IntPtr.Zero) { throw new InvalidOperationException($"{nameof(LibmGBA.BizCreate)}() returned NULL! Bad BIOS? and/or ROM?"); } try { CreateMemoryDomains(file.Length); var ser = new BasicServiceProvider(this); ser.Register <IDisassemblable>(new ArmV4Disassembler()); ser.Register <IMemoryDomains>(_memoryDomains); ServiceProvider = ser; CoreComm = comm; CoreComm.NominalWidth = 240; CoreComm.NominalHeight = 160; PutSettings(_settings); _tracer = new TraceBuffer() { Header = "ARM7: PC, machine code, mnemonic, operands, registers" }; _tracecb = new LibmGBA.TraceCallback((msg) => _tracer.Put(_traceInfo(msg))); ser.Register(_tracer); } catch { LibmGBA.BizDestroy(_core); throw; } }
public void StoreSaveRam(byte[] data) { if (data.Take(8).SequenceEqual(Encoding.ASCII.GetBytes("GBABATT\0"))) { data = LegacyFix(data); } LibmGBA.BizPutSaveRam(_core, data, data.Length); }
public void Dispose() { if (_core != IntPtr.Zero) { LibmGBA.BizDestroy(_core); _core = IntPtr.Zero; } }
public void Clear() { foreach (var cb in _callbacks) { if (LibmGBA.BizClearWatchpoint(_mgba.Core, cb.ID)) { _callbacks.Remove(cb); } } }
public bool PutSettings(Settings o) { LibmGBA.Layers mask = 0; if (o.DisplayBG0) { mask |= LibmGBA.Layers.BG0; } if (o.DisplayBG1) { mask |= LibmGBA.Layers.BG1; } if (o.DisplayBG2) { mask |= LibmGBA.Layers.BG2; } if (o.DisplayBG3) { mask |= LibmGBA.Layers.BG3; } if (o.DisplayOBJ) { mask |= LibmGBA.Layers.OBJ; } LibmGBA.BizSetLayerMask(_core, mask); LibmGBA.Sounds smask = 0; if (o.PlayCh0) { smask |= LibmGBA.Sounds.CH0; } if (o.PlayCh1) { smask |= LibmGBA.Sounds.CH1; } if (o.PlayCh2) { smask |= LibmGBA.Sounds.CH2; } if (o.PlayCh3) { smask |= LibmGBA.Sounds.CH3; } if (o.PlayChA) { smask |= LibmGBA.Sounds.CHA; } if (o.PlayChB) { smask |= LibmGBA.Sounds.CHB; } LibmGBA.BizSetSoundMask(_core, smask); _settings = o; return(false); }
public void StoreSaveRam(byte[] data) { if (data.Take(8).SequenceEqual(Encoding.ASCII.GetBytes("GBABATT\0"))) { data = LegacyFix(data); } if (!LibmGBA.BizPutSaveRam(_core, data, data.Length)) { throw new InvalidOperationException("BizPutSaveRam returned NULL!"); } }
public void SaveStateBinary(BinaryWriter writer) { LibmGBA.BizGetState(core, savebuff); writer.Write(savebuff.Length); writer.Write(savebuff); // other variables writer.Write(IsLagFrame); writer.Write(LagCount); writer.Write(Frame); }
private void WireMemoryDomainPointers_SaveRam() { var s = new LibmGBA.MemoryAreas(); LibmGBA.BizGetMemoryAreas(Core, s); _sram.Data = s.sram; if (s.sram == IntPtr.Zero) { s.sram_size = 0; } _sram.SetSize(s.sram_size); }
public byte[] CloneSaveRam() { byte[] ret = new byte[LibmGBA.BizGetSaveRamSize(core)]; if (ret.Length > 0) { LibmGBA.BizGetSaveRam(core, ret); return(ret); } else { return(null); } }
public IDictionary <string, RegisterValue> GetCpuFlagsAndRegisters() { var values = new int[RegisterNames.Length]; LibmGBA.BizGetRegisters(_core, values); var ret = new Dictionary <string, RegisterValue>(); for (var i = 0; i < RegisterNames.Length; i++) { ret[RegisterNames[i]] = new RegisterValue(values[i]); } return(ret); }
private void StartSaveStateBinaryInternal() { IntPtr p = IntPtr.Zero; int size = 0; if (!LibmGBA.BizStartGetState(_core, ref p, ref size)) { throw new InvalidOperationException("Core failed to save!"); } if (size != _savebuff.Length) { _savebuff = new byte[size]; _savebuff2 = new byte[size + 13]; } LibmGBA.BizFinishGetState(p, _savebuff, size); }
public void SaveStateBinary(BinaryWriter writer) { int size = LibmGBA.BizGetState(core, savebuff, savebuff.Length); if (size < 0) { throw new InvalidOperationException("Core failed to save!"); } writer.Write(size); writer.Write(savebuff, 0, size); // other variables writer.Write(IsLagFrame); writer.Write(LagCount); writer.Write(Frame); }
public void LoadStateBinary(BinaryReader reader) { int length = reader.ReadInt32(); if (length != savebuff.Length) { throw new InvalidOperationException("Save buffer size mismatch!"); } reader.Read(savebuff, 0, length); LibmGBA.BizPutState(core, savebuff); // other variables IsLagFrame = reader.ReadBoolean(); LagCount = reader.ReadInt32(); Frame = reader.ReadInt32(); }
public byte[] CloneSaveRam() { int len = LibmGBA.BizGetSaveRam(_core, _saveScratch, _saveScratch.Length); if (len == _saveScratch.Length) { throw new InvalidOperationException("Save buffer not long enough"); } if (len == 0) { return(null); } var ret = new byte[len]; Array.Copy(_saveScratch, ret, len); return(ret); }
private void CreateMemoryDomains(int romsize) { var le = MemoryDomain.Endian.Little; var mm = new List <MemoryDomain>(); mm.Add(_iwram = new MemoryDomainIntPtr("IWRAM", le, IntPtr.Zero, 32 * 1024, true, 4)); mm.Add(_ewram = new MemoryDomainIntPtr("EWRAM", le, IntPtr.Zero, 256 * 1024, true, 4)); mm.Add(_bios = new MemoryDomainIntPtr("BIOS", le, IntPtr.Zero, 16 * 1024, false, 4)); mm.Add(_palram = new MemoryDomainIntPtr("PALRAM", le, IntPtr.Zero, 1024, true, 4)); mm.Add(_vram = new MemoryDomainIntPtr("VRAM", le, IntPtr.Zero, 96 * 1024, true, 4)); mm.Add(_oam = new MemoryDomainIntPtr("OAM", le, IntPtr.Zero, 1024, true, 4)); mm.Add(_rom = new MemoryDomainIntPtr("ROM", le, IntPtr.Zero, romsize, true, 4)); // 128 KB is the max size for GBA savedata // mGBA does not know a game's save type (and as a result actual savedata size) on startup. // Instead, BizHawk's savedata buffer will be accessed directly for a consistent interface. mm.Add(_sram = new MemoryDomainIntPtr("SRAM", le, IntPtr.Zero, 128 * 1024, true, 4)); mm.Add(_cwram = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, le, null, null, 4)); mm.Add(new MemoryDomainDelegate("System Bus", 0x10000000, le, delegate(long addr) { var a = (uint)addr; if (a >= 0x10000000) { throw new ArgumentOutOfRangeException(); } return(LibmGBA.BizReadBus(Core, a)); }, delegate(long addr, byte val) { var a = (uint)addr; if (a >= 0x10000000) { throw new ArgumentOutOfRangeException(); } LibmGBA.BizWriteBus(Core, a, val); }, 4)); _memoryDomains = new MemoryDomainList(mm); WireMemoryDomainPointers(); }
public void LoadStateBinary(BinaryReader reader) { int length = reader.ReadInt32(); if (length > savebuff.Length) { savebuff = new byte[length]; savebuff2 = new byte[length + 13]; } reader.Read(savebuff, 0, length); if (!LibmGBA.BizPutState(core, savebuff, length)) { throw new InvalidOperationException("Core rejected the savestate!"); } // other variables IsLagFrame = reader.ReadBoolean(); LagCount = reader.ReadInt32(); Frame = reader.ReadInt32(); }
private void CreateMemoryDomains(int romsize) { var le = MemoryDomain.Endian.Little; var mm = new List <MemoryDomain>(); mm.Add(_iwram = new MemoryDomainIntPtr("IWRAM", le, IntPtr.Zero, 32 * 1024, true, 4)); mm.Add(_ewram = new MemoryDomainIntPtr("EWRAM", le, IntPtr.Zero, 256 * 1024, true, 4)); mm.Add(_bios = new MemoryDomainIntPtr("BIOS", le, IntPtr.Zero, 16 * 1024, false, 4)); mm.Add(_palram = new MemoryDomainIntPtr("PALRAM", le, IntPtr.Zero, 1024, true, 4)); mm.Add(_vram = new MemoryDomainIntPtr("VRAM", le, IntPtr.Zero, 96 * 1024, true, 4)); mm.Add(_oam = new MemoryDomainIntPtr("OAM", le, IntPtr.Zero, 1024, true, 4)); mm.Add(_rom = new MemoryDomainIntPtr("ROM", le, IntPtr.Zero, romsize, false, 4)); mm.Add(_sram = new MemoryDomainIntPtr("SRAM", le, IntPtr.Zero, 0, true, 4)); // size will be fixed in wireup mm.Add(_cwram = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, le, null, null, 4)); mm.Add(new MemoryDomainDelegate("System Bus", 0x10000000, le, delegate(long addr) { var a = (uint)addr; if (a >= 0x10000000) { throw new ArgumentOutOfRangeException(); } return(LibmGBA.BizReadBus(_core, a)); }, delegate(long addr, byte val) { var a = (uint)addr; if (a >= 0x10000000) { throw new ArgumentOutOfRangeException(); } LibmGBA.BizWriteBus(_core, a, val); }, 4)); _memoryDomains = new MemoryDomainList(mm); WireMemoryDomainPointers(); }
public void Remove(MemoryCallbackDelegate action) { var cbToRemove = _callbacks.SingleOrDefault(container => container.Callback.Callback == action); if (cbToRemove != null) { if (cbToRemove.Callback.Type == MemoryCallbackType.Execute) { _callbacks.Remove(cbToRemove); if (_callbacks.All(cb => cb.Callback.Type != MemoryCallbackType.Execute)) { _executeCallback = null; LibmGBA.BizSetExecCallback(null); } } else if (LibmGBA.BizClearWatchpoint(_mgba.Core, cbToRemove.ID)) { _callbacks.Remove(cbToRemove); } } }