| 9120e874 Andy McCall |
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 |
|
| 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 |
|
| 43 |
command = args[i]; |
| 44 |
if (i + 1 < args.Length) |
| 45 |
commandArgs = args[(i + 1)..]; |
| 46 |
i = args.Length; |
| 47 |
continue; |
| 48 |
} |
| 49 |
i++; |
| 50 |
} |
| 51 |
|
| 52 |
|
| 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 |
|
| 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 |
|
| 100 |
|
| 101 |
|
| 102 |
static async Task TryDisconnect(X16DebugClient client) |
| 103 |
{ |
| 104 |
try { await client.DisconnectAsync(false); } |
| 105 |
catch { } |
| 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 |
} |