# Makefile for Atari 800 Taipan, by B. Watson
# Written for GNU make, but seems to work with BSD make (though
# I don't test BSD make every time I change anything).

# 'make help' will show the list of targets.

# cl65 binary:
CC=cl65

# System cl65 will compile for. Don't expect this to work if you change it
# (though possibly atarixl might work someday, with newer cc65s)
SYS=atari

# Optimization flags for cc65.
#COPT=-Oirs
COPT=-O

# This is used for embedding the date and git info in the game binary.
# It'll appear on the title screen.
VER=0.99alpha
TODAY=`date +%Y%m%d`
#BRANCH=`( git branch 2> /dev/null || echo ' NOGIT' )| cut -d' ' -f2`
REV=`git rev-parse --short HEAD 2>/dev/null || echo UNKNOWN`
#VERSION="v$(VER)-$(TODAY)-$(BRANCH)-$(REV)"
VERSION="v$(VER)-$(TODAY)-$(REV)"

# Memory layout. Controlled by the Makefile from now on, no longer
# hardcoded addresses in various scripts. These are in hex. If any
# of them are changed, you *must* run 'make clean'.

# Font. Default is for the xex build. Cartridge build changes this.
FONT_ADDR=0x2000

# Title screen data will be decompressed to this address. XEX only,
# cartridge doesn't use compressed title.
TITLE_DATA_ADDR=0x2400

# Title display list, decompression code, and menu code. Should be
# TITLE_DATA_ADDR plus 0x1744. XEX only.
TITLE_CODE_ADDR=0x3b44

# Main game start address. All the code in TAIMAIN_C_SRC and
# TAIMAIN_ASM_SRC loads here. We get this address by looking for
# 'C code can load at' message when making newtitle.xex. It's the
# next byte after the end of the display list. Default is for the
# XEX, the cart changes it.
#TAIMAIN_ADDR=0x3d00
TAIMAIN_ADDR=0x3cc7

# Size of cc65 parameter stack in bytes. Default is 0x200, which is
# much bigger than actually necessary.
STACK_SIZE=0x200

# for older cc65, we needed a custom linker file.
#CFLAGS=-t $(SYS) -C custom.cfg -I. -L. $(COPT)

# for recent git cc65, we can reserve memory on the command line.
# -D__RESERVED_MEMORY__=1056 because cc65's default end of memory
# is $BC20, and we want it to end just below our font, which starts
# at $B800. cc65's runtime stack starts just below this, and is
# 2K in size (bottom is at 0xb000).
# -D__SYSTEM_CHECK__=1 stops cl65 from prepending a bit of code that
# checks to make sure there's enough memory. Older cc65 didn't do this,
# and I never missed it.
# The meaning of the -l flag is different between cc65-2.13.3
# and the later github cc65, so it's been removed here.
#CFLAGS=-t $(SYS) -T -I. -L. -Wl -D__SYSTEM_CHECK__=1 -Wl -D__RESERVED_MEMORY__=1056 $(COPT)

CFLAGS=-t $(SYS) -T -I. -L. -Wl -D__SYSTEM_CHECK__=1 -DFONT_ADDR=$(FONT_ADDR) --start-addr $(TAIMAIN_ADDR) -Wl -D__STACKSIZE__=$(STACK_SIZE) $(COPT) $(EXTRACFLAGS)

# These aren't really used:
AS=ca65
ASFLAGS=
AR=ar65

# C compiler for host system. Currently only used for building convfont
# and mkcart.
HOSTCC=gcc
HOSTCFLAGS=-Wall

# Perl binary. This Makefile relies heavily on perl.
PERL=perl

# A few files have no make rules here. LORCHA.DAT is generated as a
# side-effect of generating taifont.xex. It's a 49-byte (7x7) blob of
# Atari "internal" screen codes.

# LORCHA.DAT, and PORTSTAT.DAT aren't deleted by a
# 'make clean'.

# romfont is the 1K font extracted from the Atari 800 OS, with a
# command like:
# dd if=atariosb.rom of=1 bs=256 skip=8 count=4
# ...where atariosb.rom comes from e.g. the PC-Xformer 2.5 zip file.

# The game binary:
XEX=taipan.xex

# All the C and asm sources for taimain.xex:
TAIMAIN_HDRS=sounds.h
TAIMAIN_C_SRC=taipan.c strtonum.c
TAIMAIN_ASM_SRC=rand.s draw_lorcha.s timed_getch.s portstat.s console.s cprintul.s soundasm.s explosion.s textdecomp.s
TAIMAIN_LIBS=conio/conio.lib

