/// <summary> /// /// </summary> /// <param name="callback">null to cancel</param> /// <param name="scanline">0-227, null = end of frame</param> public void SetScanlineCallback(Action callback, int?scanline) { if (callback == null) { LibMeteor.libmeteor_setscanlinecallback(null, 400); EndOfFrameCallback = null; scanlinecb = null; } else if (scanline == null) { LibMeteor.libmeteor_setscanlinecallback(null, 400); EndOfFrameCallback = callback; scanlinecb = null; } else if (scanline >= 0 && scanline <= 227) { scanlinecb = new LibMeteor.ScanlineCallback(callback); LibMeteor.libmeteor_setscanlinecallback(scanlinecb, (int)scanline); EndOfFrameCallback = null; } else { throw new ArgumentOutOfRangeException("Scanline must be in [0, 227]!"); } }
public GBA(CoreComm comm, byte[] file) { ServiceProvider = new BasicServiceProvider(this); Tracer = new TraceBuffer { Header = " -Addr--- -Opcode- -Instruction------------------- -R0----- -R1----- -R2----- -R3----- -R4----- -R5----- -R6----- -R7----- -R8----- -R9----- -R10---- -R11---- -R12---- -R13(SP) -R14(LR) -R15(PC) -CPSR--- -SPSR---" }; (ServiceProvider as BasicServiceProvider).Register <ITraceable>(Tracer); CoreComm = comm; comm.VsyncNum = 262144; comm.VsyncDen = 4389; comm.NominalWidth = 240; comm.NominalHeight = 160; byte[] bios = CoreComm.CoreFileProvider.GetFirmware("GBA", "Bios", true, "GBA bios file is mandatory."); if (bios.Length != 16384) { throw new InvalidDataException("GBA bios must be exactly 16384 bytes!"); } if (file.Length > 32 * 1024 * 1024) { throw new InvalidDataException("Rom file is too big! No GBA game is larger than 32MB"); } Init(); LibMeteor.libmeteor_hardreset(); LibMeteor.libmeteor_loadbios(bios, (uint)bios.Length); LibMeteor.libmeteor_loadrom(file, (uint)file.Length); SetUpMemoryDomains(); }
void Init() { if (attachedcore != null) { attachedcore.Dispose(); } messagecallback = PrintMessage; inputcallback = GetInput; tracecallback = Trace; // don't set this callback now, only set if enabled LibMeteor.libmeteor_setmessagecallback(messagecallback); LibMeteor.libmeteor_setkeycallback(inputcallback); LibMeteor.libmeteor_init(); videobuffer = new int[240 * 160]; videohandle = GCHandle.Alloc(videobuffer, GCHandleType.Pinned); soundbuffer = new short[2048]; // nominal length of one frame is something like 1480 shorts? soundhandle = GCHandle.Alloc(soundbuffer, GCHandleType.Pinned); if (!LibMeteor.libmeteor_setbuffers (videohandle.AddrOfPinnedObject(), (uint)(sizeof(int) * videobuffer.Length), soundhandle.AddrOfPinnedObject(), (uint)(sizeof(short) * soundbuffer.Length))) { throw new Exception("libmeteor_setbuffers() returned false??"); } attachedcore = this; }
private void LoadCoreBinary(byte[] data) { if (!LibMeteor.libmeteor_loadstate(data, (uint)data.Length)) { throw new Exception("libmeteor_loadstate() failed!"); } }
public void ClearSaveRam() { if (disposed) { throw new ObjectDisposedException(this.GetType().ToString()); } LibMeteor.libmeteor_clearsaveram(); }
private void AddMemoryDomain(LibMeteor.MemoryArea which, int size, string name) { IntPtr data = LibMeteor.libmeteor_getmemoryarea(which); if (data == IntPtr.Zero) throw new Exception("libmeteor_getmemoryarea() returned NULL??"); MemoryDomain md = MemoryDomain.FromIntPtr(name, size, MemoryDomain.Endian.Little, data); _domainList.Add(md); }
public void StoreSaveRam(byte[] data) { if (disposed) { throw new ObjectDisposedException(this.GetType().ToString()); } if (!LibMeteor.libmeteor_loadsaveram(data, (uint)data.Length)) { throw new Exception("libmeteor_loadsaveram() returned false!"); } }
public Dictionary <string, int> GetCpuFlagsAndRegisters() { var ret = new Dictionary <string, int>(); int[] data = new int[LibMeteor.regnames.Length]; LibMeteor.libmeteor_getregs(data); for (int i = 0; i < data.Length; i++) { ret.Add(LibMeteor.regnames[i], data[i]); } return(ret); }
private void AddMemoryDomain(LibMeteor.MemoryArea which, int size, string name) { IntPtr data = LibMeteor.libmeteor_getmemoryarea(which); if (data == IntPtr.Zero) { throw new Exception("libmeteor_getmemoryarea() returned NULL??"); } MemoryDomain md = MemoryDomain.FromIntPtr(name, size, MemoryDomain.Endian.Little, data); _domainList.Add(md); }
public void GetSamples(out short[] samples, out int nsamp) { uint nbytes = LibMeteor.libmeteor_emptysound(); samples = soundbuffer; if (!coredead) { nsamp = (int)(nbytes / 4); } else { nsamp = 738; } }
public void StoreSaveRam(byte[] data) { throw new Exception("This needs to be fixed to match the VBANext Core!"); #if false if (disposed) { throw new ObjectDisposedException(this.GetType().ToString()); } if (!LibMeteor.libmeteor_loadsaveram(data, (uint)data.Length)) { throw new Exception("libmeteor_loadsaveram() returned false!"); } #endif }
public void GetGPUMemoryAreas(out IntPtr vram, out IntPtr palram, out IntPtr oam, out IntPtr mmio) { IntPtr _vram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.vram); IntPtr _palram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.palram); IntPtr _oam = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.oam); IntPtr _mmio = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.io); if (_vram == IntPtr.Zero || _palram == IntPtr.Zero || _oam == IntPtr.Zero || _mmio == IntPtr.Zero) { throw new Exception("libmeteor_getmemoryarea() failed!"); } vram = _vram; palram = _palram; oam = _oam; mmio = _mmio; }
public void Dispose() { if (!disposed) { disposed = true; videohandle.Free(); soundhandle.Free(); // guarantee crash if it gets accessed LibMeteor.libmeteor_setbuffers(IntPtr.Zero, 240 * 160 * 4, IntPtr.Zero, 4); messagecallback = null; inputcallback = null; tracecallback = null; LibMeteor.libmeteor_setmessagecallback(messagecallback); LibMeteor.libmeteor_setkeycallback(inputcallback); LibMeteor.libmeteor_settracecallback(tracecallback); _MemoryDomains.Clear(); } }
public void SetScanlineCallback(Action callback, int scanline) { if (scanline < 0 || scanline > 227) { throw new ArgumentOutOfRangeException(nameof(scanline), "Scanline must be in [0, 227]!"); } if (callback == null) { scanlinecb = null; LibMeteor.libmeteor_setscanlinecallback(null, 0); } else { scanlinecb = new LibMeteor.ScanlineCallback(callback); LibMeteor.libmeteor_setscanlinecallback(scanlinecb, scanline); } }
private byte[] SaveCoreBinary() { IntPtr ndata = IntPtr.Zero; uint nsize = 0; if (!LibMeteor.libmeteor_savestate(ref ndata, ref nsize)) { throw new Exception("libmeteor_savestate() failed!"); } if (ndata == IntPtr.Zero || nsize == 0) { throw new Exception("libmeteor_savestate() returned bad!"); } byte[] ret = new byte[nsize]; Marshal.Copy(ndata, ret, 0, (int)nsize); LibMeteor.libmeteor_savestate_destroy(ndata); return(ret); }
public void Load(byte[] rom) { byte[] bios = CoreComm.CoreFileProvider.GetFirmware("GBA", "Bios", true, "GBA bios file is mandatory."); if (bios.Length != 16384) { throw new InvalidDataException("GBA bios must be exactly 16384 bytes!"); } if (rom.Length > 32 * 1024 * 1024) { throw new InvalidDataException("Rom file is too big! No GBA game is larger than 32MB"); } Init(); LibMeteor.libmeteor_hardreset(); LibMeteor.libmeteor_loadbios(bios, (uint)bios.Length); LibMeteor.libmeteor_loadrom(rom, (uint)rom.Length); SetUpMemoryDomains(); }
public void FrameAdvance(bool render, bool rendersound = true) { Frame++; IsLagFrame = true; if (Controller.IsPressed("Power")) { LibMeteor.libmeteor_hardreset(); } // due to the design of the tracing api, we have to poll whether it's active each frame LibMeteor.libmeteor_settracecallback(Tracer.Enabled ? tracecallback : null); if (!coredead) { LibMeteor.libmeteor_frameadvance(); } if (IsLagFrame) { LagCount++; } }
public GBAGPUMemoryAreas GetMemoryAreas() { IntPtr _vram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.vram); IntPtr _palram = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.palram); IntPtr _oam = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.oam); IntPtr _mmio = LibMeteor.libmeteor_getmemoryarea(LibMeteor.MemoryArea.io); if (_vram == IntPtr.Zero || _palram == IntPtr.Zero || _oam == IntPtr.Zero || _mmio == IntPtr.Zero) { throw new Exception("libmeteor_getmemoryarea() failed!"); } return(new GBAGPUMemoryAreas { vram = _vram, palram = _palram, oam = _oam, mmio = _mmio }); }
public byte[] ReadSaveRam() { if (disposed) { throw new ObjectDisposedException(this.GetType().ToString()); } if (!LibMeteor.libmeteor_hassaveram()) { return(null); } IntPtr data = IntPtr.Zero; uint size = 0; if (!LibMeteor.libmeteor_savesaveram(ref data, ref size)) { throw new Exception("libmeteor_savesaveram() returned false!"); } byte[] ret = new byte[size]; Marshal.Copy(data, ret, 0, (int)size); LibMeteor.libmeteor_savesaveram_destroy(data); return(ret); }
void AddMemoryDomain(LibMeteor.MemoryArea which, int size, string name) { IntPtr data = LibMeteor.libmeteor_getmemoryarea(which); if (data == IntPtr.Zero) { throw new Exception("libmeteor_getmemoryarea() returned NULL??"); } MemoryDomain md = new MemoryDomain(name, size, MemoryDomain.Endian.Little, delegate(int addr) { unsafe { byte *d = (byte *)data; if (addr < 0 || addr >= size) { throw new IndexOutOfRangeException(); } return(d[addr]); } }, delegate(int addr, byte val) { unsafe { byte *d = (byte *)data; if (addr < 0 || addr >= size) { throw new IndexOutOfRangeException(); } d[addr] = val; } }); _MemoryDomains.Add(md); }
public byte[] CloneSaveRam() { throw new Exception("This needs to be fixed to match the VBANext Core!"); #if false if (disposed) { throw new ObjectDisposedException(this.GetType().ToString()); } if (!LibMeteor.libmeteor_hassaveram()) { return(null); } IntPtr data = IntPtr.Zero; uint size = 0; if (!LibMeteor.libmeteor_savesaveram(ref data, ref size)) { throw new Exception("libmeteor_savesaveram() returned false!"); } byte[] ret = new byte[size]; Marshal.Copy(data, ret, 0, (int)size); LibMeteor.libmeteor_savesaveram_destroy(data); return(ret); #endif }
public void DiscardSamples() { LibMeteor.libmeteor_emptysound(); }
void AddMemoryDomain(LibMeteor.MemoryArea which, int size, string name) { IntPtr data = LibMeteor.libmeteor_getmemoryarea(which); if (data == IntPtr.Zero) throw new Exception("libmeteor_getmemoryarea() returned NULL??"); MemoryDomain md = new MemoryDomain(name, size, MemoryDomain.Endian.Little, delegate(int addr) { unsafe { byte* d = (byte*)data; if (addr < 0 || addr >= size) throw new IndexOutOfRangeException(); return d[addr]; } }, delegate(int addr, byte val) { unsafe { byte* d = (byte*)data; if (addr < 0 || addr >= size) throw new IndexOutOfRangeException(); d[addr] = val; } }); _MemoryDomains.Add(md); }
void SetUpMemoryDomains() { _MemoryDomains.Clear(); // this must be first to coincide with "main memory" // note that ewram could also be considered main memory depending on which hairs you split AddMemoryDomain(LibMeteor.MemoryArea.iwram, 32 * 1024, "IWRAM"); AddMemoryDomain(LibMeteor.MemoryArea.ewram, 256 * 1024, "EWRAM"); AddMemoryDomain(LibMeteor.MemoryArea.bios, 16 * 1024, "BIOS"); AddMemoryDomain(LibMeteor.MemoryArea.palram, 1024, "PALRAM"); AddMemoryDomain(LibMeteor.MemoryArea.vram, 96 * 1024, "VRAM"); AddMemoryDomain(LibMeteor.MemoryArea.oam, 1024, "OAM"); // even if the rom is less than 32MB, the whole is still valid in meteor AddMemoryDomain(LibMeteor.MemoryArea.rom, 32 * 1024 * 1024, "ROM"); // special domain for system bus { MemoryDomain sb = new MemoryDomain("BUS", 1 << 28, MemoryDomain.Endian.Little, delegate(int addr) { if (addr < 0 || addr >= 0x10000000) { throw new IndexOutOfRangeException(); } return(LibMeteor.libmeteor_peekbus((uint)addr)); }, delegate(int addr, byte val) { if (addr < 0 || addr >= 0x10000000) { throw new IndexOutOfRangeException(); } LibMeteor.libmeteor_writebus((uint)addr, val); }); _MemoryDomains.Add(sb); } // special combined ram memory domain { var ew = _MemoryDomains[1]; var iw = _MemoryDomains[0]; MemoryDomain cr = new MemoryDomain("Combined WRAM", (256 + 32) * 1024, MemoryDomain.Endian.Little, delegate(int addr) { if (addr < 0 || addr >= (256 + 32) * 1024) { throw new IndexOutOfRangeException(); } if (addr >= 256 * 1024) { return(iw.PeekByte(addr & 32767)); } else { return(ew.PeekByte(addr)); } }, delegate(int addr, byte val) { if (addr < 0 || addr >= (256 + 32) * 1024) { throw new IndexOutOfRangeException(); } if (addr >= 256 * 1024) { iw.PokeByte(addr & 32767, val); } else { ew.PokeByte(addr, val); } }); _MemoryDomains.Add(cr); } MemoryDomains = new MemoryDomainList(_MemoryDomains); }