joseph@projects:~
joseph@projects:~$ cat adad8/README.md

# adad8 [github.com/BigJayToDaIzo/adad8]

My very first computer's processor (8088) emulator.

Tech: [C#] [.NET 10] [TDD]

Status: active

joseph@projects:~$ ls adad8/docs/

These are just a few highlights from the project documentation. The full notes live in the repo where CLAUDE.md, .plan, and inline comments have loads more detail.

Building an 8088 Emulator with TDD — 10,000 hardware-generated test cases per opcode. Red-Green-Refactor at the silicon level.

Why TDD for a CPU Emulator?

An emulator either matches hardware behavior or it doesn’t. There’s no “close enough.” The SingleStepTests/8088 test suite provides 10,000 hardware-generated test cases per opcode, each capturing the full CPU state before and after a single instruction execution. Every test case includes initial register values, memory contents, flag states, and the expected final state after execution.

This is TDD’s ideal scenario: an authoritative oracle that defines correct behavior down to individual flag bits.

The Workflow

Each session follows the same loop:

  1. Pick the smallest failing test, not the most interesting one, the smallest one
  2. Write a unit test that isolates the behavior
  3. Make it green with the minimum implementation
  4. Refactor only after green
  5. Run integration tests against the hardware suite to validate

The integration test harness loads gzipped JSON test data, initializes CPU state from the test’s initial block, executes the instruction bytes, then compares every register, flag, and memory byte against the expected block.

What This Catches

The hardware tests are unforgiving. They surface bugs that manual testing never would:

  • Parity flag computed on the wrong byte width
  • Auxiliary carry using a formula that only works for ADD, not SUB
  • Effective address wrapping at 16 bits vs 20 bits (two-phase wrapping)
  • Prefix bytes silently consumed by the decoder, shifting the instruction stream

Every one of these was a real bug caught by the test suite, not by inspection.

Signing Off

My favorite learning from this particular session is how easy it is to mask 6 bytes when you only mean to mask 5. I could not for the life of me figure out why the memory wasn’t properly wrapping the instant the carry bit crossed the 20-bit line. Turns out I had masked an extra order of magnitude, making overflow impossible until the 16MB mark, a memory space the world wouldn’t see until the 80286. When the overflow mask didn’t set as the integration tests expected, we found a missed edge case for the unit tests that should have ensured the flag was setting properly when that 21st bit caught a carry.

TDD mf’n rules! - jm

joseph@projects:~$ tree projects/ -L 1

projects/

├── dice_trio/ [active]
├── josephmyers.dev/ [active]
├── Sandbox/ [active]
└── TransientTracker/ [archived]
joseph@projects:~$ cat dice_trio/README.md

# dice_trio [hexdocs.pm/dice_trio]

A minimal dice rolling library that parses and rolls standard dice expressions (d6, 2d6+3, d20-1). Zero dependencies, 60 tests, built for game development.

Tech: [Gleam]

joseph@projects:~$ cat josephmyers.dev/README.md

# josephmyers.dev [josephmyers.dev]

This site. Terminal-themed portfolio built with Astro.

Tech: [Astro][TypeScript][CSS]

joseph@projects:~$ cat Sandbox/README.md

# Sandbox [github.com/BigJayToDaIzo]

My GitHub playground. Experiments, learning projects, and code exploration across various languages and technologies.

Tech: [Gleam][Rust][Lua][Go][Nix][C][TypeScript][Python]

joseph@projects:~$ cat TransientTracker/README.md

# TransientTracker [github.com/BigJayToDaIzo/TransientTracker]

ImageJ plugins for astronomical image analysis and star position measurement.

Tech: [Java][ImageJ]

joseph@projects:~$