Implement the full state machine from GAME.md §9 with no audio yet,
fixed (not random) durations, and the basic score-update + reset logic
needed to drive the GAMEOVER transition.
src/game.h / src/game.c:
- enum: STATE_TITLE, STATE_READY, STATE_WAIT, STATE_DRAW,
STATE_WIN_P1, STATE_WIN_P2, STATE_GAMEOVER
- byte state global + game_init() / game_step() pair
- per-state enter (show_screen + score_render + reset frame counter)
and step (check inputs, advance counter, transition) functions
- TITLE: flash border at 25 Hz, debounce both-fire-within-8-frames
- READY: 60 frames, WAIT: 100, DRAW: 500-frame fault timeout,
WIN: 100 frames, GAMEOVER: 300 frames
- DRAW uses rising-edge detection so holding fire from before
DRAW doesn't auto-trigger a win
- WIN_P1/WIN_P2 increment the score and re-render the score bar
- GAMEOVER shows the title screen with scores reset to 0/0
src/screens.c / src/screens.h:
- show_screen(n) now handles all 5 SCREEN_* IDs via a per-screen
descriptor table (5 × 8000-byte bitmaps + 5 × 1000-byte attrs)
- LZO-compress the 8000-byte bitmaps at build time so the 5 screens
fit in the main region; the 5 .attr tables go in a custom 'screens'
region at $A000-$C000 (BASIC ROM area, banked out as RAM)
- new show_white_screen() fills the bitmap with 0s, sets $D021/
$D022/$D023/$D020 to white, for the all-white DRAW screen
src/main.c:
- simplified to: memmap_setup → score_init → game_init → while (1)
game_step()
- sets #pragma heapsize(0) since the program doesn't use malloc
Build: ./build.sh -e — .prg is 43.9 KB, well under the 51 KB BASIC
load limit. The oscar64 emulator runs the state machine indefinitely
(both fire buttons read as pressed in the emulator, so the game
cycles through the states); no crash.
Memory layout (from .map):
$0801-$0853 startup
$0880-$0E51 code (1489 bytes)
$0E51-$7FE4 data: 5 LZO bitmaps + small tables (28723 bytes)
$7FE4-$7FEC BSS: state, frame, title_input, etc.
$7FF0-$9000 heap (16 bytes)
$9000-$A000 stack
$A000-$B388 custom 'screens' region: 5 .attr tables (5000 bytes)
nyuller
A C64 programming project using Oscar64
as the cross-compiler. Oscar64 is checked in as a git submodule under
./oscar64/.
Layout
.
├── oscar64/ # Oscar64 cross-compiler (git submodule)
├── docs/c64/ # Low-level C64 reference (memory map, VIC, CIA, SID, …)
├── src/ # Your C code
│ ├── helloworld.c
│ └── build.sh # Compile + run helper
├── OSCAR64.md # Notes on the Oscar64 compiler internals
└── PROG_C64.md # Notes on programming the C64 hardware
First-time setup
# 1. Clone with submodules:
git clone --recurse-submodules <this-repo-url>
# Or, if you already cloned without --recurse-submodules:
git submodule update --init --recursive
Building
cd src
./build.sh # compile helloworld.c → src/build/helloworld.prg
./build.sh -e # run in oscar64's built-in emulator (headless, fast)
./build.sh -v # run in VICE x64 (interactive, needs a real display)
./build.sh -V # run in VICE x64sc (interactive, cycle-exact)
./build.sh -c # just compile
build.sh will build the oscar64 compiler automatically the first time
(it runs make -C make compiler inside ./oscar64/ if
./oscar64/bin/oscar64 doesn't exist yet).
Default test tool is the oscar64 built-in emulator (-e): it
runs headless, needs no ROMs, no display, and is fast. Every Verify
step in tasks.md uses this.
VICE 3.9 is installed at /usr/bin/ (x64, x64sc, x128,
xvic, xpet) and is available via -v / -V. It is a GUI
emulator and needs a real X11 / Wayland display to render — it
won't produce useful screenshots in this headless environment.
Use it from a real terminal session for interactive play-testing
and cycle-exact validation of raster IRQ and SID timing; don't
expect to script it.
Documentation
PROG_C64.md— how the C64 hardware actually works, from a low-level programming perspective. Start here if you want to understand what's going on under the hood.OSCAR64.md— how the Oscar64 compiler works internally, plus a C64- specific section on how to use it well (memory model, bank switching, raster IRQs, common mistakes).docs/c64/— downloaded reference material: the full Commodore 64 Programmer's Reference Guide text, Christian Bauer's canonical VIC-II paper, and per-chip reference notes.