# Comment these lines out to build without big number support.
# This will stop being possible at some point.
BIGNUM_SRC=bigfloat.s
BIGNUM_HDRS=bignum.h bigfloat.h
BIGNUM_CFLAGS=-DBIGNUM=BIGFLOAT

# Uncomment these for experimental int48 big numbers. Support
# hasn't been added, so leave these commented for now.
#BIGNUM_SRC=bigint48.c
#BIGNUM_HDRS=bignum.h bigint48.h
#BIGNUM_CFLAGS=-DBIGNUM=BIGINT48

# Default rule for plain 'make' command is to build the binary.
all: checkenv $(XEX) tags

# I have F10 in my editor bound to 'make test', so:
test: clean all
	atari800 -nobasic $(XEX)

# Check the build environment.
checkenv:
	@$(PERL) -e1 && echo "perl found" && exit 0 || echo "perl missing" && exit 1
	@$(PERL) -MImage::Magick -e1 && echo "perl Image::Magick found" && exit 0 || echo "perl Image::Magick missing" && exit 1
	@$(CC) --help > /dev/null && echo "cl65 found" && exit 0 || echo "cl65 missing (install cc65)" && exit 1
	@echo "int main() { return 0; }" > 1.c && exit 0 || echo "can't create files in current directory" && exit 1
	@$(HOSTCC) -o 1 1.c && echo "host C compiler found" && exit 0 || echo "host C compiler missing or broken" && exit 1

# ctags. I forgot it can handle cc65 asm source. One wrinkle: C
# identifiers get prepended with an underscore from the POV of assembly
# code, and asm identifiers need a leading underscore to be used from
# C. There's probably a clever way to get ctags to handle this, but I
# don't know it, so I wrote a perl script to do the job.
tags:
	@ctags $(TAIMAIN_C_SRC) $(TAIMAIN_ASM_SRC) 2>/dev/null && $(PERL) fixtags.pl tags || true

help:
	@echo "Top-level targets:"
	@echo "make          - builds taipan.xex (disk version)"
	@echo "make cart     - builds taipan.rom and taipan.cart (cartridge version)"
	@echo "make test     - builds & runs taipan.xex in atari800 emulator"
	@echo "make testcart - builds & runs taipan.cart in atari800 emulator"
	@echo "make dos2     - builds & runs taipan.xex in atari800 on a "; \
	 echo "                DOS 2.0S floppy image [*]"
	@echo "make mydos    - builds & runs taipan.xex in atari800 on a "; \
	 echo "                MyDOS 4.50 floppy image [*]"
	@echo "make fenders  - builds & runs taipan.xex in atari800 on a "; \
	 echo "                Fenders 3-sector Loader floppy image [*]"
	@echo
	@echo "[*] floppy image targets require 'axe' utility, from:"
	@echo "    http://urchlay.naptime.net/~urchlay/src/axe-0.2.0.tar.gz"
	@echo
	@echo "Useful variables to add to the make command:"
	@echo "  CC          - path to cl65 binary (default: cl65, searches PATH)"
	@echo "  EXTRACFLAGS - extra options to pass to cl65"
	@echo "  HOSTCC      - path to native C compiler (default: gcc, searches PATH)"
	@echo "  HOSTCFLAGS  - extra options to pass to HOSTCC (default: -Wall)"
	@echo "  PERL        - path to perl binary (default: perl, searches PATH)"

# The above is fast & easy, but from time to time it's necessary
# to test slow loading, make sure the title screen stuff works OK.
dos2: clean all
	cp dos2.atr.in dos2.atr
	cp taipan.xex TAIPAN
	axe -w TAIPAN dos2.atr
	rm -f TAIPAN
	atari800 -nobasic -nopatch dos2.atr

fenders: clean all
	perl axecheck.pl taipan.xex
	cp taipan.xex TAIPAN
	cp fenders.atr.in fenders.atr
	axe -w TAIPAN fenders.atr
	rm -f TAIPAN
	atari800 -nopatch fenders.atr

mydos: clean all
	cp taipan.xex TAIPAN
	cp mydos.atr.in mydos.atr
	axe -w TAIPAN mydos.atr
	rm -f TAIPAN
	atari800 -nopatch mydos.atr

# We use our own custom conio instead of the one cc65 ships.
# see conion/README for details.
conio/conio.lib:
	$(MAKE) -C conio

