No description
  • Rust 72.7%
  • Assembly 22.1%
  • Python 5.1%
Find a file
JimBer110 bcde2213f0
All checks were successful
CI / build (push) Successful in 2m35s
Uppdatera README.md
2026-07-14 00:48:58 +02:00
.cargo Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
.forgejo/workflows Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
asm Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
assembler Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
assets Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
core Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
docs Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
emulator Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
tests Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
tools Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
.gitignore Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
Cargo.lock Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
Cargo.toml Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
custom_font.txt Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
Makefile Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00
README.md Uppdatera README.md 2026-07-14 00:48:58 +02:00
rust-analyzer.toml Initial commit: Cove — 16-bit fantasy console 2026-06-27 19:43:49 +02:00

Cove

Cove logo

License: MIT Rust Manual Tests

A from-scratch 16-bit fantasy console in Rust. Custom CPU, assembler, graphics pipeline, audio engine, and debugger — 11k lines across 3 crates, 317+ unit tests, 29 e2e tests, 3077 lines of documentation.

cargo build --release && cargo test && make e2e

Why this exists

I wanted to build something that touches every layer of a real system — CPU architecture, assembly language design, graphics, audio, input, memory mapping, interrupts, debugging tools — without relying on an OS or existing runtime. The constraint of a limited platform (tiny screen, tight memory, slow clock) makes for interesting engineering problems and honest optimisation work.

Architecture

flowchart LR
    A[assembler<br/>.asm → .bin] --> B[core<br/>CPU, mem, gfx,<br/>audio, syscalls]
    C[emulator<br/>SDL2 frontend,<br/>debugger REPL] --> B
    B --> D[Cartridge file<br/>.cove.png / .bin]
  • core/#![no_std], zero I/O dependencies. CPU, instruction decoder, memory-mapped I/O, graphics pipeline, audio engine, 21 syscalls. Clean separation: every component is testable in isolation.
  • assembler/ — Two-pass assembler with labels, forward references, automatic short-to-long encoding expansion, symbol table output.
  • emulator/ — SDL2 window with integer-scaled rendering, audio via rodio, memory-mapped keyboard/mouse/controller input, async HTTP, REPL debugger with breakpoints, disassembly, and backtrace.

The CPU in one minute

Feature Detail
Word size 16-bit
Registers 8 general purpose (R0R7), PC, SP, FL
Instruction encoding Mixed 16/32-bit (assembler auto-selects)
Addressing modes reg-reg, short imm (6-bit), long imm (16-bit), zero-page (64 bytes), register indirect, indexed, absolute
49 instructions ALU (ADD, SUB, MUL, DIV, AND, OR, XOR, NOT, shifts, CMP), data (MOV, LDW, LDB, STW, STB), control (JMP, Jcc with 8 condition codes, CALL reg-indirect, RET, RTI), stack (PUSH, POP, PUSHF, POPF), system (SYS, HLT, EI, DI)
Cycle costs 15 cycles per instruction, deterministic
Interrupts VBlank (60 Hz) and timer, 2-level vector table, tear-free framebuffer snapshot

Platform specs

Display 128×128, 4 bpp nibble-packed, 4 palette banks × 16 colours (24-bit RGB), integer scaling with letterboxing
Audio 4 independent channels, 5 waveforms (square 25%/50%, triangle, noise, sawtooth), ADSR envelopes, memory-mapped registers
Memory 64 KB — zero-page, code/data, 512-sprite bank, framebuffer, palette/system/audio/input registers, 2 KB save data, 4 KB stack
Tilemap Hardware-scrolling background layer, configurable width, optional transparency
Input Memory-mapped bitmapped — full keyboard, mouse (X/Y + 3 buttons), 2 controllers (analog sticks + D-pad + 8 buttons each)
Syscalls 21 — debug print, sprite, tile, text rendering, shapes (line/rect/circle), random, sqrt, sin, async HTTP (4 concurrent), save/load, PRNG seed, exit
Cartridge .cove.png = valid PNG with embedded 64 KB binary + optional background image; or raw .bin
Save data 2 KB persistent region, stored inline in cartridge file, explicit flush/reload
Assembler Two-pass, case-insensitive mnemonics, labels, .org/.dw/.db/.ds/.equ directives, string escapes, auto short/long expansion, .sym output
Debugger In-emulator REPL: step, breakpoints (address/symbol), disassembly with annotated return addresses, registers, memory hex view, stack backtrace

What's inside

37 assembly example programs in asm/:

Demo What it shows
quicksort_anim.asm Animated Lomuto quicksort — 128 bars sorted with SYS_LINE each frame
scroll_demo.asm Hardware tilemap scrolling with transparency
audio_demo.asm Multi-channel ADSR, waveforms, frequency sweeps
interrupt_demo.asm VBlank and timer interrupts with nesting
pendulum.asm Physics simulation: fixed-point trigonometry, line drawing
http_test.asm Async HTTP GET via 4-concurrent syscalls
datetime.asm Real-time clock registers
gfx.asm Full sprite + tile + text + shape compositing
sieve.asm Prime sieve — register allocation, loops, data layout
multable.asm Multiplication table — nested loops, formatted output
font_test.asm Custom font rendering via SYS_PRINT_CUSTOM

Plus 29 end-to-end tests in tests/asm/ covering every instruction group, addressing mode, flag behaviour, and syscall.

Engineering highlights

  • core/ — the CPU and memory.
  • Instruction decoder — single decode() method on a 16-bit word. Every encoding path (opcode, dst, src, extra, mode) is verified with property-style decode/encode round-trip tests.
  • Tear-free rendering — framebuffer is atomically snapshotted at the start of VBlank before the interrupt fires. The displayed frame never shows mid-update artefacts.
  • Custom two-pass assembler — labels can be forward-referenced. The assembler estimates instruction sizes, detects when a jump/immediate exceeds short-form range, expands to long form, and re-lays out the 64 KB image. Converges in 23 passes.
  • 30+ e2e tests — each .asm in tests/asm/ is assembled and run headless, with assertions on register values, memory contents, and exit codes.

Getting started

cargo build --release

# Assemble and run a demo
./target/release/assembler asm/quicksort_anim.asm -o quicksort.bin
./target/release/emulator quicksort.bin

# Headless testing
./target/release/emulator tests/asm/add.bin --cli --dump 0010-0020

# Debugger REPL
./target/release/emulator program.bin

# E2E tests
make e2e

Documentation

License

MIT