# 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 # Flags to pass to perl. We're dealing with raw binary data, not # utf-8 encoded unicode text. The -C0 tells perl to ignore any # PERL_UNICODE setting in the environment (see "perldoc perlrun"). PERLFLAGS=-C0 PERLF=$(PERL) $(PERLFLAGS) # 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.s #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 biginttest: clean $(MAKE) BIGNUM_SRC=bigint48.s BIGNUM_HDRS="bignum.h bigint48.h" BIGNUM_CFLAGS=-DBIGNUM=BIGINT48 atari800 -nobasic $(XEX) # 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 && $(PERLF) 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 " https://slackware.uk/~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: cd conio && $(MAKE) # 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 $(PERLF) multixex.pl checkmem.xex comptitle.xex newtitle.xex taifont.xex taimain.xex > $(XEX) $(PERLF) 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 $(PERLF) newtitle.pl > titledata.dat # compressed title, for faster loading. see titlecompression.txt # for gory details. comptitle.xex: titledata.dat titlecomp.pl comptitle.s.in $(PERLF) 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)" | $(PERLF) text2screen.pl > ver.dat # Help text for the title screen help.dat: help.txt text2screen.pl $(PERLF) 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 cartbank2.cfg: cartbank2.cfg.old cartbank2.cfg.new cartbank2.sh sh cartbank2.sh # 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: cartbank2.cfg $(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: $(PERLF) -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: $(PERLF) -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 splitrom.raw.2 $(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 titledata.dat cartbank2.cfg 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 $(PERLF) size.pl $(TAIMAIN_ADDR) $(STACK_SIZE) procsizes: clean all taipan.lst $(PERLF) 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)