# The game binary is a multi-part binary load file. This rule
# depends on all the pieces, and just concatenates them. We used
# to just use cat, but reportedly some (dumb, broken) xex loaders
# have trouble with $FFFF markers at the start of the second and
# further segments, so multixex.pl skips them.
$(XEX): checkmem.xex taimain.xex taifont.xex newtitle.xex comptitle.xex
	$(PERL) multixex.pl checkmem.xex comptitle.xex newtitle.xex taifont.xex taimain.xex > $(XEX)
	$(PERL) size.pl $(TAIMAIN_ADDR) $(STACK_SIZE)

# Bitmap data for the title screen, 256x184 = 47104 pixels, 8 bits
# per pixel, or 5888 bytes. Displayed in ANTIC mode F (aka GR.8),
# using GTIA narrow playfield. The original title screen for the Apple
# is a 280x192 bitmap with a few blank lines at the top & bottom. I
# squished it horizontally to 256 pixels and got rid of the blank lines,
# to save load time. Note that titledata.dat is not built into
# the xex binary as-is: it's now used as input for creating
# comptitle.xex, the compressed title screen. For the cartridge,
# titledata.dat is included as-is.
titledata.dat: newtitle.pl newtitle.png
	$(PERL) newtitle.pl > titledata.dat

# compressed title, for faster loading. see titlecompression.txt
# for gory details.
comptitle.xex: titledata.dat titlecomp.pl comptitle.s.in
	$(PERL) titlecomp.pl 133 < titledata.dat
	$(CC) -l comptitle.lst -o comptitle.xex -t none --asm-define destination=$(TITLE_DATA_ADDR) comptitle.s

# tiny 1-sector memory checker, aborts the laod if a cart is present.
checkmem.xex: checkmem.s
	$(CC) -o checkmem.xex -t none checkmem.s

# Init segment that loads after the title screen data. It sets up
# a custom display list and sets the GTIA for narrow playfield,
# then waits for a keypress. Afterwards, it restores the OS's
# display list and sets the GTIA back to normal, then exits.
# Notice this is built with "-t none" instead of "-t atari",
# since it's a lot easier to homebrew an init segment than it is
# to get cc65 to build an init segment (would need a custom linker
# script at least).
newtitle.xex: newtitle.s ver.dat help.dat
	$(CC) -l newtitle.lst -m newtitle.map -o newtitle.xex -t none --asm-define screendata=$(TITLE_DATA_ADDR) --asm-define origin=$(TITLE_CODE_ADDR) newtitle.s

# Version number in Atari screen-data form
ver.dat: text2screen.pl
	echo "$(VERSION)" | $(PERL) text2screen.pl > ver.dat

# Help text for the title screen
help.dat: help.txt text2screen.pl
	$(PERL) text2screen.pl < help.txt > help.dat

#ver.dat: mkver.pl
#	$(PERL) mkver.pl $(VERSION) > ver.dat

# The main executable. All the C and asm code goes here, except the init
# segment in newtitle.s.
taimain.xex: $(TAIMAIN_C_SRC) $(TAIMAIN_ASM_SRC) $(TAIMAIN_HDRS) $(BIGNUM_SRC) $(BIGNUM_HDRS) $(TAIMAIN_LIBS) messages.c
	$(CC) -m taipan.map $(CFLAGS) $(BIGNUM_CFLAGS) -o taimain.xex $(TAIMAIN_C_SRC) $(TAIMAIN_ASM_SRC) $(BIGNUM_SRC) $(TAIMAIN_LIBS)

#cl65 --mapfile taipan.map $(CFLAGS) -o taimain.xex taipan.c sounds.c rand.s draw_lorcha.s timed_getch.s jsleep.s portstat.s console.s

# With newer cc65s, I have to do this to get an assembly listing of just
# taipan.c. This rule not used as part of the main build, it's only for
# debugging.
taipan.lst: taipan.c
	$(CC) -m taipan.map $(CFLAGS) $(BIGNUM_CFLAGS) -c -o /dev/null -l taipan.lst -T taipan.c

# Another such rule for sounds.c:
sounds.lst: sounds.c sounds.h
	$(CC) -m sounds.map $(CFLAGS) -c -o /dev/null -l sounds.lst -T sounds.c

# The font gets loaded into RAM, in the area reserved by the
# -D__RESERVED_MEMORY__ option to cl65. To actually use the font,
# taimain.xex contains code that sets CHBAS ($02f4).
# Not mentioned in any make rule: convfont also creates LORCHA.DAT,
# which draw_lorcha.s depends on (so we touch draw_lorcha.s here).
taifont.xex: convfont romfont font
	cat romfont font | ./convfont -x > taifont.xex
	touch draw_lorcha.s

