Replace src/build.sh with Makefile (GNU make)
New targets: help (default) — show usage (was the -help/--help equivalent) compile — compile main.c → build/nyuller.prg run — compile + run in oscar64 built-in emulator run-vice — compile + run in VICE x64 (foreground) run-vice-cycle — compile + run in VICE x64sc (cycle-exact) play — compile + launch VICE x64 detached play-cycle — compile + launch VICE x64sc detached kill — kill any detached VICE clean — remove build/ artifacts build/nyuller.d64 — build the .d64 disk image from the .prg Optimization: override with 'make OPT=O3' (or O0/O1/O2/Os/g). Default is -O1 (oscar64 default). The Makefile builds oscar64 automatically if missing, uses c1541 to create the .d64 with verification, and passes -drive8type 1541 to VICE (required for autostart). Removed src/build.sh and updated all docs (README, tasks.md, AGENT_CONTEXT.md, GAME.md, helloworld.c) to reference make.
This commit is contained in:
+13
-12
@@ -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
|
||||
|
||||
-217
@@ -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 <repo>/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 <<EOF || true
|
||||
write $PRG
|
||||
EOF
|
||||
if c1541 "$D64" 2>/dev/null <<EOF | grep -q "nyuller.prg"
|
||||
list
|
||||
quit
|
||||
EOF
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "error: failed to write $PRG to $D64 (c1541 silently exited 0)" >&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"
|
||||
+2
-3
@@ -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 <stdio.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user