aboutsummaryrefslogtreecommitdiffstats
path: root/tools (follow)
Commit message (Collapse)AuthorAgeFilesLines
* tools: gbdemo - scripted, screen-synced demo driver (+ the README demo)user3 days1-0/+309
| | | | | | | | | | | | | Runs a step file: spawns a GB on the gbhub network, records the LCD to a .gbv over the emulator control socket, injects console text (hub ctl, like gbtype) and button events (gbctl) at the right moments, then renders a GIF (gbgif.py). Sync is waitfor/waitgone on the terminal's WRAM shadow (TERM_BUF $D600 + wAssign row map) read via the emulator's debug socket - steps key off real screen output, so boot/DHCP/IRC timing can vary without breaking the choreography. demo/readme.gbd is the README GIF: cold boot -> uname -> ping -> IRC session on 10.0.0.1.
* term: 7-color terminal (per-glyph fg+bg) + ANSI escapes; colorize ircuser3 days1-0/+113
| | | | | | | | | | | | | Fano-plane palette scheme: the 7 colors map onto 7 CGB BG palettes so any color pair shares one palette; a tile's palette is picked from the set of colors its two cells need (tables generated by tools/gencolor.py). Per cell a packed (bg<<4)|fg byte lives alongside the char shadow, and the glyph blitter steers glyph/empty pixels to each cell's fg/bg color slots via plane masks. An ANSI-ish CSI parser (ESC [ .. m) drives it; usr/ansi.c demos it and the irc client now renders hashed nick colors, status dimming and a channel-activity bar.
* tools: gbtype prints hub errors to stderr and exits 1user4 days1-1/+5
|
* gbhub: control socket + gbtype to inject shell input without the OSKuser4 days2-3/+153
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Typing into a Game Boy meant driving the on-screen keyboard by hand. But the link port already *is* the shell's console: bytes the hub sends un-SLIP-framed land straight on stdin (that's what GB.type() has always done for spawn-mode command scripting). This just exposes it. gbhub now serves a control socket (/tmp/gbhub.ctl, world-connectable like the join socket) accepting two commands: 'list' and 'type [idx]' followed by a payload (delimited by the client's half-close). Injection is chunked and paced to respect the 64-byte kernel console ring, so arbitrarily long input - even multi-line scripts - reaches the shell without overflow. The server runs in both daemon and spawn modes. tools/gbtype is the client: tools/gbtype 'ls -l' run a command on GB0 (Enter appended) tools/gbtype -g 1 ps target the Nth joined Game Boy tools/gbtype -n abc no trailing Enter tools/gbtype -r just press Enter tools/gbtype -l list connected Game Boys printf 'ls\nuname\n' | tools/gbtype pipe a script via stdin Options precede the command; the first non-option word starts literal text, so 'gbtype ls -l' needs no quoting. No root required. Verified end to end: injected list/uname/echo through the real CTL protocol and saw the shell execute each and echo output back.
* gbhub: make GB drops attributable, not spookyuser4 days1-5/+15
| | | | | | | | | | | | Link-drop investigation fallout - every drop looked identical because the hub discarded all the evidence: - gb_reader logs *how* a GB left (clean eof vs the exception) with timestamps on join/leave, for correlating against SSH/terminal events. - Spawn mode keeps each emulator's stderr in /tmp/gbhub_<n>.err instead of devnull - postmortems get the emulator's side of the story. - A second gbhub exits with a clear 'already running?' message instead of an ioctl traceback (and can't damage the live hub's NAT/socket).
* tools: gbhub --daemon + gbjoin - interactive multi-Game-Boy networkinguser4 days2-20/+87
| | | | | | | | | | | | | | | | | | | gbhub gains a --daemon mode: instead of spawning headless emulators, it just runs the switch/router/DHCP and accepts link connections, handing each a lease from a pool (10.0.0.2..) and freeing it on disconnect. The link socket is made world-connectable so unprivileged emulators can join. gbjoin (no root) launches a *windowed* Game Boy and plugs its link into the running hub, with its own ROM copy so battery saves don't clash. So you get real interactive Game Boys on one network: term 1: sudo tools/gbhub --daemon term 2: tools/gbjoin # windowed GB -> 10.0.0.2 term 3: tools/gbjoin # windowed GB -> 10.0.0.3 (on each: SELECT for the OSK, then e.g. ping 10.0.0.3) Verified two GBs join the daemon and get distinct leases; routing is the same code path as the (already-verified) spawn-mode GB<->GB ping.
* tools: gbhub - many Game Boys on one network (DHCP pool + inter-GB routing)user4 days1-0/+166
| | | | | | | | | | | | | | | | | A virtual switch/router/DHCP for N emulators. It leases each Game Boy a distinct address (10.0.0.2, 10.0.0.3, ...), routes packets between them by destination IP, floods broadcasts, and NATs external traffic out a TUN. No kernel changes are needed: the GB just sends to a dst IP over its one link and the hub decides GB<->GB vs GB<->internet. sudo tools/gbhub 2 netd "ping 10.0.0.2" Verified two Game Boys talking to each other: [GB0] dhcp: leased 10.0.0.2 [GB1] dhcp: leased 10.0.0.3 [GB0] netd: up (10.0.0.2) [GB1] ping 10.0.0.2 -> 4/4 received DHCP is keyed per connection (not MAC), so identical GBs still get unique IPs; each emulator gets its own ROM copy so battery saves don't clash.
* net: DHCP client - lease the IP at boot instead of hardcoding ituser4 days2-4/+90
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The address is no longer baked in. net_init starts at 0.0.0.0; a DHCP client runs as the first thing on boot (init/shell forks it and waits), and only once it has a lease (or gives up) does the prompt appear. Kernel: - IP is configurable: 0.0.0.0 until leased; NET_SETIP op stores it. - 16-bit frame length. DHCP/BOOTP packets are ~272 bytes, over the old 255-byte frame cap, so net_slip_send takes a 16-bit length, net_pump assembles into a 320-byte buffer with a 16-bit wNetRxLen, and udp_send writes a 16-bit IP total. Payloads stay <=255 (kept small on purpose) so the per-protocol datalen math is unchanged. wNetTx/wNetRxBuf 256->320, SK_RXBUF 208->288. Userland: - c/dhcp.c: DISCOVER->OFFER->REQUEST->ACK over a UDP socket, then net_setip(); times out gracefully (shell still boots) if there's no server. sh.c runs it before the prompt. Bridge (self-contained DHCP server, no dnsmasq): - tunbridge.py + netboot intercept UDP->:67 and answer OFFER/ACK leasing 10.0.0.2 (gateway 10.0.0.1); everything else is bridged/NATed as before. Regression-tested ICMP/UDP/TCP after the 16-bit change. Verified end to end: dhcp: discovering dhcp: leased 10.0.0.2 /# ping 10.0.0.1 -> 4/4 (traffic from the leased address)
* net: keep network packets out of the console (fixes shell garbage on netboot)user4 days2-0/+4
| | | | | | | | | | | | | | | | | The link port is both the console-input fallback and the network. At the shell prompt the host's multicast (mDNS/LLMNR/IGMP) was fed to the serial and KGetc read those packet bytes as console input -> garbage in the shell, OSK unusable. Two-part fix: - KGetc now skips SLIP frames (0xC0-delimited) on the serial console path, so inbound packets never surface as console input. Plain injected bytes (the headless tunbridge command path) still pass through. New wConInSkip flag. - netboot/tunbridge only forward IP packets destined to 10.0.0.2 (drop the multicast noise at the bridge). Verified: GB sits at a clean "/#" prompt while all packets (noise included) are forwarded; being-pinged (3/3) and wget still work. On the emulator, the OSK is SELECT=space, START=enter, A=z, B=x, d-pad=WASD/arrows.
* tools: netboot - interactive networked emulator (TUN + NAT + --serial-sock)user5 days1-0/+128
| | | | | | | | | | | | | | Brings up gbtun0 (10.0.0.1/24) + NAT, then launches sl0pboy with your own args and the link port bridged to the TUN over a unix socket (the emulator's new --serial-sock). Unlike headless tunbridge, the LCD + on-screen keyboard stay live, so it's a fully interactive networked Game Boy: the OSK is the console, the link port is the network. sudo tools/netboot --sixel --chrome gbos.gb # on the GB: SELECT for the OSK, then type: wget example.com / ping 1.1.1.1 GB is 10.0.0.2, host is 10.0.0.1. Requires /dev/net/tun + root. Ctrl-C or quit the emulator to tear down. tunbridge stays for headless scripted runs.
* net: real routed IP via SLIP<->TUN bridge (you can *ping* a Game Boy)user5 days1-0/+127
| | | | | | | | | | | | | | | | | | | | | tunbridge.py opens a TUN device (gbtun0, 10.0.0.1/24), NATs 10.0.0.0/24 out to the internet, spawns the emulator, and bridges raw IP packets on the TUN to/from SLIP frames on the link serial. The Game Boy (10.0.0.2) becomes a genuine routed IP host: the host kernel routes its packets for real, so the host's own `ping` command reaches it and netd answers. Verified: `sudo python3 tools/tunbridge.py netd --test` 64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=1.61 ms 4 packets transmitted, 4 received, 0% packet loss Two hard-won gotchas baked in: - Under sudo, ~ expands to /root, so resolve EMU/ROM via $SUDO_USER's home. - Only start feeding host->GB packets AFTER netd is running; raw packet bytes delivered to gbos's shell (before netd claims the serial) corrupt the shell and crash the emulator. gb->host draining starts immediately. Requires /dev/net/tun (on Proxmox LXC: allow cgroup2 device c 10:200 rwm + bind-mount /dev/net/tun into the container).
* net: IP stack milestone B - UDP echo (pseudo-header checksum)user5 days1-1/+27
| | | | | | | | | | Refactor netd into a protocol dispatcher (IP -> ICMP/UDP) and add UDP echo: swap addresses + ports and recompute the UDP checksum over the pseudo-header (src/dst IP + proto + length) plus the datagram. This is the same pseudo- header TCP uses, so it de-risks the next milestone. tools/gateway.py --mode udp sends a datagram and verifies the echo. Verified: 'hello udp gbos' echoes back with cksum=ok.
* net: real IP stack, milestone A - ICMP echo (you can ping a Game Boy)user5 days1-35/+134
| | | | | | | | | | | | | | Start of an actual TCP/IP stack on gbos (TLS stays in a proxy). netd is a userland IP responder over SLIP: our address is 10.0.0.2, the SLIP peer 10.0.0.1. It parses IPv4 headers, answers ICMP echo requests, and rebuilds the packet with correct IP + ICMP checksums (RFC 1071 one's-complement sum, carry-folded - works fine on the SM83). c/netd.c + register; tools/gateway.py gains --mode ping: it crafts ICMP echo requests over SLIP and verifies the replies. Verified: `netd` answers 4 pings, gateway reports reply from 10.0.0.2 with cksum=ok for each. Next: UDP, then TCP.
* net: chat client - async receive + OSK send over the link portuser5 days1-2/+14
| | | | | | | | | | | | | | | | | | | | | | | The application layer of the link-port demo, and it ties the whole system together: the LCD terminal displays, the on-screen keyboard types, and the link port carries a live chat. Kernel: sys_srecv_nb (non-blocking link receive; A=byte, CF=none) and sys_pollin (poll the OSK for a typed char without blocking) - syscalls 31/32. Both are what a poll loop needs to receive and type at once. Userland: c/chat.c runs a poll loop - it feeds non-blocking bytes through a SLIP receive state machine and prints whole incoming frames as messages, while pollin() drives the on-screen keyboard; SELECT shows the keys, type a line, START sends it as a frame. libc srecv_nb()/pollin(). Host: tools/gateway.py --mode chat is a simple bot peer (echoes each GB message and injects a few async ones); --keys can drive the OSK for tests. Verified: the gateway pushes 'welcome', '<alice> hey gameboy!', '<bob> nice link cable' unprompted and the GB displays all three (async receive); typing 'hi' on the OSK echoes it and emits the SLIP frame \xC0hi\xC0 (send). A Game Boy in the chat, keyboard on screen, over the link cable.
* net: wget - real HTTP over the link port via the gatewayuser5 days1-21/+45
| | | | | | | | | | | | | | | | Grow the link-port demo from echo to actual network access. The Game Boy still only does SLIP framing + display; the host gateway does DNS/TCP/HTTP. - c/netlib.h: SLIP framing factored out (header-only, per-program copy). necho.c now uses it too. - c/wget.c: `wget URL` frames the URL, then prints the reply body. The gateway streams the body back as typed frames: 'D'<chunk> ... 'E'. - tools/gateway.py: add --mode http (urlopen the frame as a URL, cap the body, chunk it) alongside --mode echo; --cmd runs any gbos command. Verified: `wget example.com` streams back the full Example Domain HTML onto the terminal; `wget sl0p.foo` fetches the real page. A Game Boy on the web, over the link cable.
* net: SLIP framing over the link port + a host gateway (echo round-trip)user5 days1-0/+69
| | | | | | | | | | | | | | | | | | | | First step of link-port networking. The LCD terminal + OSK freed the serial port from console duty, so it can be the network link. Kernel (src/net.asm): raw link-port serial that bypasses the console/ terminal - sys_ssend (transmit, GB drives the clock) and sys_srecv (receive, GB slave, blocks by yielding). Syscalls 29/30. Userland: libc ssend()/srecv(); c/necho.c does SLIP (RFC 1055) framing over them - send a packet, receive the reply, print it. Host: tools/gateway.py wraps the emulator, owns its link serial, speaks SLIP, and (for now) echoes every frame back - the "link cable adapter". Console (ASCII) bytes on the same channel are printed for visibility. Verified: `necho` sends a SLIP frame, the gateway decodes+echoes it, and gbos prints the reply - a real framed round-trip over the Game Boy link port. Next: swap the echo for actual network ops (DNS/HTTP or IRC/chat).
* font: full mixed-case + punctuation glyph set (not uppercase-only)user5 days1-95/+106
| | | | | | | | | | | | | | Replace the small-caps placeholder font with a real baseline-aligned 4x8 set covering all 96 printable ASCII: distinct lowercase with true ascenders (b d f h k l t) and descenders (g j p q y), digits, and punctuation. Metrics: caps/ascenders rows 1-5, x-height rows 2-5, baseline row 5, descenders into rows 6-7. Glyphs are ~3px wide in the 4px cell -- cramped but legible; the tile mechanism itself imposes no character-set limit. genfont.py now takes per-glyph (top, rows) so glyphs sit on the baseline. Demo strings in term_test updated to show mixed case + punctuation. Verified by screenshot: descenders visibly drop below the baseline.
* term: 40-column text terminal on the CGB LCD (4x8 dynamic tiles)user5 days2-0/+121
Add a background-tile text terminal that packs TWO 4px-wide characters into each 8x8 tile, giving a 40x18 grid instead of the 20x18 you'd get from an 8x8 font. The tilemap is static (one dedicated VRAM tile per screen position); we rebuild a tile's 16 bytes from two glyphs whenever a character changes. 360 tiles exceed the 256 a single tilemap can address, so positions 256-359 live in VRAM bank 1 via the CGB tilemap attribute bank-bit -- hence CGB-only. - Switch the ROM to CGB (rgbfix -C). Safe for the FS: every process has PROC_WRAMB=1, so SVBK stays on bank 1 and the WRAMX FS caches don't move. - CGB BG palette 0 = white bg / black text via BCPS/BCPD. - src/term.asm: term_init (palette + static tilemap + clear buffer), build_tile (combine two 4px glyphs -> one 8x8 tile, correct VRAM bank), term_redraw (rebuild all tiles), term_puts, term_show, term_test. - src/font.asm: 96-glyph 3x5-in-4x8 font, generated by tools/genfont.py. - 40x18 text buffer at $D600 (WRAMX, above the FS caches). - tools/ppmview.py: render a --shot PPM as ASCII so the LCD is inspectable from the shell during development. Verified via emulator screenshot: "GBOS TERMINAL", the alphabet, and a bank-1 row all render legibly at 40 columns. Serial shell + filesystem still work unchanged. Note: a full term_redraw builds 360 tiles and takes ~8 frames; fine for incremental single-char updates, but scrolling needs a smarter path (next milestone). Input (no keyboard) is also still TODO.