From c879adc43b91a53eb7e76f232a39abb56d8144c1 Mon Sep 17 00:00:00 2001 From: gbc dev Date: Tue, 14 Jul 2026 23:26:49 +0200 Subject: control: socket-based debug channel + gbctl CLI driver Replace the input-only FIFO's limitations with a Unix-domain socket control channel (--sock) that is a superset of the button vocabulary plus emulator introspection: read/write bus memory, get/set CPU context, single-step, PC breakpoints, value-change watchpoints, run/pause. Being a socket it replies to each command and broadcasts async 'event stop ...' lines; a stored last-stop record (stopinfo) lets per-request clients recover a missed event. Add gbctl: a stdlib-python CLI that spawns a tmux pane running the emulator on a ROM, auto-resolves the socket, and drives it with terse verbs (cpu/read/write/ reg/step/break/watch/continue/pause/press/hold/screen/stop). The FIFO stays as legacy input-only. --- src/main.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index 5ce4fb5..541ce44 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,7 @@ #include "gb.h" #include "cpu.h" #include "render.h" +#include "control.h" #include #include #include @@ -26,7 +27,10 @@ static void run_frame(GB *gb) { int main(int argc, char **argv) { if (argc < 2) { - fprintf(stderr, "usage: %s [--test seconds]\n", argv[0]); + fprintf(stderr, "usage: %s [--test seconds] [--sixel [scale]] " + "[--frameskip n] [--fps n] [--uncapped] [--fifo [path]] " + "[--sock [path]]\n", + argv[0]); return 1; } const char *rom = argv[1]; @@ -35,8 +39,11 @@ int main(int argc, char **argv) { int shot_frames = -1; const char *shot_path = "shot.ppm"; const char *fifo_path = NULL; + const char *sock_path = NULL; double target_fps = 59.73; // emulation speed cap; 0 = uncapped int frameskip = 0; // draw 1 of every (frameskip+1) frames + bool sixel = false; // use sixel graphics output + int sixel_scale = 2; // integer pixel zoom for sixel for (int i = 2; i < argc; i++) { if (!strcmp(argv[i], "--test")) { test = true; @@ -47,10 +54,16 @@ int main(int argc, char **argv) { } else if (!strcmp(argv[i], "--fifo")) { fifo_path = (i + 1 < argc && argv[i+1][0] != '-') ? argv[++i] : "/tmp/gbc.fifo"; + } else if (!strcmp(argv[i], "--sock") || !strcmp(argv[i], "--socket")) { + sock_path = (i + 1 < argc && argv[i+1][0] != '-') + ? argv[++i] : "/tmp/gbc.sock"; } else if (!strcmp(argv[i], "--fps")) { if (i + 1 < argc) target_fps = atof(argv[++i]); } else if (!strcmp(argv[i], "--frameskip")) { if (i + 1 < argc) frameskip = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--sixel")) { + sixel = true; + if (i + 1 < argc && argv[i+1][0] != '-') sixel_scale = atoi(argv[++i]); } else if (!strcmp(argv[i], "--uncapped") || !strcmp(argv[i], "--turbo")) { target_fps = 0; } @@ -90,6 +103,14 @@ int main(int argc, char **argv) { fprintf(stderr, "control fifo: echo 'a' > %s (a b start select " "up down left right; +x/-x hold/release; release)\n", fifo_path); } + if (sock_path) { + control_open(sock_path); + if (control_active()) + fprintf(stderr, "control socket: %s (buttons + debug: cpu read " + "write step break watch continue pause; 'help')\n", + sock_path); + } + if (sixel) render_set_sixel(true, sixel_scale); term_init(); // The emulator always advances every GB frame at the paced native rate so @@ -107,13 +128,16 @@ int main(int argc, char **argv) { while (running) { frames++; if (!input_poll(gb)) break; + if (!control_poll(gb)) break; // socket may inject input / debug cmds if (input_take_turbo()) turbo = !turbo; frameskip += input_take_frameskip_delta(); if (frameskip < 0) frameskip = 0; if (frameskip > 30) frameskip = 30; render_set_hud(frameskip, turbo); - run_frame(gb); // always emulate a full frame + // Emulate a full frame, honoring debugger pause/step/breakpoints when + // the control socket is active (otherwise a plain full frame). + control_run_frame(gb); // decide whether to draw this frame bool do_render = (since_render >= frameskip); @@ -148,6 +172,7 @@ int main(int argc, char **argv) { term_restore(); input_close_fifo(); + control_close(); double elapsed = now_sec() - start_time; if (elapsed > 0) fprintf(stderr, "emulated %llu frames (%.1f fps), drew %llu (%.1f fps) " -- cgit v1.3.1-sl0p