# Used by the cartridge build, but not the disk (xex) binary. This just
# builds the font without the Atari 6-byte binary load header. It ends
# up at the top of one of the cartridge banks, and is also useful for
# eyeballing the font in bitmapdump.pl or converting to other formats.
taifont: convfont romfont font
	cat romfont font | ./convfont > taifont

# PORTSTAT.DAT gets incbin'ed directly in portstat.s. It's screen-code
# data for the static part of the port status screen, which ends up in
# an array that the C code can memcpy() into screen RAM as needed.
# This make rule actually runs atari800. For it to work, you'll need
# the H: device enabled, pointed at the current directory, and set
# to writable.
PORTSTAT.DAT: mkportstats.xex
	atari800 -nobasic mkportstats.xex
	touch portstat.s

# Host tool that builds our custom font from the data ripped out of
# the Apple version, plus the Atari OS ROM. Also, all the custom
# characters for the enemy ships are defined here (as hex data. Yes,
# I converted them manually from eyeballing a screenshot of the Apple
# combat screen).
convfont: convfont.c
	$(HOSTCC) $(HOSTCFLAGS) -DFONT_ADDR=$(FONT_ADDR) -o convfont convfont.c

# text compressor
textcomp: textcomp.c
	$(HOSTCC) $(HOSTCFLAGS) -o textcomp textcomp.c

# textdecomp.s includes msg.inc
textdecomp.s: msg.inc

msg.inc: messages.c

# messages.c is a generated file
messages.c: messages.pl textcomp
	perl messages.pl > messages.c

### Cartridge-related targets. The way I'm doing this isn't 'proper': I should
#   be using cc65's linker with a fancy config script to do the bank layout
#   and such. But it's a lot easier for me to use the tools I know how to use,
#   so that's what I did.

# mkcart turns a raw binary into an atar800 .cart image with 16-byte header.
# originally I wrote this for use with the DASM assembler, but there's
# nothing DASM-specific about it.
mkcart: mkcart.c
	$(HOSTCC) $(HOSTCFLAGS) -o mkcart mkcart.c

# cc65 doc atari.html explains how to produce a raw binary file.
# using a custom crt0 to get rid of the extra RTS cc65 puts there for
# SpartaDOS compatibility (which has no effect on a cartridge image,
# except to waste 1 byte).
romable_taimain.raw: $(TAIMAIN_C_SRC) $(TAIMAIN_ASM_SRC) $(TAIMAIN_HDRS) $(BIGNUM_SRC) $(BIGNUM_HDRS) $(TAIMAIN_LIBS) crt0_cart.s messages.c
	$(CC) --config cartbank2.cfg -m taipan.map -t atari -T -I. -L. -DFONT_ADDR=0x9c00 --start-addr 0x400 -Wl -D__STACKSIZE__=0x200 -O -Wl -D__SYSTEM_CHECK__=1 -Wl -D__AUTOSTART__=1 -Wl -D__EXEHDR__=1  -DCART_TARGET=1 --asm-define CART_TARGET=1 -DBIGNUM=BIGFLOAT -o romable_taimain.raw $(TAIMAIN_C_SRC) $(TAIMAIN_ASM_SRC) $(BIGNUM_SRC) $(TAIMAIN_LIBS) crt0_cart.s

# 256 bytes of $ff filler, for the last page of each code bank. Wasting
# this little bit of space simplifies the copying code in bank7.s (no
# partial last page to copy), and guarantees I don't accidentally end
# up with a 0 in the "cart present" byte of the cart trailer.
fill256:
	$(PERL) -Mbytes -e 'print chr(0xff) x 256' > fill256

# 8192 bytes of $ff filler, for unused banks. Possibly these will be
# used for something like an interactive game manual/tutorial.
blankbank:
	$(PERL) -Mbytes -e 'print chr(0xff) x 8192' > blankbank

splitrom.raw.0: splitrom.raw.2

splitrom.raw.1: splitrom.raw.2

# split romable_taimain.raw into bank-sized chunks. if we end up
# with 3 chunks, the cart won't work correctly, so stop the build here
# in that case.
splitrom.raw.2: romable_taimain.raw
	split -b 7936 -a 1 -d romable_taimain.raw splitrom.raw.
	[ -e splitrom.raw.3 ] && echo "*** romable_taimain.raw too big" && rm -f splitrom.raw.* && exit 1 || exit 0

