Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Keep Zig sources with LF line endings.
*.zig text eol=lf
build.zig text eol=lf
build.zig.zon text eol=lf

# Mark committed ROM images as binary.
fixtures/roms/*.gb binary
fixtures/blargg/*.gb binary

# Documentation and text files.
*.md text
*.txt text
*.yml text
*.yaml text
75 changes: 75 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: ci

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Test (ubuntu)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- name: Format check
run: zig fmt --check .
- name: Unit and integration tests
run: zig build test --summary all
- name: Regenerate bundled ROMs
run: zig build fixtures
- name: Bundled ROMs match their sources
run: git diff --exit-code -- fixtures
- name: CPU instruction suite (blargg)
run: zig build test-blargg
- name: Build headless tools
run: zig build -Dsdl2=off

test-windows:
name: Test (windows)
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- name: Format check
shell: pwsh
run: zig fmt --check .
- name: Unit and integration tests
shell: pwsh
run: zig build test --summary all
- name: Regenerate bundled ROMs
shell: pwsh
run: zig build fixtures
- name: Bundled ROMs match their sources
shell: pwsh
run: git diff --exit-code -- fixtures
- name: CPU instruction suite (blargg)
shell: pwsh
run: zig build test-blargg
- name: Build headless tools
shell: pwsh
run: zig build -Dsdl2=off

windowed:
name: Windowed frontend (ubuntu)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- name: Install SDL2
run: sudo apt-get update && sudo apt-get install -y libsdl2-dev
- name: Build windowed frontend
run: zig build
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ zig-out/
*.dylib
*.exe
.DS_Store
*.gb
*.sav
*.swp

# Committed fixtures stay tracked even though raw ROMs are ignored.
*.gb
!fixtures/roms/*.gb
!fixtures/blargg/*.gb
54 changes: 54 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Contributing

Dot Matrix Deck is a work-in-progress emulator. Contributions are welcome.

## Build

Use Zig 0.16.0 or later.

Build the headless tools:

```text
zig build -Dsdl2=off
```

Build the windowed frontend. SDL2 must be installed. On Linux, install the package `libsdl2-dev`. On Windows, set the prefix with `-Dsdl2=<prefix>`.

```text
zig build
```

## Test

Run the unit, assembler, and integration tests:

```text
zig build test -Dsdl2=off
```

Run the blargg CPU instruction suite:

```text
zig build test-blargg
```

## Format

The CI workflow checks formatting. Format your changes before you open a pull request:

```text
zig fmt .
```

## Bundled ROMs

The bundled ROMs live in `fixtures`. Keep the ROM image in sync with its assembly source:

```text
zig build fixtures
git diff --exit-code -- fixtures
```

## Pull requests

Keep each pull request small and focused. Add tests for new behavior. Update the README and the roadmap when the change affects them. Do not add generated files to a pull request unless they are committed fixtures.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Dot Matrix Deck contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
20 changes: 20 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Dot Matrix Deck

Third-party test ROMs

The CPU instruction suite in fixtures/blargg is a set of public test ROMs
for the Game Boy CPU. The files are reproduced from the gb-test-roms
project by retrio. The original test suite was written by blargg.

The suite verifies the SM83 CPU against known-good behavior. Each ROM
prints a pass or fail verdict through the serial link port.

Source: https://github.com/retrio/gb-test-roms

SDL2

The windowed frontend links against SDL2. SDL2 is available under the
zlib license. See https://www.libsdl.org for details.

The windowed frontend is optional. The headless runner and the tests do
not require SDL2.
117 changes: 84 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
# Dot Matrix Deck

Dot Matrix Deck is a Game Boy emulator workbench written in Zig. It models the
SM83 CPU, the memory bus, timers, serial output, and the pixel pipeline. A
headless runner makes emulator behavior easy to inspect in scripts and CI.

## Current status

This project is under active development. The headless core is the most useful
entry point today. The SDL2 windowed frontend is available when SDL2 is
installed, but it is still being built out.
Dot Matrix Deck is a Game Boy emulator written in Zig. It emulates the SM83 CPU, the memory bus, the timers, and the pixel pipeline. A software renderer shows the screen in an SDL2 window. A headless mode runs public test ROMs for automated checks.

## Features

- SM83 CPU and instruction execution
- Memory bus with timer, serial, and pixel-processing components
- Headless ROM runner with cycle limits and serial verdicts
- Optional instruction trace output
- Small assembler tool for test ROM sources
- Deterministic unit tests for the emulator core and assembler
- SM83 CPU with all 256 opcodes
- CB prefix instructions and interrupt timing
- Memory bus with WRAM, HRAM, and the MBC1 mapper
- Timer unit with DIV, TIMA, TMA, and TAC
- Background and sprite rendering through the PPU
- Windowed frontend with keyboard controls
- Headless runner with pass or fail verdicts
- Instruction trace mode
- Cartridge header display with the --info flag
- Small assembler for test ROM sources
- Deterministic unit and integration tests

## Requirements

- Zig 0.16 or later
- SDL2 for the optional windowed frontend
- Zig 0.16.0 or later
- SDL2 for the windowed frontend

The headless build does not require SDL2. On Windows, the build searches common
MSYS2 and vcpkg prefixes. You can also set `SDL2_DIR` or pass an SDL2 prefix.
The headless build does not require SDL2. On Windows, the build searches common MSYS2 and vcpkg prefixes. You can also set `SDL2_DIR` or pass an SDL2 prefix.

## Build

Expand All @@ -41,6 +37,12 @@ Build with the windowed frontend when SDL2 is available:
zig build
```

Disable the windowed frontend explicitly:

```text
zig build -Dsdl2=off
```

## Run a ROM

Run a ROM without a window:
Expand All @@ -49,41 +51,90 @@ Run a ROM without a window:
zig build run-headless -- path/to/rom.gb
```

Useful options are `--max-cycles N`, `--trace`, and `--expect pass|fail|any`.
The runner prints serial output and returns a status from the detected verdict.

Run a ROM in the SDL2 frontend:
Run a ROM in the SDL2 window:

```text
zig build run -- path/to/rom.gb
```

Useful options are `--max-cycles N`, `--trace`, `--info`, and `--expect pass|fail|any`. The runner prints serial output and returns a status from the detected verdict.

## Sample output

Run the bundled smoke ROM:

```text
zig build run-headless -- fixtures/roms/smoke.gb
```

```text
Serial output:
PASS
Verdict: pass
```

Show the cartridge header:

```text
zig build run-headless -- fixtures/roms/smoke.gb --info
```

```text
Title: SMOKE TEST
Mapper: ROM only
ROM: 32 KiB
RAM: 0 KiB
CGB: no
SGB: no
Header: valid checksum
Global: $0000
```

## Test

Run the core and assembler tests:
Run the unit, assembler, and integration tests:

```text
zig build test -Dsdl2=off
```

The repository also contains build steps for generated fixtures and the Blargg
CPU instruction suite. Add the required fixture files before using those steps.
Run the blargg CPU instruction suite:

## Project layout
```text
zig build test-blargg
```

The integration tests assemble the smoke ROM from source and compare the image to the committed ROM. They also run the ROM through the emulator and check the serial verdict and the frame checksum.

## Test status

- Unit tests for the CPU, timer, bus, and serial output pass.
- The smoke ROM rebuilds byte for byte from its source.
- The smoke ROM reports a pass verdict through the emulator.
- The blargg CPU instruction suite passes, 11 of 11.
- The frame checksum is deterministic.

## Architecture

- `src/cpu.zig` - SM83 CPU implementation
- `src/emulator.zig` - emulator composition and core tests
- `src/bus.zig` - memory and device routing
- `src/emulator.zig` - emulator composition and core tests
- `src/cartridge.zig` - cartridge mapping and header parsing
- `src/ppu.zig` - pixel pipeline and frame buffer
- `src/timer.zig` - timer unit
- `src/headless.zig` - command-line ROM runner
- `src/main.zig` - SDL2 frontend
- `tools/gbasm.zig` - small assembler for fixture ROMs
- `src/disasm.zig` - instruction disassembler
- `src/integration.zig` - end-to-end ROM tests
- `tools/gbasm.zig` - SM83 assembler for fixture ROMs
- `fixtures/asm` - assembly sources for the bundled ROMs
- `fixtures/roms` - committed ROM images
- `fixtures/blargg` - blargg CPU instruction suite

## Limitations

Hardware coverage is incomplete. Timing accuracy, cartridge support, audio,
and frontend features will improve as the project grows.
Hardware coverage is incomplete. Timing accuracy, cartridge support, audio, and frontend features will improve as the project grows. The windowed frontend needs an SDL2 setup to build.

## License

No license file is published yet. Treat this repository as an experimental
project until a license is added.
Dot Matrix Deck is released under the MIT License. See `LICENSE` for details. The bundled test ROMs have their own provenance; see `NOTICE`.
Loading
Loading