OXYGENHUB
◆ rrdc-perf enhanced-x16-emulator / tools / x16dbg / Program.cs
7.8 KiB · C# · last changed chore(): initial commit 25 days ago source blame history raw
1
using System;
2
using System.Threading.Tasks;
3
4
namespace X16Debug;
5
6
class Program
7
{
8
    const string DefaultHost = "127.0.0.1";
9
    const int DefaultPort = 9009;
10
11
    static async Task<int> Main(string[] args)
12
    {
13
        string host = DefaultHost;
14
        int port = DefaultPort;
15
        bool interactive = false;
16
        string? command = null;
17
        string[] commandArgs = Array.Empty<string>();
18
19
        // Parse args
20
        int i = 0;
21
        while (i < args.Length)
22
        {
23
            switch (args[i])
24
            {
25
                case "-host":
26
                    if (i + 1 >= args.Length) { PrintUsage(); return 1; }
27
                    host = args[++i];
28
                    break;
29
                case "-port":
30
                    if (i + 1 >= args.Length) { PrintUsage(); return 1; }
31
                    port = int.Parse(args[++i]);
32
                    break;
33
                case "-i":
34
                case "--interactive":
35
                    interactive = true;
36
                    break;
37
                case "-h":
38
                case "--help":
39
                    PrintUsage();
40
                    return 0;
41
                default:
42
                    // First non-flag arg is the command, rest are command args
43
                    command = args[i];
44
                    if (i + 1 < args.Length)
45
                        commandArgs = args[(i + 1)..];
46
                    i = args.Length; // stop parsing
47
                    continue;
48
            }
49
            i++;
50
        }
51
52
        // If no command and not explicitly interactive, default to interactive
53
        if (command == null && !interactive)
54
            interactive = true;
55
56
        using var client = new X16DebugClient();
57
58
        try
59
        {
60
            Console.Write($"Connecting to {host}:{port}...");
61
            await client.ConnectAsync(host, port);
62
            Console.WriteLine(" OK");
63
        }
64
        catch (Exception ex)
65
        {
66
            Console.Error.WriteLine($" Failed: {ex.Message}");
67
            Console.Error.WriteLine($"Make sure x16emu is running with -debugport {port}");
68
            return 1;
69
        }
70
71
        // Perform DAP initialization handshake
72
        try
73
        {
74
            Console.Write("DAP handshake...");
75
            await client.InitializeAsync();
76
            Console.WriteLine(" OK");
77
        }
78
        catch (Exception ex)
79
        {
80
            Console.Error.WriteLine($" Failed: {ex.Message}");
81
            Console.Error.WriteLine("DAP initialization failed. Is the emulator running a DAP debug server?");
82
            return 1;
83
        }
84
85
        if (interactive)
86
        {
87
            await InteractiveMode.RunAsync(client);
88
            await TryDisconnect(client);
89
            return 0;
90
        }
91
        else
92
        {
93
            int rc = await Commands.RunOneShotAsync(client, command!, commandArgs);
94
            await TryDisconnect(client);
95
            return rc;
96
        }
97
    }
98
99
    // Leave the way a DAP client is supposed to, rather than dropping the socket
100
    // and making the server infer it. terminateDebuggee stays false so quitting
101
    // the debugger never takes the emulator with it.
102
    static async Task TryDisconnect(X16DebugClient client)
103
    {
104
        try { await client.DisconnectAsync(false); }
105
        catch { /* the server may already be gone; nothing useful to do */ }
106
    }
107
108
    static void PrintUsage()
109
    {
110
        Console.WriteLine("x16dbg - Commander X16 Emulator Debug Client (DAP)");
111
        Console.WriteLine();
112
        Console.WriteLine("Usage:");
113
        Console.WriteLine("  x16dbg [options]                  Interactive mode");
114
        Console.WriteLine("  x16dbg [options] <command> [args] One-shot command mode");
115
        Console.WriteLine();
116
        Console.WriteLine("Options:");
117
        Console.WriteLine("  -host <ip>      Host to connect to (default: 127.0.0.1)");
118
        Console.WriteLine("  -port <port>    Port to connect to (default: 9009)");
119
        Console.WriteLine("  -i              Force interactive mode");
120
        Console.WriteLine("  -h, --help      Show this help");
121
        Console.WriteLine();
122
        Console.WriteLine("Commands:");
123
        Console.WriteLine("  step                    Step one instruction");
124
        Console.WriteLine("  continue                Continue execution");
125
        Console.WriteLine("  break                   Pause execution");
126
        Console.WriteLine("  status                  Show emulator status");
127
        Console.WriteLine("  reset                   Reset CPU");
128
        Console.WriteLine("  regs                    Show all registers");
129
        Console.WriteLine("  setreg <reg> <val>      Set a register (e.g., setreg a FF)");
130
        Console.WriteLine("  mem <addr>-<end>        Read memory range (e.g., mem 1030-1040)");
131
        Console.WriteLine("  mem <addr> <len>        Read memory by length (e.g., mem 0800 10)");
132
        Console.WriteLine("  setmem <addr> <hex>     Write memory (e.g., setmem 0400 DEADBEEF)");
133
        Console.WriteLine("  vram <addr>-<end>       Read VERA video RAM (17-bit space)");
134
        Console.WriteLine("  vram <addr> <len>       Read VRAM by length (e.g., vram 1B000 20)");
135
        Console.WriteLine("  setvram <addr> <hex>    Write VRAM (e.g., setvram 1B000 DEADBEEF)");
136
        Console.WriteLine("  joy <port> [buttons]    Drive a SNES controller port (1-4)");
137
        Console.WriteLine("  bp add <addr>           Add breakpoint");
138
        Console.WriteLine("  bp remove <addr>        Remove breakpoint");
139
        Console.WriteLine("  bp list                 List all breakpoints");
140
        Console.WriteLine("  bp clear                Clear all breakpoints");
141
        Console.WriteLine();
142
        Console.WriteLine("Examples:");
143
        Console.WriteLine("  x16dbg                          Start interactive session");
144
        Console.WriteLine("  x16dbg step                     Step one instruction");
145
        Console.WriteLine("  x16dbg mem 1030-1040            Dump memory $1030-$1040");
146
        Console.WriteLine("  x16dbg bp add 080D              Set breakpoint at $080D");
147
        Console.WriteLine("  x16dbg -port 9010 status        Connect to port 9010");
148
        Console.WriteLine();
149
        Console.WriteLine("  VRAM -- VERA's video RAM, which is not in the CPU map. The CPU only");
150
        Console.WriteLine("  reaches it through the data port, so these are the only way to see it:");
151
        Console.WriteLine("  x16dbg vram 1B000 20            Dump 32 bytes of the text screen");
152
        Console.WriteLine("  x16dbg vram 0-FF                Dump the first 256 bytes of VRAM");
153
        Console.WriteLine("  x16dbg setvram 1F9C0 DEADBEEF   Poke 4 bytes into sprite attributes");
154
        Console.WriteLine();
155
        Console.WriteLine("  Joysticks -- a virtual SNES pad, no gamepad and no -joy1..-joy4 needed.");
156
        Console.WriteLine("  The button list is the whole held state, so anything left off is released:");
157
        Console.WriteLine("  x16dbg joy 1                    Show what port 1 is reporting");
158
        Console.WriteLine("  x16dbg joy 1 right a            Hold Right and A on port 1");
159
        Console.WriteLine("  x16dbg joy 1 start              Now hold only Start; Right and A let go");
160
        Console.WriteLine("  x16dbg joy 1 none               Connected, nothing held (JOY(1) = $00)");
161
        Console.WriteLine("  x16dbg joy 1 release            Empty the port again (JOY(1) = $FF)");
162
        Console.WriteLine();
163
        Console.WriteLine("Note: each one-shot command is its own debug session, and the emulator");
164
        Console.WriteLine("resumes when a session that paused it goes away. Commands that only look at");
165
        Console.WriteLine("the machine are fine that way, but anything depending on staying stopped --");
166
        Console.WriteLine("break, setreg, stepping -- belongs in interactive mode, where one session");
167
        Console.WriteLine("stays open. Memory, VRAM and joystick state persist either way.");
168
    }
169
}