using System; using System.Runtime.InteropServices; namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { /// /// static bindings into libgambatte.dll /// public static class LibGambatte { /// /// /// /// opaque state pointer [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr gambatte_create(); /// /// /// /// opaque state pointer [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_destroy(IntPtr core); [Flags] public enum LoadFlags : uint { /// Treat the ROM as not having CGB support regardless of what its header advertises FORCE_DMG = 1, /// Use GBA intial CPU register values when in CGB mode. GBA_CGB = 2, /// Use heuristics to detect and support some multicart MBCs disguised as MBC1. MULTICART_COMPAT = 4 } /// /// Load ROM image. /// /// opaque state pointer /// the rom data, can be disposed of once this function returns /// length of romdata in bytes /// RTC time when the rom is loaded /// ORed combination of LoadFlags. /// 0 on success, negative value on failure. [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, long now, LoadFlags flags); /// /// Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer, /// or until a video frame has been drawn. /// /// There are 35112 stereo sound samples in a video frame. /// May run for up to 2064 stereo samples too long. /// A stereo sample consists of two native endian 2s complement 16-bit PCM samples, /// with the left sample preceding the right one. /// /// Returns early when a new video frame has finished drawing in the video buffer, /// such that the caller may update the video output before the frame is overwritten. /// The return value indicates whether a new video frame has been drawn, and the /// exact time (in number of samples) at which it was drawn. /// /// opaque state pointer /// buffer with space >= samples + 2064 /// in: number of stereo samples to produce, out: actual number of samples produced /// sample number at which the video frame was produced. -1 means no frame was produced. [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int gambatte_runfor(IntPtr core, short[] soundbuf, ref uint samples); [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] unsafe public static extern int gambatte_runfor(IntPtr core, short* soundbuf, ref uint samples); /// /// blit from internal framebuffer to provided framebuffer /// /// opaque state pointer /// /// in pixels [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] unsafe public static extern void gambatte_blitto(IntPtr core, int* videobuf, int pitch); /// /// blit from internal framebuffer to provided framebuffer /// /// opaque state pointer /// /// in pixels [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_blitto(IntPtr core, int[] videobuf, int pitch); /// /// Reset to initial state. /// Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again. /// /// opaque state pointer /// RTC time when the reset occurs [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_reset(IntPtr core, long now); /// /// palette type for gambatte_setdmgpalettecolor /// public enum PalType : uint { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 }; /// /// /// /// opaque state pointer /// in [0, 2]: One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE. /// in [0, 3] /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setdmgpalettecolor(IntPtr core, PalType palnum, uint colornum, uint rgb32); /// /// set cgb palette lookup /// /// opaque state pointer /// uint32[32768], input color (r,g,b) is at lut[r | g << 5 | b << 10] [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setcgbpalette(IntPtr core, int[] lut); /// /// combination of button flags used by the input callback /// [Flags] public enum Buttons { A = 0x01, B = 0x02, SELECT = 0x04, START = 0x08, RIGHT = 0x10, LEFT = 0x20, UP = 0x40, DOWN = 0x80 } /// /// type of the callback for input state /// /// bitfield combination of pressed buttons [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate Buttons InputGetter(); /// /// Sets the callback used for getting input state. /// /// opaque state pointer /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setinputgetter(IntPtr core, InputGetter getinput); /// /// type of the read\write memory callbacks /// /// the address which the cpu is read\writing [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void MemoryCallback(uint address); /// /// set a callback to occur immediately BEFORE EVERY cpu read, except for opcode first byte fetches /// /// opaque state pointer /// null to clear [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setreadcallback(IntPtr core, MemoryCallback callback); /// /// set a callback to occur immediately AFTER EVERY cpu write /// /// opaque state pointer /// null to clear [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setwritecallback(IntPtr core, MemoryCallback callback); /// /// set a callback to occur immediately BEFORE EVERY cpu opcode (first byte) fetch /// /// opaque state pointer /// null to clear [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setexeccallback(IntPtr core, MemoryCallback callback); /// /// type of the cpu trace callback /// /// cpu state [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void TraceCallback(IntPtr state); /// /// set a callback to occur immediately BEFORE each opcode is executed /// /// opaque state pointer /// null to clear [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_settracecallback(IntPtr core, TraceCallback callback); /// /// type of the scanline callback /// [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void ScanlineCallback(); /// /// set a callback to occur when ly reaches a particular scanline (so at the beginning of the scanline). /// when the LCD is active, typically 145 will be the first callback after the beginning of frame advance, /// and 144 will be the last callback right before frame advance returns /// /// opaque state pointer /// null to clear /// 0-153 inclusive [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setscanlinecallback(IntPtr core, ScanlineCallback callback, int sl); /// /// type of the RTC callback /// /// what time is it, unixy [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate uint RTCCallback(); /// /// sets RTC callback. probably mandatory. /// /// opaque state pointer /// the callback [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setrtccallback(IntPtr core, RTCCallback callback); /// /// Returns true if the currently loaded ROM image is treated as having CGB support. /// /// opaque state pointer /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool gambatte_iscgb(IntPtr core); /// /// Returns true if a ROM image is loaded. /// /// opaque state pointer /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool gambatte_isloaded(IntPtr core); /// /// Get persistant cart memory. /// /// opaque state pointer /// byte buffer to write into. gambatte_savesavedatalength() bytes will be written [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_savesavedata(IntPtr core, byte[] dest); /// /// restore persistant cart memory. /// /// opaque state pointer /// byte buffer to read from. gambatte_savesavedatalength() bytes will be read [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_loadsavedata(IntPtr core, byte[] data); /// /// get the size of the persistant cart memory block. this value DEPENDS ON THE PARTICULAR CART LOADED /// /// opaque state pointer /// length in bytes. 0 means no internal persistant cart memory [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int gambatte_savesavedatalength(IntPtr core); /// /// new savestate method /// /// /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int gambatte_newstatelen(IntPtr core); /// /// new savestate method /// /// /// /// /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool gambatte_newstatesave(IntPtr core, byte[] data, int len); /// /// new savestate method /// /// /// /// /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool gambatte_newstateload(IntPtr core, byte[] data, int len); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void DataFunction(IntPtr data, int length, string name); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void SectionFunction(string name); [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_newstatesave_ex(IntPtr core, DataFunction Save, SectionFunction EnterSection, SectionFunction ExitSection); [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_newstateload_ex(IntPtr core, DataFunction Load, SectionFunction EnterSection, SectionFunction ExitSection); /// /// ROM header title of currently loaded ROM image. /// /// opaque state pointer /// [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern string gambatte_romtitle(IntPtr core); /// /// memory areas that gambatte_getmemoryarea() can return /// public enum MemoryAreas : int { vram = 0, rom = 1, wram = 2, cartram = 3, oam = 4, hram = 5, // these last two aren't returning native memory area data, but instead converted RGB32 colors bgpal = 6, sppal = 7 } /// /// get pointer to internal memory areas, for debugging purposes /// so long as you don't write to it, you should be completely sync-safe /// /// opaque state pointer /// which memory area to access /// pointer to the start of the area /// valid length of the area, in bytes /// success [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool gambatte_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref int length); /// /// read a single byte from the cpu bus. this includes all ram, rom, mmio, etc, as it is visible to the cpu (including mappers). /// while there is no cycle cost to these reads, there may be other side effects! use at your own risk. /// /// opaque state pointer /// system bus address /// byte read [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern byte gambatte_cpuread(IntPtr core, ushort addr); /// /// write a single byte to the cpu bus. while there is no cycle cost to these writes, there can be quite a few side effects. /// use at your own risk. /// /// opaque state pointe /// system bus address /// byte to write [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_cpuwrite(IntPtr core, ushort addr, byte val); /// /// link cable stuff; never touch for normal operation /// /// opaque state pointe /// todo /// todo [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int gambatte_linkstatus(IntPtr core, int which); /// /// get reg and flag values /// /// opaque state pointer /// length of at least 10, please [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_getregs(IntPtr core, int[] dest); public enum RegIndicies : int { PC, SP, A, B, C, D, E, F, H, L } } }