All docs

Compiler

The 9-phase Rust compiler pipeline, two backend architecture, multibank support and project file format.

Vectrex Studio has two compiler backends, both selectable from the IDE Settings panel. They share the same VPy input but differ in architecture and capabilities.


Why Two Backends?

The Core compiler was the original implementation — stable and well-tested. When PDB debug symbol generation was added it caused enough structural issues that a clean-room rewrite was started. The new Buildtools compiler is a modular 9-phase Rust pipeline that properly supports multibank ROMs, source-level debugging, and tree shaking.


Backend 1 — Core (Legacy)

Status: ✅ Stable · Single-bank only (32 KB ROM)

Single-pass pipeline: lexer → parser → AST → optimizer → codegen → MC6809 assembly → binary. The assembler is built-in; no external toolchain required.

Optimizations

  • Constant folding and propagation
  • Dead code elimination
  • Dead store elimination
  • Peephole patterns (power-of-two mul/div → shifts)

Limitations

  • Always outputs a fixed 32 KB ROM
  • No PDB debug symbol generation
  • No source-level breakpoints in VPy files

Use Core if your game fits in 32 KB and you need maximum reliability.


Backend 2 — Buildtools (New)

Status: ⚠️ Partial — multibank works, some edge cases remain

A modular multi-crate Rust pipeline with one crate per phase.

PhaseCrateResponsibility
1vpy_loaderLoad .vpyproj project file (TOML)
2vpy_parserParse VPy source to AST
3vpy_unifierMerge multi-file ASTs, resolve imports
4vpy_bank_allocatorAssign functions/data to ROM banks
5vpy_codegenAST → MC6809 assembly (with tree shaking)
6vpy_assemblerMC6809 assembly → machine code (two-pass)
7vpy_linkerSymbol resolution, inter-bank references
8vpy_binary_writerEmit final .bin ROM image
9vpy_debug_genGenerate .pdb debug symbol file

Use Buildtools if you need multibank support or source-level debugging (breakpoints in .vpy files).


Multibank ROMs

Games bigger than 32 KB are supported with zero code changes. Add two META directives:

META ROM_TOTAL_SIZE = 524288   # 512 KB total
META ROM_BANK_SIZE  = 16384    # 16 KB per bank (default)

The compiler calculates bank count, assigns functions via call graph analysis, and generates all bank-switching wrappers automatically. Your VPy code stays the same.

Memory map

$0000-$3FFF  Banked window (16 KB) — changes based on register
$4000-$7FFF  Fixed bank  (16 KB)   — last bank, always visible

$4000        ROM_BANK_REG (write) — select active bank

The fixed bank always contains main(), interrupt handlers, and the bank-switching runtime.


Project File Format (.vpyproj)

[project]
name        = "mygame"
version     = "0.1.0"
entry       = "src/main.vpy"
description = "My Vectrex game"
author      = "Your Name"
 
[build]
output         = "build/mygame.bin"
target         = "vectrex"
optimization   = 2
debug_symbols  = true   # required for source-level debugging
 
[sources]
vpy = ["src/**/*.vpy"]
 
[resources]
vectors = ["assets/vectors/*.vec"]
music   = ["assets/music/*.vmus"]
sfx     = ["assets/sfx/*.vsfx"]
FieldRequiredDescription
project.entryYesMain .vpy file
build.outputYesOutput .bin path
build.debug_symbolsNoEnable PDB generation (Buildtools only)
build.optimizationNo0–2, default 2

Building from the Command Line

# Build with Buildtools
cargo run --bin vectrexc -- build program.vpy --bin
 
# Run tests
cargo test --all -p vectrex_emulator