283 lines
14 KiB
Makefile
283 lines
14 KiB
Makefile
# Apple IIgs build rules (llvm-mos w65816: clang + llvm-mc + link816).
|
|
#
|
|
# make/support/iigs/clang-build.sh drives compile (clang) / assemble
|
|
# (llvm-mc) / link (link816) against the prebuilt w65816 runtime.
|
|
# Hand-rolled asm lives in src/iigs/*.s (llvm-mc GAS syntax);
|
|
# bank placement is handled by -ffunction-sections + link816
|
|
# dead-stripping.
|
|
#
|
|
# STATUS: the launchable-binary pipeline (multi-segment OMF emission +
|
|
# disk packaging + GS/OS launch) is still being brought up. `iigs-lib`
|
|
# compile-checks every library + example translation unit, and
|
|
# `iigs-clang-smoke` (not part of the default goal: it needs MAME)
|
|
# validates the full clang -> llvm-mc -> link816 -> MAME path end to end. Per-example binary targets build via
|
|
# clang-build.sh; large examples need the multi-segment OMF wiring still
|
|
# in progress.
|
|
#
|
|
# This file holds JoeyLib's library for the IIgs, programRules, the IIgs
|
|
# rules for one program, which make/programs.mk instantiates for every
|
|
# program, and the disk images made of programs (a project reaches all three
|
|
# through make/project.mk). JoeyLib's own examples and the IIgs gates are at
|
|
# the end.
|
|
|
|
PLATFORM := iigs
|
|
include $(dir $(lastword $(MAKEFILE_LIST)))/common.mk
|
|
|
|
OBJDIR := $(BUILD)/obj
|
|
|
|
CLANG := $(LLVM816_ROOT)/tools/llvm-mos-build/bin/clang
|
|
$(call requireTool,$(CLANG),toolchain:iigs)
|
|
$(call requireTool,$(IIGS_AS),toolchain:iigs)
|
|
$(call requireTool,$(IIGS_NTP_DIR)/ninjatrackerplus.s,toolchain:iigs)
|
|
LLVM_MC := $(LLVM816_ROOT)/tools/llvm-mos-build/bin/llvm-mc
|
|
AR := $(LLVM816_ROOT)/tools/llvm-mos-build/bin/llvm-ar
|
|
CCWRAP := $(LLVM816_ROOT)/scripts/ccRegallocFallback.sh
|
|
RT_INC := $(LLVM816_ROOT)/runtime/include
|
|
CFLAGS := --target=w65816 -O2 -ffreestanding -ffunction-sections $(EXTRA_CFLAGS)
|
|
INCLUDES := -I$(RT_INC) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/joey -I$(SRC_CORE) -I$(REPO_DIR)/src/codegen
|
|
LIB := $(LIBDIR)/libjoey.a
|
|
|
|
PORT_C_SRCS := $(wildcard $(SRC_DIR)/iigs/*.c)
|
|
# Hand-rolled asm, migrated to llvm-mc GAS .s.
|
|
PORT_ASM_SRCS := $(wildcard $(SRC_DIR)/iigs/*.s)
|
|
|
|
# IIgs uses NTPstreamsound for SFX, not the libxmp+overlay combo that
|
|
# DOS and ST share, so src/core/audioSfxMix.c is unused here.
|
|
CORE_C_SRCS_IIGS := $(filter-out %/audioSfxMix.c, $(CORE_C_SRCS))
|
|
|
|
# Sprite codegen: the 65816 emitter (spriteEmitIigs.c) now lives in src/iigs/
|
|
# and is picked up by PORT_C_SRCS; only the CPU-independent compile dispatch
|
|
# remains in src/codegen.
|
|
CODEGEN_SRCS := $(REPO_DIR)/src/codegen/spriteCompile.c $(REPO_DIR)/src/codegen/spriteStage.c
|
|
|
|
LIB_C_SRCS := $(CORE_C_SRCS_IIGS) $(GENERIC_C_SRCS) $(PORT_C_SRCS) $(CODEGEN_SRCS)
|
|
LIB_SRCS := $(LIB_C_SRCS) $(PORT_ASM_SRCS)
|
|
|
|
# Library header set for archive rebuild triggering (coarse on purpose: any
|
|
# header change forces a full lib recompile -- a needless rebuild is safe, a
|
|
# missed one is not).
|
|
IIGS_LIB_HDRS := $(wildcard $(INCLUDE_DIR)/joey/*.h) $(wildcard $(SRC_CORE)/*.h) $(wildcard $(REPO_DIR)/src/codegen/*.h) $(wildcard $(SRC_DIR)/iigs/*.h) $(wildcard $(REPO_DIR)/src/m68k/*.h)
|
|
|
|
# NinjaTrackerPlus replayer: Merlin32-assemble ninjatrackerplus.s to a 34KB
|
|
# binary that ships next to the program; jlpAudioInit loads "ntpplayer" from
|
|
# disk at run time (src/iigs/audio_full.c NTP_PATH), so every disk a program
|
|
# goes on carries it (make-iigs-disk.sh). The source is assembled
|
|
# with JoeyLib's interrupt window added to NTPstreamsound (NTP_PATCH).
|
|
NTP_SRC := $(IIGS_NTP_DIR)/ninjatrackerplus.s
|
|
NTP_PATCH := $(REPO_DIR)/make/support/iigs/ntpIrqWindow.py
|
|
NTP_BIN := $(BUILD)/audio/ntpplayer.bin
|
|
IIGS_MERLIN := $(IIGS_AS)
|
|
|
|
$(NTP_BIN): $(NTP_SRC) $(NTP_PATCH) $(IIGS_MERLIN)
|
|
@mkdir -p $(BUILD)/audio
|
|
@python3 $(NTP_PATCH) $(NTP_SRC) $(BUILD)/audio/ninjatrackerplus.s
|
|
cd $(BUILD)/audio && $(IIGS_MERLIN) . ninjatrackerplus.s
|
|
mv $(BUILD)/audio/ntpplayer $@
|
|
|
|
# Compile-check every library and example translation unit with clang,
|
|
# and assemble every .s with llvm-mc. This is the canonical "does the
|
|
# IIgs source still build" gate while the launchable pipeline is wired.
|
|
# The real static library: compile every library TU (through the regalloc
|
|
# fallback, matching clang-build.sh) + assemble every .s, then archive them
|
|
# into libjoey.a. link816 reads the archive natively and --gc-sections selects
|
|
# what each example references, so examples link $(LIB) exactly like the other
|
|
# ports. `iigs-lib' is kept as the canonical build/compile-check entry point.
|
|
$(LIB): $(LIB_SRCS) $(IIGS_LIB_HDRS)
|
|
@mkdir -p $(OBJDIR) $(LIBDIR)
|
|
@set -e; objs=""; \
|
|
for c in $(LIB_C_SRCS); do \
|
|
o=$(OBJDIR)/$$(echo $$c | sed 's#[/.]#_#g').o; \
|
|
echo " CC $$c"; \
|
|
$(CCWRAP) $(CLANG) $(CFLAGS) $(INCLUDES) -c $$c -o $$o; \
|
|
objs="$$objs $$o"; \
|
|
done; \
|
|
for s in $(PORT_ASM_SRCS); do \
|
|
o=$(OBJDIR)/$$(basename $$s .s).o; \
|
|
echo " AS $$s"; \
|
|
$(LLVM_MC) -arch=w65816 -filetype=obj $$s -o $$o; \
|
|
objs="$$objs $$o"; \
|
|
done; \
|
|
rm -f $@; \
|
|
echo " AR $@"; \
|
|
$(AR) rcs $@ $$objs
|
|
|
|
iigs-lib: $(LIB)
|
|
|
|
# ---- programs -----------------------------------------------------------------
|
|
# A program is an S16 OMF named NAME, in bin/. It runs off a ProDOS volume:
|
|
# make-iigs-disk.sh packs programs, NTP and their DATA onto a data disk, and
|
|
# make-iigs-game-disk.sh one program into a bootable volume (below). DATA is
|
|
# staged apart for that, in build/iigs/data/NAME/DATA, and the optional files
|
|
# in build/iigs/data/NAME/OPTIONAL (make/common.mk's programOptionalDir).
|
|
PROGRAM_EXT :=
|
|
PROGRAM_DATA_APART := yes
|
|
PROGRAM_OPTIONAL_APART := yes
|
|
DEP_DIR := $(PROGRAM_BUILD)/dep
|
|
|
|
# One program, $(1) its id: clang-build.sh compiles, links and wraps it, and
|
|
# writes one header-dependency file for all its sources. ID_IIGS_OVERFLOW_CAP
|
|
# opts into large overflow segments (see clang-build.sh). NTP rides on every
|
|
# disk a program goes on, so it is built first.
|
|
define programRules
|
|
$(if $(call programVar,$(1),OVERFLOW_CAP),$(call programBin,$(1)): export JOEY_OVERFLOW_CAP := $(call programVar,$(1),OVERFLOW_CAP))
|
|
$(call programBin,$(1)): $(call programVar,$(1),SRCS) $(LIB) $(IIGS_CLANG_BUILD) | $(NTP_BIN)
|
|
@mkdir -p $$(dir $$@) $(DEP_DIR)
|
|
$(IIGS_CLANG_BUILD) -M $(DEP_DIR)/$(1).d $(call programVar,$(1),CFLAGS) $(INCLUDES) -o $$@ $(call programVar,$(1),SRCS) $(LIB)
|
|
endef
|
|
|
|
-include $(wildcard $(DEP_DIR)/*.d)
|
|
|
|
# ONE self-booting volume per program (ID_IIGS_GAME_DISK; iigs-game-disk
|
|
# GAME=NAME for any): a GS/OS system stripped to what JoeyLib actually uses,
|
|
# a launcher in place of the Finder, and the program in its own folder so
|
|
# that folder can be copied to a hard drive and run from there. Boot to the
|
|
# program is 21.8 s against 43.4 s for the two-floppy boot disk. The size is
|
|
# chosen per program: one that fits beside a stripped system gets a bootable
|
|
# 800KB 3.5" floppy, and a bigger one a 2048KB volume, which MAME can only
|
|
# boot off a CFFA2 card because its 3.5 drive is 800KB GCR:
|
|
# mame apple2gs -sl7 cffa2 -hard1 build/iigs/bin/NAME.2mg
|
|
# GAME_DISK_SIZE forces a size. Each builds its OWN one-program data disk
|
|
# (NAME-data.2mg) first rather than using JoeyLib's joey.2mg, which carries
|
|
# the small examples and whose exact contents the gates depend on.
|
|
IIGS_GAME_DISKS = $(foreach p,$(PORT_PROGRAMS),$(if $(call programVar,$(p),GAME_DISK),$(call programName,$(p))))
|
|
IIGS_GAME = $(or $(GAME),$(firstword $(IIGS_GAME_DISKS)))
|
|
PORT_PACKAGES = $(if $(IIGS_GAME_DISKS),iigs-game-disks)
|
|
|
|
# The commands that make program $$g's (a shell variable's) game disk.
|
|
IIGS_GAME_DISK_CMDS = BINDIR="$(BINDIR)" NTP_BIN="$(NTP_BIN)" JOEY_DISK_EXAMPLES="$$g" \
|
|
$(REPO_DIR)/scripts/make-iigs-disk.sh $(BINDIR)/$$g-data.2mg && \
|
|
JOEY_GAME_DISK_SIZE="$(or $(GAME_DISK_SIZE),auto)" \
|
|
$(REPO_DIR)/scripts/make-iigs-game-disk.sh $(BINDIR)/$$g.2mg $$g $$g $(BINDIR)/$$g-data.2mg
|
|
|
|
.PHONY: iigs-game-disk iigs-game-disks iigs-verify-game-disk
|
|
iigs-game-disk: programs $(NTP_BIN)
|
|
g=$(IIGS_GAME); $(IIGS_GAME_DISK_CMDS)
|
|
|
|
iigs-game-disks: programs $(NTP_BIN)
|
|
@set -e; for g in $(IIGS_GAME_DISKS); do $(IIGS_GAME_DISK_CMDS); done
|
|
|
|
# Boot one game disk headlessly and assert it reaches the program and draws.
|
|
# An 800KB image goes in the 3.5 drive, a larger one on a CFFA2 card.
|
|
iigs-verify-game-disk: iigs-game-disk
|
|
$(REPO_DIR)/scripts/verify-iigs-game-disk.sh $(BINDIR)/$(IIGS_GAME).2mg
|
|
|
|
# ---- JoeyLib's own build: its examples and the IIgs gates -----------------------
|
|
ifndef JOEY_PROJECT
|
|
|
|
include $(REPO_DIR)/make/examples.mk
|
|
include $(REPO_DIR)/make/programs.mk
|
|
|
|
# Default: build (compile-check) the library. The MAME smoke test is
|
|
# `iigs-clang-smoke`; disks and examples are `iigs-disk`.
|
|
.DEFAULT_GOAL := all
|
|
.PHONY: all iigs iigs-lib iigs-clang-smoke iigs-examples iigs-disk iigs-disk-all iigs-verify iigs-verify-all iigs-verify-audio iigs-verify-save iigs-verify-serial iigs-verify-serial-loss iigs-verify-shrtail iigs-verify-tilebank clean-iigs clean
|
|
all iigs: iigs-lib
|
|
|
|
# Per-example launchable binaries with their DATA -- all of them: leaving
|
|
# some out once made `make iigs` silently test 8-day-old binaries against new
|
|
# assets.
|
|
iigs-examples: programs
|
|
|
|
# Build the JOEYLIB data disk (build/iigs/bin/joey.2mg) that the gates, and
|
|
# `joey-run build/iigs/bin/joey.2mg`, mount beside GS/OS. Packs the launchable
|
|
# examples as ProDOS S16 apps (an 800KB floppy can't hold every example; see
|
|
# make-iigs-disk.sh) with their DATA. NTP_BIN rides along so jlpAudioInit's
|
|
# runtime load of "ntpplayer" finds it on the volume -- without it every
|
|
# example logs "audioInit failed".
|
|
iigs-disk: programs $(NTP_BIN)
|
|
BINDIR="$(BINDIR)" NTP_BIN="$(NTP_BIN)" $(REPO_DIR)/scripts/make-iigs-disk.sh $(BINDIR)/joey.2mg
|
|
|
|
# Every launchable example on one image. The full set will not fit an 800KB
|
|
# 3.5" floppy, so this is a 16 MB ProDOS hard-disk image (joey-all.2mg): boot
|
|
# it in MAME with
|
|
# `-sl7 cffa2 -hard1 <GS/OS> -hard2 build/iigs/bin/joey-all.2mg` and launch
|
|
# any example from the JOEYLIB volume in the Finder.
|
|
iigs-disk-all: programs $(NTP_BIN)
|
|
BINDIR="$(BINDIR)" NTP_BIN="$(NTP_BIN)" \
|
|
JOEY_DISK_SIZE="16MB" \
|
|
JOEY_DISK_EXAMPLES="DRAW PATTERN KEYS JOY SPRITE SERIAL SERTEST SAVE TILEBANK AUDIO UBER ADV2 ADV" \
|
|
$(REPO_DIR)/scripts/make-iigs-disk.sh $(BINDIR)/joey-all.2mg
|
|
|
|
# Headless visual-verification gate: boot GS/OS under MAME, launch the DRAW
|
|
# example off joey.2mg, and assert the SHR framebuffer was actually rendered
|
|
# (many distinct colors -> pixels/lines/circles/tiles/flood all drew). Pass
|
|
# VERIFY_EXAMPLE=name to check a different example.
|
|
iigs-verify: iigs-disk
|
|
$(REPO_DIR)/scripts/verify-iigs.sh $(or $(VERIFY_EXAMPLE),draw)
|
|
|
|
# Audio gate: AUDIOPRB (AUDIO pressing its own keys, make/examples.mk) off a
|
|
# one-program disk of its own: NTP's sound interrupt installed, the DOC's
|
|
# master volume up, and the tracker's, the noise's and the stream's slots
|
|
# carrying waveforms (~10 s).
|
|
iigs-verify-audio: $(call programBin,AUDIOPRB) $(NTP_BIN)
|
|
$(REPO_DIR)/scripts/verify-iigs-audio.sh $(call programBin,AUDIOPRB)
|
|
|
|
# Cross-channel SCC gate: opening the modem port must leave the printer channel
|
|
# (AppleTalk's) transmitting. Builds its own one-example disk; ~2 min.
|
|
iigs-verify-serial: $(call programBin,SCCPROBE)
|
|
$(REPO_DIR)/scripts/verify-iigs-serial.sh
|
|
|
|
# Receive-loss gate: 4096 bytes streamed at 9600 baud while the program does
|
|
# nothing but full-screen presents must all arrive. Runs the modem port (SCC)
|
|
# and a Super Serial Card in slot 2 (6551) on the installed MAME, with the SCC
|
|
# receive FIFO cut to the real chip's 3 bytes (JOEY_Z80SCC_RX_FIFO=3) and the
|
|
# card's a2ssc firmware from iigsFirmware; see the script header. ~3 min per mode.
|
|
# The card runs at SERLOSS_SSC_BAUD (make/examples.mk says why).
|
|
iigs-verify-serial-loss: $(call programBin,SERLOSS) $(call programBin,SERLOSSS)
|
|
$(REPO_DIR)/scripts/verify-iigs-serial-loss.sh scc
|
|
SERLOSS_BAUD=$(SERLOSS_SSC_BAUD) $(REPO_DIR)/scripts/verify-iigs-serial-loss.sh ssc
|
|
|
|
# Boot-verify every launchable example on joey.2mg (per-example thresholds).
|
|
iigs-verify-all: iigs-disk
|
|
$(REPO_DIR)/scripts/verify-iigs-all.sh
|
|
|
|
# Gate the 712 display-state bytes ABOVE the pixel block: the SCB array
|
|
# ($E1:9D00-$9DC7) and all 16 palettes ($E1:9E00-$9FFF). Nothing else in the
|
|
# tree can see them -- the golden hash covers the STAGE, not $E1, and P9's
|
|
# pixel compare stops at $9CFF -- so a wrong palette is invisible to every
|
|
# other gate and shows only as wrong colors on a real screen. That blind spot
|
|
# is why a phantom "PEI-slam corrupts palettes 1-15" note survived five weeks.
|
|
#
|
|
# UBER's shrTailUpload / shrTailSlam rows live behind #ifdef UBER_PROBE, which
|
|
# no normal build defines, so this target benches UBERPROB (make/examples.mk:
|
|
# UBER built with them, into build/iigs/probe/bin) off a single-app disk of its
|
|
# own. The goldened UBER binary, joey.2mg and joeylog.txt are all left
|
|
# untouched.
|
|
IIGS_PROBE_DIR := $(PROGRAM_BUILD)/probe
|
|
|
|
iigs-verify-shrtail: $(call programBin,UBERPROB) $(NTP_BIN)
|
|
BINDIR="$(call programDir,UBERPROB)" NTP_BIN="$(NTP_BIN)" JOEY_DISK_EXAMPLES="UBER" \
|
|
$(REPO_DIR)/scripts/make-iigs-disk.sh $(IIGS_PROBE_DIR)/uberprobe.2mg
|
|
BENCH_DATA_DISK="$(IIGS_PROBE_DIR)/uberprobe.2mg" BENCH_OUT_LOG="$(IIGS_PROBE_DIR)/probelog.txt" \
|
|
BENCH_MAX_FRAMES="$(or $(PROBE_MAX_FRAMES),45000)" $(REPO_DIR)/scripts/bench-iigs.sh
|
|
@grep -E 'shrParity|shrTailUpload|shrTailSlam' $(IIGS_PROBE_DIR)/probelog.txt || \
|
|
{ echo "iigs-verify-shrtail: FAIL - no probe rows captured" >&2; exit 1; }
|
|
@grep -qE 'shrTail(Upload|Slam) FAIL' $(IIGS_PROBE_DIR)/probelog.txt && \
|
|
{ echo "iigs-verify-shrtail: FAIL - \$$E1 SCB/palette block mismatched the stage" >&2; exit 1; } || true
|
|
@echo "iigs-verify-shrtail: PASS"
|
|
|
|
# Tile-bank gate: TILEBANK loads this port's own .tbk bake both ways off its
|
|
# own one-example disk; both must hash like the host gate's, and every other
|
|
# target's bake must be refused. NTP_BIN keeps the disk's audio init quiet.
|
|
iigs-verify-tilebank: $(call programBin,TILEBANK) $(TILEBANK_DATA) $(NTP_BIN)
|
|
$(REPO_DIR)/scripts/verify-iigs-tilebank.sh
|
|
|
|
# Runtime gate for the save HAL's GS/OS calls (Create + GetDevNumber/DInfo/
|
|
# Volume): boots SAVE under MAME and checks the save-OK lamp + disk-free bar.
|
|
iigs-verify-save: $(call programBin,SAVE) $(call programBin,DRAW)
|
|
$(REPO_DIR)/scripts/verify-iigs-save.sh
|
|
|
|
# End-to-end smoke test: clang -> llvm-mc -> link816 -> MAME, validating
|
|
# the ported asm computes correctly on emulated hardware.
|
|
iigs-clang-smoke:
|
|
$(REPO_DIR)/make/support/iigs/clang-smoke.sh
|
|
|
|
clean-iigs:
|
|
rm -rf $(BUILD)
|
|
|
|
# `clean` as an alias for `clean-iigs`. Without it a bare
|
|
# `make -f make/iigs.mk clean` FAILS -- and with stderr discarded that
|
|
# looks like success while leaving stale objects the next build links.
|
|
clean: clean-iigs
|
|
|
|
endif
|