<feed xmlns='http://www.w3.org/2005/Atom'>
<title>gbos.git/tools, branch master</title>
<subtitle>gbos - a tiny Unix-flavored OS for the Game Boy Color (kernel, shell, coreutils in C, RAM filesystem)</subtitle>
<id>https://git.sl0p.foo/gbos.git/atom/tools?h=master</id>
<link rel='self' href='https://git.sl0p.foo/gbos.git/atom/tools?h=master'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/'/>
<updated>2026-07-18T20:45:32Z</updated>
<entry>
<title>demo: boot the SL0PBOY-forked BIOS in the README gif</title>
<updated>2026-07-18T20:45:32Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-18T20:45:32Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=feed40c878b1505abce583a09b751b50cdd087cb'/>
<id>urn:sha1:feed40c878b1505abce583a09b751b50cdd087cb</id>
<content type='text'>
gbdemo resolves a bare --bios to bios/sl0pboy_bios.bin when present
(else stock gbc_bios.bin). Generate the fork with the emulator's
tools/mk_sl0pboy_bios.py. The gif now opens on the SL0PBOY boot
animation - logo drop, colorize, chime - before gbos comes up.
</content>
</entry>
<entry>
<title>demo: boot through the CGB BIOS + double-speed ROM in the README gif</title>
<updated>2026-07-18T20:11:07Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-18T20:11:07Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=6450173e19d93547f4e67a345df0b8c262ad6efc'/>
<id>urn:sha1:6450173e19d93547f4e67a345df0b8c262ad6efc</id>
<content type='text'>
spawn --bios shows the real power-on show (logo drop + splash) before
gbos boots; gbdemo resolves a bare --bios to the emulator's bundled
boot ROM by absolute path (the tmux pane cwd is wherever the user is).
The screen-synced waitfor absorbs the extra ~4s - only the first
prompt timeout got a bump. Regenerated with the double-speed kernel:
same demo, boots and scrolls visibly snappier.
</content>
</entry>
<entry>
<title>tools: gbdemo - scripted, screen-synced demo driver (+ the README demo)</title>
<updated>2026-07-18T18:41:37Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-18T18:41:37Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=4673e7571360e18d490e6c07196ad1f01405b305'/>
<id>urn:sha1:4673e7571360e18d490e6c07196ad1f01405b305</id>
<content type='text'>
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 -&gt; uname
-&gt; ping -&gt; IRC session on 10.0.0.1.
</content>
</entry>
<entry>
<title>term: 7-color terminal (per-glyph fg+bg) + ANSI escapes; colorize irc</title>
<updated>2026-07-18T18:41:27Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-18T18:41:27Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=9e7d5f6e5e01b7473b84bc3449d7f8e0f78e7045'/>
<id>urn:sha1:9e7d5f6e5e01b7473b84bc3449d7f8e0f78e7045</id>
<content type='text'>
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&lt;&lt;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.
</content>
</entry>
<entry>
<title>tools: gbtype prints hub errors to stderr and exits 1</title>
<updated>2026-07-17T22:31:27Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T22:31:27Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=e30b5cd3029b54296ddc9af9b02588d7cc06fd86'/>
<id>urn:sha1:e30b5cd3029b54296ddc9af9b02588d7cc06fd86</id>
<content type='text'>
</content>
</entry>
<entry>
<title>gbhub: control socket + gbtype to inject shell input without the OSK</title>
<updated>2026-07-17T18:31:00Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T18:31:00Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=138e0ad2eb25ee078464c7e2ff7d6a919a188634'/>
<id>urn:sha1:138e0ad2eb25ee078464c7e2ff7d6a919a188634</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>gbhub: make GB drops attributable, not spooky</title>
<updated>2026-07-17T17:47:12Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T17:47:12Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=6f8243ef094241d3a4175fd2deed23fe5ee946ce'/>
<id>urn:sha1:6f8243ef094241d3a4175fd2deed23fe5ee946ce</id>
<content type='text'>
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_&lt;n&gt;.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).
</content>
</entry>
<entry>
<title>tools: gbhub --daemon + gbjoin - interactive multi-Game-Boy networking</title>
<updated>2026-07-17T12:26:06Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T12:26:06Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=584b19508b31f444ae02a974b96d1a50b8e650a2'/>
<id>urn:sha1:584b19508b31f444ae02a974b96d1a50b8e650a2</id>
<content type='text'>
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 -&gt; 10.0.0.2
    term 3:  tools/gbjoin            # windowed GB -&gt; 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&lt;-&gt;GB ping.
</content>
</entry>
<entry>
<title>tools: gbhub - many Game Boys on one network (DHCP pool + inter-GB routing)</title>
<updated>2026-07-17T12:19:02Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T12:19:02Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=4bc5adf806a1f06ddfc456fa63ebebd3ae8e8a04'/>
<id>urn:sha1:4bc5adf806a1f06ddfc456fa63ebebd3ae8e8a04</id>
<content type='text'>
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&lt;-&gt;GB vs GB&lt;-&gt;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 -&gt; 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.
</content>
</entry>
<entry>
<title>net: DHCP client - lease the IP at boot instead of hardcoding it</title>
<updated>2026-07-17T12:11:22Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-07-17T12:11:22Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/gbos.git/commit/?id=a2cb756693229c7880d926d2cdde2f838c697415'/>
<id>urn:sha1:a2cb756693229c7880d926d2cdde2f838c697415</id>
<content type='text'>
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 &lt;=255 (kept small on purpose) so the per-protocol datalen math
  is unchanged. wNetTx/wNetRxBuf 256-&gt;320, SK_RXBUF 208-&gt;288.

Userland:
- c/dhcp.c: DISCOVER-&gt;OFFER-&gt;REQUEST-&gt;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-&gt;: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   -&gt; 4/4 (traffic from the leased address)
</content>
</entry>
</feed>