bank0: splitrom.raw.0 fill256
	cat splitrom.raw.0 fill256 > bank0

bank1: splitrom.raw.1 fill256
	cat splitrom.raw.1 fill256 > bank1

#bank2: splitrom.raw.2 fill256
#	cl65 -l bank2.lst -m bank2.map -t none -o bank2 bank2.s

bank2: rodata.8000 bank2.s taifont romable_taimain.raw
	$(CC) -l bank2.lst -m bank2.map -t none -o bank2 bank2.s

bank3: bank3.s titledata.dat ver.dat help.dat newtitle.s
	$(CC) -l bank3.lst -m bank3.map -t none -o bank3 bank3.s

# raw ROM, for burning to EPROM/flash.
taipan.rom: bank0 bank1 bank2 bank3
	cat bank0 bank1 bank2 bank3 > taipan.rom

# .cart version with atari800-compatible header.
taipan.cart: taipan.rom mkcart
	./mkcart -otaipan.cart -t12 taipan.rom
	./mkcart -ctaipan.cart

cart: checkenv taipan.cart

testcart: clean cart
	atari800 taipan.cart


### Rules for building various file types with the cc65 toolchain.
.s.o:
	$(AS) $(ASFLAGS) -o $@ $<

.c.o:
	$(CC) $(CFLAGS) -c -o $@ $<

%.xex: %.c
	$(CC) --mapfile map $(CFLAGS) -o $@ $<

# Obligatory clean and distclean rules.
clean:
	rm -f *.o *.lst convfont mkcart gzip2deflate *.xex AUTORUN.SYS taipan.atr dos2.atr mydos.atr fenders.atr ver.dat help.dat tags cartmsg.dat splitrom.raw.* taipan.rom taipan.cart bank[0-9] fill256 blankbank romable_taimain.raw splitrom.raw.* comptitle.s comptitle.dat conio/*.o conio/*.lib messages.c textcomp

distclean: clean
	rm -f *~ core .*.swp 1.* 2.* 1 2 3 map map.* *.map a b c foo bar baz

push:
	sh push.sh

size: clean all
	$(PERL) size.pl $(TAIMAIN_ADDR) $(STACK_SIZE)

procsizes: clean all taipan.lst
	$(PERL) procsizes.pl > procsizes
	cat procsizes

# Cruft. Was used for testing the enemy ship animation.
lorchatest: lorchatest.c draw_lorcha.s taifont.xex
	$(CC) -t atari -O -T -o lorchatest1.xex lorchatest.c draw_lorcha.s
	cat taifont.xex lorchatest1.xex > lorchatest.xex
	atari800 -nobasic lorchatest.xex

#### cruft, from when I was planning to use a 32K cart:
# this was a blind alley: zlib is too slow to decompress, plus there's
# no need to compress taimain.xex since I'm able to use a 64K cart.

# gzip2deflate downloaded from https://github.com/pfusik/zlib6502
# I could have used deflator.c that ships with cc65's source, but
# it's deprecated by its own upstream (same author as gzip2deflate).
gzip2deflate: gzip2deflate.c
	$(HOSTCC) $(HOSTCFLAGS) -o gzip2deflate gzip2deflate.c

zlibtest.xex: gzip2deflate zlibtest.c zlibtestdata.s romable_taimain.raw
	gzip -9c < romable_taimain.raw | ./gzip2deflate > rom.dfl
	$(CC) -t atari -m zlibtest.map -l zlibtest.lst -Wl -D__SYSTEM_CHECK__=1 --start-addr 0x7000 -o zlibtest.xex zlibtest.c zlibtestdata.s
romable_taimain.xex: $(TAIMAIN_C_SRC) $(TAIMAIN_ASM_SRC) $(TAIMAIN_HDRS)
	rm -f taimain.xex
	$(MAKE) TAIMAIN_ADDR=0x3ff EXTRACFLAGS="-DCART_TARGET=1 --asm-define CART_TARGET=1"
	mv taimain.xex romable_taimain.xex

###

soundtest: sounds.c
	$(CC) -DTESTXEX -t atari -o sounds.xex sounds.c
	atari800 -nobasic sounds.xex

# former textmode title screen, was generated by TITLE.LST. Replaced
# by graphical title screen.
#title.xex: TITLE.DAT
#	$(PERL) title.pl TITLE.DAT > title.xex

# old title
#$(XEX): taimain.xex taifont.xex title.xex
#	cat taifont.xex title.xex taimain.xex > $(XEX)