Emulation Milestones and TypeScript Migration
Intel 8088 demos, Zig-based 6502 experiments, and migrating the frontend to TypeScript for better type safety.
I spent most of today watching the TypeScript compiler catch message shape mismatches I would have missed for weeks. The UART bus worker now has typed contracts with the frontend, and when I changed the status field from a string to an enum, the compiler found every place that needed updating. That’s the win: not prettier code, but fewer silent failures at runtime.
The migration touched the workers first—uart-bus.worker.ts, the interpreter worker, the language backend adapters—because those are the boundaries where things go wrong. The frontend passes a message, the worker parses it, and if either side changes the shape without telling the other, you get undefined behaviour that only surfaces when you’re demoing to someone. Now the compiler enforces the contract.
On the core side, two threads ran in parallel. The Intel 8088 is now running C programs compiled with gcc-ia16, including a Fibonacci generator that spits out the first 30 numbers. Getting the toolchain working meant Docker containers, libc stubs, and fixing a MOVZX instruction that the original 8088 doesn’t have (replaced with XOR). But the payoff is that I can write test programs in C instead of hand-assembling every instruction.
Meanwhile, the Zig MOS 6502 core in cores/mos6502-zig/ is taking shape. Today I implemented the memory module, the UART, and the LDA instruction with all its addressing modes. The Zig core mirrors the Rust core’s UART model at $D000-$D001, which makes it useful for side-by-side validation. Two implementations of the same CPU, two languages, one test suite.
The Rust MOS 6502 core models C64-era memory behaviour and exposes a clean switch when I need a flat address space for tests:
pub(crate) raw_memory_mode: bool,
This flag disables C64 banking and leaves UART active so the Klaus Dormann tests can run without video or ROM overlays. The core still runs at 1 MHz, but the memory model collapses when correctness is the priority.
The C64 video system merged today. The text adapter is a mapping layer that turns PETSCII into Unicode box drawing so a VIC-II-era screen can survive in a browser:
const TL_CORNER = 0xe0; // ┌
const TR_CORNER = 0xf2; // ┐
const BL_CORNER = 0xee; // └
const BR_CORNER = 0xfd; // ┘
const HORIZ = 0xc0; // ─
const VERT = 0xdd; // │
It’s not a full video chip, but it’s a faithful text bridge—the smallest behaviour I need for now.
Tomorrow: finish the Zig 6502 instruction set and start the Forth REPL polish. The dungeon crawler also needs its combat system wired up.
Next: dungeon features, Forth polish, and core work
Previous: 2026-01-23