VectreC — Writing C for the Vectrex in 2026

From “hello world” to a complete Pong, in two cmoc invocations

The Vectrex turned 43 this year, and somewhere between nostalgia and stubbornness, I keep finding excuses to ship code to it. The latest is VectreC — a ready-to-build CMOC toolchain that takes plain C and hands you back a .bin ROM image that runs in an emulator or on real silicon. No autoconf rabbit holes, no hunting for the right lwtools version, no patching headers at 1 am.

This post walks through what’s in the box, builds the canonical Hello World, and then compiles the final chapter of the Vectrex Pong tutorial to show how little code stands between you and a finished game.

What VectreC actually is

VectreC bundles three things into one install:

  • CMOC 0.1.67 — Pierre Sarrazin’s C compiler targeting the Motorola 6809

  • lwtools — William Astle’s assembler, linker, and archiver (lwasm, lwlink, lwar)

  • A Vectrex stdlib — headers plus precompiled libraries wrapping the Vectrex BIOS, originally written by Johan Van den Brande and extended here

The wrapper uses naming conventions compatible with gcc6809, so code can be ported between toolchains without a rewrite. macOS users get a one-shot ./build.sh; Windows users can grab a prebuilt redist package or build natively with MSYS2.

After installation, you have a self-contained directory — typically ~/retro-tools/vectrec/ — with the compiler, the 6809 toolchain, and the stdlib sitting next to each other.

Install — start from zero

Pick your platform and follow the README. Both paths end at the same place: a working cmoc and a stdlib/ you can point at.

  • macOS: README_macOS.mdgit clone, then ./build.sh. Homebrew handles lwtools, bison and flex automatically.

  • Windows: README_Windows.md — grab the prebuilt redist ZIP, or build natively under MSYS2 with build-windows.sh.

Once the install finishes you should have these binaries on disk:

~/retro-tools/vectrec/
├── cmoc          # CMOC compiler
├── lwasm         # 6809 assembler
├── lwlink        # 6809 linker
├── lwar          # 6809 archiver
└── stdlib/       # Vectrex headers + precompiled libraries

The retro-tools/ path is just a default, not a requirement. The toolchain is fully relocatable — pass any directory as the first argument to build.sh (e.g. ./build.sh /opt/vectrec or ./build.sh ~/vectrec) and point $VECTREC at it. I use ~/retro-tools/ only because I keep several retro toolchains side by side.

That’s the toolchain. Everything below assumes $VECTREC points at that directory.

Hello, beam

The smallest interesting Vectrex program is six lines of real code. From examples/hello.c:

#include <vectrex/bios.h>

int main()
{
    while (1)
    {
        wait_recal();               // sync to the 50 Hz frame
        intensity_a(0x7f);          // beam intensity (0x00..0x7f)
        print_str_c(0x10, -0x50, (char *)"HELLO WORLD!");
    }
    return 0;
}

That’s it. Set up the frame, crank the beam to full intensity, draw a string. The loop runs forever because there is no “operating system” to return to — the Vectrex BIOS is the program’s host, and wait_recal() is the heartbeat.

Build it:

VECTREC=$HOME/retro-tools/vectrec
$VECTREC/cmoc -I$VECTREC/stdlib -L$VECTREC/stdlib --vectrex -o hello.bin hello.c

On my machine that produces a 1,656-byte ROM. Drop it into VecX (or whatever emulator you prefer) and “HELLO WORLD!” lights up the glass.

From hello world to a full game: Vectrex Pong

The Hello World shows the toolchain works. The interesting question is: how much further is a real game?

The companion repo vectrex-pong answers that across ten short chapters — game loop, drawing, movement, collision, scoring, joystick input, and finally sound. The final chapter, tutorial1-chapter-10-with-sound.c, is 294 lines of C for a complete two-player Pong with music and hit effects.

A few details worth pointing out from that final file:

  • Cartridge metadata via pragmas. No magic addresses, no hand-poked bytes:

#pragma vx_copyright "2020"
#pragma vx_title_pos 0,-80
#pragma vx_title_size -8, 80
#pragma vx_title "g PONG"
#pragma vx_music vx_music_1
  • The compiler emits the Vectrex cartridge header for you. The title screen “just works.”

  • A game_object struct per entity. Paddles, ball and border share one shape with x/y, speed, scale and a bounding box. Plain C — no classes, no allocator, fits the platform.

  • Vector lists as const arrays. The paddle and ball shapes are literal int8_t[] tables passed to the BIOS draw routines. That’s the whole “asset pipeline.”

  • Sound as a byte array. The hit effect is one line of hex feeding the AY-3-8912 PSG:

static const uint8_t hit_sound[] = {0x00,0x00,0x01,0x00,...,0xff};

Build the final ROM the same way as hello.c:

$VECTREC/cmoc -I$VECTREC/stdlib -L$VECTREC/stdlib --vectrex \
    -o pong.bin src/tutorial1-chapter-10-with-sound.c

Result: 4,775 bytes. A complete, playable Pong with sound, in under 5 KB. That is the entire pitch for retro development in one number.


Why this matters (a little)

There is a fashion right now for “constrained” environments — handhelds with weak GPUs, Pico-8, low-poly engines. The Vectrex predates all of that and is genuinely constrained: 1 KB of RAM, a single beam tracing vectors on a CRT, a BIOS that schedules your frame for you. The discipline transfers. You learn quickly that allocating in a frame is a mistake, that bounding boxes beat pixel-perfect collisions, and that “draw less” is almost always the right answer.

VectreC’s job is to keep the tooling from being the constraint. You should be fighting the hardware, not autotools.


Get started

If you build something, I’d love to see the ROM. And if you’ve never written for a 1982 vector console before — start with hello.c. You’re six lines from a glowing screen.