public void CpuWriteBE<T>(int addr, T data) where T : struct { switch(Type.GetTypeCode(typeof(T))) { case TypeCode.Byte: case TypeCode.SByte: Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr), (byte) (object) data); break; case TypeCode.Int16: case TypeCode.UInt16: ushort u16 = (ushort) (object) data; Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr), (byte) (u16 >> 8)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 1), (byte) (u16 & 0xff)); break; case TypeCode.Int32: case TypeCode.UInt32: uint u32 = (uint) (object) data; Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr), (byte) (u32 >> 24)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 1), (byte) (u32 >> 16)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 2), (byte) (u32 >> 8)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 3), (byte) (u32 & 0xff)); break; case TypeCode.Int64: case TypeCode.UInt64: ulong u64 = (ulong) (object) data; Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr), (byte) (u64 >> 56)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 1), (byte) (u64 >> 48)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 2), (byte) (u64 >> 40)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 3), (byte) (u64 >> 32)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 4), (byte) (u64 >> 24)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 5), (byte) (u64 >> 16)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 6), (byte) (u64 >> 8)); Libgambatte.gambatte_cpuwrite(Handle, (ushort) (addr + 7), (byte) (u64 & 0xff)); break; } }
// Emulates until the next video frame has to be drawn. Returns the hit address. public int AdvanceFrame(Joypad joypad = Joypad.None) { CurrentJoypad = joypad; RunFor(SamplesPerFrame - BufferSamples); CurrentJoypad = Joypad.None; return(Libgambatte.gambatte_gethitinterruptaddress(Handle)); }
public T CpuReadBE <T>(int addr) where T : struct { switch (Type.GetTypeCode(typeof(T))) { case TypeCode.Byte: case TypeCode.SByte: return((T)(object)Libgambatte.gambatte_cpuread(Handle, (ushort)(addr))); case TypeCode.Int16: case TypeCode.UInt16: return((T)(object)(ushort)((Libgambatte.gambatte_cpuread(Handle, (ushort)(addr)) << 8) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 1))))); case TypeCode.Int32: case TypeCode.UInt32: return((T)(object)(uint)((Libgambatte.gambatte_cpuread(Handle, (ushort)(addr)) << 24) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 1)) << 16) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 2)) << 8) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 3))))); case TypeCode.Int64: case TypeCode.UInt64: return((T)(object)(ulong)((Libgambatte.gambatte_cpuread(Handle, (ushort)(addr)) << 56) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 1)) << 48) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 2)) << 40) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 3)) << 32) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 4)) << 24) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 5)) << 16) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 6)) << 8) | (Libgambatte.gambatte_cpuread(Handle, (ushort)(addr + 7))))); default: return(default); } }
public void Dispose() { if (Scene != null) { Scene.Dispose(); } Libgambatte.gambatte_destroy(Handle); }
// Emulates while holding the specified input until the program counter hits one of the specified breakpoints. public unsafe virtual int Hold(Joypad joypad, params int[] addrs) { fixed(int *addrPtr = addrs) // Note: Not fixing the pointer causes an AccessValidationException. { Libgambatte.gambatte_setinterruptaddresses(Handle, addrPtr, addrs.Length); int hitaddress; do { hitaddress = AdvanceFrame(joypad); } while(Array.IndexOf(addrs, hitaddress) == -1); Libgambatte.gambatte_setinterruptaddresses(Handle, null, 0); return(hitaddress); } }
public GameBoy(string biosFile, string romFile, SpeedupFlags speedupFlags = SpeedupFlags.None) { ROM = new ROM(romFile); Debug.Assert(ROM.HeaderChecksumMatches(), "Cartridge header checksum mismatch!"); Handle = Libgambatte.gambatte_create(); Debug.Assert(Libgambatte.gambatte_loadbios(Handle, biosFile, 0x900, 0x31672598) == 0, "Unable to load BIOS!"); Debug.Assert(Libgambatte.gambatte_load(Handle, romFile, LoadFlags.GbaFlag | LoadFlags.GcbMode | LoadFlags.ReadOnlySav) == 0, "Unable to load ROM!"); VideoBuffer = new byte[160 * 144 * 4]; AudioBuffer = new byte[(SamplesPerFrame + 2064) * 2 * 2]; // Stereo 16-bit samples InputGetter = () => CurrentJoypad; Libgambatte.gambatte_setinputgetter(Handle, InputGetter); string symPath = "symfiles/" + Path.GetFileNameWithoutExtension(romFile) + ".sym"; if (File.Exists(symPath)) { SYM = new SYM(symPath); ROM.Symbols = SYM; } SetSpeedupFlags(speedupFlags); StateSize = Libgambatte.gambatte_savestate(Handle, null, 160, null); SaveStateLabels = new Dictionary <string, int>(); byte[] state = SaveState(); ByteStream data = new ByteStream(state); data.Seek(3); data.Seek(data.u24be()); while (data.Position < state.Length) { string label = ""; byte character; while ((character = data.u8()) != 0x00) { label += Convert.ToChar(character); } int size = data.u24be(); SaveStateLabels[label] = (int)data.Position; data.Seek(size); } }
// Emulates 'runsamples' number of samples, or until a video frame has to be drawn. (1 sample = 2 cpu cycles) public int RunFor(int runsamples) { int videoFrameDoneSampleCount = Libgambatte.gambatte_runfor(Handle, VideoBuffer, 160, AudioBuffer, ref runsamples); int outsamples = videoFrameDoneSampleCount >= 0 ? BufferSamples + videoFrameDoneSampleCount : BufferSamples + runsamples; BufferSamples += runsamples; BufferSamples -= outsamples; EmulatedSamples += (ulong)outsamples; if (Scene != null) { Scene.OnAudioReady(outsamples); // returns a positive value if the video frame hass been completed. if (videoFrameDoneSampleCount >= 0) { Scene.Begin(); Scene.Render(); Scene.End(); } } return(runsamples); }
// Emulates 'runsamples' number of samples, or until a video frame has to be drawn. (1 sample = 2 cpu cycles) public int RunFor(int runsamples) { int videoFrameDoneSampleCount = Libgambatte.gambatte_runfor(Handle, VideoBuffer, 160, AudioBuffer, ref runsamples); int outsamples = videoFrameDoneSampleCount >= 0 ? BufferSamples + videoFrameDoneSampleCount : BufferSamples + runsamples; BufferSamples += runsamples; BufferSamples -= outsamples; EmulatedSamples += (ulong)outsamples; if (Scene != null) { Scene.OnAudioReady(outsamples); // returns a positive value if a video frame needs to be drawn. if (videoFrameDoneSampleCount >= 0) { Scene.Begin(); Scene.Render(); Scene.End(); } } return(Libgambatte.gambatte_gethitinterruptaddress(Handle)); }
public GameBoy(string biosFile, string romFile, string savFile = null, SpeedupFlags speedupFlags = SpeedupFlags.None) { ROM = new ROM(romFile); Debug.Assert(ROM.HeaderChecksumMatches(), "Cartridge header checksum mismatch!"); string romName = Path.GetFileNameWithoutExtension(romFile); if (savFile == null || savFile == "") { File.Delete("roms/" + romName + ".sav"); } else { File.WriteAllBytes("roms/" + romName + ".sav", File.ReadAllBytes(savFile)); } Handle = Libgambatte.gambatte_create(); Debug.Assert(Libgambatte.gambatte_loadbios(Handle, biosFile, 0x900, 0x31672598) == 0, "Unable to load BIOS!"); Debug.Assert(Libgambatte.gambatte_load(Handle, romFile, LoadFlags.GbaFlag | LoadFlags.GcbMode | LoadFlags.ReadOnlySav) == 0, "Unable to load ROM!"); VideoBuffer = new byte[160 * 144 * 4]; AudioBuffer = new byte[(SamplesPerFrame + 2064) * 2 * 2]; // Stereo 16-bit samples InputGetter = () => CurrentJoypad; Libgambatte.gambatte_setinputgetter(Handle, InputGetter); string symPath = "symfiles/" + romName + ".sym"; if (File.Exists(symPath)) { SYM = new SYM(symPath); ROM.Symbols = SYM; } SetSpeedupFlags(speedupFlags); StateSize = Libgambatte.gambatte_savestate(Handle, null, 160, null); }
public void SetRTCDivisorOffset(int rtcDivisorOffset) { Libgambatte.gambatte_setrtcdivisoroffset(Handle, rtcDivisorOffset); }
// Sets flags to control non-critical processes for CPU-concerned emulation. public void SetSpeedupFlags(SpeedupFlags flags) { Libgambatte.gambatte_setspeedupflags(Handle, flags); }
// Loads the emulator state given by a buffer. public void LoadState(byte[] buffer) { Libgambatte.gambatte_loadstate(Handle, buffer, buffer.Length); }
// Returns the emulator state as a buffer. public byte[] SaveState() { byte[] state = new byte[StateSize]; Libgambatte.gambatte_savestate(Handle, null, 160, state); return(state); }
// Reads one byte of data from the CPU bus. public byte CpuRead(int addr) { return(Libgambatte.gambatte_cpuread(Handle, (ushort)addr)); }
// Writes one byte of data to the CPU bus. public void CpuWrite(int addr, byte data) { Libgambatte.gambatte_cpuwrite(Handle, (ushort)addr, data); }
public void HardReset(bool fade = false) { Libgambatte.gambatte_reset(Handle, fade ? 101 * (2 << 14) : 0); BufferSamples = 0; }