From c714fc8927c454b5cf4735429b4cc9cde7aa5760 Mon Sep 17 00:00:00 2001 From: gbc dev Date: Fri, 17 Jul 2026 01:08:48 +0200 Subject: rebrand: gbc -> sl0pboy (binary, README, tooling) --- Makefile | 2 +- README.md | 78 ++++++++++++++++++++++++++++---------------------------- gbctl | 6 ++--- src/control.c | 2 +- src/main.c | 12 ++++----- tools/gbgif.py | 2 +- tools/gbhud.py | 2 +- tools/gbmovie.py | 2 +- tools/gbshot.py | 2 +- 9 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 74fdda6..0223819 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ SRCDIR := src BUILD := build SRCS := $(wildcard $(SRCDIR)/*.c) OBJS := $(patsubst $(SRCDIR)/%.c,$(BUILD)/%.o,$(SRCS)) -BIN := $(BUILD)/gbc +BIN := $(BUILD)/sl0pboy .PHONY: all clean run diff --git a/README.md b/README.md index cd8687c..8ce3002 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# gbc — a Game Boy Color emulator in C, rendered to the terminal +# sl0pboy — a Game Boy Color emulator in C, rendered to the terminal A from-scratch Game Boy / Game Boy Color emulator written in plain C11. It renders graphics directly to the terminal using 24-bit (truecolor) ANSI escape @@ -17,15 +17,15 @@ over 2 s (~108×). Terminal resize (`SIGWINCH`) triggers a full repaint. ```sh make -./build/gbc path/to/rom.gb # interactive (ROM is the final argument) -./build/gbc --test 30 rom.gb # run 30s, log serial to stderr (test roms) -./build/gbc --shot 60 out.ppm rom.gb # run 60 frames, dump a PPM screenshot -./build/gbc --sixel 3 rom.gb # sixel graphics output at 3x zoom -./build/gbc --sixel 3 --chrome rom.gb # ...wrapped in a Game Boy body/frame -./build/gbc --bios rom.gb # boot through the BIOS before the game -./build/gbc --sock rom.gb # open a control/debug socket (/tmp/gbc.sock) -./build/gbc --headless rom.gb # no video; serial <-> stdio (OS console) -./build/gbc --help # full option list +./build/sl0pboy path/to/rom.gb # interactive (ROM is the final argument) +./build/sl0pboy --test 30 rom.gb # run 30s, log serial to stderr (test roms) +./build/sl0pboy --shot 60 out.ppm rom.gb # run 60 frames, dump a PPM screenshot +./build/sl0pboy --sixel 3 rom.gb # sixel graphics output at 3x zoom +./build/sl0pboy --sixel 3 --chrome rom.gb # ...wrapped in a Game Boy body/frame +./build/sl0pboy --bios rom.gb # boot through the BIOS before the game +./build/sl0pboy --sock rom.gb # open a control/debug socket (/tmp/sl0pboy.sock) +./build/sl0pboy --headless rom.gb # no video; serial <-> stdio (OS console) +./build/sl0pboy --help # full option list ``` ### Boot ROM / BIOS (`--bios`) @@ -37,9 +37,9 @@ Nintendo logo drop, and on a CGB the color splash + chime) before control is handed to the game: ```sh -./build/gbc --bios roms/pky.gbc # defaults to bios/gbc_bios.bin -./build/gbc --bios path/to/boot.bin roms/pky.gbc -./build/gbc --bios --sixel 3 --chrome roms/pky.gbc # boot inside the shell +./build/sl0pboy --bios roms/pky.gbc # defaults to bios/gbc_bios.bin +./build/sl0pboy --bios path/to/boot.bin roms/pky.gbc +./build/sl0pboy --bios --sixel 3 --chrome roms/pky.gbc # boot inside the shell ``` The boot ROM is mapped over low memory (with the CGB header hole at @@ -62,10 +62,10 @@ Emulation is paced to native speed by default; add `--uncapped` to run flat out. Because it's plain stdio it pipes and scripts cleanly: ```sh -./build/gbc --headless os.gb # interactive byte console -./build/gbc --headless --uncapped os.gb # as fast as possible -printf 'ls\n' | ./build/gbc --headless os.gb # feed input, capture output -./build/gbc --headless os.gb | tee session.log +./build/sl0pboy --headless os.gb # interactive byte console +./build/sl0pboy --headless --uncapped os.gb # as fast as possible +printf 'ls\n' | ./build/sl0pboy --headless os.gb # feed input, capture output +./build/sl0pboy --headless os.gb | tee session.log ``` The serial console model matches what a GB program expects: write the byte to @@ -83,8 +83,8 @@ mlterm, Contour, recent iTerm2, etc.) pass `--sixel [scale]` to render true pixels instead of half-blocks: ```sh -./build/gbc --sixel rom.gb # default 2x zoom (320×288 pixels) -./build/gbc --sixel 4 rom.gb # 4x zoom +./build/sl0pboy --sixel rom.gb # default 2x zoom (320×288 pixels) +./build/sl0pboy --sixel 4 rom.gb # 4x zoom ``` Each frame builds a per-frame palette from the framebuffer (≤256 entries — 4 @@ -103,7 +103,7 @@ buttons, Start/Select and a speaker grille. The controls light up while the matching button is held, so it doubles as an on-screen input display: ```sh -./build/gbc --sixel 3 --chrome rom.gb +./build/sl0pboy --sixel 3 --chrome rom.gb ``` The shell is drawn with flat colors so it adds only a handful of palette @@ -118,9 +118,9 @@ palette by luminance for the classic monochrome-LCD look — this even greens out full-color CGB games for that retro vibe: ```sh -./build/gbc --sixel 3 --chrome --palette dmg rom.gb # classic DMG-01 pea green -./build/gbc --sixel 3 --green rom.gb # alias for --palette dmg -./build/gbc --palette gray rom.gb # GB-Pocket grayscale +./build/sl0pboy --sixel 3 --chrome --palette dmg rom.gb # classic DMG-01 pea green +./build/sl0pboy --sixel 3 --green rom.gb # alias for --palette dmg +./build/sl0pboy --palette gray rom.gb # GB-Pocket grayscale ``` Names: `dmg`/`green` (the iconic `#9bbc0f` pea-green ramp) and `pocket`/`gray` @@ -136,9 +136,9 @@ frame skipping — the machine keeps running in real time while the terminal is refreshed less often: ```sh -./build/gbc --frameskip 2 rom.gb # emulate 60 fps, draw every 3rd frame (20 fps) -./build/gbc --fps 120 rom.gb # run the game at 2x speed -./build/gbc --uncapped rom.gb # run as fast as possible (turbo) +./build/sl0pboy --frameskip 2 rom.gb # emulate 60 fps, draw every 3rd frame (20 fps) +./build/sl0pboy --fps 120 rom.gb # run the game at 2x speed +./build/sl0pboy --uncapped rom.gb # run as fast as possible (turbo) ``` | Flag | Meaning | @@ -169,20 +169,20 @@ after each keypress (relying on the terminal's key-repeat for sustained holds). ### External control channel (FIFO) -Start with `--fifo [path]` (default `/tmp/gbc.fifo`) to open a named pipe that +Start with `--fifo [path]` (default `/tmp/sl0pboy.fifo`) to open a named pipe that accepts button commands from any process. Unlike the terminal keyboard, this can send true key-**release** events, so it gives deterministic input for scripting and automated testing. ```sh -./build/gbc --fifo /tmp/gbc.fifo rom.gb & -echo 'a' > /tmp/gbc.fifo # momentary tap of A -echo 'start' > /tmp/gbc.fifo # tap Start -echo '+left' > /tmp/gbc.fifo # press and HOLD Left -echo 'a b' > /tmp/gbc.fifo # tap A and B together (Left still held) -echo '-left' > /tmp/gbc.fifo # release Left -echo 'release' > /tmp/gbc.fifo # release everything held -echo 'a:30' > /tmp/gbc.fifo # tap A, held for 30 frames +./build/sl0pboy --fifo /tmp/sl0pboy.fifo rom.gb & +echo 'a' > /tmp/sl0pboy.fifo # momentary tap of A +echo 'start' > /tmp/sl0pboy.fifo # tap Start +echo '+left' > /tmp/sl0pboy.fifo # press and HOLD Left +echo 'a b' > /tmp/sl0pboy.fifo # tap A and B together (Left still held) +echo '-left' > /tmp/sl0pboy.fifo # release Left +echo 'release' > /tmp/sl0pboy.fifo # release everything held +echo 'a:30' > /tmp/sl0pboy.fifo # tap A, held for 30 frames ``` Commands (one line, space/comma separated tokens, case-insensitive): @@ -202,16 +202,16 @@ use the socket control channel below, which is a strict superset. ### Socket control & debug channel -Start with `--sock [path]` (default `/tmp/gbc.sock`) to open a Unix-domain +Start with `--sock [path]` (default `/tmp/sl0pboy.sock`) to open a Unix-domain stream socket. It accepts everything the FIFO does **plus** emulator introspection commands, and — being a socket — it *replies* to each command and pushes asynchronous events when execution stops. Connect any line-oriented client: ```sh -./build/gbc --sock /tmp/gbc.sock rom.gb & -socat - UNIX-CONNECT:/tmp/gbc.sock # interactive -# or: nc -U /tmp/gbc.sock +./build/sl0pboy --sock /tmp/sl0pboy.sock rom.gb & +socat - UNIX-CONNECT:/tmp/sl0pboy.sock # interactive +# or: nc -U /tmp/sl0pboy.sock ``` The protocol is line based (one command per line). Replies start with `ok` or diff --git a/gbctl b/gbctl index b926461..ce8ba15 100755 --- a/gbctl +++ b/gbctl @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""gbctl — drive the gbc emulator's socket control/debug channel from the CLI. +"""gbctl — drive the sl0pboy emulator's socket control/debug channel from the CLI. Model mirrors gdb-driver: spawn a tmux pane running the emulator with a control socket, then drive it with terse verbs, then stop. Socket auto-resolves to the @@ -25,7 +25,7 @@ single live instance (else pass --sock / set GBCTL_SOCK). import json, os, re, socket, subprocess, sys, time, glob HERE = os.path.dirname(os.path.abspath(__file__)) -BIN = os.path.join(HERE, "build", "gbc") +BIN = os.path.join(HERE, "build", "sl0pboy") REGDIR = os.path.join(os.environ.get("XDG_RUNTIME_DIR", "/tmp"), "gbctl") # --------------------------------------------------------------------------- @@ -202,7 +202,7 @@ def cmd_spawn(argv): cmd = [BIN, "--sock", sock_path] + emu_args + [rom] # ROM is the final arg # exec via a shell wrapper so the pane stays around & shows a title - shell_cmd = "printf '\\033]2;gbc %s\\007'; exec %s" % ( + shell_cmd = "printf '\\033]2;sl0pboy %s\\007'; exec %s" % ( os.path.basename(rom), " ".join(_shquote(c) for c in cmd)) if split == "window": r = subprocess.run(["tmux", "new-window", "-P", "-F", "#{pane_id}", diff --git a/src/control.c b/src/control.c index 16e769a..04c8932 100644 --- a/src/control.c +++ b/src/control.c @@ -596,7 +596,7 @@ static void accept_new(void) { if (slot < 0) { close(cf); continue; } // table full clients[slot].fd = cf; clients[slot].len = 0; - reply(cf, "ok gbc control channel; 'help' for commands"); + reply(cf, "ok sl0pboy control channel; 'help' for commands"); } } diff --git a/src/main.c b/src/main.c index 1f3a868..5191218 100644 --- a/src/main.c +++ b/src/main.c @@ -66,8 +66,8 @@ static void print_usage(FILE *out, const char *prog) { " --bios [path] run a boot ROM first (default bios/gbc_bios.bin)\n" "\n" "control channels:\n" -" --fifo [path] button-input named pipe (default /tmp/gbc.fifo)\n" -" --sock [path] control/debug socket (default /tmp/gbc.sock)\n" +" --fifo [path] button-input named pipe (default /tmp/sl0pboy.fifo)\n" +" --sock [path] control/debug socket (default /tmp/sl0pboy.sock)\n" "\n" "headless & testing:\n" " --headless no video; wire serial <-> stdio (OS console)\n" @@ -131,9 +131,9 @@ int main(int argc, char **argv) { if (!has_val) { fprintf(stderr, "%s: --keys needs a value\n", prog); return 1; } keys = argv[++i]; } else if (!strcmp(a, "--fifo")) { - fifo_path = has_val ? argv[++i] : "/tmp/gbc.fifo"; + fifo_path = has_val ? argv[++i] : "/tmp/sl0pboy.fifo"; } else if (!strcmp(a, "--sock") || !strcmp(a, "--socket")) { - sock_path = has_val ? argv[++i] : "/tmp/gbc.sock"; + sock_path = has_val ? argv[++i] : "/tmp/sl0pboy.sock"; } else if (!strcmp(a, "--fps")) { if (!has_val) { fprintf(stderr, "%s: --fps needs a value\n", prog); return 1; } target_fps = atof(argv[++i]); @@ -191,7 +191,7 @@ int main(int argc, char **argv) { // Headless: no rendering, no terminal UI. Tie the serial port to stdio so // an OS on the GB gets a plain byte console (TX -> stdout, RX <- stdin). // Paced to native speed unless --uncapped. Piping works for scripted tests: - // printf 'ls\n' | gbc rom.gb --headless + // printf 'ls\n' | sl0pboy rom.gb --headless if (headless) { gb->serial_out_fd = STDOUT_FILENO; gb->serial_in_fd = STDIN_FILENO; @@ -214,7 +214,7 @@ int main(int argc, char **argv) { t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; tcsetattr(STDIN_FILENO, TCSANOW, &t); - fprintf(stderr, "[gbc: interactive serial console - Ctrl-C to quit]\n"); + fprintf(stderr, "[sl0pboy: interactive serial console - Ctrl-C to quit]\n"); } bool uncapped = (target_fps <= 0); double start_t = now_sec(); diff --git a/tools/gbgif.py b/tools/gbgif.py index c7c8943..f02c1f6 100644 --- a/tools/gbgif.py +++ b/tools/gbgif.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Turn a gbc `.gbv` frame capture into an animated GIF. +"""Turn a sl0pboy `.gbv` frame capture into an animated GIF. Capture one with the emulator's control socket: ./gbctl record start /abs/path/out.gbv 2 # 2 = capture every 2nd frame (~30fps) diff --git a/tools/gbhud.py b/tools/gbhud.py index 84e6b82..aaa91bc 100755 --- a/tools/gbhud.py +++ b/tools/gbhud.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""gbhud.py [--sock PATH] [--sym PATH] — live debug HUD for the gbc emulator +"""gbhud.py [--sock PATH] [--sym PATH] — live debug HUD for the sl0pboy emulator running Pokemon Yellow. Reads WRAM over the control socket, resolves symbols from pokeyellow.sym, parses game state, and pretty-prints it, refreshing ~5Hz. diff --git a/tools/gbmovie.py b/tools/gbmovie.py index dc92989..56ee7c1 100644 --- a/tools/gbmovie.py +++ b/tools/gbmovie.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Build TAS-style input movies for the gbc emulator's `input play` replayer. +"""Build TAS-style input movies for the sl0pboy emulator's `input play` replayer. A movie is a text file of ` [buttons...]` lines: hold the given buttons (a b start select up down left right; none/'-' = released) for that many frames. diff --git a/tools/gbshot.py b/tools/gbshot.py index 95a45f1..8604c39 100644 --- a/tools/gbshot.py +++ b/tools/gbshot.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """gbshot.py — reconstruct the current GB screen from VRAM (BG + window + sprites, both CGB banks) and save a 24-bit BMP. Grayscale from -the 2bpp tile values (enough to read menus/sprites). Uses the gbc control socket.""" +the 2bpp tile values (enough to read menus/sprites). Uses the sl0pboy control socket.""" import socket, sys, struct def main(): -- cgit v1.3.1-sl0p