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
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
* text=auto

*.zig text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.asm text eol=lf

*.gb binary
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
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ zig-out/
*.dylib
*.exe
.DS_Store
*.gb
*.sav
*.swp
*.ppm

# Generated ROM images are ignored by default, but the bundled test
# fixtures are committed so that CI can run the ROM suites.
*.gb
!fixtures/roms/*.gb
!fixtures/blargg/*.gb
47 changes: 47 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Contributing

Thank you for your interest in Dot Matrix Deck.

## Ground rules

- Keep the emulator core free of SDL2 dependencies.
- Keep the headless build working without SDL2.
- Write deterministic tests for new behavior.
- Run `zig fmt` on every file you change.
- Keep the bundle ROMs reproducible. Change the assembler source, then
regenerate the ROMs with `zig build fixtures`.

## How to build

Requires Zig 0.16 or later.

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

Run the windowed frontend with SDL2 installed:

```text
zig build
```

## How to add a test ROM

1. Write an assembly source under `fixtures/asm`.
2. Generate the ROM with `zig build fixtures`.
3. Add integration checks in `src/integration.zig`.
4. Commit both the source and the generated ROM.

## How to run the blargg suite

Add the blargg cpu_instrs ROMs to `fixtures/blargg`, then run:

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

## How to report an issue

Open an issue on GitHub.
Include the ROM name, the expected result, and the actual result.
Include the headless command you used.
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 Daniel Cuevas

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.
26 changes: 26 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# NOTICE

## Project

Dot Matrix Deck is a Game Boy emulator written in Zig.
It is licensed under the MIT License.
See the LICENSE file for the full text.

## Test ROMs

The bundled blargg CPU test ROMs in fixtures/blargg come from the
Game Boy CPU Instruction Behavior Test by Shay Green (blargg).
The ROMs are distributed through the retrio/gb-test-roms archive at
https://github.com/retrio/gb-test-roms.

The ROMs verify the behavior of the SM83 instruction set.
They run in the headless runner through the `zig build test-blargg` step.

The bundled smoke ROM in fixtures/roms is assembled from
fixtures/asm/smoke.asm by the gbasm tool in this repository.

## Third-party software

The windowed frontend links against SDL2.
SDL2 is provided by the system package manager or a local prefix.
The emulator itself does not ship or redistribute SDL2 source code.
112 changes: 81 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,44 @@
# 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.
Dot Matrix Deck is a Game Boy emulator written in Zig.
It models the SM83 CPU, the memory bus, timers, serial output, and the pixel pipeline.
A software renderer shows the screen in an SDL2 window.
A headless mode runs test ROMs and reports pass or fail verdicts.

## Current status
## What you can do

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.
Run a game in a window with keyboard controls.
Run a test ROM without a window and read its serial verdict.
Inspect a cartridge header with the `--info` flag.
Disassemble instructions with the `--trace` flag.
Verify the CPU against the blargg instruction suite.

## Features
## Value of this project

- 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
The core is small and readable.
Every subsystem has deterministic tests.
The bundled smoke ROM proves the full pipeline works.
The blargg suite proves the CPU is correct.
CI rebuilds the ROMs from source and checks them byte for byte.

## Requirements

- Zig 0.16 or later
- SDL2 for the optional windowed frontend
You need Zig 0.16 or later.
You need SDL2 for the windowed frontend only.
The headless build does not need SDL2.

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.
On Windows, the build searches common MSYS2 and vcpkg prefixes.
You can set `SDL2_DIR` or pass an SDL2 prefix with `-Dsdl2`.

## Build

Build the headless runner and assembler:
Build the headless runner and the assembler:

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

Build with the windowed frontend when SDL2 is available:
Build the windowed frontend when SDL2 is available:

```text
zig build
Expand All @@ -49,41 +52,88 @@ 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.
Useful options are `--max-cycles N`, `--trace`, `--info`, and `--expect pass|fail|any`.
The runner prints the serial output.
The exit code follows the detected verdict.

Run a ROM in the SDL2 frontend:

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

Controls: Z is B, X is A, Enter is Start, Backspace is Select, Arrows are the D-pad, Esc quits.

## Test

Run the core and assembler tests:
Run the core, 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:

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

Regenerate the bundled ROMs from their assembly sources:

```text
zig build fixtures
```

## Project layout

- `src/cpu.zig` - SM83 CPU implementation
- `src/emulator.zig` - emulator composition and core tests
- `src/bus.zig` - memory and device routing
- `src/ppu.zig` - pixel pipeline
- `src/timer.zig` - timer unit
- `src/cartridge.zig` - cartridge and header parsing
- `src/serial.zig` - serial output helpers
- `src/disasm.zig` - disassembler
- `src/emulator.zig` - emulator composition
- `src/headless.zig` - command-line ROM runner
- `src/main.zig` - SDL2 frontend
- `tools/gbasm.zig` - small assembler for fixture ROMs
- `src/integration.zig` - end-to-end ROM tests
- `tools/gbasm.zig` - SM83 assembler for test ROMs
- `fixtures/` - bundled test ROMs and their sources

## Sample output

Run the bundled smoke ROM:

```text
$ zig build run-headless -- fixtures/roms/smoke.gb --max-cycles 5000000
Serial output:
PASS
Verdict: pass
```

Inspect a cartridge header:

```text
$ zig build run-headless -- fixtures/roms/smoke.gb --max-cycles 1000 --info
Title: SMOKE TEST
Mapper: ROM only
ROM: 32 KiB
RAM: 0 KiB
CGB: no
SGB: no
Header: valid checksum
Global: $0000
```

## Limitations

Hardware coverage is incomplete. Timing accuracy, cartridge support, audio,
and frontend features will improve as the project grows.
Timing accuracy is incomplete.
Cartridge support covers ROM-only and MBC1 mappers.
Audio is not implemented.
The windowed frontend is a basic player; it has no menu bar or save states.

## License

No license file is published yet. Treat this repository as an experimental
project until a license is added.
Dot Matrix Deck is licensed under the MIT License.
See the LICENSE file for details.
The NOTICE file lists the third-party test ROMs used by the test suite.
Loading
Loading