| Commit message (Collapse) | Author | Files | Lines |
|
Decimates the LCD N x N before the half-block encode so the monitor pane
takes 160/N cols x 72/N rows. Display-only: capture, recording and sixel
still read the full-res framebuffer.
Decimation is max-luma pick, not box-average: terminal fonts are 1px
bright strokes on dark background, and averaging dims them into grey
mush (the 'blurry font' regression). Keeping the brightest source pixel
of each block preserves stroke brightness and hue.
|
|
The control socket was only opened on the windowed path, so a --headless
GB couldn't be inspected. A scriptable, invisible GB is exactly the one
you most want to peek into - reading kernel WRAM over the debug socket is
how the TCP field-offset corruption got pinned down. Open it in the
headless loop too and poll it each frame; close it on exit.
|
|
The clean-exit opcode used to print nothing, so any guest crash that
walked into a stray $ED byte was indistinguishable from a silent
socket death (one of the kill vectors in the link-drop investigation).
Now it identifies itself on stderr with pc/af/bc/de/hl/sp.
|
|
Root-cause work for the 'idle link-socket drop' (see gbos
docs/link-drop-investigation.md): when the hub restarts or the bridge
dies, the link fd went dead forever - and before SIGPIPE was ignored,
the next console-echo write() would kill the whole emulator silently.
Now, in --serial-sock mode, EOF on read or EPIPE/ECONNRESET/ENOTCONN/
EBADF on either direction marks the link dead, closes the fd, and
retries connect() every 500ms from the serial poll path (the guest
polls constantly, so no extra plumbing). RX stays pending while down
(serial_no_eof semantics), so the guest just sees a quiet link that
comes back. Logs 'link socket lost / reconnected' either way.
Verified: SIGKILL the hub, restart it - every GB reconnects within ~1s
and keeps its lease.
|
|
Runtime chatter (link reconnect notices, input debug, cart warnings) was
landing mid-sixel-stream and corrupting the picture. Redirect fd 2 to
/dev/null for the duration of the display loop; restored on exit so the
final stats line still prints. Startup errors before the display begins
are unaffected.
|
|
The serial fds are serviced by cpu_step in every mode, so wiring them to a
connected unix socket lets networking run alongside a live display (--sixel /
terminal) - unlike --headless, which needs stdio for the serial. The emulator
connects to PATH (retrying ~1s so a launcher can listen first) and uses it
non-blocking with no EOF-exit; it overrides the headless stdio serial.
Pairs with gbos tools/netboot, which listens on PATH, brings up a TUN+NAT, and
bridges the socket <-> TUN. In windowed mode the OSK is the console and the
link port is pure network - cleanly separated. Verified: host pings the GB 3/3
over the socket link.
|
|
|
|
- Rewrite argument handling: the ROM is now the final argument and options
precede it (parsed in argv[1..argc-2] so optional-value flags never swallow
the ROM). Add grouped --help/-h, unknown-option errors, and clear 'missing
value'/'no ROM' diagnostics.
- Add --chrome, --palette/--green, and --bios flags; set the display/capture
options before the --shot and recording paths so screenshots and recordings
honor them. Make --shot dump the composited capture frame.
- gbctl: pass the ROM last when spawning the emulator.
- gitignore the (copyrighted) bios/ directory; document all new flags.
|
|
The video recorder now writes render_capture_frame() instead of the raw
LCD framebuffer, so captures match what's shown: chrome frames record at
their larger dimensions (written into the .gbv header) and the LCD palette
is baked in. Button presses also show up lit in recordings.
|
|
- --chrome: draw a DMG-style 'sl0pboy' shell around the LCD in sixel mode,
with a bitmap-font silk-screen (logo, labels), speaker grille, power LED,
and buttons that light up while held.
- LCD palette recolor (render_set_palette): remap the LCD to a 4-shade
palette by luminance for the classic monochrome look ('dmg'/'green' pea
green, 'pocket'/'gray'); applies to every render path.
- Refactor the sixel encoder into generic build_palette_buf/encode_sixel_buf
operating on any RGB888 buffer, shared by the bare LCD and the chrome canvas.
- render_capture_size/frame: produce the exact displayed frame (recolor +
chrome) as an RGB buffer, for screenshots and video recording.
|
|
Add optional boot ROM emulation. When a boot ROM image is loaded, gb_reset
starts execution at PC=0 with power-on register state instead of the
documented post-boot state; the ROM overlays low memory (with the CGB
0x0100-0x01FF header hole showing the cartridge through) until the game
writes 0xFF50 to hand off. gb_load_bootrom() accepts 256-byte (DMG) or
2304-byte (CGB) images.
|
|
--keys "udlrabse." plays scripted joypad taps (each char = one button
held 10 frames then released 10, so the guest sees a clean edge); pairs
with --headless --shot to drive on-screen input and capture the result.
When --keys is active, serial-RX EOF stays pending instead of sending
$04, so a shell blocked on read waits for OSK input instead of exiting.
|
|
Lets scripted runs feed stdin to the serial console AND capture the
resulting screen, e.g. printf 'ls\nexit\n' | gbc rom.gb --headless --shot 0 out.ppm
Previously --shot ran frames with no stdin, so anything waiting on input
(a shell) only showed its first prompt.
|
|
The unused SM83 opcode $ED now sets gb->poweroff, which breaks the headless
loop so the normal cart_free()->cart_save() path runs. Lets a guest OS shut the
emulator down cleanly (and flush its .sav) instead of relying on an external
timeout/SIGTERM, which could SIGKILL before the save. run_frame() also stops on
poweroff so exit is immediate.
|
|
When stdin is a terminal, --headless now disables canonical mode + local echo
so keystrokes reach the guest immediately and only the guest echoes (no doubled
chars). Piped/redirected stdin is untouched (scripted input still works). Keep
ISIG so Ctrl-C quits; restore termios on exit. VMIN=1 so a no-data non-blocking
read is EAGAIN, not a 0-byte read the serial layer would misread as EOF.
|
|
read()==0 completes the external-clock transfer with SB=0x04 (EOT), so a gbos
program's readc() sees EOF instead of polling forever. Enables cat/wc-style
tools and lets the shell exit on Ctrl-D / pipe end.
|
|
- external-clock transfers (SC=$80) deliver a stdin byte into SB without
echoing to stdout, and stay pending when no input is available -> programs
can poll for input cleanly. internal-clock (SC=$81) stays pure TX.
|
|
- --headless: no rendering/TUI; serial TX -> stdout, RX <- stdin (nonblocking)
- generalize serial: serial_out_fd/serial_in_fd on the GB; internal-clock
transfer now shifts in a real RX byte (from stdin) instead of always 0xFF
- paced to native speed by default, --uncapped for turbo; pipes/scripts cleanly
- README: document headless serial console
|
|
Two socket features for building reproducible showcase clips:
- record start <path> [everyN] / record stop: append the RGB888 framebuffer of
each produced frame to a flat 'GBCV' capture file (downsample with everyN).
tools/gbgif.py turns it into a GIF (or PNG frames). Capture is decoupled from
wall-clock/turbo/frameskip, so timing is always correct.
- input play <path> [reset] / input stop: drive the joypad from a synthesized
TAS-style movie (text: '<frames> [buttons...]' per line), frame-locked so
replay is deterministic. 'reset' does an exact power-on (preserve cart
ROM+SRAM, zero all other state) so a movie replays byte-identically -- verified
by hashing two runs. tools/gbmovie.py is a Python builder for movies.
|
|
In --sixel mode the emulator drew a status line (title/skip/[f]ast/q:quit) under
the image; drop it so sixel output is nothing but the game graphics.
|
|
A client that connects and closes before reading (e.g. the HUD's liveness
probe) made the greeting write() raise SIGPIPE, terminating the whole emulator
- this was behind much of the 'it keeps dying' this session. Also: gbhud now
re-resolves the live instance from the registry on every reconnect (skipping
stale sockets by test-connecting), so the HUD follows respawns, and its box
rendering is ANSI-width-correct.
|
|
The APU was a black hole: reads returned 0xFF, writes were dropped. That hangs
any game that fades music out by decrementing the NR50/rAUDVOL volume register
until it reads 0 (Pokemon's StopMusic spin-wait) - the write never stuck, the
read never hit 0, infinite loop. Store the 48 sound registers and return them
with the standard hardware read-back OR-masks (NR50 mask 0x00 = exact readback).
No synthesis, just correct register behavior.
|
|
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.
|
|
Emulation always runs at native rate (correct game speed); --frameskip N draws
only 1 of every N+1 frames so a slow terminal no longer bottlenecks the loop.
Adds --fps cap, --uncapped/--turbo, live [ ] and f keys, HUD readout, and an
exit summary of emulated-vs-drawn fps. Replaces the confusing --render-fps.
|
|
Adds --fifo [path] opening a named pipe that accepts button commands from any
process. Supports momentary taps (a, start, name:N), deterministic hold/release
(+name / -name), and 'release'. Merges with keyboard input; held state carries
true key-up semantics the terminal can't provide. GBC_INPUT_DEBUG traces state.
|
|
Only cells that changed since the previous frame are redrawn, using cursor
positioning to skip unchanged runs. Static screens write nothing after the
first frame (~108x reduction on acid2). SIGWINCH forces a full repaint.
Verified pixel-exact against the framebuffer (11520/11520 cells, 0 mismatch).
|
|
|
|
|
|
Passes blargg cpu_instrs (all 11), instr_timing, mem_timing.
|