using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Avalonia; using Mesen.Config; using Mesen.Debugger; using Mesen.Utilities; namespace Mesen.Interop { public class DebugApi { private const string DllPath = EmuApi.DllName; [DllImport(DllPath)] public static extern void InitializeDebugger(); [DllImport(DllPath)] public static extern void ReleaseDebugger(); [DllImport(DllPath)] public static extern void ResumeExecution(); [DllImport(DllPath)] public static extern void Step(CpuType cpuType, Int32 instructionCount, StepType type = StepType.Step); [DllImport(DllPath)] public static extern void StartLogTraceToFile([MarshalAs(UnmanagedType.LPUTF8Str)] string filename); [DllImport(DllPath)] public static extern void StopLogTraceToFile(); [DllImport(DllPath)] public static extern void SetTraceOptions(CpuType cpuType, InteropTraceLoggerOptions options); public const int TraceLogBufferSize = 30000; [DllImport(DllPath)] public static extern void ClearExecutionTrace(); [DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern UInt32 GetExecutionTraceWrapper(IntPtr output, UInt32 startOffset, UInt32 maxRowCount); public static unsafe TraceRow[] GetExecutionTrace(UInt32 startOffset, UInt32 maxRowCount) { TraceRow[] rows = new TraceRow[maxRowCount]; UInt32 rowCount; fixed(TraceRow* ptr = rows) { rowCount = DebugApi.GetExecutionTraceWrapper((IntPtr)ptr, startOffset, maxRowCount); } Array.Resize(ref rows, (int)rowCount); return rows; } public static UInt32 GetExecutionTraceSize() { return DebugApi.GetExecutionTraceWrapper(IntPtr.Zero, 0, DebugApi.TraceLogBufferSize); } [DllImport(DllPath, EntryPoint = "GetDebuggerLog")] private static extern void GetDebuggerLogWrapper(IntPtr outLog, Int32 maxLength); public static string GetLog() { return Utf8Utilities.CallStringApi(GetDebuggerLogWrapper, 100000); } [DllImport(DllPath)] private static extern UInt32 GetDisassemblyOutput(CpuType type, UInt32 address, [In, Out] InteropCodeLineData[] lineData, UInt32 rowCount); public static CodeLineData[] GetDisassemblyOutput(CpuType type, UInt32 address, UInt32 rowCount) { InteropCodeLineData[] rows = new InteropCodeLineData[rowCount]; for(int i = 0; i < rowCount; i++) { rows[i].Comment = new byte[1000]; rows[i].Text = new byte[1000]; rows[i].ByteCode = new byte[8]; } UInt32 resultCount = DebugApi.GetDisassemblyOutput(type, address, rows, rowCount); CodeLineData[] result = new CodeLineData[resultCount]; for(int i = 0; i < resultCount; i++) { result[i] = new CodeLineData(rows[i]); } return result; } [DllImport(DllPath)] public static extern int GetDisassemblyRowAddress(CpuType type, UInt32 address, int rowOffset); [DllImport(DllPath)] public static extern int SearchDisassembly(CpuType type, [MarshalAs(UnmanagedType.LPUTF8Str)] string searchString, int startAddress, DisassemblySearchOptions options); [DllImport(DllPath)] private static extern UInt32 FindOccurrences(CpuType type, [MarshalAs(UnmanagedType.LPUTF8Str)] string searchString, DisassemblySearchOptions options, [In, Out] InteropCodeLineData[] lineData, UInt32 maxResultCount); public static CodeLineData[] FindOccurrences(CpuType type, string searchString, DisassemblySearchOptions options) { UInt32 maxResultCount = 500; InteropCodeLineData[] rows = new InteropCodeLineData[maxResultCount]; for(int i = 0; i < maxResultCount; i++) { rows[i].Comment = new byte[1000]; rows[i].Text = new byte[1000]; rows[i].ByteCode = new byte[8]; } UInt32 resultCount = DebugApi.FindOccurrences(type, searchString, options, rows, maxResultCount); CodeLineData[] result = new CodeLineData[resultCount]; for(int i = 0; i < resultCount; i++) { result[i] = new CodeLineData(rows[i]); } return result; } [DllImport(DllPath)] private static extern void GetCpuState(IntPtr state, CpuType cpuType); public unsafe static T GetCpuState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(CpuType cpuType) where T : struct, BaseState { byte* ptr = stackalloc byte[Marshal.SizeOf()]; DebugApi.GetCpuState((IntPtr)ptr, cpuType); return Marshal.PtrToStructure((IntPtr)ptr); } [DllImport(DllPath)] private static extern void GetPpuState(IntPtr state, CpuType cpuType); public unsafe static T GetPpuState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(CpuType cpuType) where T : struct, BaseState { byte* ptr = stackalloc byte[Marshal.SizeOf()]; DebugApi.GetPpuState((IntPtr)ptr, cpuType); return Marshal.PtrToStructure((IntPtr)ptr); } public static BaseState GetPpuState(CpuType cpuType) { return cpuType switch { CpuType.Snes => GetPpuState(cpuType), CpuType.Nes => GetPpuState(cpuType), CpuType.Gameboy => GetPpuState(cpuType), CpuType.Pce => GetPpuState(cpuType), CpuType.Sms => GetPpuState(cpuType), CpuType.Gba => GetPpuState(cpuType), CpuType.Ws => GetPpuState(cpuType), _ => throw new Exception("Unsupported cpu type") }; } [DllImport(DllPath)] private static extern void GetPpuToolsState(CpuType cpuType, IntPtr state); public unsafe static T GetPpuToolsState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(CpuType cpuType) where T : struct, BaseState { byte* ptr = stackalloc byte[Marshal.SizeOf()]; DebugApi.GetPpuToolsState(cpuType, (IntPtr)ptr); return Marshal.PtrToStructure((IntPtr)ptr); } public static BaseState GetPpuToolsState(CpuType cpuType) { return cpuType switch { CpuType.Snes => GetPpuToolsState(cpuType), CpuType.Nes => GetPpuToolsState(cpuType), CpuType.Gameboy => GetPpuToolsState(cpuType), CpuType.Pce => GetPpuToolsState(cpuType), CpuType.Sms => GetPpuToolsState(cpuType), CpuType.Gba => GetPpuToolsState(cpuType), CpuType.Ws => GetPpuToolsState(cpuType), _ => throw new Exception("Unsupported cpu type") }; } [DllImport(DllPath)] private static extern void SetPpuState(IntPtr state, CpuType cpuType); public unsafe static void SetPpuState(T state, CpuType cpuType) where T : BaseState { Debug.Assert(state.GetType().IsValueType); Debug.Assert(IsValidPpuState(ref state, cpuType)); byte* stateBuffer = stackalloc byte[Marshal.SizeOf()]; Marshal.StructureToPtr(state, (IntPtr)stateBuffer, false); DebugApi.SetPpuState((IntPtr)stateBuffer, cpuType); } [DllImport(DllPath)] private static extern void SetCpuState(IntPtr state, CpuType cpuType); public unsafe static void SetCpuState(T state, CpuType cpuType) where T : BaseState { Debug.Assert(state.GetType().IsValueType); Debug.Assert(IsValidCpuState(ref state, cpuType)); byte* stateBuffer = stackalloc byte[Marshal.SizeOf()]; Marshal.StructureToPtr(state, (IntPtr)stateBuffer, false); DebugApi.SetCpuState((IntPtr)stateBuffer, cpuType); } [DllImport(DllPath)] private static extern void GetConsoleState(IntPtr state, ConsoleType consoleType); public unsafe static T GetConsoleState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(ConsoleType consoleType) where T : struct, BaseState { byte* ptr = stackalloc byte[Marshal.SizeOf()]; DebugApi.GetConsoleState((IntPtr)ptr, consoleType); return Marshal.PtrToStructure((IntPtr)ptr); } [DllImport(DllPath)] public static extern void SetProgramCounter(CpuType cpuType, UInt32 address); [DllImport(DllPath)] public static extern UInt32 GetProgramCounter(CpuType cpuType, [MarshalAs(UnmanagedType.I1)] bool getInstPc); [DllImport(DllPath)] public static extern Int32 LoadScript([MarshalAs(UnmanagedType.LPUTF8Str)]string name, [MarshalAs(UnmanagedType.LPUTF8Str)]string path, [MarshalAs(UnmanagedType.LPUTF8Str)] string content, Int32 scriptId = -1); [DllImport(DllPath)] public static extern void RemoveScript(Int32 scriptId); [DllImport(DllPath, EntryPoint = "GetScriptLog")] private static extern void GetScriptLogWrapper(Int32 scriptId, IntPtr outScriptLog, Int32 maxLength); public unsafe static string GetScriptLog(Int32 scriptId) { byte[] outScriptLog = new byte[100000]; fixed(byte* ptr = outScriptLog) { DebugApi.GetScriptLogWrapper(scriptId, (IntPtr)ptr, outScriptLog.Length); return Utf8Utilities.PtrToStringUtf8((IntPtr)ptr); } } [DllImport(DllPath)] public static extern Int64 EvaluateExpression([MarshalAs(UnmanagedType.LPUTF8Str)] string expression, CpuType cpuType, out EvalResultType resultType, [MarshalAs(UnmanagedType.I1)] bool useCache); [DllImport(DllPath)] public static extern DebuggerFeatures GetDebuggerFeatures(CpuType type); [DllImport(DllPath)] public static extern CpuInstructionProgress GetInstructionProgress(CpuType type); [DllImport(DllPath)] public static extern Int32 GetMemorySize(MemoryType type); [DllImport(DllPath)] public static extern Byte GetMemoryValue(MemoryType type, UInt32 address); [DllImport(DllPath)] public static extern void SetMemoryValue(MemoryType type, UInt32 address, byte value); [DllImport(DllPath)] public static extern void SetMemoryValues(MemoryType type, UInt32 address, [In] byte[] data, Int32 length); [DllImport(DllPath)] public static extern void SetMemoryState(MemoryType type, [In] byte[] buffer, Int32 length); [DllImport(DllPath)][return: MarshalAs(UnmanagedType.I1)] public static extern bool HasUndoHistory(); [DllImport(DllPath)] public static extern void PerformUndo(); [DllImport(DllPath)] public static extern void UpdateFrozenAddresses(CpuType cpuType, UInt32 start, UInt32 end, [MarshalAs(UnmanagedType.I1)] bool freeze); [DllImport(DllPath)] private static extern void GetFrozenState(CpuType type, UInt32 start, UInt32 end, [In, Out] byte[] outState); public static byte[] GetFrozenState(CpuType cpuType, UInt32 start, UInt32 end) { byte[] outState = new byte[end - start + 1]; DebugApi.GetFrozenState(cpuType, start, end, outState); return outState; } [DllImport(DllPath)] public static extern AddressInfo GetAbsoluteAddress(AddressInfo relAddress); [DllImport(DllPath)] public static extern AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType); [DllImport(DllPath)] public static extern void SetLabel(uint address, MemoryType memType, [MarshalAs(UnmanagedType.LPUTF8Str)] string label, [MarshalAs(UnmanagedType.LPUTF8Str)] string comment); [DllImport(DllPath)] public static extern void ClearLabels(); [DllImport(DllPath)] public static extern void SetBreakpoints([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] InteropBreakpoint[] breakpoints, UInt32 length); [DllImport(DllPath)] public static extern void SetInputOverrides(UInt32 index, DebugControllerState state); [DllImport(DllPath)] private static extern void GetAvailableInputOverrides([In, Out] byte[] availableIndexes); public static List GetAvailableInputOverrides() { byte[] availableIndexes = new byte[8]; GetAvailableInputOverrides(availableIndexes); List indexes = new List(); for(int i = 0; i < 8; i++) { if(availableIndexes[i] != 0) { indexes.Add(i); } } return indexes; } [DllImport(DllPath, EntryPoint = "GetRomHeader")] private static extern void GetRomHeaderWrapper([In, Out] byte[] headerData, ref UInt32 size); public static byte[] GetRomHeader() { UInt32 size = 0x1000; byte[] headerData = new byte[size]; DebugApi.GetRomHeaderWrapper(headerData, ref size); Array.Resize(ref headerData, (Int32)size); return headerData; } [DllImport(DllPath)][return: MarshalAs(UnmanagedType.I1)] public static extern bool SaveRomToDisk([MarshalAs(UnmanagedType.LPUTF8Str)] string filename, [MarshalAs(UnmanagedType.I1)] bool saveAsIps, CdlStripOption cdlStripOption); [DllImport(DllPath, EntryPoint = "GetMemoryValues")] private static extern void GetMemoryValuesWrapper(MemoryType type, UInt32 start, UInt32 end, [In, Out] byte[] buffer); public static byte[] GetMemoryValues(MemoryType type, UInt32 start, UInt32 end) { byte[] buffer = new byte[end - start + 1]; DebugApi.GetMemoryValuesWrapper(type, start, end, buffer); return buffer; } public static void GetMemoryValues(MemoryType type, UInt32 start, UInt32 end, ref byte[] dst) { Array.Resize(ref dst, (int)(end - start + 1)); DebugApi.GetMemoryValuesWrapper(type, start, end, dst); } [DllImport(DllPath, EntryPoint = "GetMemoryState")] private static extern void GetMemoryStateWrapper(MemoryType type, [In, Out] byte[] buffer); public static byte[] GetMemoryState(MemoryType type) { byte[] buffer = new byte[DebugApi.GetMemorySize(type)]; DebugApi.GetMemoryStateWrapper(type, buffer); return buffer; } public static void GetMemoryState(MemoryType type, ref byte[] dst) { int length = DebugApi.GetMemorySize(type); Array.Resize(ref dst, length); DebugApi.GetMemoryStateWrapper(type, dst); } [DllImport(DllPath)] private static extern DebugTilemapInfo GetTilemap(CpuType cpuType, InteropGetTilemapOptions options, IntPtr state, IntPtr ppuToolsState, byte[] vram, UInt32[] palette, IntPtr outputBuffer); public unsafe static DebugTilemapInfo GetTilemap(CpuType cpuType, GetTilemapOptions options, BaseState state, BaseState ppuToolsState, byte[] vram, UInt32[] palette, IntPtr outputBuffer) { Debug.Assert(state.GetType().IsValueType); Debug.Assert(IsValidPpuState(ref state, cpuType)); fixed(byte* compareVramPtr = options.CompareVram) { fixed(AddressCounters* accessCounters = options.AccessCounters) { byte* stateBuffer = stackalloc byte[GetStateSize(state)]; Marshal.StructureToPtr(state, (IntPtr)stateBuffer, false); byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)]; Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false); InteropGetTilemapOptions interopOptions = options.ToInterop(); interopOptions.CompareVram = (IntPtr)compareVramPtr; interopOptions.AccessCounters = (IntPtr)accessCounters; return DebugApi.GetTilemap(cpuType, interopOptions, (IntPtr)stateBuffer, (IntPtr)ppuToolsStateBuffer, vram, palette, outputBuffer); } } } [DllImport(DllPath)] private static extern FrameInfo GetTilemapSize(CpuType cpuType, InteropGetTilemapOptions options, IntPtr state); public unsafe static FrameInfo GetTilemapSize(CpuType cpuType, GetTilemapOptions options, BaseState state) { Debug.Assert(state.GetType().IsValueType); Debug.Assert(IsValidPpuState(ref state, cpuType)); byte* ptr = stackalloc byte[GetStateSize(state)]; Marshal.StructureToPtr(state, (IntPtr)ptr, false); return DebugApi.GetTilemapSize(cpuType, options.ToInterop(), (IntPtr)ptr); } [DllImport(DllPath)] private static extern DebugTilemapTileInfo GetTilemapTileInfo(UInt32 x, UInt32 y, CpuType cpuType, InteropGetTilemapOptions options, byte[] vram, IntPtr state, IntPtr ppuToolsState); public unsafe static DebugTilemapTileInfo? GetTilemapTileInfo(UInt32 x, UInt32 y, CpuType cpuType, GetTilemapOptions options, byte[] vram, BaseState state, BaseState ppuToolsState) { Debug.Assert(state.GetType().IsValueType); Debug.Assert(IsValidPpuState(ref state, cpuType)); byte* ptr = stackalloc byte[GetStateSize(state)]; Marshal.StructureToPtr(state, (IntPtr)ptr, false); byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)]; Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false); DebugTilemapTileInfo info = DebugApi.GetTilemapTileInfo(x, y, cpuType, options.ToInterop(), vram, (IntPtr)ptr, (IntPtr)ppuToolsStateBuffer); return info.Row >= 0 ? info : null; } [DllImport(DllPath)] public static extern void GetTileView(CpuType cpuType, GetTileViewOptions options, byte[] source, int srcSize, UInt32[] palette, IntPtr buffer); [DllImport(DllPath)] private static extern DebugSpritePreviewInfo GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, IntPtr state, IntPtr ppuToolsState); public unsafe static DebugSpritePreviewInfo GetSpritePreviewInfo(CpuType cpuType, GetSpritePreviewOptions options, BaseState state, BaseState ppuToolsState) { Debug.Assert(state.GetType().IsValueType); Debug.Assert(IsValidPpuState(ref state, cpuType)); byte* ptr = stackalloc byte[GetStateSize(state)]; Marshal.StructureToPtr(state, (IntPtr)ptr, false); byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)]; Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false); return DebugApi.GetSpritePreviewInfo(cpuType, options, (IntPtr)ptr, (IntPtr)ppuToolsStateBuffer); } [DllImport(DllPath)] private static extern void GetSpriteList(CpuType cpuType, GetSpritePreviewOptions options, IntPtr state, IntPtr ppuToolsState, byte[] vram, byte[]? spriteRam, UInt32[] palette, IntPtr sprites, IntPtr spritePreviews, IntPtr screenPreview); public unsafe static void GetSpriteList(ref DebugSpriteInfo[] result, ref UInt32[] spritePreviews, CpuType cpuType, GetSpritePreviewOptions options, BaseState state, BaseState ppuToolsState, byte[] vram, byte[] spriteRam, UInt32[] palette, IntPtr screenPreview) { Debug.Assert(state.GetType().IsValueType); Debug.Assert(IsValidPpuState(ref state, cpuType)); byte* statePtr = stackalloc byte[GetStateSize(state)]; Marshal.StructureToPtr(state, (IntPtr)statePtr, false); byte* ppuToolsStateBuffer = stackalloc byte[GetStateSize(ppuToolsState)]; Marshal.StructureToPtr(ppuToolsState, (IntPtr)ppuToolsStateBuffer, false); int count = (int)GetSpritePreviewInfo(cpuType, options, (IntPtr)statePtr, (IntPtr)ppuToolsStateBuffer).SpriteCount; if(count != result.Length) { Array.Resize(ref result, count); } if(count*128*128 != spritePreviews.Length) { Array.Resize(ref spritePreviews, count*128*128); } fixed(DebugSpriteInfo* spritesPtr = result) { fixed(UInt32* spritePreviewsPtr = spritePreviews) { DebugApi.GetSpriteList(cpuType, options, (IntPtr)statePtr, (IntPtr)ppuToolsStateBuffer, vram, spriteRam.Length > 0 ? spriteRam : null, palette, (IntPtr)spritesPtr, (IntPtr)spritePreviewsPtr, screenPreview); } } } [DllImport(DllPath)] public static extern DebugPaletteInfo GetPaletteInfo(CpuType cpuType, GetPaletteInfoOptions options = new()); [DllImport(DllPath)] public static extern void SetPaletteColor(CpuType cpuType, int colorIndex, UInt32 color); [DllImport(DllPath)] public static extern int GetTilePixel(AddressInfo tileAddress, TileFormat format, int x, int y); [DllImport(DllPath)] public static extern void SetTilePixel(AddressInfo tileAddress, TileFormat format, int x, int y, int color); [DllImport(DllPath)] public static extern void SetViewerUpdateTiming(Int32 viewerId, Int32 scanline, Int32 cycle, CpuType cpuType); [DllImport(DllPath)] public static extern void RemoveViewerId(int viewerId, CpuType cpuType); [DllImport(DllPath)] private static extern UInt32 GetDebugEventCount(CpuType cpuType); [DllImport(DllPath, EntryPoint = "GetDebugEvents")] private static extern void GetDebugEventsWrapper(CpuType cpuType, [In, Out] DebugEventInfo[] eventArray, ref UInt32 maxEventCount); public static DebugEventInfo[] GetDebugEvents(CpuType cpuType) { UInt32 maxEventCount = GetDebugEventCount(cpuType); DebugEventInfo[] debugEvents = new DebugEventInfo[maxEventCount]; DebugApi.GetDebugEventsWrapper(cpuType, debugEvents, ref maxEventCount); if(maxEventCount < debugEvents.Length) { //Remove the excess from the array if needed Array.Resize(ref debugEvents, (int)maxEventCount); } return debugEvents; } [DllImport(DllPath)] public static extern void SetEventViewerConfig(CpuType cpuType, InteropSnesEventViewerConfig config); [DllImport(DllPath)] public static extern void SetEventViewerConfig(CpuType cpuType, InteropNesEventViewerConfig config); [DllImport(DllPath)] public static extern void SetEventViewerConfig(CpuType cpuType, InteropGbEventViewerConfig config); [DllImport(DllPath)] public static extern void SetEventViewerConfig(CpuType cpuType, InteropGbaEventViewerConfig config); [DllImport(DllPath)] public static extern void SetEventViewerConfig(CpuType cpuType, InteropPceEventViewerConfig config); [DllImport(DllPath)] public static extern void SetEventViewerConfig(CpuType cpuType, InteropSmsEventViewerConfig config); [DllImport(DllPath)] public static extern void SetEventViewerConfig(CpuType cpuType, InteropWsEventViewerConfig config); [DllImport(DllPath, EntryPoint = "GetEventViewerEvent")] private static extern DebugEventInfo GetEventViewerEventWrapper(CpuType cpuType, UInt16 scanline, UInt16 cycle); public static DebugEventInfo? GetEventViewerEvent(CpuType cpuType, UInt16 scanline, UInt16 cycle) { DebugEventInfo evt = DebugApi.GetEventViewerEventWrapper(cpuType, scanline, cycle); if(evt.ProgramCounter != UInt32.MaxValue) { return evt; } return null; } [DllImport(DllPath)] public static extern UInt32 TakeEventSnapshot(CpuType cpuType, [MarshalAs(UnmanagedType.I1)] bool forAutoRefresh); [DllImport(DllPath)] public static extern FrameInfo GetEventViewerDisplaySize(CpuType cpuType); [DllImport(DllPath)] public static extern void GetEventViewerOutput(CpuType cpuType, IntPtr buffer, UInt32 bufferSize); [DllImport(DllPath, EntryPoint = "GetCallstack")] private static extern void GetCallstackWrapper(CpuType type, [In, Out] StackFrameInfo[] callstackArray, ref UInt32 callstackSize); public static StackFrameInfo[] GetCallstack(CpuType type) { StackFrameInfo[] callstack = new StackFrameInfo[512]; UInt32 callstackSize = 0; DebugApi.GetCallstackWrapper(type, callstack, ref callstackSize); Array.Resize(ref callstack, (int)callstackSize); return callstack; } [DllImport(DllPath)] public static extern void ResetProfiler(CpuType type); [DllImport(DllPath, EntryPoint = "GetProfilerData")] private static extern void GetProfilerDataWrapper(CpuType type, IntPtr profilerData, ref UInt32 functionCount); public static unsafe int GetProfilerData(CpuType type, ref ProfiledFunction[] profilerData) { UInt32 functionCount = 0; fixed(ProfiledFunction* ptr = profilerData) { DebugApi.GetProfilerDataWrapper(type, (IntPtr)ptr, ref functionCount); } return (int)functionCount; } [DllImport(DllPath, EntryPoint = "GetTokenList")] private static extern void GetTokenListWrapper(CpuType cpuType, IntPtr tokenListBuffer); public static unsafe string[] GetTokenList(CpuType type) { byte[] tokenListBuffer = new byte[1000]; fixed(byte* ptr = tokenListBuffer) { DebugApi.GetTokenListWrapper(type, (IntPtr)ptr); } int index = Array.IndexOf(tokenListBuffer, 0); if(index >= 0) { return UTF8Encoding.UTF8.GetString(tokenListBuffer, 0, index).Split("|", StringSplitOptions.RemoveEmptyEntries); } return Array.Empty(); } [DllImport(DllPath)] public static extern void ResetMemoryAccessCounts(); public static unsafe void GetMemoryAccessCounts(MemoryType type, ref AddressCounters[] counts) { int size = DebugApi.GetMemorySize(type); Array.Resize(ref counts, size); fixed(AddressCounters* ptr = counts) { DebugApi.GetMemoryAccessCountsWrapper(0, (uint)size, type, (IntPtr)ptr); } } public static AddressCounters[] GetMemoryAccessCounts(MemoryType type) { int size = DebugApi.GetMemorySize(type); AddressCounters[] counts = new AddressCounters[size]; GetMemoryAccessCounts(type, ref counts); return counts; } [DllImport(DllPath, EntryPoint = "GetMemoryAccessCounts")] private static extern void GetMemoryAccessCountsWrapper(UInt32 offset, UInt32 length, MemoryType type, IntPtr counts); public static unsafe AddressCounters[] GetMemoryAccessCounts(UInt32 offset, UInt32 length, MemoryType type) { AddressCounters[] counts = new AddressCounters[length]; fixed(AddressCounters* ptr = counts) { DebugApi.GetMemoryAccessCountsWrapper(offset, length, type, (IntPtr)ptr); } return counts; } [DllImport(DllPath, EntryPoint = "GetCdlData")] private static extern void GetCdlDataWrapper(UInt32 offset, UInt32 length, MemoryType memType, [In, Out] CdlFlags[] cdlData); public static CdlFlags[] GetCdlData(UInt32 offset, UInt32 length, MemoryType memType) { CdlFlags[] cdlData = new CdlFlags[length]; DebugApi.GetCdlDataWrapper(offset, length, memType, cdlData); return cdlData; } public static CdlFlags[] GetCdlData(CpuType cpuType) { return DebugApi.GetCdlData(0, (uint)DebugApi.GetMemorySize(cpuType.GetPrgRomMemoryType()), cpuType.GetPrgRomMemoryType()); } [DllImport(DllPath)] public static extern void ResetCdl(MemoryType memType); [DllImport(DllPath)] public static extern void SaveCdlFile(MemoryType memType, [MarshalAs(UnmanagedType.LPUTF8Str)] string cdlFile); [DllImport(DllPath)] public static extern void LoadCdlFile(MemoryType memType, [MarshalAs(UnmanagedType.LPUTF8Str)] string cdlFile); [DllImport(DllPath)] public static extern void SetCdlData(MemoryType memType, [In] byte[] cdlData, Int32 length); [DllImport(DllPath)] public static extern void MarkBytesAs(MemoryType memType, UInt32 start, UInt32 end, CdlFlags type); [DllImport(DllPath)] public static extern CdlStatistics GetCdlStatistics(MemoryType memType); [DllImport(DllPath)] private static extern UInt32 GetCdlFunctions(MemoryType memType, IntPtr functions, UInt32 maxSize); public unsafe static UInt32[] GetCdlFunctions(MemoryType memType) { UInt32[] functions = new UInt32[0x40000]; UInt32 count; fixed(UInt32* functionPtr = functions) { count = DebugApi.GetCdlFunctions(memType, (IntPtr)functionPtr, (UInt32)functions.Length); } Array.Resize(ref functions, (int)count); return functions; } [DllImport(DllPath, EntryPoint = "AssembleCode")] private static extern UInt32 AssembleCodeWrapper(CpuType cpuType, [MarshalAs(UnmanagedType.LPUTF8Str)] string code, UInt32 startAddress, [In, Out] Int16[] assembledCodeBuffer); public static Int16[] AssembleCode(CpuType cpuType, string code, UInt32 startAddress) { code = code.Replace(Environment.NewLine, "\n"); Int16[] assembledCode = new Int16[100000]; UInt32 size = DebugApi.AssembleCodeWrapper(cpuType, code, startAddress, assembledCode); Array.Resize(ref assembledCode, (int)size); return assembledCode; } private static bool IsValidCpuState(ref T state, CpuType cpuType) where T : BaseState { return cpuType switch { CpuType.Snes => state is SnesCpuState, CpuType.Spc => state is SpcState, CpuType.NecDsp => state is NecDspState, CpuType.Sa1 => state is SnesCpuState, CpuType.Gsu => state is GsuState, CpuType.Cx4 => state is Cx4State, CpuType.St018 => state is ArmV3CpuState, CpuType.Gameboy => state is GbCpuState, CpuType.Nes => state is NesCpuState, CpuType.Pce => state is PceCpuState, CpuType.Sms => state is SmsCpuState, CpuType.Gba => state is GbaCpuState, CpuType.Ws => state is WsCpuState, _ => false }; } private static bool IsValidPpuState(ref T state, CpuType cpuType) where T : BaseState { return cpuType.GetConsoleType() switch { ConsoleType.Snes => state is SnesPpuState, ConsoleType.Nes => state is NesPpuState, ConsoleType.Gameboy => state is GbPpuState, ConsoleType.PcEngine => state is PceVideoState, ConsoleType.Sms => state is SmsVdpState, ConsoleType.Gba => state is GbaPpuState, ConsoleType.Ws => state is WsPpuState, _ => false }; } private static int GetStateSize(BaseState state) { #pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. return Marshal.SizeOf(state.GetType()); #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. } } public enum MemoryType { SnesMemory, SpcMemory, Sa1Memory, NecDspMemory, GsuMemory, Cx4Memory, St018Memory, GameboyMemory, NesMemory, NesPpuMemory, PceMemory, SmsMemory, GbaMemory, WsMemory, SnesPrgRom, SnesWorkRam, SnesSaveRam, SnesVideoRam, SnesSpriteRam, SnesCgRam, SnesRegister, SpcRam, SpcRom, SpcDspRegisters, DspProgramRom, DspDataRom, DspDataRam, Sa1InternalRam, GsuWorkRam, Cx4DataRam, BsxPsRam, BsxMemoryPack, St018PrgRom, St018DataRom, St018WorkRam, SufamiTurboFirmware, SufamiTurboSecondCart, SufamiTurboSecondCartRam, GbPrgRom, GbWorkRam, GbCartRam, GbHighRam, GbBootRom, GbVideoRam, GbSpriteRam, NesPrgRom, NesInternalRam, NesWorkRam, NesSaveRam, NesNametableRam, NesMapperRam, NesSpriteRam, NesSecondarySpriteRam, NesPaletteRam, NesChrRam, NesChrRom, PcePrgRom, PceWorkRam, PceSaveRam, PceCdromRam, PceCardRam, PceAdpcmRam, PceArcadeCardRam, PceVideoRam, PceVideoRamVdc2, PceSpriteRam, PceSpriteRamVdc2, PcePaletteRam, SmsPrgRom, SmsWorkRam, SmsCartRam, SmsBootRom, SmsVideoRam, SmsPaletteRam, SmsPort, GbaPrgRom, GbaBootRom, GbaSaveRam, GbaIntWorkRam, GbaExtWorkRam, GbaVideoRam, GbaSpriteRam, GbaPaletteRam, WsPrgRom, WsWorkRam, WsCartRam, WsCartEeprom, WsBootRom, WsInternalEeprom, WsPort, None, } [StructLayout(LayoutKind.Sequential)] public struct AddressCounters { public UInt64 ReadStamp; public UInt64 WriteStamp; public UInt64 ExecStamp; public UInt32 ReadCounter; public UInt32 WriteCounter; public UInt32 ExecCounter; } public struct AddressInfo { public Int32 Address; public MemoryType Type; } public enum MemoryOperationType { Read = 0, Write = 1, ExecOpCode = 2, ExecOperand = 3, DmaRead = 4, DmaWrite = 5, DummyRead = 6, DummyWrite = 7, PpuRenderingRead = 8, Idle = 9 } public struct MemoryOperationInfo { public UInt32 Address; public Int32 Value; public MemoryOperationType Type; public MemoryType MemType; } public enum DebugEventType { Register, Nmi, Irq, Breakpoint, BgColorChange, SpriteZeroHit, DmcDmaRead, DmaRead } public struct DmaChannelConfig { public UInt16 SrcAddress; public UInt16 TransferSize; public UInt16 HdmaTableAddress; public byte SrcBank; public byte DestAddress; [MarshalAs(UnmanagedType.I1)] public bool DmaActive; [MarshalAs(UnmanagedType.I1)] public bool InvertDirection; [MarshalAs(UnmanagedType.I1)] public bool Decrement; [MarshalAs(UnmanagedType.I1)] public bool FixedTransfer; [MarshalAs(UnmanagedType.I1)] public bool HdmaIndirectAddressing; public byte TransferMode; public byte HdmaBank; public byte HdmaLineCounterAndRepeat; [MarshalAs(UnmanagedType.I1)] public bool DoTransfer; [MarshalAs(UnmanagedType.I1)] public bool HdmaFinished; [MarshalAs(UnmanagedType.I1)] public bool UnusedControlFlag; public byte UnusedRegister; } public enum EventFlags { PreviousFrame = 1 << 0, RegFirstWrite = 1 << 1, RegSecondWrite = 1 << 2, HasTargetMemory = 1 << 3, SmsVdpPaletteWrite = 1 << 4, ReadWriteOp = 1 << 5, } public record struct DebugEventInfo { public MemoryOperationInfo Operation; public DebugEventType Type; public UInt32 ProgramCounter; public Int16 Scanline; public UInt16 Cycle; public Int16 BreakpointId; public sbyte DmaChannel; public DmaChannelConfig DmaChannelInfo; public EventFlags Flags; public Int32 RegisterId; public MemoryOperationInfo TargetMemory; public UInt32 Color; }; [StructLayout(LayoutKind.Sequential)] public struct InteropEventViewerCategoryCfg { [MarshalAs(UnmanagedType.I1)] public bool Visible; public UInt32 Color; } [StructLayout(LayoutKind.Sequential)] public class InteropSnesEventViewerConfig { public InteropEventViewerCategoryCfg Irq; public InteropEventViewerCategoryCfg Nmi; public InteropEventViewerCategoryCfg MarkedBreakpoints; public InteropEventViewerCategoryCfg PpuRegisterReads; public InteropEventViewerCategoryCfg PpuRegisterCgramWrites; public InteropEventViewerCategoryCfg PpuRegisterVramWrites; public InteropEventViewerCategoryCfg PpuRegisterOamWrites; public InteropEventViewerCategoryCfg PpuRegisterMode7Writes; public InteropEventViewerCategoryCfg PpuRegisterBgOptionWrites; public InteropEventViewerCategoryCfg PpuRegisterBgScrollWrites; public InteropEventViewerCategoryCfg PpuRegisterWindowWrites; public InteropEventViewerCategoryCfg PpuRegisterOtherWrites; public InteropEventViewerCategoryCfg ApuRegisterReads; public InteropEventViewerCategoryCfg ApuRegisterWrites; public InteropEventViewerCategoryCfg CpuRegisterReads; public InteropEventViewerCategoryCfg CpuRegisterWrites; public InteropEventViewerCategoryCfg WorkRamRegisterReads; public InteropEventViewerCategoryCfg WorkRamRegisterWrites; [MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] ShowDmaChannels = new byte[8]; } [StructLayout(LayoutKind.Sequential)] public class InteropNesEventViewerConfig { public InteropEventViewerCategoryCfg Irq; public InteropEventViewerCategoryCfg Nmi; public InteropEventViewerCategoryCfg MarkedBreakpoints; public InteropEventViewerCategoryCfg MapperRegisterWrites; public InteropEventViewerCategoryCfg MapperRegisterReads; public InteropEventViewerCategoryCfg ApuRegisterWrites; public InteropEventViewerCategoryCfg ApuRegisterReads; public InteropEventViewerCategoryCfg ControlRegisterWrites; public InteropEventViewerCategoryCfg ControlRegisterReads; public InteropEventViewerCategoryCfg Ppu2000Write; public InteropEventViewerCategoryCfg Ppu2001Write; public InteropEventViewerCategoryCfg Ppu2003Write; public InteropEventViewerCategoryCfg Ppu2004Write; public InteropEventViewerCategoryCfg Ppu2005Write; public InteropEventViewerCategoryCfg Ppu2006Write; public InteropEventViewerCategoryCfg Ppu2007Write; public InteropEventViewerCategoryCfg Ppu2002Read; public InteropEventViewerCategoryCfg Ppu2004Read; public InteropEventViewerCategoryCfg Ppu2007Read; public InteropEventViewerCategoryCfg DmcDmaReads; public InteropEventViewerCategoryCfg OtherDmaReads; public InteropEventViewerCategoryCfg SpriteZeroHit; [MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents; [MarshalAs(UnmanagedType.I1)] public bool ShowNtscBorders; } [StructLayout(LayoutKind.Sequential)] public class InteropGbEventViewerConfig { public InteropEventViewerCategoryCfg Irq; public InteropEventViewerCategoryCfg MarkedBreakpoints; public InteropEventViewerCategoryCfg PpuRegisterCgramWrites; public InteropEventViewerCategoryCfg PpuRegisterVramWrites; public InteropEventViewerCategoryCfg PpuRegisterOamWrites; public InteropEventViewerCategoryCfg PpuRegisterBgScrollWrites; public InteropEventViewerCategoryCfg PpuRegisterWindowWrites; public InteropEventViewerCategoryCfg PpuRegisterOtherWrites; public InteropEventViewerCategoryCfg PpuRegisterCgramReads; public InteropEventViewerCategoryCfg PpuRegisterVramReads; public InteropEventViewerCategoryCfg PpuRegisterOamReads; public InteropEventViewerCategoryCfg PpuRegisterBgScrollReads; public InteropEventViewerCategoryCfg PpuRegisterWindowReads; public InteropEventViewerCategoryCfg PpuRegisterOtherReads; public InteropEventViewerCategoryCfg ApuRegisterReads; public InteropEventViewerCategoryCfg ApuRegisterWrites; public InteropEventViewerCategoryCfg SerialReads; public InteropEventViewerCategoryCfg SerialWrites; public InteropEventViewerCategoryCfg TimerReads; public InteropEventViewerCategoryCfg TimerWrites; public InteropEventViewerCategoryCfg InputReads; public InteropEventViewerCategoryCfg InputWrites; public InteropEventViewerCategoryCfg OtherRegisterReads; public InteropEventViewerCategoryCfg OtherRegisterWrites; [MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents; } [StructLayout(LayoutKind.Sequential)] public class InteropGbaEventViewerConfig { public InteropEventViewerCategoryCfg Irq; public InteropEventViewerCategoryCfg MarkedBreakpoints; public InteropEventViewerCategoryCfg PaletteReads; public InteropEventViewerCategoryCfg PaletteWrites; public InteropEventViewerCategoryCfg VramReads; public InteropEventViewerCategoryCfg VramWrites; public InteropEventViewerCategoryCfg OamReads; public InteropEventViewerCategoryCfg OamWrites; public InteropEventViewerCategoryCfg PpuRegisterBgScrollReads; public InteropEventViewerCategoryCfg PpuRegisterBgScrollWrites; public InteropEventViewerCategoryCfg PpuRegisterWindowReads; public InteropEventViewerCategoryCfg PpuRegisterWindowWrites; public InteropEventViewerCategoryCfg PpuRegisterOtherReads; public InteropEventViewerCategoryCfg PpuRegisterOtherWrites; public InteropEventViewerCategoryCfg DmaRegisterReads; public InteropEventViewerCategoryCfg DmaRegisterWrites; public InteropEventViewerCategoryCfg ApuRegisterReads; public InteropEventViewerCategoryCfg ApuRegisterWrites; public InteropEventViewerCategoryCfg SerialReads; public InteropEventViewerCategoryCfg SerialWrites; public InteropEventViewerCategoryCfg TimerReads; public InteropEventViewerCategoryCfg TimerWrites; public InteropEventViewerCategoryCfg InputReads; public InteropEventViewerCategoryCfg InputWrites; public InteropEventViewerCategoryCfg OtherRegisterReads; public InteropEventViewerCategoryCfg OtherRegisterWrites; [MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents; } [StructLayout(LayoutKind.Sequential)] public class InteropPceEventViewerConfig { public InteropEventViewerCategoryCfg Irq; public InteropEventViewerCategoryCfg MarkedBreakpoints; public InteropEventViewerCategoryCfg VdcStatusReads; public InteropEventViewerCategoryCfg VdcVramWrites; public InteropEventViewerCategoryCfg VdcVramReads; public InteropEventViewerCategoryCfg VdcRegSelectWrites; public InteropEventViewerCategoryCfg VdcControlWrites; public InteropEventViewerCategoryCfg VdcRcrWrites; public InteropEventViewerCategoryCfg VdcHvConfigWrites; public InteropEventViewerCategoryCfg VdcMemoryWidthWrites; public InteropEventViewerCategoryCfg VdcScrollWrites; public InteropEventViewerCategoryCfg VdcDmaWrites; public InteropEventViewerCategoryCfg VceWrites; public InteropEventViewerCategoryCfg VceReads; public InteropEventViewerCategoryCfg PsgWrites; public InteropEventViewerCategoryCfg PsgReads; public InteropEventViewerCategoryCfg TimerWrites; public InteropEventViewerCategoryCfg TimerReads; public InteropEventViewerCategoryCfg IoWrites; public InteropEventViewerCategoryCfg IoReads; public InteropEventViewerCategoryCfg IrqControlWrites; public InteropEventViewerCategoryCfg IrqControlReads; public InteropEventViewerCategoryCfg CdRomWrites; public InteropEventViewerCategoryCfg CdRomReads; public InteropEventViewerCategoryCfg AdpcmWrites; public InteropEventViewerCategoryCfg AdpcmReads; public InteropEventViewerCategoryCfg ArcadeCardWrites; public InteropEventViewerCategoryCfg ArcadeCardReads; [MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents; } [StructLayout(LayoutKind.Sequential)] public class InteropSmsEventViewerConfig { public InteropEventViewerCategoryCfg Irq; public InteropEventViewerCategoryCfg Nmi; public InteropEventViewerCategoryCfg MarkedBreakpoints; public InteropEventViewerCategoryCfg VdpPaletteWrite; public InteropEventViewerCategoryCfg VdpVramWrite; public InteropEventViewerCategoryCfg VdpVCounterRead; public InteropEventViewerCategoryCfg VdpHCounterRead; public InteropEventViewerCategoryCfg VdpVramRead; public InteropEventViewerCategoryCfg VdpControlPortRead; public InteropEventViewerCategoryCfg VdpControlPortWrite; public InteropEventViewerCategoryCfg PsgWrite; public InteropEventViewerCategoryCfg IoWrite; public InteropEventViewerCategoryCfg IoRead; public InteropEventViewerCategoryCfg MemoryControlWrite; public InteropEventViewerCategoryCfg GameGearPortWrite; public InteropEventViewerCategoryCfg GameGearPortRead; [MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents; } [StructLayout(LayoutKind.Sequential)] public class InteropWsEventViewerConfig { public InteropEventViewerCategoryCfg PpuPaletteRead; public InteropEventViewerCategoryCfg PpuPaletteWrite; public InteropEventViewerCategoryCfg PpuVramRead; public InteropEventViewerCategoryCfg PpuVramWrite; public InteropEventViewerCategoryCfg PpuVCounterRead; public InteropEventViewerCategoryCfg PpuScrollRead; public InteropEventViewerCategoryCfg PpuScrollWrite; public InteropEventViewerCategoryCfg PpuWindowRead; public InteropEventViewerCategoryCfg PpuWindowWrite; public InteropEventViewerCategoryCfg PpuOtherRead; public InteropEventViewerCategoryCfg PpuOtherWrite; public InteropEventViewerCategoryCfg AudioRead; public InteropEventViewerCategoryCfg AudioWrite; public InteropEventViewerCategoryCfg SerialRead; public InteropEventViewerCategoryCfg SerialWrite; public InteropEventViewerCategoryCfg DmaRead; public InteropEventViewerCategoryCfg DmaWrite; public InteropEventViewerCategoryCfg InputRead; public InteropEventViewerCategoryCfg InputWrite; public InteropEventViewerCategoryCfg IrqRead; public InteropEventViewerCategoryCfg IrqWrite; public InteropEventViewerCategoryCfg TimerRead; public InteropEventViewerCategoryCfg TimerWrite; public InteropEventViewerCategoryCfg EepromRead; public InteropEventViewerCategoryCfg EepromWrite; public InteropEventViewerCategoryCfg CartRead; public InteropEventViewerCategoryCfg CartWrite; public InteropEventViewerCategoryCfg OtherRead; public InteropEventViewerCategoryCfg OtherWrite; public InteropEventViewerCategoryCfg Irq; public InteropEventViewerCategoryCfg MarkedBreakpoints; [MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents; } public enum TilemapDisplayMode { Default, Grayscale, AttributeView } public enum TilemapHighlightMode { None, Changes, Writes } public class GetTilemapOptions { public byte Layer; public byte[]? CompareVram; public AddressCounters[]? AccessCounters; public UInt64 MasterClock; public TilemapHighlightMode TileHighlightMode; public TilemapHighlightMode AttributeHighlightMode; public TilemapDisplayMode DisplayMode; public InteropGetTilemapOptions ToInterop() { return new InteropGetTilemapOptions() { Layer = Layer, MasterClock = MasterClock, TileHighlightMode = TileHighlightMode, AttributeHighlightMode = AttributeHighlightMode, DisplayMode = DisplayMode }; } } public struct InteropGetTilemapOptions { public byte Layer; public IntPtr CompareVram; public IntPtr AccessCounters; public UInt64 MasterClock; public TilemapHighlightMode TileHighlightMode; public TilemapHighlightMode AttributeHighlightMode; public TilemapDisplayMode DisplayMode; } public enum TileBackground { Default, Transparent, PaletteColor, Black, White, Magenta, } public enum SpriteBackground { Gray, Background, Transparent, Black, White, Magenta, } public enum SpriteVisibility : byte { Visible = 0, Offscreen = 1, Disabled = 2 } public enum NullableBoolean : sbyte { Undefined = -1, False = 0, True = 1 } public enum TilemapMirroring { None, Horizontal, Vertical, SingleScreenA, SingleScreenB, FourScreens, } public struct DebugTilemapInfo { public UInt32 Bpp; public TileFormat Format; public TilemapMirroring Mirroring; public UInt32 TileWidth; public UInt32 TileHeight; public UInt32 ScrollX; public UInt32 ScrollWidth; public UInt32 ScrollY; public UInt32 ScrollHeight; public UInt32 RowCount; public UInt32 ColumnCount; public UInt32 TilemapAddress; public UInt32 TilesetAddress; public sbyte Priority; } public struct DebugTilemapTileInfo { public Int32 Row; public Int32 Column; public Int32 Width; public Int32 Height; public Int32 TileMapAddress; public Int32 TileIndex; public Int32 TileAddress; public Int32 PixelData; public Int32 PaletteIndex; public Int32 PaletteAddress; public Int32 BasePaletteIndex; public Int32 AttributeAddress; public Int16 AttributeData; public NullableBoolean HorizontalMirroring; public NullableBoolean VerticalMirroring; public NullableBoolean HighPriority; }; public enum TileFilter { None, HideUnused, HideUsed } public struct GetTileViewOptions { public MemoryType MemType; public TileFormat Format; public TileLayout Layout; public TileFilter Filter; public TileBackground Background; public Int32 Width; public Int32 Height; public Int32 StartAddress; public Int32 Palette; [MarshalAs(UnmanagedType.I1)] public bool UseGrayscalePalette; } public struct GetSpritePreviewOptions { public SpriteBackground Background; } public struct GetPaletteInfoOptions { public TileFormat Format; } public struct DebugSpritePreviewInfo { public UInt32 Width; public UInt32 Height; public UInt32 SpriteCount; public Int32 CoordOffsetX; public Int32 CoordOffsetY; public UInt32 VisibleX; public UInt32 VisibleY; public UInt32 VisibleWidth; public UInt32 VisibleHeight; [MarshalAs(UnmanagedType.I1)] public bool WrapBottomToTop; [MarshalAs(UnmanagedType.I1)] public bool WrapRightToLeft; } public enum DebugSpritePriority { Undefined = -1, Number0 = 0, Number1 = 1, Number2 = 2, Number3 = 3, Foreground = 4, Background = 5 } public unsafe struct DebugSpriteInfo { public Int32 TileIndex; public Int32 TileAddress; public Int32 PaletteAddress; public TileFormat Format; public Int16 SpriteIndex; public Int16 X; public Int16 Y; public Int16 RawX; public Int16 RawY; public Int16 Bpp; public Int16 Palette; public DebugSpritePriority Priority; public UInt16 Width; public UInt16 Height; public NullableBoolean HorizontalMirror; public NullableBoolean VerticalMirror; public NullableBoolean MosaicEnabled; public NullableBoolean BlendingEnabled; public NullableBoolean WindowMode; public NullableBoolean TransformEnabled; public NullableBoolean DoubleSize; public sbyte TransformParamIndex; public SpriteVisibility Visibility; [MarshalAs(UnmanagedType.I1)] public bool UseExtendedVram; public NullableBoolean UseSecondTable; public UInt32 TileCount; public fixed UInt32 TileAddresses[8*8]; } public enum RawPaletteFormat { Indexed, Rgb555, Rgb333, Rgb222, Rgb444, Bgr444, } public unsafe struct DebugPaletteInfo { public MemoryType PaletteMemType; public UInt32 PaletteMemOffset; [MarshalAs(UnmanagedType.I1)] public bool HasMemType; public UInt32 ColorCount; public UInt32 BgColorCount; public UInt32 SpriteColorCount; public UInt32 SpritePaletteOffset; public UInt32 ColorsPerPalette; public RawPaletteFormat RawFormat; public fixed UInt32 RawPalette[512]; public fixed UInt32 RgbPalette[512]; public unsafe UInt32[] GetRgbPalette() { UInt32[] result = new UInt32[ColorCount]; fixed(UInt32* pal = RgbPalette) { for(int i = 0; i < ColorCount; i++) { result[i] = pal[i]; } } return result; } public unsafe UInt32[] GetRawPalette() { UInt32[] result = new UInt32[ColorCount]; fixed(UInt32* pal = RawPalette) { for(int i = 0; i < ColorCount; i++) { result[i] = pal[i]; } } return result; } }; public enum TileFormat { Bpp2, Bpp4, Bpp8, DirectColor, Mode7, Mode7DirectColor, Mode7ExtBg, NesBpp2, PceSpriteBpp4, PceSpriteBpp2Sp01, PceSpriteBpp2Sp23, PceBackgroundBpp2Cg0, PceBackgroundBpp2Cg1, SmsBpp4, SmsSgBpp1, GbaBpp4, GbaBpp8, WsBpp4Packed } public static class TileFormatExtensions { public static PixelSize GetTileSize(this TileFormat format) { return format switch { TileFormat.PceSpriteBpp4 => new PixelSize(16, 16), TileFormat.PceSpriteBpp2Sp01 => new PixelSize(16, 16), TileFormat.PceSpriteBpp2Sp23 => new PixelSize(16, 16), _ => new PixelSize(8, 8), }; } public static int GetBitsPerPixel(this TileFormat format) { return format switch { TileFormat.Bpp2 => 2, TileFormat.Bpp4 => 4, TileFormat.Bpp8 => 8, TileFormat.DirectColor => 8, TileFormat.Mode7 => 16, TileFormat.Mode7DirectColor => 16, TileFormat.Mode7ExtBg => 16, TileFormat.NesBpp2 => 2, TileFormat.PceSpriteBpp4 => 4, //Treat all PCE 2BPP modes as 4bpp because the tile data still //covers the same amount of space in RAM as the 4bpp tiles TileFormat.PceSpriteBpp2Sp01 => 4, TileFormat.PceSpriteBpp2Sp23 => 4, TileFormat.PceBackgroundBpp2Cg0 => 4, TileFormat.PceBackgroundBpp2Cg1 => 4, TileFormat.SmsBpp4 => 4, TileFormat.SmsSgBpp1 => 1, TileFormat.GbaBpp4 => 4, TileFormat.GbaBpp8 => 8, TileFormat.WsBpp4Packed => 4, _ => throw new Exception("TileFormat not supported"), }; } public static int GetBytesPerTile(this TileFormat format) { int bitsPerPixel = format.GetBitsPerPixel(); PixelSize tileSize = format.GetTileSize(); return tileSize.Width * tileSize.Height * bitsPerPixel / 8; } } public enum TileLayout { Normal, SingleLine8x16, SingleLine16x16 }; [Serializable] public struct InteropTraceLoggerOptions { [MarshalAs(UnmanagedType.I1)] public bool Enabled; [MarshalAs(UnmanagedType.I1)] public bool IndentCode; [MarshalAs(UnmanagedType.I1)] public bool UseLabels; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)] public byte[] Condition; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)] public byte[] Format; } public enum VectorType { Indirect, Direct, x86, x86WithOffset } public struct CpuVectorDefinition { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] public byte[] Name; public UInt32 Address; public VectorType Type; } public struct DebuggerFeatures { [MarshalAs(UnmanagedType.I1)] public bool RunToIrq; [MarshalAs(UnmanagedType.I1)] public bool RunToNmi; [MarshalAs(UnmanagedType.I1)] public bool StepOver; [MarshalAs(UnmanagedType.I1)] public bool StepOut; [MarshalAs(UnmanagedType.I1)] public bool StepBack; [MarshalAs(UnmanagedType.I1)] public bool ChangeProgramCounter; [MarshalAs(UnmanagedType.I1)] public bool CallStack; [MarshalAs(UnmanagedType.I1)] public bool CpuCycleStep; public byte IrqVectorOffset; public byte CpuVectorCount; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public CpuVectorDefinition[] CpuVectors; } public struct CpuInstructionProgress { public UInt64 StartCycle; public UInt64 CurrentCycle; public UInt32 LastOpCode; public MemoryOperationInfo LastMemOperation; } public enum EvalResultType { Numeric = 0, Boolean = 1, Invalid = 2, DivideBy0 = 3, OutOfScope = 4 } public struct StackFrameInfo { public UInt32 Source; public AddressInfo AbsSource; public UInt32 Target; public AddressInfo AbsTarget; public UInt32 Return; public UInt32 ReturnStackPointer; public AddressInfo AbsReturn; public StackFrameFlags Flags; }; public enum StackFrameFlags { None = 0, Nmi = 1, Irq = 2 } public enum CpuType : byte { Snes, Spc, NecDsp, Sa1, Gsu, Cx4, St018, Gameboy, Nes, Pce, Sms, Gba, Ws } public enum StepType { Step, StepOut, StepOver, CpuCycleStep, PpuStep, PpuScanline, PpuFrame, SpecificScanline, RunToNmi, RunToIrq, StepBack } public enum BreakSource { Unspecified = -1, Breakpoint = 0, Pause, CpuStep, PpuStep, Irq, Nmi, InternalOperation, BreakOnBrk, BreakOnCop, BreakOnWdm, BreakOnStp, BreakOnUninitMemoryRead, GbInvalidOamAccess, GbInvalidVramAccess, GbDisableLcdOutsideVblank, GbInvalidOpCode, GbNopLoad, GbOamCorruption, NesBreakOnDecayedOamRead, NesBreakOnPpu2000ScrollGlitch, NesBreakOnPpu2006ScrollGlitch, BreakOnUnofficialOpCode, NesBusConflict, NesBreakOnCpuCrash, NesBreakOnExtOutputMode, PceBreakOnInvalidVramAddress, SmsNopLoad, GbaInvalidOpCode, GbaNopLoad, GbaUnalignedMemoryAccess, BreakOnUndefinedOpCode } public struct BreakEvent { public BreakSource Source; public CpuType SourceCpu; public MemoryOperationInfo Operation; public Int32 BreakpointId; } public enum CdlStripOption { StripNone = 0, StripUnused = 1, StripUsed = 2 } public enum CdlFlags : byte { None = 0x00, Code = 0x01, Data = 0x02, JumpTarget = 0x04, SubEntryPoint = 0x08, IndexMode8 = 0x10, MemoryMode8 = 0x20, NesChrDrawn = 0x01, NesPcmData = 0x80 } public struct CdlStatistics { public UInt32 CodeBytes; public UInt32 DataBytes; public UInt32 TotalBytes; public UInt32 JumpTargetCount; public UInt32 FunctionCount; //CHR ROM (NES-specific) public UInt32 DrawnChrBytes; public UInt32 TotalChrBytes; } public struct ProfiledFunction { public UInt64 ExclusiveCycles; public UInt64 InclusiveCycles; public UInt64 CallCount; public UInt64 MinCycles; public UInt64 MaxCycles; public AddressInfo Address; public StackFrameFlags Flags; public UInt64 GetAvgCycles() { return CallCount == 0 ? 0 : (InclusiveCycles / CallCount); } } public unsafe struct TraceRow { public UInt32 ProgramCounter; public CpuType Type; public fixed byte ByteCode[8]; public byte ByteCodeSize; public UInt32 LogSize; public fixed byte LogOutput[500]; public unsafe string GetOutput() { fixed(byte* output = LogOutput) { return UTF8Encoding.UTF8.GetString(output, (int)LogSize); } } public byte[] GetByteCode() { byte[] result = new byte[ByteCodeSize]; fixed(byte* ptr = ByteCode) { for(int i = 0; i < ByteCodeSize; i++) { result[i] = ptr[i]; } } return result; } public unsafe string GetByteCodeStr() { fixed(byte* output = ByteCode) { StringBuilder sb = new StringBuilder(); int i; for(i = 0; i < ByteCodeSize && i < 8; i++) { sb.Append(ByteCode[i].ToString("X2") + " "); } return sb.ToString().Trim(); } } } public struct DisassemblySearchOptions { [MarshalAs(UnmanagedType.I1)] public bool MatchCase; [MarshalAs(UnmanagedType.I1)] public bool MatchWholeWord; [MarshalAs(UnmanagedType.I1)] public bool SearchBackwards; [MarshalAs(UnmanagedType.I1)] public bool SkipFirstLine; } public struct DebugControllerState { [MarshalAs(UnmanagedType.I1)] public bool A; [MarshalAs(UnmanagedType.I1)] public bool B; [MarshalAs(UnmanagedType.I1)] public bool X; [MarshalAs(UnmanagedType.I1)] public bool Y; [MarshalAs(UnmanagedType.I1)] public bool L; [MarshalAs(UnmanagedType.I1)] public bool R; [MarshalAs(UnmanagedType.I1)] public bool U; [MarshalAs(UnmanagedType.I1)] public bool D; [MarshalAs(UnmanagedType.I1)] public bool Up; [MarshalAs(UnmanagedType.I1)] public bool Down; [MarshalAs(UnmanagedType.I1)] public bool Left; [MarshalAs(UnmanagedType.I1)] public bool Right; [MarshalAs(UnmanagedType.I1)] public bool Select; [MarshalAs(UnmanagedType.I1)] public bool Start; } }