# Sharp X68000 (elf2x68k / m68k-xelf-gcc) build rules. # # The port draws planar into the text plane (src/x68000/halPlanar.c), shares # the Amiga's 68k planar fills, plots and sprite emitter (src/m68k), plays # chip music on the OPM and samples through the ADPCM channel. # # The toolchain is elf2x68k (BSD-3, gcc 13.4.0 / binutils / newlib), installed # by ./install.sh (X68K_ROOT). m68k-xelf-gcc emits ELF; the driver's # -Wl,-elf2x68k pass converts it to a Human68k .X. include $(dir $(lastword $(MAKEFILE_LIST)))/common.mk # The libxmp-lite rules below define a real target before `all`, which would # otherwise silently become make's default goal (symptom: a bare `make -f # make/x68000.mk` reports only "libxmplite.a is up to date" and builds nothing). .DEFAULT_GOAL := all $(call requireTool,$(X68K_ROOT)/bin/m68k-xelf-gcc,toolchain:x68000) $(call requireTool,$(LIBXMP_DIR)/include/libxmp-lite/xmp.h,toolchain:x68000) PLATFORM := x68000 BUILD := $(REPO_DIR)/build/$(PLATFORM) LIBDIR := $(BUILD)/lib BINDIR := $(BUILD)/bin X68K_CC := $(X68K_ROOT)/bin/m68k-xelf-gcc X68K_AR := $(X68K_ROOT)/bin/m68k-xelf-ar # The linker is driven by a wrapper script (m68k-elf/bin/ld.x) that shells out # to `m68k-xelf-ld.bfd` by bare name, so the toolchain's own bin/ MUST be on # PATH or the link dies with "m68k-xelf-ld.bfd: command not found". Compiling # and archiving work fine without it, so this only bites at link time. export PATH := $(X68K_ROOT)/bin:$(PATH) CFLAGS := $(COMMON_CFLAGS) -m68000 -fomit-frame-pointer \ -DJOEYLIB_PLATFORM_X68000 \ -I$(LIBXMP_DIR)/include \ -I$(SRC_DIR)/x68000 -I$(SRC_68K) -I$(REPO_DIR)/src/codegen -MMD -MP LDFLAGS := -lm PORT_C_SRCS := $(wildcard $(SRC_DIR)/x68000/*.c) # Raw interrupt shims (timer tick, frame count, SCB raster, SCC receive): each # saves every register and returns with RTE, which a C function cannot. And # the present's copy (x68kPresent.s). PORT_S_SRCS := $(wildcard $(SRC_DIR)/x68000/*.s) # Sprite codegen is the shared 68k PLANAR emitter, unchanged. Its # AMIGA_PLANE_STRIDE is SURFACE_WIDTH/8 = 40, which is this port's surface # stride too -- the display's 128-byte stride never reaches the emitter, which # only ever addresses the surface. So sprites COMPILE here rather than # interpret; spriteEmitStub.o is gone. CODEGEN_DIR := $(REPO_DIR)/src/codegen LIB_OBJS := \ $(patsubst $(SRC_CORE)/%.c,$(BUILD)/obj/core/%.o,$(CORE_C_SRCS)) \ $(patsubst $(SRC_DIR)/generic/%.c,$(BUILD)/obj/generic/%.o,$(GENERIC_C_SRCS)) \ $(patsubst $(SRC_DIR)/x68000/%.c,$(BUILD)/obj/port/%.o,$(PORT_C_SRCS)) \ $(patsubst $(SRC_DIR)/x68000/%.s,$(BUILD)/obj/port/%.o,$(PORT_S_SRCS)) \ $(BUILD)/obj/68k/planarFill.o \ $(BUILD)/obj/68k/planarPlot.o \ $(BUILD)/obj/68k/stageBands.o \ $(BUILD)/obj/68k/spriteEmitPlanar68k.o \ $(BUILD)/obj/codegen/spriteCompile.o \ $(BUILD)/obj/codegen/spriteStage.o # libxmp-lite: the Protracker decoder shared with the DOS and ST ports. Same # build recipe as make/atarist.mk -- LIBXMP_CORE_DISABLE_IT keeps it off math.h, # which this newlib does not usefully provide for a 68000 target. # LIBXMP_DIR comes from the installer's config.mk. LIBXMP_SRC := $(filter-out %/win32.c, $(wildcard $(LIBXMP_DIR)/src/*.c) $(wildcard $(LIBXMP_DIR)/src/loaders/*.c)) LIBXMP_OBJDIR := $(BUILD)/obj/libxmp-lite LIBXMP_OBJS := $(patsubst $(LIBXMP_DIR)/src/%.c,$(LIBXMP_OBJDIR)/%.o,$(LIBXMP_SRC)) LIBXMP_AR := $(LIBDIR)/libxmplite.a LIBXMP_CFLAGS := -DLIBXMP_CORE_PLAYER -DLIBXMP_CORE_DISABLE_IT -DHAVE_FNMATCH=0 \ -I$(LIBXMP_DIR)/include -I$(LIBXMP_DIR)/include/libxmp-lite \ -I$(LIBXMP_DIR)/src -Wno-error -w $(LIBXMP_OBJDIR)/%.o: $(LIBXMP_DIR)/src/%.c @mkdir -p $(dir $@) $(X68K_CC) $(COMMON_CFLAGS) -m68000 -fomit-frame-pointer $(LIBXMP_CFLAGS) -c $< -o $@ $(LIBXMP_AR): $(LIBXMP_OBJS) @mkdir -p $(dir $@) $(X68K_AR) rcs $@ $(LIBXMP_OBJS) LIB := $(LIBDIR)/libjoey.a # Every example but Space Taxi is its sources plus the library, linked by the # one rule below. Worth knowing which ones the gates use: # PATTERN the SCB acceptance vehicle: 8 bands of 25 lines with 8 gradient # palettes, so a misplaced band boundary is immediately visible. # UBER the golden-hash vehicle: every public op, a hash per op, which # tools/diff-uber-hashes compares against the IIgs reference. # AUDIO both audio paths: JYM1 chip music on the OPM, MOD/SFX on ADPCM. # KEYS the input and mouse vehicle: key predicates, the typed line # (jlInputGetChar) and its verification row. # SERIAL the RS-232C gate's echo program. # SERMOUSE the serial + mouse gate's program: streams both ways on the # RS-232C port (SCC channel A) while the mouse (channel B) moves. # TILEBANK the tile-bank gate's program: this port's .tbk bake loaded both # ways and pixel-checked, every other target's bake refused. # SCB the SCB gate's program: all 16 palettes, 147 palette changes a # frame (every line for 128 of them), for the raster interrupt # that reloads the text plane's one palette as the beam scans. HELLO_SRC := $(EXAMPLES)/hello/hello.c PATTERN_SRC := $(EXAMPLES)/pattern/pattern.c DRAW_SRC := $(EXAMPLES)/draw/draw.c KEYS_SRC := $(EXAMPLES)/keys/keys.c SERIAL_SRC := $(EXAMPLES)/serial/serial.c SERTEST_SRC := $(EXAMPLES)/sertest/sertest.c SERMOUSE_SRC := $(EXAMPLES)/sermouse/sermouse.c SAVE_SRC := $(EXAMPLES)/save/save.c TILEBANK_SRC := $(EXAMPLES)/tilebank/tilebank.c SCB_SRC := $(EXAMPLES)/scb/scb.c JOY_SRC := $(EXAMPLES)/joy/joy.c SPRITE_SRC := $(EXAMPLES)/sprite/sprite.c AUDIO_SRC := $(EXAMPLES)/audio/audio.c UBER_SRC := $(EXAMPLES)/uber/uber.c ADV_SRC := $(EXAMPLES)/adventure/adventure.c ADV2_SRC := $(EXAMPLES)/adventure2/adventure2.c AGI_SRC := $(EXAMPLES)/agi/agi.c $(EXAMPLES)/agi/agiRes.c $(EXAMPLES)/agi/agiPic.c $(EXAMPLES)/agi/agiView.c $(EXAMPLES)/agi/agiVm.c $(EXAMPLES)/agi/agiObj.c $(EXAMPLES)/agi/agiText.c EXAMPLES_X := HELLO PATTERN DRAW KEYS SERIAL SERTEST SERMOUSE SAVE TILEBANK SCB JOY SPRITE AUDIO UBER ADV ADV2 AGI EXAMPLE_BINS := $(foreach e,$(EXAMPLES_X),$(BINDIR)/$(e).X) # AUDIO loads DATA/test.mod and DATA/test.sfx from beside the program. DATA_DIR := $(BINDIR)/DATA DATA_FILES := $(DATA_DIR)/test.mod $(DATA_DIR)/test.sfx # TILEBANK's DATA/tilebank: this port's bake of the tile-bank fixture, the # other targets' bakes it must refuse, and the expected pixels (common.mk). TILEBANK_DATA := $(DATA_DIR)/tilebank/own.tbk # Space Taxi ships in its own folder with its DATA, as on the other ports, # so its megabyte of data never rides onto every other program's floppy. STAXI_DIR := $(BINDIR)/STAXI STAXI_BIN := $(STAXI_DIR)/STAXI.X STAXI_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stAudio.c $(EXAMPLES)/spacetaxi/stLevelCels.c .PHONY: all x68000 x68000-lib x68000-examples x68000-verify-serial x68000-verify-mouse x68000-verify-serial-mouse x68000-verify-serial-scb x68000-verify-joy x68000-verify-tilebank x68000-verify-scb x68000-verify-golden clean-x68000 clean all x68000: x68000-lib x68000-examples x68000-lib: $(LIB) $(LIBXMP_AR) x68000-examples: $(EXAMPLE_BINS) $(STAXI_BIN) $(DATA_FILES) $(TILEBANK_DATA) $(BUILD)/obj/core/%.o: $(SRC_CORE)/%.c @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -c $< -o $@ $(BUILD)/obj/generic/%.o: $(SRC_DIR)/generic/%.c @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -c $< -o $@ # Port-local asm. Same object dir as the port C objects; make picks between the # two pattern rules by which prerequisite exists. $(BUILD)/obj/port/%.o: $(SRC_DIR)/x68000/%.s @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -c $< -o $@ $(BUILD)/obj/68k/%.o: $(SRC_68K)/%.s @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -c $< -o $@ $(BUILD)/obj/68k/%.o: $(SRC_68K)/%.c @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -c $< -o $@ $(BUILD)/obj/codegen/%.o: $(CODEGEN_DIR)/%.c @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -I$(CODEGEN_DIR) -c $< -o $@ $(BUILD)/obj/port/%.o: $(SRC_DIR)/x68000/%.c @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -c $< -o $@ $(LIB): $(LIB_OBJS) @mkdir -p $(dir $@) $(X68K_AR) rcs $@ $(LIB_OBJS) .SECONDEXPANSION: $(EXAMPLE_BINS): $(BINDIR)/%.X: $$($$*_SRC) $(LIB) $(LIBXMP_AR) @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) $($*_SRC) $(LIB) $(LIBXMP_AR) $(LDFLAGS) -o $@ $(DATA_DIR)/%: $(REPO_DIR)/assets/% @mkdir -p $(dir $@) cp $< $@ $(TILEBANK_DATA): $(TILEBANK_BAKE_DEPS) python3 $(TILEBANK_STAGE) $(PLATFORM) $(TILEBANK_PNG) $(dir $@) # Space Taxi asset variables (the rules follow the binary below); make # expands prerequisites when it reads the rule, so these come first. STAXI_GEN_DIR := $(EXAMPLES)/spacetaxi/generated/x68000 STAXI_RUN_DIR := $(STAXI_DIR)/DATA STAXI_LEVEL_GEN := $(foreach n,$(STAXI_LEVEL_NUMS),$(STAXI_GEN_DIR)/levels/level$(n).dat) \ $(STAXI_GEN_DIR)/levels/title.dat STAXI_LEVEL_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_LEVEL_GEN)) SPRITEBAKE_BIN := $(REPO_DIR)/build/tools/spritebake-x68000 STAXIBAKE_BIN := $(REPO_DIR)/build/tools/staxibake STAXICELS_SPR_GEN := $(STAXI_GEN_DIR)/sprites/staxicels.spr STAXICELS_SPC_GEN := $(STAXICELS_SPR_GEN:.spr=.spc) STAXICELS_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXICELS_SPC_GEN)) STAXI_ASSET_DSTS := $(STAXI_LEVEL_RUN) $(STAXICELS_SPC_RUN) # Per-level hook-sprite banks: the cels stLevelCelList names for each # level that has hook sprites, baked from its level file and pre-compiled # for this target, so no cel is JIT-compiled mid-ride. Levels without # hook sprites have no bank; the game JIT-compiles at level entry when a # bank is missing. # ...except on the X68000, where they do not fit. The Human68k floppy is # 1232 KB and these eight banks are 787 KB of it (level09 alone is 236 KB, # level10 175, level17 165), which with the 296 KB binary, the levels and # the speech put the disk about 300 KB over however small speech gets. # stRenderLevelCels already handles their absence the right way: it builds # and compiles the level's cels at ENTRY, behind the LOADING bar, so the # ride itself still never compiles. That is also what spacetaxi.c's # codegen-arena comment says the 68k ports are meant to do -- their cels # are big and their JIT is fast. Set STAXI_CEL_LEVELS to the list above to # ship them again if the payload ever moves to a hard disk image. STAXI_CEL_LEVELS := STAXILEVEL_SPR_GEN := $(foreach n,$(STAXI_CEL_LEVELS),$(STAXI_GEN_DIR)/sprites/level$(n).spr) STAXILEVEL_SPC_GEN := $(STAXILEVEL_SPR_GEN:.spr=.spc) STAXILEVEL_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXILEVEL_SPC_GEN)) STAXI_ASSET_DSTS += $(STAXILEVEL_SPC_RUN) # Speech baked to sample bytes per passenger pitch (assets/genSpeechPcm.py): # expanding bits at play time is what keeps "HEY TAXI" from stalling the # ride; the C64 run-length source stays in stSpeechData.c as the input. STAXI_SPEECH_GEN := $(STAXI_GEN_DIR)/speech.bin STAXI_SPEECH_RUN := $(STAXI_RUN_DIR)/speech.bin STAXI_ASSET_DSTS += $(STAXI_SPEECH_RUN) $(STAXI_SPEECH_GEN): $(EXAMPLES)/spacetaxi/stSpeechData.c $(EXAMPLES)/spacetaxi/assets/genSpeechPcm.py @mkdir -p $(dir $@) # --single: one polarity, 60 KB instead of 120 KB. The 1232 KB # Human68k floppy cannot hold the two-polarity file alongside the # binary and the levels -- it came up 18 KB short -- and the player # negates the samples itself when the running polarity is odd. python3 $(EXAMPLES)/spacetaxi/assets/genSpeechPcm.py $< $@ --single $(STAXI_SPEECH_RUN): $(STAXI_SPEECH_GEN) @mkdir -p $(dir $@) cp $< $@ # Space Taxi. -s (strip) because the image it ships on is a 1232 KB # Human68k floppy: the unstripped binary is most of the volume on its # own. The DATA tree next to it (levels + the precompiled cel bank) is # what joey-run copies onto the data floppy. $(STAXI_BIN): $(STAXI_SRCS) $(LIB) $(LIBXMP_AR) $(call staxiData,$(STAXI_ASSET_DSTS)) @mkdir -p $(dir $@) $(X68K_CC) $(CFLAGS) -s -I$(EXAMPLES)/spacetaxi $(STAXI_SRCS) $(LIB) $(LIBXMP_AR) $(LDFLAGS) -o $@ # Space Taxi asset staging, the amiga.mk pattern cut down to what this # port loads at run time: the 24 levels + title extracted from the C64 # dump, and the cel bank baked by staxibake and pre-compiled for THIS # target by spritebake-x68000 (the planar 68k emitter under target byte # 5, so an Amiga or DOS bank is refused by the loader). Tiles and the # font come from the C64 data in stC64Data.c, so no .tbk is staged. .SECONDARY: $(STAXI_LEVEL_GEN) $(STAXICELS_SPR_GEN) $(STAXICELS_SPC_GEN) $(STAXILEVEL_SPR_GEN) $(STAXILEVEL_SPC_GEN) $(STAXI_LEVEL_GEN) &: $(STAXI_RAW_DUMP) $(ROMTOLEVEL_BIN) @mkdir -p $(STAXI_GEN_DIR)/levels python3 $(ROMTOLEVEL_BIN) $(STAXI_RAW_DUMP) $(STAXI_GEN_DIR)/levels $(SPRITEBAKE_BIN): FORCE $(MAKE) -f $(REPO_DIR)/make/tools.mk spritebake-x68000 $(STAXIBAKE_BIN): FORCE $(MAKE) -f $(REPO_DIR)/make/tools.mk staxibake $(STAXICELS_SPR_GEN): $(STAXIBAKE_BIN) $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stC64Data.c @mkdir -p $(dir $@) $(STAXIBAKE_BIN) $@ $(STAXI_GEN_DIR)/sprites/%.spc: $(STAXI_GEN_DIR)/sprites/%.spr $(SPRITEBAKE_BIN) $(SPRITEBAKE_BIN) $< $@ $(STAXI_RUN_DIR)/levels/%.dat: $(STAXI_GEN_DIR)/levels/%.dat @mkdir -p $(dir $@) cp $< $@ $(STAXI_RUN_DIR)/sprites/%.spc: $(STAXI_GEN_DIR)/sprites/%.spc @mkdir -p $(dir $@) cp $< $@ # Both-directions RS-232C gate (~1 min). x68000-verify-serial: $(BINDIR)/SERIAL.X $(REPO_DIR)/scripts/verify-x68000-serial.sh # Mouse gate: injected MAME mouse packets through the IOCS ROM into # jlMouse* state, read back from KEYS.X's verification scanline. x68000-verify-mouse: $(BINDIR)/KEYS.X $(REPO_DIR)/scripts/verify-x68000-mouse.sh # Serial + mouse together: both share the SCC, so stream both ways on the # RS-232C port while the mouse moves, and check neither disturbs the other. x68000-verify-serial-mouse: $(BINDIR)/SERMOUSE.X $(REPO_DIR)/scripts/verify-x68000-serial-mouse.sh # Serial + mouse under per-line palette changes: the serial + mouse gate with # examples/sermouse built for a dense SCB at 9600, 19200 and 38400 (~3 min). x68000-verify-serial-scb: $(LIB) $(LIBXMP_AR) $(REPO_DIR)/scripts/verify-x68000-serial-scb.sh # Joystick gate: every direction, both triggers and every release on both # ports, held through MAME's pads and read back from JOY.X's display (~10 s). x68000-verify-joy: $(BINDIR)/JOY.X $(REPO_DIR)/scripts/verify-x68000-joy.sh # Tile-bank gate: this port's own .tbk bake loaded both ways must hash like # the host gate's, and every other target's bake must be refused (~1 min). x68000-verify-tilebank: $(BINDIR)/TILEBANK.X $(TILEBANK_DATA) $(REPO_DIR)/scripts/verify-x68000-tilebank.sh # SCB gate: every text-palette reload of a 147-change screen, timed on the # beam, lands between the last stage pixel of the line above its band and the # band's first (~10 s). x68000-verify-scb: $(BINDIR)/SCB.X $(REPO_DIR)/scripts/verify-x68000-scb.sh # Golden-hash gate against the Apple IIgs reference (~1 min: UBER with # one-frame windows, which is all the hashes need). x68000-verify-golden: $(LIB) $(LIBXMP_AR) $(REPO_DIR)/scripts/verify-x68000-golden.sh clean-x68000: rm -rf $(BUILD) # `clean` as an alias for `clean-x68000`. Without it a bare # `make -f make/x68000.mk clean` FAILS -- and with stderr discarded that # looks like success while leaving stale objects the next build links. clean: clean-x68000 -include $(shell find $(BUILD) -name '*.d' 2>/dev/null) # Shorter stem than the %.spr-from-%.png pattern, so it wins for level banks. $(STAXI_GEN_DIR)/sprites/level%.spr: $(STAXI_GEN_DIR)/levels/level%.dat $(STAXIBAKE_BIN) $(EXAMPLES)/spacetaxi/stLevelCels.c @mkdir -p $(dir $@) $(STAXIBAKE_BIN) --level $< $@