diff options
| author | gbc dev <gbc@localhost> | 2026-07-14 23:26:49 +0200 |
|---|---|---|
| committer | gbc dev <gbc@localhost> | 2026-07-14 23:26:49 +0200 |
| commit | c879adc43b91a53eb7e76f232a39abb56d8144c1 (patch) | |
| tree | 3bd8cd77fed46ceb62504d2fb067f349bad2cf0e /src/main.c | |
| parent | speed control: frame skipping to decouple terminal draw from emulation (diff) | |
| download | sl0pboy-c879adc43b91a53eb7e76f232a39abb56d8144c1.tar.gz sl0pboy-c879adc43b91a53eb7e76f232a39abb56d8144c1.tar.xz sl0pboy-c879adc43b91a53eb7e76f232a39abb56d8144c1.zip | |
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.
Diffstat (limited to 'src/main.c')
| -rw-r--r-- | src/main.c | 29 |
1 files changed, 27 insertions, 2 deletions
@@ -1,6 +1,7 @@ #include "gb.h" #include "cpu.h" #include "render.h" +#include "control.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -26,7 +27,10 @@ static void run_frame(GB *gb) { int main(int argc, char **argv) { if (argc < 2) { - fprintf(stderr, "usage: %s <rom> [--test seconds]\n", argv[0]); + fprintf(stderr, "usage: %s <rom> [--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) " |
