Anatomy of a Retro BIOS
Designing firmware for emulated retro computers—reset vectors, service calls, UART I/O, toolchains, and the boot theatre that makes it feel real.
In-depth technical explorations of specific topics, technologies, and implementations.
Designing firmware for emulated retro computers—reset vectors, service calls, UART I/O, toolchains, and the boot theatre that makes it feel real.
Centralizing modem, line, backend, and peripheral audio in a single bus system, after a demo where the volume knob only worked on half the sounds.
A deadpan text adventure about mild chaos, built on a time budget: 79 tests, procedural honk audio, and a migration ending instead of a game over screen.
Mapping code history onto sixteen oscillators: why a harmonic series turned to mud, how gain has to follow perception, and the double-ramp bug behind the pulsing.
Chart.js redraws the full scene on every update, which is right for a dashboard and wrong for playback. Replacing it with a Canvas 2D renderer.
The iteration that turned a text adventure into something playable: balance tuning, achievement scaffolding, and the 1081-line manual that made it legible.
Building cross-assemblers for retro CPUs in Rust, migrating to Pest parsers, and discovering why load addresses matter more than you think.
Rebuilding the DATAPAC PAD experience in code: the command loop, X.25 NUAs, and five period-authentic hosts behind a 300-baud prompt.
Shrinking the emulator's main bundle from 1.1MB to 104KB by lazy-loading backends, and hiding the fetch inside the dial tone.
JetStream redelivered the message and the work was still lost. Moving job ownership out of the queue and into the database.
Five classic CPU cores in Rust, compiled to WebAssembly: 8008, 8080, 8088, Z80, and 6502, and the edge cases that keep emulation honest.
A BBS emulator that outgrew localStorage: gRPC services, NATS messaging, a gateway, and the question of whether any of it was necessary.
Passkeys in a 300‑baud world: the smallest WebAuthn flow, the server state it requires, and how I kept it in tune with emulator.ca's identity model.
Building a Kansas City Standard cassette peripheral: FSK at 2400/1200 Hz, tape transport simulation, and why saving 8 KB takes five minutes.
Building BASIC, Forth, and Scheme interpreters in Rust, running them in browser workers, and what the contrast between them revealed.
Why you can't just shovel bytes through a virtual modem: RTS/CTS backpressure, buffer gates, and the timing budget that makes dial-up feel like dial-up.
Building a Z-Machine transpiler in Rust: opcode decoding, Z-strings, branch offsets, and the constraints that make Infocom's bytecode tick.
Translating PETSCII screen memory into ANSI terminal output: character maps, colour approximation, and the minimal contract a terminal-based VIC‑II can keep.
Simulating Bell 212A and V.32bis handshakes: phase modulation, training sweeps, and why the negotiation audio has the shape it does.
Implementing the 1962 modem standard behind 300 baud dialup: FSK modulation, Goertzel demodulation, and the two-band split that makes full duplex work.