diff --git a/GAME.md b/GAME.md index 63d045d..859d3a4 100644 --- a/GAME.md +++ b/GAME.md @@ -355,7 +355,6 @@ src/ ├── draw.c / .h # the white-screen + counter rendering ├── rasterirq.c / .h # 50 Hz frame tick ├── notes.h # SID frequency table -├── build.sh # (already exists) └── build/ # (gitignored) output ``` diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4ce5f5f --- /dev/null +++ b/Makefile @@ -0,0 +1,234 @@ +# nyuller — C64 game (Oscar64 cross-compiler) +# ============================================================ +# GNU Make wrapper for building and running via oscar64 / VICE. +# +# Default target: help + +# --- paths ------------------------------------------------- +ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +OSCAR64_DIR := $(ROOT)/oscar64 +OSCAR64_BIN := $(OSCAR64_DIR)/bin/oscar64 +BUILD_DIR := $(ROOT)/build + +SRC := main.c +PRG := $(BUILD_DIR)/nyuller.prg +D64 := $(BUILD_DIR)/nyuller.d64 +LOG := $(BUILD_DIR)/vice.log +PID_FILE := $(BUILD_DIR)/vice.pid +SRC_DIR := $(ROOT)/src + +# --- oscar64 flags ---------------------------------------- +# Override with: make OPT=O3 (or O0/O1/O2/Os/g) +OPT ?= O1 +OPT_FLAGS := -$(OPT) + +# --- VICE flags ------------------------------------------- +VICE_FLAGS := +confirmonexit -drive8type 1541 + +# --- phony targets ---------------------------------------- +.PHONY: help compile run run-vice run-vice-cycle-exact \ + play play-cycle-exact kill clean ensure-build-dir + +# ============================================================ +# help (default) +# ============================================================ +help: + @echo "" + @echo " nyuller — C64 game (Oscar64 cross-compiler)" + @echo " ──────────────────────────────────────────────" + @echo "" + @echo " Compile" + @echo " make compile main.c → build/nyuller.prg (-O1)" + @echo " make compile same as above" + @echo " make OPT=O3 compile with -O3 (release build)" + @echo " make OPT=O0 compile with -O0 (debug build)" + @echo " make OPT=Os compile with -Os (optimize for size)" + @echo "" + @echo " Run" + @echo " make run compile + run in oscar64 emulator (headless, fast)" + @echo " make run-vice compile + run in VICE x64 (foreground, blocks)" + @echo " make run-vice-cycle compile + run in VICE x64sc (cycle-exact, slow)" + @echo "" + @echo " Play (detached — returns to shell)" + @echo " make play compile + launch VICE x64 in background" + @echo " make play-cycle compile + launch VICE x64sc in background" + @echo " make kill kill any running detached VICE" + @echo "" + @echo " Clean" + @echo " make clean remove build/ artifacts and VICE log/pid files" + @echo "" + @echo " Output (in build/)" + @echo " nyuller.prg loadable C64 program" + @echo " nyuller.d64 disk image wrapping nyuller.prg (for VICE autostart)" + @echo " nyuller.asm full 6502 listing" + @echo " nyuller.map region/section/object placement" + @echo " nyuller.lbl VICE monitor label commands" + @echo "" + @echo " VICE note: -drive8type 1541 is required for autostart to work." + @echo " Without this flag the autostart LOAD\"*\",8,1 fails with ?DEVICE" + @echo " NOT PRESENT. We have the original 1541 ROM installed at:" + @echo " ~/.local/share/vice/DRIVES/dos1541-325302-01+901229-05.bin" + @echo "" + @echo " Default joystick keys in VICE (rebindable under Settings):" + @echo " Port 2 (left, Scoot) W/A/S/D + Left Ctrl (fire)" + @echo " Port 1 (right, Hare) Arrows + Right Shift (fire)" + @echo "" + +# ============================================================ +# ensure-build-dir +# ============================================================ +ensure-build-dir: + @mkdir -p "$(BUILD_DIR)" + +# ============================================================ +# compile +# ============================================================ +compile: ensure-build-dir + @# Build the oscar64 compiler first if it doesn't exist. + @if [ ! -x "$(OSCAR64_BIN)" ]; then \ + echo "oscar64 compiler not found at $(OSCAR64_BIN); building it..."; \ + cd "$(OSCAR64_DIR)" && make -C make compiler; \ + fi + @if [ ! -x "$(OSCAR64_BIN)" ]; then \ + echo "error: $(OSCAR64_BIN) is still missing after build" >&2; \ + echo " try: cd $(OSCAR64_DIR) && make -C make compiler" >&2; \ + exit 1; \ + fi + @echo "compiling $(SRC) with $(OSCAR64_BIN) -> $(BUILD_DIR)/" + cd "$(SRC_DIR)" && "$(OSCAR64_BIN)" -i="$(OSCAR64_DIR)/include" -o="$(PRG)" $(OPT_FLAGS) "$(SRC)" + +# ============================================================ +# run — oscar64 built-in emulator (headless, fast) +# ============================================================ +run: ensure-build-dir + @if [ ! -x "$(OSCAR64_BIN)" ]; then \ + echo "oscar64 compiler not found at $(OSCAR64_BIN); building it..."; \ + cd "$(OSCAR64_DIR)" && make -C make compiler; \ + fi + @if [ ! -x "$(OSCAR64_BIN)" ]; then \ + echo "error: $(OSCAR64_BIN) is still missing after build" >&2; \ + echo " try: cd $(OSCAR64_DIR) && make -C make compiler" >&2; \ + exit 1; \ + fi + @echo "running $(SRC) in oscar64's built-in emulator" + cd "$(SRC_DIR)" && "$(OSCAR64_BIN)" -i="$(OSCAR64_DIR)/include" -o="$(PRG)" $(OPT_FLAGS) -e "$(SRC)" + +# ============================================================ +# run-vice — VICE x64 (foreground, blocks terminal) +# ============================================================ +run-vice: $(D64) + @echo "running nyuller in VICE x64 (blocking)" + x64 $(VICE_FLAGS) -autostart "$(D64)" + +# ============================================================ +# run-vice-cycle — VICE x64sc (foreground, cycle-exact, slow) +# ============================================================ +run-vice-cycle: $(D64) + @echo "running nyuller in VICE x64sc (cycle-exact, blocking)" + x64sc $(VICE_FLAGS) -autostart "$(D64)" + +# ============================================================ +# play — VICE x64 detached (returns to shell) +# ============================================================ +play: compile $(D64) + @# Kill any previous VICE first. + @existing=$$(pgrep -f 'x64(sc)? \+confirmonexit.*nyuller\.d64' 2>/dev/null || true); \ + if [ -n "$$existing" ]; then \ + echo "killing previous VICE process(es): $$existing"; \ + kill $$existing 2>/dev/null || true; \ + sleep 1; \ + kill -9 $$existing 2>/dev/null || true; \ + fi + @echo "launching VICE x64 in the background with $(D64)..." + @setsid nohup x64 $(VICE_FLAGS) -autostart "$(D64)" \ + > "$(LOG)" 2>&1 < /dev/null & echo $$! > "$(PID_FILE)" + @sleep 1 + @if kill -0 "$$(cat "$(PID_FILE)")" 2>/dev/null; then \ + echo ""; \ + echo "VICE launched (PID $$(cat "$(PID_FILE)")). Look for the x64 window on your desktop."; \ + echo "Default keys: Port 1 (Hare) = Arrows + Right Shift (fire)"; \ + echo " Port 2 (Scoot) = W A S D + Left Ctrl (fire)"; \ + echo "Rebind under Settings → Input devices → Joystick settings."; \ + echo "To stop VICE later: make kill"; \ + echo "Log file: $(LOG)"; \ + else \ + echo "error: VICE failed to start; see $(LOG) for details" >&2; \ + exit 1; \ + fi + +# ============================================================ +# play-cycle — VICE x64sc detached (cycle-exact, returns to shell) +# ============================================================ +play-cycle: compile $(D64) + @existing=$$(pgrep -f 'x64(sc)? \+confirmonexit.*nyuller\.d64' 2>/dev/null || true); \ + if [ -n "$$existing" ]; then \ + echo "killing previous VICE process(es): $$existing"; \ + kill $$existing 2>/dev/null || true; \ + sleep 1; \ + kill -9 $$existing 2>/dev/null || true; \ + fi + @echo "launching VICE x64sc in the background with $(D64)..." + @setsid nohup x64sc $(VICE_FLAGS) -autostart "$(D64)" \ + > "$(LOG)" 2>&1 < /dev/null & echo $$! > "$(PID_FILE)" + @sleep 1 + @if kill -0 "$$(cat "$(PID_FILE)")" 2>/dev/null; then \ + echo ""; \ + echo "VICE launched (PID $$(cat "$(PID_FILE)")). Look for the x64sc window on your desktop."; \ + echo "Default keys: Port 1 (Hare) = Arrows + Right Shift (fire)"; \ + echo " Port 2 (Scoot) = W A S D + Left Ctrl (fire)"; \ + echo "Rebind under Settings → Input devices → Joystick settings."; \ + echo "To stop VICE later: make kill"; \ + echo "Log file: $(LOG)"; \ + else \ + echo "error: VICE failed to start; see $(LOG) for details" >&2; \ + exit 1; \ + fi + +# ============================================================ +# kill — stop any detached VICE +# ============================================================ +kill: + @# pgrep -f uses ERE: + is a quantifier, so the regex must escape it. + @# x64(sc)? matches both "x64" and "x64sc". The process is launched + @# with the literal argument string `+confirmonexit`. + @pids=$$(pgrep -f 'x64(sc)? \+confirmonexit.*nyuller\.d64' 2>/dev/null || true); \ + if [ -n "$$pids" ]; then \ + echo "killing VICE process(es): $$pids"; \ + kill $$pids 2>/dev/null || true; \ + sleep 1; \ + kill -9 $$pids 2>/dev/null || true; \ + else \ + echo "no VICE process running (autostart of nyuller.d64)"; \ + fi + @rm -f "$(PID_FILE)" "$(LOG)" + +# ============================================================ +# $(D64) — build the .d64 disk image from the .prg +# ============================================================ +# c1541's exit code is unreliable (the interactive form always +# exits 0 even on failure), so the only reliable success signal +# is listing the disk afterwards and checking the PRG is there. +# The flag-form `c1541 -list image` doesn't work (c1541 treats +# it as a unit number), so we use the interactive heredoc form. +# All c1541 calls are wrapped in `|| true` so the final +# list-and-grep is the authoritative check. +$(D64): $(PRG) | ensure-build-dir + @echo "wrapping $(PRG) in $(D64) (VICE autostart needs a disk image)..." + @c1541 -format ny,of d64 "$(D64)" >/dev/null 2>&1 || true + @echo "write $(PRG)" | c1541 "$(D64)" >/dev/null 2>&1 || true + @if printf "list\nquit\n" | c1541 "$(D64)" 2>/dev/null | grep -q "nyuller.prg"; then \ + :; \ + else \ + echo "error: failed to write $(PRG) to $(D64) (c1541 silently exited 0)" >&2; \ + rm -f "$(D64)"; \ + exit 1; \ + fi + +# ============================================================ +# clean +# ============================================================ +clean: + rm -f "$(PRG)" "$(D64)" "$(BUILD_DIR)/nyuller.asm" "$(BUILD_DIR)/nyuller.map" \ + "$(BUILD_DIR)/nyuller.lbl" "$(BUILD_DIR)/nyuller.int" "$(BUILD_DIR)/nyuller.dbj" \ + "$(BUILD_DIR)/nyuller.csz" "$(PID_FILE)" "$(LOG)" + @echo "cleaned build/" diff --git a/README.md b/README.md index 69e7939..b586ad5 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ as the cross-compiler. Oscar64 is checked in as a git submodule under ├── build/ # Build output (gitignored) ├── docs/c64/ # Low-level C64 reference (memory map, VIC, CIA, SID, …) ├── src/ # Your C code -│ ├── helloworld.c -│ └── build.sh # Compile + run helper +│ └── *.c, *.h +├── Makefile # Build + run targets (gnu make) ├── OSCAR64.md # Notes on the Oscar64 compiler internals └── PROG_C64.md # Notes on programming the C64 hardware ``` @@ -31,28 +31,28 @@ git submodule update --init --recursive ## Building ```sh -cd src -./build.sh # compile main.c → build/nyuller.prg (-O1) -./build.sh -e # run in oscar64's built-in emulator (headless, fast) -./build.sh -p # PLAY: launch VICE in background (see build.sh --help) -./build.sh -v # run in VICE x64 (foreground, blocks terminal) -./build.sh -V # run in VICE x64sc (cycle-exact, foreground) -./build.sh --kill # kill any detached VICE process -./build.sh -c # just compile -./build.sh -O3 # release build (auto-ZP, outliner, aggressive inlining) +make # show help with all targets +make compile # compile → build/nyuller.prg (-O1) +make run # compile + run in oscar64 emulator (headless, fast) +make play # compile + launch VICE x64 in background +make kill # kill any detached VICE +make OPT=O3 # release build (auto-ZP, outliner, aggressive inlining) +make clean # remove build/ artifacts ``` -`build.sh` will build the oscar64 compiler automatically the first time +`make` 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 +Run `make help` for the full list of targets with descriptions. + +**Default test tool is the oscar64 built-in emulator** (`make run`): 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 +`xvic`, `xpet`) and is available via `make run-vice` / `make run-vice-cycle`. +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 diff --git a/src/AGENT_CONTEXT.md b/src/AGENT_CONTEXT.md index 008c7d0..4ba904c 100644 --- a/src/AGENT_CONTEXT.md +++ b/src/AGENT_CONTEXT.md @@ -28,29 +28,30 @@ context you need to do the work. ├── source_images/ # The 5 source PNGs for the game screens └── src/ # YOUR CODE GOES HERE ├── helloworld.c # Existing minimal working program - ├── build.sh # Build script (handles compiler build, runs tests) + ├── build.sh # Legacy build script (replaced by Makefile) └── build/ # Output directory (gitignored) ``` ## Build and test (this is the ONLY way to verify your work) ```sh -cd /home/ballz/work/teletype/nyuller/src -./build.sh # compile helloworld.c → build/helloworld.prg -./build.sh -e # run in oscar64's built-in emulator (HEADLESS, fast) -./build.sh -v # (DO NOT USE) VICE x64 — requires a real display -./build.sh -V # (DO NOT USE) VICE x64sc — same problem +cd /home/ballz/work/teletype/nyuller +make # show help with all targets +make compile # compile → build/nyuller.prg +make run # compile + run in oscar64 emulator (HEADLESS, fast) +make play # compile + launch VICE in background +make kill # kill any detached VICE ``` -**The oscar64 built-in emulator (`-e`) is the only test tool.** VICE +**The oscar64 built-in emulator (`make run`) is the only test tool.** VICE does not work in this headless environment (no display, blank screenshots, manual ROM fetching). Do not waste time on VICE. -The `-e` flag runs the same `.prg` file the C64 will run, with no +The `run` target runs the same `.prg` file the C64 will run, with no setup, no ROMs, and at high speed. -`build.sh` will auto-build the oscar64 compiler if it's missing. -It calls `oscar64 -i=/home/ballz/work/teletype/nyuller/oscar64/include -o=build/helloworld.prg helloworld.c` -to compile, and the same command with `-e` to run. +`make` will auto-build the oscar64 compiler if it's missing. +It runs `cd src && oscar64 -i=…/include -o=…/build/nyuller.prg main.c` +to compile, and `cd src && oscar64 -i=…/include -o=…/build/nyuller.prg -e main.c` to run. The build artifacts in `build/` are: `helloworld.prg` (the C64 program), `helloworld.asm` (6502 listing), `helloworld.map` (region/section/object @@ -180,6 +181,6 @@ $21-$24) goes to $D800-$DBE7. When you're done, report back: 1. What you built (1-2 sentence summary) -2. The output of `./build.sh -e` (proves it compiled and runs) +2. The output of `make run` (proves it compiled and runs) 3. The git commit hash and one-line summary 4. Any concerns or follow-up work for the next phase diff --git a/src/build.sh b/src/build.sh deleted file mode 100755 index 993c4c4..0000000 --- a/src/build.sh +++ /dev/null @@ -1,217 +0,0 @@ -#!/bin/sh -# build.sh — compile and optionally run a single C64 program with Oscar64. -# -# Usage: -# ./build.sh # compile main.c → build/nyuller.prg (-O1) -# ./build.sh -e # run in oscar64's built-in emulator (headless, fast) -# ./build.sh -p # PLAY: compile, wrap in .d64, launch VICE x64 detached -# ./build.sh -P # PLAY: same as -p but with VICE x64sc (cycle-exact) -# ./build.sh -v # run in VICE x64 (foreground, blocks terminal) -# ./build.sh -V # run in VICE x64sc (foreground, blocks terminal) -# ./build.sh --kill # kill any running VICE x64/x64sc process -# ./build.sh -c # just compile -# ./build.sh -O0 # compile with -O0 (no optimization; debug build) -# ./build.sh -O2 # compile with -O2 (more aggressive inlining) -# ./build.sh -O3 # compile with -O3 (release build; auto-ZP, outliner) -# ./build.sh -Os # compile with -Os (optimize for size) -# ./build.sh -g # compile with -g (adds source-level debug info) -# -# Output (in /build/): -# nyuller.prg — loadable C64 program (run with x64, VICE, or real hw) -# nyuller.asm — full 6502 listing -# nyuller.map — region/section/object placement -# nyuller.lbl — VICE monitor label commands -# nyuller.d64 — disk image wrapping nyuller.prg (for VICE autostart) -# -# VICE note: -drive8type 1541 is required for autostart to work. VICE -# defaults to the 1541-II (drive type 1542), whose ROM we don't have -# installed; without this flag the autostart `LOAD"*",8,1` fails with -# ?DEVICE NOT PRESENT. We have the original 1541 ROM at -# ~/.local/share/vice/DRIVES/dos1541-325302-01+901229-05.bin. -# -# For the development loop, use -e (oscar64's built-in emulator). It runs -# without a display, needs no ROMs, and is faster than VICE. Use -p when -# you want to play the game interactively — it launches VICE in the -# background and returns control to your shell so you can do other things. -# -# Default joystick keys in VICE (Settings → Input devices → Joystick -# settings to rebind if needed): -# Port 2 (left, Scoot): W/A/S/D for up/left/right/down, Left Ctrl for fire -# Port 1 (right, Hare): Arrow keys for up/left/right/down, Right Shift for fire -# (You can rebind under Settings → Input devices → Joystick settings.) -# -# Optimization: the default is oscar64's default (-O1). Pass -O3 to -# produce a release build (auto-zero-page, outliner, aggressive inlining). -# The release build is functionally identical to the default build on -# cycle-accurate timings — the audio and frame counters are still -# 50 Hz because they use the raster IRQ, not CPU-bound loops. - -set -e - -# --- locate the oscar64 compiler ----------------------------------------- -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -OSCAR64_DIR="$ROOT/oscar64" -OSCAR64_BIN="$OSCAR64_DIR/bin/oscar64" -BUILD_DIR="$ROOT/build" -PRG="$BUILD_DIR/nyuller.prg" -D64="$BUILD_DIR/nyuller.d64" - -mkdir -p "$BUILD_DIR" - -# --- kill any running VICE ------------------------------------------------ -if [ "${1:-}" = "--kill" ]; then - # pgrep -f uses ERE: + is a quantifier, so the regex must escape it. - # x64(sc)? matches both "x64" and "x64sc". The process is launched - # with the literal argument string `+confirmonexit`. - pids=$(pgrep -f "x64(sc)? \+confirmonexit.*nyuller\.d64" 2>/dev/null || true) - if [ -n "$pids" ]; then - echo "killing VICE process(es): $pids" - kill $pids 2>/dev/null || true - sleep 1 - kill -9 $pids 2>/dev/null || true - else - echo "no VICE process running (autostart of nyuller.d64)" - fi - rm -f "$BUILD_DIR/vice.pid" "$BUILD_DIR/vice.log" - exit 0 -fi - -# Build the compiler if it's missing. -if [ ! -x "$OSCAR64_BIN" ]; then - echo "oscar64 compiler not found at $OSCAR64_BIN; building it..." - ( cd "$OSCAR64_DIR" && make -C make compiler ) -fi - -if [ ! -x "$OSCAR64_BIN" ]; then - echo "error: $OSCAR64_BIN is still missing after build" >&2 - echo " try: cd $OSCAR64_DIR && make -C make compiler" >&2 - exit 1 -fi - -# --- parse args ----------------------------------------------------------- -SRC=main.c -EMU_CMD="" -PLAY_VICE="" -OPT_FLAGS="" - -for arg in "$@"; do - case "$arg" in - -e) EMU_CMD="oscar64" ;; - -v) EMU_CMD="x64" ;; - -V) EMU_CMD="x64sc" ;; - -p) PLAY_VICE="x64" ;; - -P) PLAY_VICE="x64sc" ;; - -c) ;; - -O0) OPT_FLAGS="$OPT_FLAGS -O0" ;; - -O1) OPT_FLAGS="$OPT_FLAGS -O1" ;; - -O2) OPT_FLAGS="$OPT_FLAGS -O2" ;; - -O3) OPT_FLAGS="$OPT_FLAGS -O3" ;; - -Os) OPT_FLAGS="$OPT_FLAGS -Os" ;; - -g) OPT_FLAGS="$OPT_FLAGS -g" ;; - -*) echo "unknown flag: $arg" >&2; exit 1 ;; - esac -done - -# Reject conflicting flag combinations: -v/-V (foreground VICE) and -# -p/-P (background VICE) would both fire, leaving two emulator windows. -if [ -n "$EMU_CMD" ] && [ -n "$PLAY_VICE" ]; then - echo "error: cannot combine a foreground VICE flag (-v/-V) with a play flag (-p/-P)" >&2 - echo " use -v to run in the foreground, or -p to detach and continue" >&2 - exit 1 -fi - -# --- compile -------------------------------------------------------------- -echo "compiling $SRC with $OSCAR64_BIN -> $BUILD_DIR/" -"$OSCAR64_BIN" -i="$OSCAR64_DIR/include" -o="$PRG" $OPT_FLAGS "$SRC" - -# build_d64() — wrap $PRG in $D64. c1541's exit code is unreliable -# (the interactive form always exits 0 even on failure), so the only -# reliable success signal is listing the disk afterwards and checking -# the PRG is there. The flag-form `c1541 -list image` doesn't work -# (c1541 treats it as a unit number), so we use the interactive -# heredoc form. All c1541 calls are wrapped in `|| true` so set -e -# doesn't trip on transient non-zero exits from the format / write -# steps; the final list-and-grep is the authoritative check. -build_d64() { - if ! command -v c1541 >/dev/null 2>&1; then - echo "error: c1541 not found (needed to build the .d64 wrapper)" >&2 - return 1 - fi - c1541 -format ny,of d64 "$D64" >/dev/null 2>&1 || true - c1541 "$D64" >/dev/null 2>&1 </dev/null <&2 - return 1 - fi -} - -# --- optional actions ----------------------------------------------------- -case "$EMU_CMD" in - "oscar64") - echo "running nyuller.prg in oscar64's built-in emulator" - "$OSCAR64_BIN" -i="$OSCAR64_DIR/include" -o="$PRG" $OPT_FLAGS -e "$SRC" - ;; - "x64"|"x64sc") - echo "wrapping $PRG in $D64 (VICE autostart needs a disk image)..." - build_d64 - if [ -z "${DISPLAY:-}" ]; then - echo "warning: no \$DISPLAY set; VICE won't show a window" >&2 - fi - echo "running nyuller in VICE ($EMU_CMD, blocking)" - "$EMU_CMD" +confirmonexit -drive8type 1541 -autostart "$D64" - ;; -esac - -if [ -n "$PLAY_VICE" ]; then - if [ -z "${DISPLAY:-}" ]; then - echo "error: no \$DISPLAY set; cannot launch VICE in a window" >&2 - exit 1 - fi - if ! command -v "$PLAY_VICE" >/dev/null 2>&1; then - echo "error: $PLAY_VICE not found in PATH" >&2 - exit 1 - fi - # If a previous VICE is still running, kill it before launching a - # new one — otherwise the two windows will fight for the same - # display and the old one's nyuller will keep running in the - # background. - existing=$(pgrep -f "x64(sc)? \+confirmonexit.*nyuller\.d64" 2>/dev/null || true) - if [ -n "$existing" ]; then - echo "killing previous VICE process(es): $existing" - kill $existing 2>/dev/null || true - sleep 1 - kill -9 $existing 2>/dev/null || true - fi - echo "wrapping $PRG in $D64 (VICE autostart needs a disk image)..." - build_d64 - echo "launching VICE $PLAY_VICE in the background with $D64..." - log="$BUILD_DIR/vice.log" - ( setsid nohup "$PLAY_VICE" +confirmonexit -drive8type 1541 -autostart "$D64" \ - > "$log" 2>&1 < /dev/null & echo $! > "$BUILD_DIR/vice.pid" ) - # setsid + nohup detach VICE from this shell so it survives our exit. - pid=$(cat "$BUILD_DIR/vice.pid") - sleep 1 - if kill -0 "$pid" 2>/dev/null; then - echo "" - echo "VICE launched (PID $pid). Look for the x64 window on your desktop." - echo "Default keys: Port 1 (Hare) = Arrows + Right Shift (fire)" - echo " Port 2 (Scoot) = W A S D + Left Ctrl (fire)" - echo "Rebind under Settings → Input devices → Joystick settings." - echo "To stop VICE later: ./build.sh --kill" - echo "Log file: $log" - else - echo "error: VICE failed to start; see $log for details" >&2 - exit 1 - fi -fi - -echo "done: $PRG" diff --git a/src/helloworld.c b/src/helloworld.c index 597d9c8..118ded4 100644 --- a/src/helloworld.c +++ b/src/helloworld.c @@ -2,9 +2,8 @@ // // Builds a .prg that prints "Hello World" on the C64 text screen and exits. // -// Build: ../scripts/build.sh -// Run: x64 helloworld.prg (or use ../scripts/build.sh -e to run in -// the built-in oscar64 emulator) +// Build: make compile +// Run: make run #include diff --git a/tasks.md b/tasks.md index fe21ea6..6650eb3 100644 --- a/tasks.md +++ b/tasks.md @@ -17,7 +17,7 @@ produces files in `./src/data/`. ## 0.1. Test environment **The oscar64 built-in emulator is the primary test tool.** It's -invoked with `build.sh -e` (or `oscar64 -i=… -e source.c`) and +invoked with `make run` (or `oscar64 -i=… -e source.c`) and runs the same `.prg` file the C64 will run, with no setup, no display, no ROMs, and at high speed. It is the default for the development loop and is what every phase's *Verify* step uses. @@ -28,7 +28,7 @@ In this headless environment, the ROMs had to be fetched manually, the KERNAL/BASIC/CHAR/1541 ROMs were not bundled with the package, and the autostart mechanism produced blank screenshots (no display to render to). We attempted to get VICE working and abandoned -the effort after deciding it wasn't worth the time. The `build.sh +the effort after deciding it wasn't worth the time. The `make run` -v` / `-V` flags remain in place for the rare case where someone has a real terminal session and wants to use VICE interactively, but **no phase of this project depends on VICE for verification**, @@ -36,11 +36,11 @@ and the `-v` / `-V` flags are *optional* additions, not required. | Tool | Headless? | Use it for | |------|-----------|------------| -| `build.sh -e` (oscar64 built-in) | Yes | Default for every Verify step. Fast, deterministic, runs in CI. | -| `build.sh -v` / `-V` (VICE) | No | Optional, interactive only. VICE is unreliable in this headless env and not used for verification. | +| `make run` (oscar64 built-in) | Yes | Default for every Verify step. Fast, deterministic, runs in CI. | +| `make run-vice` / `make run-vice-cycle` (VICE) | No | Optional, interactive only. VICE is unreliable in this headless env and not used for verification. | | `x128` / `xvic` / `xpet` | No | Out of scope (we target C64 PAL). | -**Bottom line for the plan:** every `Verify` step uses `build.sh -e` +**Bottom line for the plan:** every `Verify` step uses `make run` (unless explicitly noted). VICE is referenced only in Phase 8 (end-to-end testing) and in the optional Phase 9 (NTSC) — both of which assume a developer with a real terminal session will run @@ -64,11 +64,11 @@ the tests. runs. - [x] ✅ Repo initialized, oscar64 is a submodule at `./oscar64/`. -- [x] ✅ `src/helloworld.c` + `src/build.sh` produce +- [x] ✅ `src/helloworld.c` + `make compile` produce `build/helloworld.prg`. - [x] ✅ `GAME.md` written. - [x] ✅ Source artwork in `./source_images/`. -- [ ] ⏳ **Verify:** `cd src && ./build.sh -e` runs the hello-world +- [ ] ⏳ **Verify:** `cd src && ./make run` runs the hello-world program in the oscar64 built-in emulator. (Optional: launch `x64 build/helloworld.prg` in a real terminal session to see the screen.) @@ -168,7 +168,7 @@ state. pressed (active low: `(PEEK(0xDC00+port) & 0x10) == 0`). **Verify:** -- `cd src && ./build.sh -e` displays the title screen in the +- `cd src && ./make run` displays the title screen in the oscar64 built-in emulator for 5 seconds (or until fire is pressed) then exits. - (Optional, interactive) `x64 build/nyuller.prg` in a real @@ -303,7 +303,7 @@ random source. **Verify:** - The game still works in the oscar64 built-in emulator - (`build.sh -e`). + (`make run`). - (Optional, interactive) Launch `x64sc build/nyuller.prg` in a real terminal to confirm the game runs at cycle-exact PAL timing (50.125 Hz). The state transitions happen on the right @@ -432,7 +432,7 @@ with no rough edges. We also do the real-hardware test. transition. Just a quick low square wave. - [ ] Make sure scores are reset on entering GAMEOVER → TITLE. - [ ] Run the full game in the oscar64 built-in emulator - (`build.sh -e`) for the development loop, and (optionally, + (`make run`) for the development loop, and (optionally, when you have a real terminal session) in `x64` / `x64sc` for interactive play-testing and cycle-exact validation. Coverage: - P1 wins 5 in a row (cheat test: hold fire on port 1 the @@ -449,8 +449,8 @@ with no rough edges. We also do the real-hardware test. - [ ] If we have a real C64 or a Turbo Everdrive, test on real hardware. Otherwise document that we tested in the oscar64 emulator + `x64sc` cycle-exact mode. -- [ ] Strip `-g` from the release build. Add a `-O3` build - target to build.sh. +- [ ] Strip `-g` from the release build. Add a `make OPT=O3` build + target to Makefile (already supported via `make compile OPT=O3`). - [ ] Final pass: review the .map file, check no section is larger than expected, check no RAM region is over-allocated. - [ ] Final sanity check: load the release build into `x64sc`