using System; using System.Runtime.InteropServices; using BizHawk.Common.BizInvoke; namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES { public abstract class LibQuickNES { public const string dllname = "libquicknes.dll"; /// /// setup extra mappers. should be done before anything else /// [BizImport(CallingConvention.Cdecl)] public abstract void qn_setup_mappers(); /// /// create a new quicknes context /// /// NULL on failure [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_new(); /// /// destroy a quicknes context /// /// context previously returned from qn_new() [BizImport(CallingConvention.Cdecl)] public abstract void qn_delete(IntPtr e); /// /// load an ines file /// /// context /// file /// length of file /// [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_loadines(IntPtr e, byte[] data, int length); /// /// set audio sample rate /// /// context /// hz /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_set_sample_rate(IntPtr e, int rate); /// /// emulate a single frame /// /// context /// pad 1 input /// pad 2 input /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_emulate_frame(IntPtr e, int pad1, int pad2); /// /// blit to rgb32 /// /// Context /// rgb32 256x240 packed /// rgb32 colors, 512 of them [BizImport(CallingConvention.Cdecl)] public abstract void qn_blit(IntPtr e, int[] dest, int[] colors, int cropleft, int croptop, int cropright, int cropbottom); /// /// get quicknes's default palette /// /// 1536 bytes suitable for qn_blit [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_get_default_colors(); /// /// get number of times joypad was read in most recent frame /// /// context /// 0 means lag [BizImport(CallingConvention.Cdecl)] public abstract int qn_get_joypad_read_count(IntPtr e); /// /// get audio info for most recent frame /// /// context /// number of samples actually created /// 1 for mono, 2 for stereo [BizImport(CallingConvention.Cdecl)] public abstract void qn_get_audio_info(IntPtr e, ref int sample_count, ref int chan_count); /// /// get audio for most recent frame. must not be called more than once per frame! /// /// context /// sample buffer /// length to read into sample buffer /// length actually read [BizImport(CallingConvention.Cdecl)] public abstract int qn_read_audio(IntPtr e, short[] dest, int max_samples); /// /// reset the console /// /// context /// true for powercycle, false for reset button [BizImport(CallingConvention.Cdecl)] public abstract void qn_reset(IntPtr e, bool hard); /// /// get the required byte size of a savestate /// /// context /// size is returned /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_state_size(IntPtr e, ref int size); /// /// save state to buffer /// /// context /// buffer /// length of buffer /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_state_save(IntPtr e, byte[] dest, int size); /// /// load state from buffer /// /// context /// buffer /// length of buffer /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_state_load(IntPtr e, byte[] src, int size); /// /// query battery ram state /// /// context /// true if battery backup sram exists [BizImport(CallingConvention.Cdecl)] public abstract bool qn_has_battery_ram(IntPtr e); /// /// query battery ram size /// /// context /// size is returned /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_battery_ram_size(IntPtr e, ref int size); /// /// save battery ram to buffer /// /// context /// buffer /// size /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_battery_ram_save(IntPtr e, byte[] dest, int size); /// /// load battery ram from buffer /// /// context /// buffer /// size /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_battery_ram_load(IntPtr e, byte[] src, int size); /// /// clear battery ram /// /// context /// string error [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_battery_ram_clear(IntPtr e); /// /// set sprite limit; does not affect emulation /// /// context /// 0 to hide, 8 for normal, 64 for all [BizImport(CallingConvention.Cdecl)] public abstract void qn_set_sprite_limit(IntPtr e, int n); /// /// get memory area for debugging /// /// Context /// /// /// /// /// /// [BizImport(CallingConvention.Cdecl)] public abstract bool qn_get_memory_area(IntPtr e, int which, ref IntPtr data, ref int size, ref bool writable, ref IntPtr name); /// /// peek the system bus /// /// Context /// 0000:ffff, but non-ram/rom addresses won't work /// [BizImport(CallingConvention.Cdecl)] public abstract byte qn_peek_prgbus(IntPtr e, int addr); /// /// poke the system bus /// /// Context /// 0000:ffff, but non-ram/rom addresses won't work /// [BizImport(CallingConvention.Cdecl)] public abstract void qn_poke_prgbus(IntPtr e, int addr, byte val); /// /// get internal registers /// /// Context /// a, x, y, sp, pc, p [BizImport(CallingConvention.Cdecl)] public abstract void qn_get_cpuregs(IntPtr e, [Out] int[] dest); /// /// get the mapper that's loaded /// /// Context /// recieves mapper number /// mapper name [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_get_mapper(IntPtr e, ref int number); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void TraceCallback(IntPtr data); /// /// set a trace callback to be run on each cycle /// /// Context /// [BizImport(CallingConvention.Cdecl)] public abstract void qn_set_tracecb(IntPtr e, TraceCallback cb); [BizImport(CallingConvention.Cdecl)] public abstract byte qn_get_reg2000(IntPtr e); [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_get_palmem(IntPtr e); [BizImport(CallingConvention.Cdecl)] public abstract IntPtr qn_get_oammem(IntPtr e); [BizImport(CallingConvention.Cdecl)] public abstract byte qn_peek_ppu(IntPtr e, int addr); [BizImport(CallingConvention.Cdecl)] public abstract void qn_peek_ppubus(IntPtr e, byte[] dest); /// /// handle "string error" as returned by some quicknes functions /// /// public static void ThrowStringError(IntPtr p) { if (p == IntPtr.Zero) return; string s = Marshal.PtrToStringAnsi(p); if (s == "Unsupported mapper" || s == "Not an iNES file" // Not worth making a new exception for the iNES error, they ultimately are the same problem || s == " truncated file" // This is a garbage rom not worth anyone's time but at least NesHawk handles these better, and these occur before the core has a chance to assess an unsupported mapper ) { throw new Emulation.Common.UnsupportedGameException("Quicknes unsupported mapper"); } else { throw new InvalidOperationException("LibQuickNES error: " + s); } } } }