diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 74a53987..0ac38056 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -10,34 +10,16 @@ jobs: with: repository: 'davidgiven/cpm65' path: 'cpm65' - - uses: actions/checkout@v3 - with: - repository: 'davidgiven/llvm-mos-sdk' - path: 'llvm-mos-sdk' - - name: get llvm-mos-sdk version - run: echo "MOS_SDK_VERSION=$(cd llvm-mos-sdk && git rev-parse --short HEAD)" >> $GITHUB_ENV - name: apt - run: sudo apt update && sudo apt install cc1541 cpmtools libfmt-dev ninja-build fp-compiler - - - name: cache llvm-mos - id: cache-llvm-mos - uses: actions/cache@v3 - env: - cache-name: cache-llvm-mos - with: - path: ~/llvm-mos - key: ${{ runner.os }}-build-${{ env.cache-name }}-ver-${{ env.MOS_SDK_VERSION }} + run: sudo apt update && sudo apt install cc1541 cpmtools libfmt-dev fp-compiler moreutils - - if: ${{ steps.cache-llvm-mos.outputs.cache-hit != 'true' }} - name: install llvm-mos + - name: install llvm-mos run: | - mkdir -p llvm-mos-sdk/build - (cd llvm-mos-sdk/build && cmake -G "Ninja" -DCMAKE_INSTALL_PREFIX=$HOME/llvm-mos ..) - (cd llvm-mos-sdk/build && ninja install) + wget -O - https://github.com/llvm-mos/llvm-mos-sdk/releases/latest/download/llvm-mos-linux.tar.xz | tar xJf - -C $HOME - name: make - run: PATH=$PATH:$HOME/llvm-mos/bin make -C cpm65 LLVM= + run: make -C cpm65 LLVM=$HOME/llvm-mos/bin - name: Upload build artifacts uses: actions/upload-artifact@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b016dbb8..015ee908 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,34 +13,16 @@ jobs: with: repository: 'davidgiven/cpm65' path: 'cpm65' - - uses: actions/checkout@v3 - with: - repository: 'davidgiven/llvm-mos-sdk' - path: 'llvm-mos-sdk' - - name: get llvm-mos-sdk version - run: echo "MOS_SDK_VERSION=$(cd llvm-mos-sdk && git rev-parse --short HEAD)" >> $GITHUB_ENV - name: apt - run: sudo apt update && sudo apt install cc1541 cpmtools libfmt-dev ninja-build fp-compiler - - - name: cache llvm-mos - id: cache-llvm-mos - uses: actions/cache@v3 - env: - cache-name: cache-llvm-mos - with: - path: ~/llvm-mos - key: ${{ runner.os }}-build-${{ env.cache-name }}-ver-${{ env.MOS_SDK_VERSION }} + run: sudo apt update && sudo apt install cc1541 cpmtools libfmt-dev fp-compiler moreutils - - if: ${{ steps.cache-llvm-mos.outputs.cache-hit != 'true' }} - name: install llvm-mos + - name: install llvm-mos run: | - mkdir -p llvm-mos-sdk/build - (cd llvm-mos-sdk/build && cmake -G "Ninja" -DCMAKE_INSTALL_PREFIX=$HOME/llvm-mos ..) - (cd llvm-mos-sdk/build && ninja install) + wget -O - https://github.com/llvm-mos/llvm-mos-sdk/releases/latest/download/llvm-mos-linux.tar.xz | tar xJf - -C $HOME - name: make - run: PATH=$PATH:$HOME/llvm-mos/bin make -C cpm65 LLVM= + run: make -C cpm65 LLVM=$HOME/llvm-mos/bin - name: date run: | diff --git a/Makefile b/Makefile index 4e25d110..46e0a5db 100644 --- a/Makefile +++ b/Makefile @@ -1,410 +1,14 @@ -CXX = g++ -CC = gcc -FPC = fpc -LLVM ?= /opt/bin/ +export LLVM = /opt/llvm-mos/bin +export CC6502 = $(LLVM)/mos-cpm65-clang +export LD6502 = $(LLVM)/ld.lld +export AR6502 = $(LLVM)/llvm-ar -CFLAGS = -O0 -g -I. -CXXFLAGS = $(CFLAGS) \ - -std=c++17 -CFLAGS65 = -Os -g -I. \ - -Wno-main-return-type \ - -Wno-incompatible-library-redeclaration +export CFLAGS6502 = -Os -g \ + -Wno-main-return-type -OBJDIR = .obj +export OBJ = .obj -TARGETS = \ - apple2e.po \ - atari800.atr \ - atari800hd.atr \ - atari800xlhd.atr \ - bbcmicro.ssd \ - c64.d64 \ - oric.dsk \ - pet4032.d64 \ - pet8032.d64 \ - pet8096.d64 \ - vic20.d64 \ - x16.zip \ - -MINIMAL_APPS = \ - $(OBJDIR)/apps/bedit.com \ - $(OBJDIR)/apps/capsdrv.com \ - $(OBJDIR)/apps/cpuinfo.com \ - $(OBJDIR)/apps/devices.com \ - $(OBJDIR)/apps/dinfo.com \ - $(OBJDIR)/apps/dump.com \ - $(OBJDIR)/apps/ls.com \ - $(OBJDIR)/asm.com \ - $(OBJDIR)/copy.com \ - $(OBJDIR)/stat.com \ - $(OBJDIR)/submit.com \ - apps/dump.asm \ - apps/ls.asm \ - apps/cpm65.inc \ - apps/drivers.inc \ - -APPS = \ - $(MINIMAL_APPS) \ - $(OBJDIR)/third_party/altirrabasic/atbasic.com \ - $(OBJDIR)/objdump.com \ - apps/bedit.asm \ - apps/cpuinfo.asm \ - apps/dinfo.asm \ - cpmfs/asm.txt \ - cpmfs/basic.txt \ - cpmfs/bedit.txt \ - cpmfs/demo.sub \ - cpmfs/hello.asm \ - -SCREEN_APPS = \ - $(OBJDIR)/apps/cls.com \ - apps/cls.asm \ - $(OBJDIR)/qe.com \ - $(OBJDIR)/life.com \ - $(OBJDIR)/apps/scrntest.com \ - -LIBCPM_OBJS = \ - $(OBJDIR)/lib/printi.o \ - $(OBJDIR)/lib/bdos.o \ - $(OBJDIR)/lib/xfcb.o \ - $(OBJDIR)/lib/screen.o \ - -LIBBIOS_OBJS = \ - $(OBJDIR)/src/bios/biosentry.o \ - $(OBJDIR)/src/bios/relocate.o \ - $(OBJDIR)/src/bios/loader.o \ - -LIBCOMMODORE_OBJS = \ - $(OBJDIR)/src/bios/commodore/ieee488.o \ - $(OBJDIR)/src/bios/commodore/petscii.o \ - -CPMEMU_OBJS = \ - $(OBJDIR)/tools/cpmemu/main.o \ - $(OBJDIR)/tools/cpmemu/emulator.o \ - $(OBJDIR)/tools/cpmemu/fileio.o \ - $(OBJDIR)/tools/cpmemu/biosbdos.o \ - $(OBJDIR)/third_party/lib6502/lib6502.o \ - -all: $(TARGETS) - -$(OBJDIR)/%: $(OBJDIR)/tools/%.o - @mkdir -p $(dir $@) - $(CXX) $(CXXFLAGS) -o $@ $< -lfmt - -bin/cpmemu: $(CPMEMU_OBJS) - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $(CPMEMU_OBJS) -lreadline - -bin/%: $(OBJDIR)/tools/%.o - @mkdir -p $(dir $@) - $(CXX) $(CXXFLAGS) -o $@ $< - -bin/fontconvert: $(OBJDIR)/tools/fontconvert.o $(OBJDIR)/tools/libbdf.o - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -o $@ $^ - -bin/mads: third_party/mads/mads.pas - @mkdir -p $(dir $@) - $(FPC) -Mdelphi -vh -Os $< -o$@ - -$(OBJDIR)/mkcombifs: $(OBJDIR)/tools/mkcombifs.o - @mkdir -p $(dir $@) - $(CXX) $(CXXFLAGS) -o $@ $^ -lfmt - -$(OBJDIR)/third_party/%.o: third_party/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -c -o $@ $< - -$(OBJDIR)/third_party/%.o: third_party/%.cc - @mkdir -p $(dir $@) - $(CXX) $(CXXFLAGS) -c -o $@ $< - -$(OBJDIR)/tools/%.o: tools/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -c -o $@ $< - -$(OBJDIR)/tools/%.o: tools/%.cc - @mkdir -p $(dir $@) - $(CXX) $(CXXFLAGS) -c -o $@ $< - -$(OBJDIR)/%.o: %.S include/zif.inc include/mos.inc include/cpm65.inc include/driver.inc - @mkdir -p $(dir $@) - $(LLVM)mos-cpm65-clang $(CFLAGS65) -c -o $@ $< -I include - -$(OBJDIR)/third_party/altirrabasic/%.bin: \ - $(wildcard third_party/altirrabasic/source/*.s) \ - $(wildcard third_party/altirrabasic/source/*.inc) \ - $(wildcard third_party/altirrabasic/kernel/*.s) \ - bin/mads \ - $(OBJDIR)/xextobin - @mkdir -p $(dir $@) - rm -f $(patsubst %.bin,%.xex,$@) - bin/mads third_party/altirrabasic/source/atbasic.s \ - -c \ - -o:$(patsubst %.bin,%.xex,$@) \ - -s \ - -l:$(patsubst %.bin,%.lst,$@) \ - -t:$(patsubst %.bin,%.map,$@) \ - -d:ZPBASE=$(ZPBASE) \ - -d:TEXTBASE='$$$(TEXTBASE)' - $(OBJDIR)/xextobin -i $(patsubst %.bin,%.xex,$@) -o $@ -b 0x$(TEXTBASE) - -$(OBJDIR)/third_party/altirrabasic/atbasic.core.bin: ZPBASE=0 -$(OBJDIR)/third_party/altirrabasic/atbasic.core.bin: TEXTBASE=0200 -$(OBJDIR)/third_party/altirrabasic/atbasic.zp.bin: ZPBASE=1 -$(OBJDIR)/third_party/altirrabasic/atbasic.zp.bin: TEXTBASE=0200 -$(OBJDIR)/third_party/altirrabasic/atbasic.tpa.bin: ZPBASE=0 -$(OBJDIR)/third_party/altirrabasic/atbasic.tpa.bin: TEXTBASE=0300 - -$(OBJDIR)/third_party/altirrabasic/atbasic.com: \ - $(OBJDIR)/third_party/altirrabasic/atbasic.core.bin \ - $(OBJDIR)/third_party/altirrabasic/atbasic.zp.bin \ - $(OBJDIR)/third_party/altirrabasic/atbasic.tpa.bin \ - $(OBJDIR)/multilink - @mkdir -p $(dir $@) - $(OBJDIR)/multilink -o $@ \ - $(OBJDIR)/third_party/altirrabasic/atbasic.core.bin \ - $(OBJDIR)/third_party/altirrabasic/atbasic.zp.bin \ - $(OBJDIR)/third_party/altirrabasic/atbasic.tpa.bin - -$(OBJDIR)/libcommodore.a: $(LIBCOMMODORE_OBJS) - @mkdir -p $(dir $@) - $(LLVM)llvm-ar rs $@ $^ - -$(OBJDIR)/libbios.a: $(LIBBIOS_OBJS) - @mkdir -p $(dir $@) - $(LLVM)llvm-ar rs $@ $^ - -$(OBJDIR)/libcpm.a: $(LIBCPM_OBJS) - @mkdir -p $(dir $@) - $(LLVM)llvm-ar rs $@ $^ - -$(OBJDIR)/%.o: %.c - @mkdir -p $(dir $@) - $(LLVM)mos-cpm65-clang $(CFLAGS65) -c -I. -o $@ $^ - -$(OBJDIR)/%.com: $(OBJDIR)/third_party/%.o $(OBJDIR)/libcpm.a - @mkdir -p $(dir $@) - $(LLVM)mos-cpm65-clang $(CFLAGS65) -I. -o $@ $^ - -$(OBJDIR)/%.com: $(OBJDIR)/apps/%.o $(OBJDIR)/libcpm.a - @mkdir -p $(dir $@) - $(LLVM)mos-cpm65-clang $(CFLAGS65) -v -I. -o $@ $^ - -$(OBJDIR)/%.com: %.asm $(OBJDIR)/asm.com bin/cpmemu $(wildcard apps/*.inc) - @mkdir -p $(dir $@) - bin/cpmemu $(OBJDIR)/asm.com -pA=$(dir $<) -pB=$(dir $@) \ - a:$(notdir $<) b:$(notdir $@) - test -f $@ - -$(OBJDIR)/bdos.sys: $(OBJDIR)/src/bdos.o $(OBJDIR)/libcpm.a - @mkdir -p $(dir $@) - $(LLVM)mos-cpm65-clang $(CFLAGS65) -I. -o $@ $^ - $(LLVM)llvm-objdump -S $@.elf > $@.lst - -$(OBJDIR)/ccp.sys: $(OBJDIR)/src/ccp.o $(OBJDIR)/libcpm.a - @mkdir -p $(dir $@) - $(LLVM)mos-cpm65-clang $(CFLAGS65) -I. -o $@ $^ - -$(OBJDIR)/apple2e.bios: $(OBJDIR)/src/bios/apple2e.o $(OBJDIR)/libbios.a scripts/apple2e.ld scripts/apple2e-prelink.ld Makefile - @mkdir -p $(dir $@) - $(LLVM)ld.lld -T scripts/apple2e-prelink.ld -o $(OBJDIR)/apple2e.o $< $(OBJDIR)/libbios.a --defsym=BIOS_SIZE=0x8000 - $(LLVM)ld.lld -Map $(patsubst %.bios,%.map,$@) -T scripts/apple2e.ld -o $@ $< $(OBJDIR)/libbios.a --defsym=BIOS_SIZE=$$($(LLVM)llvm-objdump --section-headers $(OBJDIR)/apple2e.o | gawk --non-decimal-data '/ [0-9]+/ { size[$$2] = ("0x"$$3)+0 } END { print(size[".text"] + size[".data"] + size[".bss"]) }') - -$(OBJDIR)/oric.exe: $(OBJDIR)/src/bios/oric.o $(OBJDIR)/libbios.a scripts/oric.ld scripts/oric-prelink.ld scripts/oric-common.ld Makefile - @mkdir -p $(dir $@) - $(LLVM)ld.lld -Map $(patsubst %.exe,%.map,$@) -T scripts/oric-prelink.ld -o $(OBJDIR)/oric-prelink.o $< $(OBJDIR)/libbios.a --defsym=BIOS_SIZE=0x4000 - $(LLVM)ld.lld -Map $(patsubst %.exe,%.map,$@) -T scripts/oric.ld -o $@ $< $(OBJDIR)/libbios.a --defsym=BIOS_SIZE=$$($(LLVM)llvm-objdump --section-headers $(OBJDIR)/oric-prelink.o | gawk --non-decimal-data '/ [0-9]+/ { size[$$2] = ("0x"$$3)+0 } END { print(size[".text"] + size[".data"] + size[".bss"]) }') - -$(OBJDIR)/%.exe: $(OBJDIR)/src/bios/%.o $(OBJDIR)/libbios.a scripts/%.ld - @mkdir -p $(dir $@) - $(LLVM)ld.lld -Map $(patsubst %.exe,%.map,$@) -T scripts/$*.ld -o $@ $< $(filter %.a,$^) $(LINKFLAGS) - -$(OBJDIR)/4x8font.inc: bin/fontconvert third_party/tomsfonts/atari-small.bdf - @mkdir -p $(dir $@) - bin/fontconvert third_party/tomsfonts/atari-small.bdf > $@ - -$(OBJDIR)/bbcmicrofs.img: $(APPS) $(SCREEN_APPS) $(OBJDIR)/ccp.sys - mkfs.cpm -f bbc192 $@ - cpmcp -f bbc192 $@ $(OBJDIR)/ccp.sys $(APPS) $(SCREEN_APPS) 0: - cpmchattr -f bbc192 $@ sr 0:ccp.sys - -bbcmicro.ssd: $(OBJDIR)/bbcmicro.exe $(OBJDIR)/bdos.sys Makefile $(OBJDIR)/bbcmicrofs.img $(OBJDIR)/mkdfs - $(OBJDIR)/mkdfs -O $@ \ - -N CP/M-65 \ - -f $(OBJDIR)/bbcmicro.exe -n \!boot -l 0x400 -e 0x400 -B 2 \ - -f $(OBJDIR)/bdos.sys -n bdos \ - -f $(OBJDIR)/bbcmicrofs.img -n cpmfs - -$(OBJDIR)/c64.exe: $(OBJDIR)/libcommodore.a -c64.d64: $(OBJDIR)/c64.exe $(OBJDIR)/bdos.sys Makefile $(APPS) $(OBJDIR)/ccp.sys \ - $(OBJDIR)/mkcombifs - @rm -f $@ - cc1541 -q -n "cp/m-65" $@ - cc1541 -q \ - -t -u 0 \ - -r 18 -f cpm -w $(OBJDIR)/c64.exe \ - $@ - $(OBJDIR)/mkcombifs $@ - cpmcp -f c1541 $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) 0: - cpmchattr -f c1541 $@ sr 0:bdos.sys 0:ccp.sys 0:cbmfs.sys - -$(OBJDIR)/generic-1m-cpmfs.img: $(OBJDIR)/bdos.sys $(APPS) $(OBJDIR)/ccp.sys - @rm -f $@ - mkfs.cpm -f generic-1m $@ - cpmcp -f generic-1m $@ $(OBJDIR)/ccp.sys $(APPS) 0: - cpmchattr -f generic-1m $@ sr 0:ccp.sys - -$(OBJDIR)/x16.exe: $(OBJDIR)/libcommodore.a -x16.zip: $(OBJDIR)/x16.exe $(OBJDIR)/bdos.sys $(OBJDIR)/generic-1m-cpmfs.img - @rm -f $@ - zip -9 $@ -j $^ - printf "@ x16.exe\n@=CPM\n" | zipnote -w $@ - printf "@ bdos.sys\n@=BDOS\n" | zipnote -w $@ - printf "@ generic-1m-cpmfs.img\n@=CPMFS\n" | zipnote -w $@ - -$(OBJDIR)/apple2e.bios.swapped: $(OBJDIR)/apple2e.bios bin/shuffle - bin/shuffle -i $< -o $@ -b 256 -t 16 -r -m 02468ace13579bdf - -$(OBJDIR)/apple2e.boottracks: $(OBJDIR)/apple2e.bios.swapped - cp $(OBJDIR)/apple2e.bios.swapped $@ - truncate -s 4096 $@ - -apple2e.po: $(OBJDIR)/apple2e.boottracks $(OBJDIR)/bdos.sys $(APPS) $(OBJDIR)/ccp.sys Makefile diskdefs bin/shuffle - @rm -f $@ - mkfs.cpm -f appleiie -b $(OBJDIR)/apple2e.boottracks $@ - cpmcp -f appleiie $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) 0: - cpmchattr -f appleiie $@ sr 0:ccp.sys 0:bdos.sys - truncate -s 143360 $@ - -$(OBJDIR)/pet4032.exe: LINKFLAGS += --no-check-sections -$(OBJDIR)/pet4032.exe: $(OBJDIR)/libcommodore.a -$(OBJDIR)/src/bios/pet4032.o: CFLAGS65 += -DPET4032 -pet4032.d64: $(OBJDIR)/pet4032.exe $(OBJDIR)/bdos.sys Makefile $(APPS) $(SCREEN_APPS) $(OBJDIR)/ccp.sys \ - $(OBJDIR)/mkcombifs - @rm -f $@ - cc1541 -i 15 -q -n "cp/m-65" $@ - cc1541 -q \ - -t -u 0 \ - -r 18 -f cpm -w $(OBJDIR)/pet4032.exe \ - $@ - $(OBJDIR)/mkcombifs $@ - cpmcp -f c1541 $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) $(SCREEN_APPS) 0: - cpmchattr -f c1541 $@ sr 0:ccp.sys 0:cbmfs.sys 0:bdos.sys - -$(OBJDIR)/pet8096.exe: LINKFLAGS += --no-check-sections -$(OBJDIR)/pet8096.exe: $(OBJDIR)/libcommodore.a -$(OBJDIR)/src/bios/pet8096.o: CFLAGS65 += -DPET8096 -pet8096.d64: $(OBJDIR)/pet8096.exe $(OBJDIR)/bdos.sys Makefile $(APPS) $(SCREEN_APPS) $(OBJDIR)/ccp.sys \ - $(OBJDIR)/mkcombifs - @rm -f $@ - cc1541 -i 15 -q -n "cp/m-65" $@ - cc1541 -q \ - -t -u 0 \ - -r 18 -f cpm -w $(OBJDIR)/pet8096.exe \ - $@ - $(OBJDIR)/mkcombifs $@ - cpmcp -f c1541 $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) $(SCREEN_APPS) 0: - cpmchattr -f c1541 $@ sr 0:ccp.sys 0:cbmfs.sys 0:bdos.sys - -$(OBJDIR)/pet8032.exe: LINKFLAGS += --no-check-sections -$(OBJDIR)/pet8032.exe: $(OBJDIR)/libcommodore.a -$(OBJDIR)/src/bios/pet8032.o: CFLAGS65 += -DPET8032 -pet8032.d64: $(OBJDIR)/pet8032.exe $(OBJDIR)/bdos.sys Makefile $(APPS) $(SCREEN_APPS) $(OBJDIR)/ccp.sys \ - $(OBJDIR)/mkcombifs - @rm -f $@ - cc1541 -i 15 -q -n "cp/m-65" $@ - cc1541 -q \ - -t -u 0 \ - -r 18 -f cpm -w $(OBJDIR)/pet8032.exe \ - $@ - $(OBJDIR)/mkcombifs $@ - cpmcp -f c1541 $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) $(SCREEN_APPS) 0: - cpmchattr -f c1541 $@ sr 0:ccp.sys 0:cbmfs.sys 0:bdos.sys - -$(OBJDIR)/vic20.exe: LINKFLAGS += --no-check-sections -$(OBJDIR)/vic20.exe: $(OBJDIR)/libcommodore.a -$(OBJDIR)/src/bios/vic20.o: $(OBJDIR)/4x8font.inc -vic20.d64: $(OBJDIR)/vic20.exe $(OBJDIR)/bdos.sys Makefile $(APPS) \ - $(OBJDIR)/ccp.sys $(OBJDIR)/mkcombifs - @rm -f $@ - cc1541 -i 15 -q -n "cp/m-65" $@ - cc1541 -q \ - -t -u 0 \ - -r 18 -f cpm -w $(OBJDIR)/vic20.exe \ - $@ - $(OBJDIR)/mkcombifs $@ - cpmcp -f c1541 $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) 0: - cpmchattr -f c1541 $@ sr 0:cbmfs.sys 0:ccp.sys 0:bdos.sys - -# Atari targets call /usr/bin/printf directly because 'make' calls /bin/sh -# which might be the Defective Annoying SHell which has a broken printf -# implementation. - -$(OBJDIR)/src/bios/atari800.o: CFLAGS65 += -DATARI_SD -$(OBJDIR)/atari800.exe: -atari800.atr: $(OBJDIR)/atari800.exe $(OBJDIR)/bdos.sys Makefile \ - $(MINIMAL_APPS) $(OBJDIR)/ccp.sys $(OBJDIR)/a8setfnt.com \ - $(SCREEN_APPS) $(OBJDIR)/a8tty80drv.com - dd if=/dev/zero of=$@ bs=128 count=720 - mkfs.cpm -f atari90 $@ - cp $(OBJDIR)/a8setfnt.com $(OBJDIR)/setfnt.com - cp $(OBJDIR)/a8tty80drv.com $(OBJDIR)/tty80drv.com - cpmcp -f atari90 $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(MINIMAL_APPS) $(SCREEN_APPS) 0: - cpmcp -f atari90 $@ $(OBJDIR)/apps/ls.com $(OBJDIR)/setfnt.com $(OBJDIR)/tty80drv.com third_party/fonts/atari/olivetti.fnt 1: - cpmchattr -f atari90 $@ sr 0:ccp.sys o:bdos.sys - dd if=$(OBJDIR)/atari800.exe of=$@ bs=128 conv=notrunc - mv $@ $@.raw - /usr/bin/printf '\x96\x02\x80\x16\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > $@ - cat $@.raw >> $@ - rm $@.raw - -$(OBJDIR)/src/bios/atari800hd.o: CFLAGS65 += -DATARI_HD -$(OBJDIR)/atari800hd.exe: -atari800hd.atr: $(OBJDIR)/atari800hd.exe $(OBJDIR)/bdos.sys Makefile \ - $(APPS) $(OBJDIR)/ccp.sys $(OBJDIR)/a8setfnt.com \ - $(SCREEN_APPS) $(OBJDIR)/a8tty80drv.com - dd if=/dev/zero of=$@ bs=128 count=8190 - mkfs.cpm -f atarihd $@ - cp $(OBJDIR)/a8setfnt.com $(OBJDIR)/setfnt.com - cp $(OBJDIR)/a8tty80drv.com $(OBJDIR)/tty80drv.com - cpmcp -f atarihd $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) $(SCREEN_APPS) 0: - cpmcp -f atarihd $@ $(OBJDIR)/apps/ls.com $(OBJDIR)/setfnt.com $(OBJDIR)/tty80drv.com third_party/fonts/atari/*.fnt 1: - cpmchattr -f atarihd $@ sr 0:ccp.sys 0:bdos.sys - dd if=$(OBJDIR)/atari800hd.exe of=$@ bs=128 conv=notrunc - mv $@ $@.raw - /usr/bin/printf '\x96\x02\xf0\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > $@ - cat $@.raw >> $@ - rm $@.raw - -$(OBJDIR)/src/bios/atari800xlhd.o: CFLAGS65 += -DATARI_HD -DATARI_XL -$(OBJDIR)/atari800xlhd.exe: -atari800xlhd.atr: $(OBJDIR)/atari800xlhd.exe $(OBJDIR)/bdos.sys Makefile \ - $(APPS) $(OBJDIR)/ccp.sys $(OBJDIR)/a8setfnt.com \ - $(SCREEN_APPS) $(OBJDIR)/a8tty80drv.com - dd if=/dev/zero of=$@ bs=128 count=8190 - mkfs.cpm -f atarihd $@ - cp $(OBJDIR)/a8setfnt.com $(OBJDIR)/setfnt.com - cp $(OBJDIR)/a8tty80drv.com $(OBJDIR)/tty80drv.com - cpmcp -f atarihd $@ $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) $(SCREEN_APPS) 0: - cpmcp -f atarihd $@ $(OBJDIR)/apps/ls.com $(OBJDIR)/setfnt.com $(OBJDIR)/tty80drv.com third_party/fonts/atari/*.fnt 1: - cpmchattr -f atarihd $@ sr 0:ccp.sys 0:bdos.sys - dd if=$(OBJDIR)/atari800xlhd.exe of=$@ bs=128 conv=notrunc - mv $@ $@.raw - /usr/bin/printf '\x96\x02\xf0\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > $@ - cat $@.raw >> $@ - rm $@.raw - -oric.dsk: $(OBJDIR)/oric.exe $(OBJDIR)/bdos.sys Makefile \ - $(APPS) $(SCREEN_APPS) $(OBJDIR)/ccp.sys $(OBJDIR)/mkoricdsk - mkfs.cpm -f oric -b $(OBJDIR)/oric.exe $(OBJDIR)/oric.img - cpmcp -f oric $(OBJDIR)/oric.img $(OBJDIR)/bdos.sys $(OBJDIR)/ccp.sys $(APPS) $(SCREEN_APPS) 0: - cpmchattr -f oric $(OBJDIR)/oric.img sr 0:ccp.sys 0:bdos.sys - $(OBJDIR)/mkoricdsk -i $(OBJDIR)/oric.img -o $@ - -clean: - rm -rf $(OBJDIR) bin $(TARGETS) - -.DELETE_ON_ERROR: -.SECONDARY: +.PHONY: all +all: +all +include build/ab.mk diff --git a/apps/build.py b/apps/build.py new file mode 100644 index 00000000..465582b7 --- /dev/null +++ b/apps/build.py @@ -0,0 +1,39 @@ +from build.ab import Rule, Target, Targets, normalrule +from build.llvm import llvmprogram + + +@Rule +def asm(self, name, src: Target = None, deps: Targets = []): + normalrule( + replaces=self, + ins=[src], + outs=["out.com"], + deps=["tools/cpmemu", "apps+asm"] + deps, + commands=[ + "chronic {deps[0]} {deps[1]} -pA=$(dir {ins[0]}) -pB=$(dir {outs[0]})" + + " a:$(notdir {ins[0]}) b:$(notdir {outs[0]})", + "test -f {outs[0]}", + ], + label="ASM", + ) + + +# CP/M-65 assembler programs. + +for prog in [ + "bedit", + "capsdrv", + "cls", + "cpuinfo", + "devices", + "dinfo", + "dump", + "ls", + "scrntest", +]: + asm(name=prog, src=("./%s.asm" % prog), deps=["./cpm65.inc"]) + +# Simple C programs. + +for prog in ["asm", "copy", "stat", "submit", "objdump", "qe", "life"]: + llvmprogram(name=prog, srcs=["./%s.c" % prog], deps=["lib+cpm65"]) diff --git a/build.py b/build.py new file mode 100644 index 00000000..ecbad162 --- /dev/null +++ b/build.py @@ -0,0 +1,26 @@ +from build.ab import export +from build.pkg import package + +package(name="libreadline", package="readline") +package(name="libfmt", package="fmt") + +export( + name="all", + items={ + "bin/cpmemu": "tools/cpmemu", + "bin/mads": "third_party/mads", + "bin/atbasic.com": "third_party/altirrabasic", + "bbcmicro.ssd": "src/arch/bbcmicro+diskimage", + "oric.dsk": "src/arch/oric+diskimage", + "apple2e.po": "src/arch/apple2e+diskimage", + "atari800.atr": "src/arch/atari800+atari800_diskimage", + "atari800hd.atr": "src/arch/atari800+atari800hd_diskimage", + "atari800xlhd.atr": "src/arch/atari800+atari800xlhd_diskimage", + "c64.d64": "src/arch/commodore+c64_diskimage", + "pet4032.d64": "src/arch/commodore+pet4032_diskimage", + "pet8032.d64": "src/arch/commodore+pet8032_diskimage", + "pet8096.d64": "src/arch/commodore+pet8096_diskimage", + "vic20.d64": "src/arch/commodore+vic20_diskimage", + "x16.zip": "src/arch/x16+diskimage", + }, +) diff --git a/build/_objectify.py b/build/_objectify.py new file mode 100644 index 00000000..17148954 --- /dev/null +++ b/build/_objectify.py @@ -0,0 +1,19 @@ +import sys +from functools import partial + +if len(sys.argv) != 3: + sys.exit("Usage: %s " % sys.argv[0]) +filename = sys.argv[1] +symbol = sys.argv[2] + +print("const uint8_t " + symbol + "[] = {") +n = 0 +with open(filename, "rb") as in_file: + for c in iter(partial(in_file.read, 1), b""): + print("0x%02X," % ord(c), end="") + n += 1 + if n % 16 == 0: + print() +print("};") + +print("const size_t " + symbol + "_len = sizeof(" + symbol + ");") diff --git a/build/ab.mk b/build/ab.mk new file mode 100644 index 00000000..aa5d2395 --- /dev/null +++ b/build/ab.mk @@ -0,0 +1,54 @@ +ifeq ($(findstring 4.,$(MAKE_VERSION)),) +$(error You need GNU Make 4.x for this (if you're on OSX, use gmake).) +endif + +OBJ ?= .obj +PYTHON ?= python3 +CC ?= gcc +CXX ?= g++ +AR ?= ar +CFLAGS ?= -g -Og +LDFLAGS ?= -g +PKG_CONFIG ?= pkg-config +ECHO ?= echo + +ifdef VERBOSE + hide = +else + ifdef V + hide = + else + hide = @ + endif +endif + +ifeq ($(OS), Windows_NT) + EXT ?= .exe +endif +EXT ?= + +include $(OBJ)/build.mk + +.SECONDARY: +.DELETE_ON_ERROR: + +.PHONY: update-ab +update-ab: + @echo "Press RETURN to update ab from the repository, or CTRL+C to cancel." \ + && read a \ + && (curl -L https://github.com/davidgiven/ab/releases/download/dev/distribution.tar.xz | tar xvJf -) \ + && echo "Done." + +.PHONY: clean +clean:: + @echo CLEAN + $(hide) rm -rf $(OBJ) bin + +export PYTHONHASHSEED = 1 +build-files = $(shell find . -name 'build.py') $(wildcard build/*.py) $(wildcard config.py) +$(OBJ)/build.mk: Makefile $(build-files) + @echo "AB" + @mkdir -p $(OBJ) + $(hide) $(PYTHON) -X pycache_prefix=$(OBJ) build/ab.py -t +all -o $@ \ + build.py || rm -f $@ + diff --git a/build/ab.py b/build/ab.py new file mode 100644 index 00000000..61d948c3 --- /dev/null +++ b/build/ab.py @@ -0,0 +1,506 @@ +from collections.abc import Iterable, Sequence +from os.path import * +from types import SimpleNamespace +import argparse +import functools +import importlib +import importlib.abc +import importlib.util +import inspect +import re +import sys +import builtins +import string + +defaultGlobals = {} +targets = {} +unmaterialisedTargets = set() +materialisingStack = [] +outputFp = None +cwdStack = [""] + +sys.path += ["."] +old_import = builtins.__import__ + + +def new_import(name, *args, **kwargs): + if name not in sys.modules: + path = name.replace(".", "/") + ".py" + if isfile(path): + sys.stderr.write(f"loading {path}\n") + loader = importlib.machinery.SourceFileLoader(name, path) + + spec = importlib.util.spec_from_loader( + name, loader, origin="built-in" + ) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + cwdStack.append(dirname(path)) + spec.loader.exec_module(module) + cwdStack.pop() + + return old_import(name, *args, **kwargs) + + +builtins.__import__ = new_import + + +class ABException(BaseException): + pass + + +class ParameterList(Sequence): + def __init__(self, parent=[]): + self.data = parent + + def __getitem__(self, i): + return self.data[i] + + def __len__(self): + return len(self.data) + + def __str__(self): + return " ".join(self.data) + + def __add__(self, other): + newdata = self.data.copy() + other + return ParameterList(newdata) + + def __repr__(self): + return f"" + + +class Invocation: + name = None + callback = None + types = None + ins = None + outs = None + binding = None + + def materialise(self, replacing=False): + if self in unmaterialisedTargets: + if not replacing and (self in materialisingStack): + print("Found dependency cycle:") + for i in materialisingStack: + print(f" {i.name}") + print(f" {self.name}") + sys.exit(1) + + materialisingStack.append(self) + + # Perform type conversion to the declared rule parameter types. + + try: + self.args = {} + for k, v in self.binding.arguments.items(): + if k != "kwargs": + t = self.types.get(k, None) + if t: + v = t(v).convert(self) + self.args[k] = v + else: + for kk, vv in v.items(): + t = self.types.get(kk, None) + if t: + vv = t(vv).convert(self) + self.args[kk] = vv + + # Actually call the callback. + + cwdStack.append(self.cwd) + self.callback(**self.args) + cwdStack.pop() + except BaseException as e: + print( + f"Error materialising {self} ({id(self)}): {self.callback}" + ) + print(f"Arguments: {self.args}") + raise e + + if self.outs is None: + raise ABException(f"{self.name} didn't set self.outs") + + if self in unmaterialisedTargets: + unmaterialisedTargets.remove(self) + + materialisingStack.pop() + + def __repr__(self): + return "" % self.name + + +def Rule(func): + sig = inspect.signature(func) + + @functools.wraps(func) + def wrapper(*, name=None, replaces=None, **kwargs): + cwd = None + if name: + if ("+" in name) and not name.startswith("+"): + (cwd, _) = name.split("+", 1) + if not cwd: + cwd = cwdStack[-1] + + if name: + i = Invocation() + if name.startswith("./"): + name = join(cwd, name) + elif "+" not in name: + name = cwd + "+" + name + + i.name = name + i.localname = name.split("+")[-1] + + if name in targets: + raise ABException(f"target {i.name} has already been defined") + targets[name] = i + elif replaces: + i = replaces + name = i.name + else: + raise ABException("you must supply either name or replaces") + + i.cwd = cwd + i.types = func.__annotations__ + i.callback = func + setattr(i, func.__name__, SimpleNamespace()) + + i.binding = sig.bind(name=name, self=i, **kwargs) + i.binding.apply_defaults() + + unmaterialisedTargets.add(i) + if replaces: + i.materialise(replacing=True) + return i + + defaultGlobals[func.__name__] = wrapper + return wrapper + + +class Type: + def __init__(self, value): + self.value = value + + +class List(Type): + def convert(self, invocation): + value = self.value + if not value: + return [] + if type(value) is str: + return [value] + return list(value) + + +class Targets(Type): + def convert(self, invocation): + value = self.value + if not value: + return [] + if type(value) is str: + value = [value] + if type(value) is list: + value = targetsof(value, cwd=invocation.cwd) + return value + + +class Target(Type): + def convert(self, invocation): + value = self.value + if not value: + return None + return targetof(value, cwd=invocation.cwd) + + +class TargetsMap(Type): + def convert(self, invocation): + value = self.value + if not value: + return {} + if type(value) is dict: + return { + k: targetof(v, cwd=invocation.cwd) for k, v in value.items() + } + raise ABException(f"wanted a dict of targets, got a {type(value)}") + + +def flatten(*xs): + def recurse(xs): + for x in xs: + if isinstance(x, Iterable) and not isinstance(x, (str, bytes)): + yield from recurse(x) + else: + yield x + + return list(recurse(xs)) + + +def fileinvocation(s): + i = Invocation() + i.name = s + i.outs = [s] + targets[s] = i + return i + + +def targetof(s, cwd): + if isinstance(s, Invocation): + s.materialise() + return s + + if type(s) != str: + raise ABException("parameter of targetof is not a single target") + + if s in targets: + t = targets[s] + t.materialise() + return t + + if s.startswith(".+"): + s = cwd + s[1:] + elif s.startswith("./"): + s = normpath(join(cwd, s)) + elif s.endswith("/"): + return fileinvocation(s) + elif s.startswith("$"): + return fileinvocation(s) + + if "+" not in s: + if isdir(s): + s = s + "+" + basename(s) + else: + return fileinvocation(s) + + (path, target) = s.split("+", 2) + loadbuildfile(join(path, "build.py")) + if not s in targets: + raise ABException(f"build file at {path} doesn't contain +{target}") + i = targets[s] + i.materialise() + return i + + +def targetsof(*xs, cwd): + return flatten([targetof(x, cwd) for x in flatten(xs)]) + + +def filenamesof(*xs): + s = [] + for t in flatten(xs): + if type(t) == str: + t = normpath(t) + s += [t] + else: + s += [f for f in [normpath(f) for f in filenamesof(t.outs)]] + return s + + +def targetnamesof(*xs): + s = [] + for x in flatten(xs): + if type(x) == str: + x = normpath(x) + if x not in s: + s += [x] + else: + if x.name not in s: + s += [x.name] + return s + + +def filenameof(x): + xs = filenamesof(x) + if len(xs) != 1: + raise ABException("expected a single item") + return xs[0] + + +def stripext(path): + return splitext(path)[0] + + +def emit(*args): + outputFp.write(" ".join(flatten(args))) + outputFp.write("\n") + + +def templateexpand(s, invocation): + class Formatter(string.Formatter): + def get_field(self, name, a1, a2): + return ( + eval(name, invocation.callback.__globals__, invocation.args), + False, + ) + + def format_field(self, value, format_spec): + if type(self) == str: + return value + return " ".join( + [templateexpand(f, invocation) for f in filenamesof(value)] + ) + + return Formatter().format(s) + + +def emitter_rule(name, ins, outs, deps=[]): + emit("") + emit(".PHONY:", name) + if outs: + emit(name, ":", filenamesof(outs), ";") + emit(filenamesof(outs), "&:", filenamesof(ins), filenamesof(deps)) + else: + emit(name, "&:", filenamesof(ins), filenamesof(deps)) + + +def emitter_endrule(name): + pass + + +def emitter_label(s): + emit("\t$(hide)", "$(ECHO)", s) + + +def emitter_exec(cs): + for c in cs: + emit("\t$(hide)", c) + + +def unmake(*ss): + return [ + re.sub(r"\$\(([^)]*)\)", r"$\1", s) for s in flatten(filenamesof(ss)) + ] + + +@Rule +def simplerule( + self, + name, + ins: Targets = None, + outs: List = [], + deps: Targets = None, + commands: List = [], + label="RULE", + **kwargs, +): + self.ins = ins + self.outs = outs + self.deps = deps + emitter_rule(self.name, ins + deps, outs) + emitter_label(templateexpand("{label} {name}", self)) + + dirs = [] + for out in filenamesof(outs): + dir = dirname(out) + if dir and dir not in dirs: + dirs += [dir] + + cs = [("mkdir -p %s" % dir) for dir in dirs] + for c in commands: + cs += [templateexpand(c, self)] + emitter_exec(cs) + emitter_endrule(self.name) + + +@Rule +def normalrule( + self, + name=None, + ins: Targets = None, + deps: Targets = None, + outs: List = [], + label="RULE", + objdir=None, + commands: List = [], + **kwargs, +): + objdir = objdir or join("$(OBJ)", name) + + self.normalrule.objdir = objdir + simplerule( + replaces=self, + ins=ins, + deps=deps, + outs=[join(objdir, f) for f in outs], + label=label, + commands=commands, + **kwargs, + ) + + +@Rule +def export(self, name=None, items: TargetsMap = {}, deps: Targets = None): + cs = [] + self.ins = items.values() + self.outs = [] + for dest, src in items.items(): + destf = filenameof(dest) + dir = dirname(destf) + + srcs = filenamesof(src) + if len(srcs) != 1: + raise ABException( + "a dependency of an export must have exactly one output file" + ) + + emitter_rule(self.name + "+" + destf, srcs, [destf]) + emitter_label(f"CP {destf}") + if dir: + emitter_exec(["mkdir -p " + dir]) + + emitter_exec(["cp %s %s" % (srcs[0], destf)]) + self.outs += [destf] + + emitter_rule(self.name, self.outs, [], deps) + emit("\t@") + + if self.outs: + emit("clean::") + emit("\t$(hide) rm -f " + (" ".join(filenamesof(self.outs)))) + self.outs += deps + + emitter_endrule(self.name) + + +def loadbuildfile(filename): + filename = filename.replace("/", ".").removesuffix(".py") + builtins.__import__(filename) + + +def load(filename): + loadbuildfile(filename) + callerglobals = inspect.stack()[1][0].f_globals + for k, v in defaultGlobals.items(): + callerglobals[k] = v + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("-o", "--output") + parser.add_argument("files", nargs="+") + parser.add_argument("-t", "--targets", action="append") + args = parser.parse_args() + if not args.targets: + raise ABException("no targets supplied") + + global outputFp + outputFp = open(args.output, "wt") + + for k in ("Rule", "Targets", "load", "filenamesof", "stripext"): + defaultGlobals[k] = globals()[k] + + global __name__ + sys.modules["build.ab"] = sys.modules[__name__] + __name__ = "build.ab" + + for f in args.files: + loadbuildfile(f) + + for t in flatten([a.split(",") for a in args.targets]): + if t not in targets: + raise ABException("target %s is not defined" % t) + targets[t].materialise() + emit("AB_LOADED = 1\n") + + +main() diff --git a/build/c.py b/build/c.py new file mode 100644 index 00000000..04d5b626 --- /dev/null +++ b/build/c.py @@ -0,0 +1,287 @@ +from os.path import basename, join +from build.ab import ( + ABException, + Rule, + Targets, + TargetsMap, + List, + filenameof, + flatten, + filenamesof, + normalrule, + stripext, +) +from os.path import * +from types import SimpleNamespace + + +def cfileimpl(self, name, srcs, deps, suffix, commands, label, kind, cflags): + libraries = [d for d in deps if hasattr(d, "clibrary")] + for library in libraries: + if library.clibrary.cflags: + cflags += library.clibrary.cflags + + outleaf = stripext(basename(filenameof(srcs[0]))) + suffix + + normalrule( + replaces=self, + ins=srcs, + deps=deps, + outs=[outleaf], + label=label, + commands=commands, + cflags=cflags, + ) + + +@Rule +def cfile( + self, + name, + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], + suffix=".o", + commands=["$(CC) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"], + label="CC", +): + cfileimpl(self, name, srcs, deps, suffix, commands, label, "cfile", cflags) + + +@Rule +def cxxfile( + self, + name, + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], + suffix=".o", + commands=["$(CXX) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"], + label="CXX", +): + cfileimpl( + self, name, srcs, deps, suffix, commands, label, "cxxfile", cflags + ) + + +def findsources(name, srcs, deps, cflags, filerule): + objs = [] + for s in flatten(srcs): + objs += [ + filerule( + name=join(name, f.removeprefix("$(OBJ)/")), + srcs=[f], + deps=deps, + cflags=cflags, + ) + for f in filenamesof(s) + if f.endswith(".c") + or f.endswith(".cc") + or f.endswith(".cpp") + or f.endswith(".S") + or f.endswith(".s") + ] + if any(f.endswith(".o") for f in filenamesof(s)): + objs += [s] + + return objs + + +def libraryimpl( + self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, kind +): + if not srcs and not hdrs: + raise ABException( + "clibrary contains no sources and no exported headers" + ) + + libraries = [d for d in deps if hasattr(d, "clibrary")] + for library in libraries: + if library.clibrary.cflags: + cflags += library.clibrary.cflags + if library.clibrary.ldflags: + ldflags += library.clibrary.ldflags + + for f in filenamesof(srcs): + if f.endswith(".h"): + deps += [f] + + hdrcs = [] + hdrins = list(hdrs.values()) + hdrouts = [] + i = 0 + for dest, src in hdrs.items(): + s = filenamesof(src) + if len(s) != 1: + raise ABException( + "a dependency of an export must have exactly one output file" + ) + + hdrcs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"] + hdrouts += [dest] + i = i + 1 + + if not hasattr(self, "clibrary"): + self.clibrary = SimpleNamespace() + if srcs: + hr = None + if hdrcs: + hr = normalrule( + name=f"{name}_hdrs", + ins=hdrins, + outs=hdrouts, + label="HEADERS", + commands=hdrcs, + ) + hr.materialise() + + actualsrcs = findsources( + name, + srcs, + deps + ([f"{name}_hdrs"] if hr else []), + cflags + ([f"-I{hr.normalrule.objdir}"] if hr else []), + kind, + ) + + normalrule( + replaces=self, + ins=actualsrcs, + outs=[basename(name) + ".a"], + label=label, + commands=commands if actualsrcs else [], + ) + + self.clibrary.ldflags = ldflags + self.clibrary.cflags = ["-I" + hr.normalrule.objdir] if hr else [] + else: + r = normalrule( + replaces=self, + ins=hdrins, + outs=hdrouts, + label="HEADERS", + commands=hdrcs, + ) + r.materialise() + + self.clibrary.ldflags = ldflags + self.clibrary.cflags = ["-I" + r.normalrule.objdir] + + +@Rule +def clibrary( + self, + name, + srcs: Targets = None, + deps: Targets = None, + hdrs: TargetsMap = {}, + cflags: List = [], + ldflags: List = [], + commands=["$(AR) cqs {outs[0]} {ins}"], + label="LIB", + cfilerule=cfile, +): + return libraryimpl( + self, + name, + srcs, + deps, + hdrs, + cflags, + ldflags, + commands, + label, + cfilerule, + ) + + +@Rule +def cxxlibrary( + self, + name, + srcs: Targets = None, + deps: Targets = None, + hdrs: TargetsMap = {}, + cflags: List = [], + ldflags: List = [], + commands=["$(AR) cqs {outs[0]} {ins}"], + label="LIB", +): + return libraryimpl( + self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, cxxfile + ) + + +def programimpl( + self, name, srcs, deps, cflags, ldflags, commands, label, filerule, kind +): + libraries = [d for d in deps if hasattr(d, "clibrary")] + for library in libraries: + if library.clibrary.cflags: + cflags += library.clibrary.cflags + if library.clibrary.ldflags: + ldflags += library.clibrary.ldflags + + deps += [f for f in filenamesof(srcs) if f.endswith(".h")] + + ars = [f for f in filenamesof(libraries) if f.endswith(".a")] + normalrule( + replaces=self, + ins=(findsources(name, srcs, deps, cflags, filerule) + ars + ars), + outs=[basename(name) + "$(EXT)"], + deps=deps, + label=label, + commands=commands, + ldflags=ldflags, + ) + + +@Rule +def cprogram( + self, + name, + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], + ldflags: List = [], + commands=["$(CC) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"], + label="CLINK", + cfilerule=cfile, + cfilekind="cprogram", +): + programimpl( + self, + name, + srcs, + deps, + cflags, + ldflags, + commands, + label, + cfilerule, + cfilekind, + ) + + +@Rule +def cxxprogram( + self, + name, + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], + ldflags: List = [], + commands=["$(CXX) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"], + label="CXXLINK", +): + programimpl( + self, + name, + srcs, + deps, + cflags, + ldflags, + commands, + label, + cxxfile, + "cxxprogram", + ) diff --git a/build/llvm.py b/build/llvm.py new file mode 100644 index 00000000..74b23bfb --- /dev/null +++ b/build/llvm.py @@ -0,0 +1,84 @@ +from build.ab import Rule, Targets, Target, List +from build.c import cprogram, cfile, clibrary + + +@Rule +def llvmcfile( + self, + name, + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], + suffix=".o", + commands=["$(CC6502) -c -o {outs[0]} {ins[0]} $(CFLAGS6502) {cflags}"], + label="CC6502", +): + cfile( + replaces=self, + srcs=srcs, + deps=deps, + cflags=cflags, + suffix=suffix, + commands=commands, + label=label, + ) + + +@Rule +def llvmprogram( + self, + name=None, + srcs: Targets = None, + deps: Targets = None, + cflags: List = None, + ldflags: List = None, + commands: List = ["$(CC6502) -o {outs[0]} {ins} {ldflags} $(LDFLAGS6502)"], + label="CLINK6502", +): + cprogram( + replaces=self, + srcs=srcs, + deps=deps, + cflags=cflags, + ldflags=ldflags, + commands=commands, + label=label, + cfilerule=llvmcfile, + cfilekind="llvmprogram", + ) + + +@Rule +def llvmrawprogram( + self, + name, + linkscript: Target, + deps: Targets = None, + commands=[ + "$(LD6502) -Map {outs[0]}.map -T {deps[-1]} -o {outs[0]} {ins} {ldflags}" + ], + label="LD6502", + **kwargs +): + cprogram( + replaces=self, + deps=deps + [linkscript], + commands=commands, + label=label, + cfilerule=llvmcfile, + cfilekind="llvmprogram", + **kwargs + ) + + +@Rule +def llvmclibrary( + name, self, commands=["$(AR6502) cqs {outs[0]} {ins}"], **kwargs +): + clibrary( + replaces=self, + commands=commands, + cfilerule=llvmcfile, + label="LIB6502", + **kwargs + ) diff --git a/build/pkg.py b/build/pkg.py new file mode 100644 index 00000000..769cc15f --- /dev/null +++ b/build/pkg.py @@ -0,0 +1,38 @@ +from build.ab import Rule, emit, Target +from types import SimpleNamespace +import os +import subprocess + +emit( + """ +PKG_CONFIG ?= pkg-config +PACKAGES := $(shell $(PKG_CONFIG) --list-all | cut -d' ' -f1 | sort) +""" +) + + +@Rule +def package(self, name, package=None, fallback: Target = None): + emit("ifeq ($(filter %s, $(PACKAGES)),)" % package) + if fallback: + emit(f"PACKAGE_CFLAGS_{package} :=", fallback.clibrary.cflags) + emit(f"PACKAGE_LDFLAGS_{package} := ", fallback.clibrary.ldflags) + emit(f"PACKAGE_DEP_{package} := ", fallback.name) + else: + emit(f"$(error Required package '{package}' not installed.)") + emit("else") + emit( + f"PACKAGE_CFLAGS_{package} := $(shell $(PKG_CONFIG) --cflags {package})" + ) + emit( + f"PACKAGE_LDFLAGS_{package} := $(shell $(PKG_CONFIG) --libs {package})" + ) + emit(f"PACKAGE_DEP_{package} := ") + emit("endif") + + self.clibrary = SimpleNamespace() + self.clibrary.cflags = [f"$(PACKAGE_CFLAGS_{package})"] + self.clibrary.ldflags = [f"$(PACKAGE_LDFLAGS_{package})"] + + self.ins = [] + self.outs = [f"$(PACKAGE_DEP_{package})"] diff --git a/build/protobuf.py b/build/protobuf.py new file mode 100644 index 00000000..27483cbf --- /dev/null +++ b/build/protobuf.py @@ -0,0 +1,65 @@ +from os.path import join +from build.ab import Rule, Targets, emit, normalrule, filenamesof, flatten +from build.c import cxxlibrary +import build.pkg +from types import SimpleNamespace + +emit( + """ +PROTOC ?= protoc +ifeq ($(filter protobuf, $(PACKAGES)),) +$(error Required package 'protobuf' not installed.)" +endif +""" +) + + +@Rule +def proto(self, name, srcs: Targets = None, deps: Targets = None): + normalrule( + replaces=self, + ins=srcs, + outs=[f"{name}.descriptor"], + deps=deps, + commands=[ + "$(PROTOC) --include_source_info --descriptor_set_out={outs[0]} {ins}" + ], + label="PROTO", + ) + self.proto.srcs = filenamesof(srcs) + flatten( + [s.proto.srcs for s in flatten(deps)] + ) + + +@Rule +def protocc(self, name, srcs: Targets = None, deps: Targets = None): + outs = [] + protos = [] + for f in flatten([s.proto.srcs for s in flatten(srcs + deps)]): + if f.endswith(".proto"): + cc = f.replace(".proto", ".pb.cc") + h = f.replace(".proto", ".pb.h") + protos += [f] + srcs += [f] + outs += [cc, h] + + r = normalrule( + name=f"{name}_srcs", + ins=protos, + outs=outs, + deps=deps, + commands=["$(PROTOC) --cpp_out={self.normalrule.objdir} {ins}"], + label="PROTOCC", + ) + + r.materialise() + headers = { + f: join(r.normalrule.objdir, f) for f in outs if f.endswith(".pb.h") + } + + cxxlibrary( + replaces=self, + srcs=[f"{name}_srcs"], + hdrs=headers, + cflags=[f"-I{r.normalrule.objdir}"], + ) diff --git a/build/utils.py b/build/utils.py new file mode 100644 index 00000000..0ce1cbc6 --- /dev/null +++ b/build/utils.py @@ -0,0 +1,43 @@ +from build.ab import Rule, normalrule, Target, filenameof, Targets +from os.path import basename + + +@Rule +def objectify(self, name, src: Target, symbol): + normalrule( + replaces=self, + ins=["build/_objectify.py", src], + outs=[basename(filenameof(src)) + ".h"], + commands=["$(PYTHON) {ins[0]} {ins[1]} " + symbol + " > {outs}"], + label="OBJECTIFY", + ) + + +@Rule +def test( + self, + name, + command: Target = None, + commands=None, + ins: Targets = None, + deps: Targets = None, + label="TEST", +): + if command: + normalrule( + replaces=self, + ins=[command], + outs=["sentinel"], + commands=["{ins[0]}", "touch {outs}"], + deps=deps, + label=label, + ) + else: + normalrule( + replaces=self, + ins=ins, + outs=["sentinel"], + commands=commands + ["touch {outs}"], + deps=deps, + label=label, + ) diff --git a/config.py b/config.py new file mode 100644 index 00000000..13233804 --- /dev/null +++ b/config.py @@ -0,0 +1,36 @@ +MINIMAL_APPS = { + "0:asm.com": "apps+asm", + "0:bedit.com": "apps+bedit", + "0:capsdrv.com": "apps+capsdrv", + "0:copy.com": "apps+copy", + "0:cpuinfo.com": "apps+cpuinfo", + "0:devices.com": "apps+devices", + "0:dinfo.com": "apps+dinfo", + "0:dump.com": "apps+dump", + "0:ls.com": "apps+ls", + "0:stat.com": "apps+stat", + "0:submit.com": "apps+submit", +} + +MINIMAL_APPS_SRCS = { + "0:dump.asm": "apps/dump.asm", + "0:ls.asm": "apps/ls.asm", + "0:cpm65.inc": "apps/cpm65.inc", + "0:drivers.inc": "apps/drivers.inc", +} + +BIG_APPS = { + "0:atbasic.com": "third_party/altirrabasic", + "0:objdump.com": "apps+objdump", + "0:scrntest.com": "apps+scrntest", +} + +BIG_APPS_SRCS = {} + +SCREEN_APPS = { + "0:cls.com": "apps+cls", + "0:life.com": "apps+life", + "0:qe.com": "apps+qe", +} + +SCREEN_APPS_SRCS = {"0:cls.asm": "apps/cls.asm"} diff --git a/include/build.py b/include/build.py new file mode 100644 index 00000000..5308ba42 --- /dev/null +++ b/include/build.py @@ -0,0 +1,12 @@ +from build.llvm import llvmclibrary + +llvmclibrary( + name="include", + hdrs={ + "cpm65.inc": "./cpm65.inc", + "driver.inc": "./driver.inc", + "jumptables.inc": "./jumptables.inc", + "wait.inc": "./wait.inc", + "zif.inc": "./zif.inc", + }, +) diff --git a/lib/build.py b/lib/build.py new file mode 100644 index 00000000..8c83df5b --- /dev/null +++ b/lib/build.py @@ -0,0 +1,11 @@ +from build.llvm import llvmclibrary + +llvmclibrary(name="bdos", srcs=["./bdos.S"], deps=["include"]) +llvmclibrary(name="xfcb", srcs=["./xfcb.S"], deps=["include"]) + +llvmclibrary( + name="cpm65", + srcs=["./printi.S", "./screen.S"], + hdrs={"lib/printi.h": "./printi.h", "lib/screen.h": "./screen.h"}, + deps=["include"], +) diff --git a/scripts/pet4032.ld b/scripts/pet4032.ld deleted file mode 120000 index 8eafaed7..00000000 --- a/scripts/pet4032.ld +++ /dev/null @@ -1 +0,0 @@ -pet.ld \ No newline at end of file diff --git a/scripts/pet8032.ld b/scripts/pet8032.ld deleted file mode 120000 index 8eafaed7..00000000 --- a/scripts/pet8032.ld +++ /dev/null @@ -1 +0,0 @@ -pet.ld \ No newline at end of file diff --git a/scripts/size.awk b/scripts/size.awk new file mode 100644 index 00000000..41974095 --- /dev/null +++ b/scripts/size.awk @@ -0,0 +1,7 @@ +/ [0-9]+/ { + size[$2] = ("0x"$3)+0 +} + +END { + print(size[".text"] + size[".data"] + size[".bss"]) +} diff --git a/scripts/apple2e-prelink.ld b/src/arch/apple2e/apple2e-prelink.ld similarity index 100% rename from scripts/apple2e-prelink.ld rename to src/arch/apple2e/apple2e-prelink.ld diff --git a/src/bios/apple2e.S b/src/arch/apple2e/apple2e.S similarity index 100% rename from src/bios/apple2e.S rename to src/arch/apple2e/apple2e.S diff --git a/scripts/apple2e.ld b/src/arch/apple2e/apple2e.ld similarity index 100% rename from scripts/apple2e.ld rename to src/arch/apple2e/apple2e.ld diff --git a/src/arch/apple2e/build.py b/src/arch/apple2e/build.py new file mode 100644 index 00000000..f686e37b --- /dev/null +++ b/src/arch/apple2e/build.py @@ -0,0 +1,60 @@ +from build.ab import normalrule +from tools.build import mkdfs, mkcpmfs, shuffle +from build.llvm import llvmrawprogram, llvmcfile +from config import ( + MINIMAL_APPS, + MINIMAL_APPS_SRCS, + BIG_APPS, + BIG_APPS_SRCS, + SCREEN_APPS, + SCREEN_APPS_SRCS, +) + +llvmcfile( + name="bios_obj", + srcs=["./apple2e.S"], + deps=["include", "src/lib+bioslib"], +) + +llvmrawprogram( + name="bios_prelink", + srcs=[".+bios_obj"], + deps=["src/lib+bioslib"], + linkscript="./apple2e-prelink.ld", + ldflags=["--defsym=BIOS_SIZE=0x4000"], +) + +llvmrawprogram( + name="bios", + srcs=[".+bios_obj"], + deps=[ + ".+bios_prelink", + "scripts/size.awk", + "src/lib+bioslib", + ], + linkscript="./apple2e.ld", + ldflags=[ + "--defsym=BIOS_SIZE=$$($(LLVM)/llvm-objdump --section-headers {deps[0]} " + + "| gawk --non-decimal-data -f scripts/size.awk)" + ], +) + +shuffle( + name="bios_shuffled", + src=".+bios", + blocksize=256, + blockspertrack=16, + map="02468ace13579bdf", +) + +mkcpmfs( + name="diskimage", + format="appleiie", + bootimage=".+bios_shuffled", + size=143360, + items={"0:ccp.sys": "src+ccp", "0:bdos.sys": "src+bdos"} + | MINIMAL_APPS + | MINIMAL_APPS_SRCS + | BIG_APPS + | BIG_APPS_SRCS, +) diff --git a/src/bios/atari800.S b/src/arch/atari800/atari800.S similarity index 100% rename from src/bios/atari800.S rename to src/arch/atari800/atari800.S diff --git a/include/atari800.inc b/src/arch/atari800/atari800.inc similarity index 100% rename from include/atari800.inc rename to src/arch/atari800/atari800.inc diff --git a/scripts/atari800.ld b/src/arch/atari800/atari800.ld similarity index 100% rename from scripts/atari800.ld rename to src/arch/atari800/atari800.ld diff --git a/scripts/atari800hd.ld b/src/arch/atari800/atari800hd.ld similarity index 100% rename from scripts/atari800hd.ld rename to src/arch/atari800/atari800hd.ld diff --git a/scripts/atari800xlhd.ld b/src/arch/atari800/atari800xlhd.ld similarity index 100% rename from scripts/atari800xlhd.ld rename to src/arch/atari800/atari800xlhd.ld diff --git a/src/arch/atari800/build.py b/src/arch/atari800/build.py new file mode 100644 index 00000000..100414ea --- /dev/null +++ b/src/arch/atari800/build.py @@ -0,0 +1,122 @@ +from build.ab import normalrule +from tools.build import mkcpmfs +from build.llvm import llvmrawprogram, llvmclibrary +from config import ( + MINIMAL_APPS, + MINIMAL_APPS_SRCS, + BIG_APPS, + BIG_APPS_SRCS, + SCREEN_APPS, + SCREEN_APPS_SRCS, +) + +llvmclibrary(name="headers", hdrs={"atari800.inc": "./atari800.inc"}) + +llvmrawprogram( + name="atari800_bios", + srcs=["./atari800.S"], + deps=["include", "src/lib+bioslib", ".+headers"], + linkscript="./atari800.ld", +) + +mkcpmfs( + name="atari800_rawdiskimage", + format="atari90", + bootimage=".+atari800_bios", + items={ + "0:ccp.sys": "src+ccp", + "0:bdos.sys": "src+bdos", + "0:setfnt.com": "src/arch/atari800/utils+setfnt", + "0:tty80drv.com": "src/arch/atari800/utils+tty80drv", + "0:olivetti.fnt": "third_party/fonts/atari/olivetti.fnt", + } + | MINIMAL_APPS + | BIG_APPS, +) + +normalrule( + name="atari800_diskimage", + ins=[".+atari800_rawdiskimage"], + outs=["atari80.atr"], + commands=[ + r"/usr/bin/printf '\x96\x02\x80\x16\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > {outs[0]}", + "cat {ins[0]} >> {outs[0]}", + ], + label="MAKEATR", +) + +llvmrawprogram( + name="atari800hd_bios", + srcs=["./atari800.S"], + deps=["include", "src/lib+bioslib", ".+headers"], + cflags=["-DATARI_HD"], + linkscript="./atari800hd.ld", +) + +mkcpmfs( + name="atari800hd_rawdiskimage", + format="atarihd", + bootimage=".+atari800hd_bios", + items={ + "0:ccp.sys": "src+ccp", + "0:bdos.sys": "src+bdos", + "0:setfnt.com": "src/arch/atari800/utils+setfnt", + "0:tty80drv.com": "src/arch/atari800/utils+tty80drv", + "1:olivetti.fnt": "third_party/fonts/atari/olivetti.fnt", + } + | MINIMAL_APPS + | MINIMAL_APPS_SRCS + | BIG_APPS + | BIG_APPS_SRCS + | SCREEN_APPS + | SCREEN_APPS_SRCS, +) + +normalrule( + name="atari800hd_diskimage", + ins=[".+atari800hd_rawdiskimage"], + outs=["atari80hd.atr"], + commands=[ + r"/usr/bin/printf '\x96\x02\xf0\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > {outs[0]}", + "cat {ins[0]} >> {outs[0]}", + ], + label="MAKEATR", +) + +llvmrawprogram( + name="atari800xlhd_bios", + srcs=["./atari800.S"], + deps=["include", "src/lib+bioslib", ".+headers"], + cflags=["-DATARI_HD", "-DATARI_XL"], + linkscript="./atari800xlhd.ld", +) + +mkcpmfs( + name="atari800xlhd_rawdiskimage", + format="atarihd", + bootimage=".+atari800xlhd_bios", + items={ + "0:ccp.sys": "src+ccp", + "0:bdos.sys": "src+bdos", + "0:setfnt.com": "src/arch/atari800/utils+setfnt", + "0:tty80drv.com": "src/arch/atari800/utils+tty80drv", + "1:olivetti.fnt": "third_party/fonts/atari/olivetti.fnt", + } + | MINIMAL_APPS + | MINIMAL_APPS_SRCS + | BIG_APPS + | BIG_APPS_SRCS + | SCREEN_APPS + | SCREEN_APPS_SRCS, +) + +normalrule( + name="atari800xlhd_diskimage", + ins=[".+atari800xlhd_rawdiskimage"], + outs=["atari80xlhd.atr"], + commands=[ + r"/usr/bin/printf '\x96\x02\xf0\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > {outs[0]}", + "cat {ins[0]} >> {outs[0]}", + ], + label="MAKEATR", +) diff --git a/src/arch/atari800/utils/build.py b/src/arch/atari800/utils/build.py new file mode 100644 index 00000000..610441cc --- /dev/null +++ b/src/arch/atari800/utils/build.py @@ -0,0 +1,13 @@ +from build.llvm import llvmprogram + +llvmprogram(name="setfnt", srcs=["./setfnt.c"], deps=["lib+cpm65"]) + +llvmprogram( + name="tty80drv", + srcs=["./tty80drv.S"], + deps=[ + "include", + "src/arch/atari800+headers", + "third_party/fonts/atari+ivo3x6", + ], +) diff --git a/apps/a8setfnt.c b/src/arch/atari800/utils/setfnt.c similarity index 100% rename from apps/a8setfnt.c rename to src/arch/atari800/utils/setfnt.c diff --git a/apps/a8tty80drv.S b/src/arch/atari800/utils/tty80drv.S similarity index 99% rename from apps/a8tty80drv.S rename to src/arch/atari800/utils/tty80drv.S index 3f024f13..29e82c45 100644 --- a/apps/a8tty80drv.S +++ b/src/arch/atari800/utils/tty80drv.S @@ -38,7 +38,7 @@ #include "zif.inc" ; force to include the clang version and not the asm.com version -#include "include/cpm65.inc" +#include "cpm65.inc" #include "atari800.inc" #include "driver.inc" @@ -834,7 +834,7 @@ banner: ; position) equals 576 bytes font: - #include "../third_party/fonts/atari/ivo3x6.inc" + #include "third_party/fonts/atari/ivo3x6.inc" ; ------------------------------------------------------------------------- diff --git a/src/bios/bbcmicro.S b/src/arch/bbcmicro/bbcmicro.S similarity index 100% rename from src/bios/bbcmicro.S rename to src/arch/bbcmicro/bbcmicro.S diff --git a/scripts/bbcmicro.ld b/src/arch/bbcmicro/bbcmicro.ld similarity index 100% rename from scripts/bbcmicro.ld rename to src/arch/bbcmicro/bbcmicro.ld diff --git a/src/arch/bbcmicro/build.py b/src/arch/bbcmicro/build.py new file mode 100644 index 00000000..7a99d391 --- /dev/null +++ b/src/arch/bbcmicro/build.py @@ -0,0 +1,42 @@ +from build.ab import normalrule +from tools.build import mkdfs, mkcpmfs +from build.llvm import llvmrawprogram +from config import ( + MINIMAL_APPS, + MINIMAL_APPS_SRCS, + BIG_APPS, + BIG_APPS_SRCS, + SCREEN_APPS, + SCREEN_APPS_SRCS, +) + +llvmrawprogram( + name="bios", + srcs=["./bbcmicro.S", "./mos.inc"], + deps=["include", "src/lib+bioslib"], + linkscript="./bbcmicro.ld", +) + +mkcpmfs( + name="cpmfs", + format="bbc192", + items={"0:ccp.sys": "src+ccp"} + | MINIMAL_APPS + | MINIMAL_APPS_SRCS + | BIG_APPS + | BIG_APPS_SRCS + | SCREEN_APPS + | SCREEN_APPS_SRCS, +) + +mkdfs( + name="diskimage", + out="bbcmicro.ssd", + title="CP/M-65", + opt=2, + items={ + "!boot@0x0400": ".+bios", + "bdos": "src+bdos", + "cpmfs": ".+cpmfs", + }, +) diff --git a/include/mos.inc b/src/arch/bbcmicro/mos.inc similarity index 100% rename from include/mos.inc rename to src/arch/bbcmicro/mos.inc diff --git a/src/arch/commodore/build.py b/src/arch/commodore/build.py new file mode 100644 index 00000000..d9142344 --- /dev/null +++ b/src/arch/commodore/build.py @@ -0,0 +1,124 @@ +from build.ab import normalrule, TargetsMap, filenameof, Rule +from tools.build import mkcpmfs +from build.llvm import llvmrawprogram, llvmclibrary +from config import ( + MINIMAL_APPS, + MINIMAL_APPS_SRCS, + BIG_APPS, + BIG_APPS_SRCS, + SCREEN_APPS, + SCREEN_APPS_SRCS, +) + +COMMODORE_ITEMS = ( + {"0:ccp.sys": "src+ccp", "0:bdos.sys": "src+bdos"} + | MINIMAL_APPS + | MINIMAL_APPS_SRCS + | BIG_APPS + | BIG_APPS_SRCS +) + +COMMODORE_ITEMS_WITH_SCREEN = COMMODORE_ITEMS | SCREEN_APPS | SCREEN_APPS_SRCS + + +@Rule +def mkcbmfs(self, name, items: TargetsMap = {}, title="CBMFS", id=None): + cs = ["rm -f {outs[0]}"] + ins = [] + + cmd = "chronic cc1541 -q " + if id: + cmd += "-i %d " % id + cmd += '-n "%s" {outs[0]}' % title + cs += [cmd] + + for k, v in items.items(): + cs += [ + "chronic cc1541 -q -t -u 0 -r 18 -f %s -w %s {outs[0]}" + % (k, filenameof(v)) + ] + ins += [v] + + cs += ["{deps[0]} -f {outs[0]}"] + normalrule( + replaces=self, + ins=ins, + outs=[name + ".img"], + deps=["tools+mkcombifs"], + commands=cs, + label="MKCBMFS", + ) + + +llvmclibrary( + name="commodore_lib", srcs=["./ieee488.S", "./petscii.S"], deps=["include"] +) + +llvmrawprogram( + name="pet4032_bios", + srcs=["./pet.S"], + deps=["src/lib+bioslib", "include", ".+commodore_lib"], + cflags=["-DPET4032"], + ldflags=["--no-check-sections"], + linkscript="./pet.ld", +) + +llvmrawprogram( + name="pet8032_bios", + srcs=["./pet.S"], + deps=["src/lib+bioslib", "include", ".+commodore_lib"], + cflags=["-DPET8032"], + ldflags=["--no-check-sections"], + linkscript="./pet.ld", +) + +llvmrawprogram( + name="pet8096_bios", + srcs=["./pet.S"], + deps=["src/lib+bioslib", "include", ".+commodore_lib"], + cflags=["-DPET8096"], + ldflags=["--no-check-sections"], + linkscript="./pet8096.ld", +) + +llvmrawprogram( + name="c64_bios", + srcs=["./c64.S"], + deps=["src/lib+bioslib", "include", ".+commodore_lib"], + linkscript="./c64.ld", +) + +llvmrawprogram( + name="vic20_bios", + srcs=["./vic20.S"], + deps=[ + ".+commodore_lib", + "include", + "src/lib+bioslib", + "third_party/tomsfonts+4x8", + ], + linkscript="./vic20.ld", +) + +for target in ["c64", "pet4032", "pet8032", "pet8096", "vic20"]: + mkcbmfs( + name=target + "_cbmfs", + title="cp/m-65: %s" % target, + items={"cpm": ".+%s_bios" % target}, + ) + +for target in ["pet4032", "pet8032", "pet8096"]: + mkcpmfs( + name=target + "_diskimage", + format="c1541", + template=".+%s_cbmfs" % target, + items=COMMODORE_ITEMS_WITH_SCREEN, + ) + +for target in ["c64", "vic20"]: + mkcpmfs( + name=target + "_diskimage", + format="c1541", + template=".+%s_cbmfs" % target, + items=COMMODORE_ITEMS_WITH_SCREEN, + ) diff --git a/src/bios/c64.S b/src/arch/commodore/c64.S similarity index 100% rename from src/bios/c64.S rename to src/arch/commodore/c64.S diff --git a/scripts/c64.ld b/src/arch/commodore/c64.ld similarity index 100% rename from scripts/c64.ld rename to src/arch/commodore/c64.ld diff --git a/src/bios/commodore/ieee488.S b/src/arch/commodore/ieee488.S similarity index 100% rename from src/bios/commodore/ieee488.S rename to src/arch/commodore/ieee488.S diff --git a/src/bios/pet.S b/src/arch/commodore/pet.S similarity index 100% rename from src/bios/pet.S rename to src/arch/commodore/pet.S diff --git a/scripts/pet.ld b/src/arch/commodore/pet.ld similarity index 100% rename from scripts/pet.ld rename to src/arch/commodore/pet.ld diff --git a/scripts/pet8096.ld b/src/arch/commodore/pet8096.ld similarity index 100% rename from scripts/pet8096.ld rename to src/arch/commodore/pet8096.ld diff --git a/src/bios/commodore/petscii.S b/src/arch/commodore/petscii.S similarity index 100% rename from src/bios/commodore/petscii.S rename to src/arch/commodore/petscii.S diff --git a/src/bios/vic20.S b/src/arch/commodore/vic20.S similarity index 99% rename from src/bios/vic20.S rename to src/arch/commodore/vic20.S index 9240cc2d..f83cd313 100644 --- a/src/bios/vic20.S +++ b/src/arch/commodore/vic20.S @@ -765,7 +765,7 @@ zproc draw_glyph rts font_tab: - #include ".obj/4x8font.inc" + #include "4x8font.inc" zendproc zproc toggle_cursor diff --git a/scripts/vic20.ld b/src/arch/commodore/vic20.ld similarity index 100% rename from scripts/vic20.ld rename to src/arch/commodore/vic20.ld diff --git a/src/arch/oric/build.py b/src/arch/oric/build.py new file mode 100644 index 00000000..577b28bf --- /dev/null +++ b/src/arch/oric/build.py @@ -0,0 +1,56 @@ +from build.ab import normalrule +from tools.build import mkcpmfs, mkoricdsk +from build.llvm import llvmrawprogram, llvmcfile +from config import ( + MINIMAL_APPS, + MINIMAL_APPS_SRCS, + BIG_APPS, + BIG_APPS_SRCS, + SCREEN_APPS, + SCREEN_APPS_SRCS, +) + +llvmcfile( + name="bios_obj", + srcs=["./oric.S"], + deps=["include", "src/lib+bioslib"], +) + +llvmrawprogram( + name="bios_prelink", + srcs=[".+bios_obj"], + deps=["src/lib+bioslib", "./oric-common.ld"], + linkscript="./oric-prelink.ld", + ldflags=["--defsym=BIOS_SIZE=0x4000"], +) + +llvmrawprogram( + name="bios", + srcs=[".+bios_obj"], + deps=[ + ".+bios_prelink", + "scripts/size.awk", + "src/lib+bioslib", + "./oric-common.ld", + ], + linkscript="./oric.ld", + ldflags=[ + "--defsym=BIOS_SIZE=$$($(LLVM)/llvm-objdump --section-headers {deps[0]} " + + "| gawk --non-decimal-data -f scripts/size.awk)" + ], +) + +mkcpmfs( + name="cpmfs", + format="oric", + bootimage=".+bios", + items={"0:ccp.sys": "src+ccp", "0:bdos.sys": "src+bdos"} + | MINIMAL_APPS + | MINIMAL_APPS_SRCS + | BIG_APPS + | BIG_APPS_SRCS + | SCREEN_APPS + | SCREEN_APPS_SRCS, +) + +mkoricdsk(name="diskimage", src=".+cpmfs") diff --git a/scripts/oric-common.ld b/src/arch/oric/oric-common.ld similarity index 100% rename from scripts/oric-common.ld rename to src/arch/oric/oric-common.ld diff --git a/scripts/oric-prelink.ld b/src/arch/oric/oric-prelink.ld similarity index 93% rename from scripts/oric-prelink.ld rename to src/arch/oric/oric-prelink.ld index f6cf46d4..a5b6ff38 100644 --- a/scripts/oric-prelink.ld +++ b/src/arch/oric/oric-prelink.ld @@ -20,5 +20,5 @@ SECTIONS { *(sector3) } - INCLUDE "scripts/oric-common.ld" + INCLUDE "src/arch/oric/oric-common.ld" } diff --git a/src/bios/oric.S b/src/arch/oric/oric.S similarity index 100% rename from src/bios/oric.S rename to src/arch/oric/oric.S diff --git a/scripts/oric.ld b/src/arch/oric/oric.ld similarity index 93% rename from scripts/oric.ld rename to src/arch/oric/oric.ld index ba70559a..f439311a 100644 --- a/scripts/oric.ld +++ b/src/arch/oric/oric.ld @@ -22,7 +22,7 @@ SECTIONS { . = ALIGN(256); } >microdiscboot AT>initram - INCLUDE "scripts/oric-common.ld" + INCLUDE "src/arch/oric/oric-common.ld" } OUTPUT_FORMAT { diff --git a/src/arch/x16/build.py b/src/arch/x16/build.py new file mode 100644 index 00000000..50d60725 --- /dev/null +++ b/src/arch/x16/build.py @@ -0,0 +1,43 @@ +from build.ab import normalrule +from tools.build import mkdfs, mkcpmfs +from build.llvm import llvmrawprogram +from config import ( + MINIMAL_APPS, + MINIMAL_APPS_SRCS, + BIG_APPS, + BIG_APPS_SRCS, +) + +llvmrawprogram( + name="x16", + srcs=["./x16.S"], + deps=["include", "src/lib+bioslib", "src/arch/commodore+commodore_lib"], + linkscript="./x16.ld", +) + +mkcpmfs( + name="cpmfs", + format="generic-1m", + items={"0:ccp.sys": "src+ccp"} + | MINIMAL_APPS + | MINIMAL_APPS_SRCS + | BIG_APPS + | BIG_APPS_SRCS, +) + +normalrule( + name="diskimage", + ins=[ + ".+cpmfs", + ".+x16", + "src+bdos", + ], + outs=["x16.zip"], + commands=[ + "zip -9qj {outs[0]} {ins}", + r'printf "@ src+bdos\n@=BDOS\n" | zipnote -w {outs[0]}', + r'printf "@ x16+x16\n@=CPM\n" | zipnote -w {outs[0]}', + r'printf "@ x16+cpmfs.img\n@=CPMFS\n" | zipnote -w {outs[0]}', + ], + label="ZIP", +) diff --git a/src/bios/x16.S b/src/arch/x16/x16.S similarity index 100% rename from src/bios/x16.S rename to src/arch/x16/x16.S diff --git a/scripts/x16.ld b/src/arch/x16/x16.ld similarity index 97% rename from scripts/x16.ld rename to src/arch/x16/x16.ld index f0288e66..466010d4 100644 --- a/scripts/x16.ld +++ b/src/arch/x16/x16.ld @@ -9,7 +9,7 @@ SECTIONS { .zp : { *(.zp .zp.*) __ZP1_START__ = .; - __ZP1_END__ = 0x100; + __ZP1_END__ = 0xff; __ZP0_START__ = 0x22; __ZP0_END__ = 0x80; diff --git a/src/bios/atari800hd.S b/src/bios/atari800hd.S deleted file mode 120000 index c14d3dda..00000000 --- a/src/bios/atari800hd.S +++ /dev/null @@ -1 +0,0 @@ -atari800.S \ No newline at end of file diff --git a/src/bios/atari800xlhd.S b/src/bios/atari800xlhd.S deleted file mode 120000 index c14d3dda..00000000 --- a/src/bios/atari800xlhd.S +++ /dev/null @@ -1 +0,0 @@ -atari800.S \ No newline at end of file diff --git a/src/bios/pet4032.S b/src/bios/pet4032.S deleted file mode 120000 index 730b25cc..00000000 --- a/src/bios/pet4032.S +++ /dev/null @@ -1 +0,0 @@ -pet.S \ No newline at end of file diff --git a/src/bios/pet8032.S b/src/bios/pet8032.S deleted file mode 120000 index 730b25cc..00000000 --- a/src/bios/pet8032.S +++ /dev/null @@ -1 +0,0 @@ -pet.S \ No newline at end of file diff --git a/src/bios/pet8096.S b/src/bios/pet8096.S deleted file mode 120000 index 730b25cc..00000000 --- a/src/bios/pet8096.S +++ /dev/null @@ -1 +0,0 @@ -pet.S \ No newline at end of file diff --git a/src/build.py b/src/build.py new file mode 100644 index 00000000..a56a2107 --- /dev/null +++ b/src/build.py @@ -0,0 +1,7 @@ +from build.llvm import llvmprogram + +llvmprogram(name="bdos", srcs=["./bdos.S"], deps=["include"]) + +llvmprogram( + name="ccp", srcs=["./ccp.S"], deps=["include", "lib+bdos", "lib+xfcb"] +) diff --git a/src/bios/biosentry.S b/src/lib/biosentry.S similarity index 99% rename from src/bios/biosentry.S rename to src/lib/biosentry.S index d7b3303c..e3b0645f 100644 --- a/src/bios/biosentry.S +++ b/src/lib/biosentry.S @@ -3,7 +3,6 @@ ; see the COPYING file in the root project directory for the full text. #include "zif.inc" -#include "mos.inc" #include "cpm65.inc" #include "driver.inc" #include "jumptables.inc" diff --git a/src/lib/build.py b/src/lib/build.py new file mode 100644 index 00000000..700b6d8b --- /dev/null +++ b/src/lib/build.py @@ -0,0 +1,7 @@ +from build.llvm import llvmclibrary + +llvmclibrary( + name="bioslib", + srcs=["./biosentry.S", "./relocate.S", "./loader.S"], + deps=["include"], +) diff --git a/src/bios/loader.S b/src/lib/loader.S similarity index 100% rename from src/bios/loader.S rename to src/lib/loader.S diff --git a/src/bios/relocate.S b/src/lib/relocate.S similarity index 100% rename from src/bios/relocate.S rename to src/lib/relocate.S diff --git a/third_party/altirrabasic/build.py b/third_party/altirrabasic/build.py new file mode 100644 index 00000000..1b79f219 --- /dev/null +++ b/third_party/altirrabasic/build.py @@ -0,0 +1,39 @@ +from third_party.mads.build import mads +from tools.build import multilink, xextobin + +VARIANTS = { + "core": {"ZPBASE": 0, "TEXTBASE": 0x0200}, + "zp": {"ZPBASE": 1, "TEXTBASE": 0x0200}, + "tpa": {"ZPBASE": 0, "TEXTBASE": 0x0300}, +} + +for name, defines in VARIANTS.items(): + xex = mads( + name=name + "_xex", + src="./source/atbasic.s", + deps=[ + "./kernel/mathpack.s", + "./source/variables.s", + "./source/list.s", + "./source/error.s", + "./source/printerror.s", + "./source/statements.s", + "./source/exec.s", + "./source/math.s", + "./source/io.s", + "./source/parser.s", + "./source/cioemu.s", + "./source/util.s", + "./source/parserbytecode.s", + "./source/functions.s", + "./source/evaluator.s", + "./source/memory.s", + "./source/data.s", + ], + defines=defines, + ) + + xextobin(name=name, src=xex, address=defines["TEXTBASE"]) + + +multilink(name="altirrabasic", core=".+core", zp=".+zp", tpa=".+tpa") diff --git a/third_party/fonts/atari/build.py b/third_party/fonts/atari/build.py new file mode 100644 index 00000000..c9b4df93 --- /dev/null +++ b/third_party/fonts/atari/build.py @@ -0,0 +1,5 @@ +from build.llvm import llvmclibrary + +llvmclibrary( + name="ivo3x6", hdrs={"third_party/fonts/atari/ivo3x6.inc": "./ivo3x6.inc"} +) diff --git a/third_party/lib6502/build.py b/third_party/lib6502/build.py new file mode 100644 index 00000000..a59bbca6 --- /dev/null +++ b/third_party/lib6502/build.py @@ -0,0 +1,10 @@ +from build.c import clibrary + +clibrary( + name="lib6502", + srcs=["./lib6502.c"], + hdrs={ + "third_party/lib6502/6502data.h": "./6502data.h", + "third_party/lib6502/lib6502.h": "./lib6502.h", + }, +) diff --git a/third_party/mads/build.py b/third_party/mads/build.py new file mode 100644 index 00000000..8db74f00 --- /dev/null +++ b/third_party/mads/build.py @@ -0,0 +1,25 @@ +from build.ab import normalrule, emit, Rule, Targets, Target + +emit("FPC ?= fpc") + +normalrule( + name="mads", + ins=["./mads.pas"], + outs=["mads"], + commands=["chronic $(FPC) -Mdelphi -Os {ins[0]} -o{outs[0]}"], + label="FREEPASCAL", +) + + +@Rule +def mads(self, name=None, src: Target = None, deps: Targets = None, defines={}): + ds = [f"-d:{k}={v}" for k, v in defines.items()] + + normalrule( + replaces=self, + ins=[src], + outs=[name + ".bin"], + deps=["third_party/mads"] + deps, + commands=["chronic {deps[0]} {ins[0]} -c -o:{outs[0]} " + " ".join(ds)], + label="MADS", + ) diff --git a/third_party/tomsfonts/build.py b/third_party/tomsfonts/build.py new file mode 100644 index 00000000..316008ce --- /dev/null +++ b/third_party/tomsfonts/build.py @@ -0,0 +1,10 @@ +from build.llvm import llvmclibrary +from tools.build import fontconvert + +llvmclibrary( + name="ivo3x6", hdrs={"third_party/fonts/atari/ivo3x6.inc": "./ivo3x6.inc"} +) + +fontconvert(name="4x8_h", src="./atari-small.bdf") + +llvmclibrary(name="4x8", hdrs={"4x8font.inc": ".+4x8_h"}) diff --git a/tools/build.py b/tools/build.py new file mode 100644 index 00000000..1a14821e --- /dev/null +++ b/tools/build.py @@ -0,0 +1,153 @@ +from build.ab import Rule, Target, normalrule, filenameof, targetsof, TargetsMap +from build.c import cxxprogram, cprogram + +cxxprogram(name="multilink", srcs=["./multilink.cc"], deps=["+libfmt"]) +cxxprogram(name="xextobin", srcs=["./xextobin.cc"], deps=["+libfmt"]) +cxxprogram(name="shuffle", srcs=["./shuffle.cc"], deps=["+libfmt"]) +cxxprogram(name="mkoricdsk", srcs=["./mkoricdsk.cc"], deps=["+libfmt"]) +cxxprogram(name="mkcombifs", srcs=["./mkcombifs.cc"], deps=["+libfmt"]) +cprogram(name="mkdfs", srcs=["./mkdfs.c"]) +cprogram( + name="fontconvert", srcs=["./fontconvert.c", "./libbdf.c", "./libbdf.h"] +) + + +@Rule +def multilink( + self, name=None, core: Target = None, zp: Target = None, tpa: Target = None +): + normalrule( + replaces=self, + ins=[core, zp, tpa], + outs=[name + ".com"], + deps=["tools+multilink"], + commands=["{deps[0]} -o {outs[0]} {ins}"], + label="MULTILINK", + ) + + +@Rule +def xextobin(self, name=None, src: Target = None, address=0): + normalrule( + replaces=self, + ins=[src], + outs=[name + ".bin"], + deps=["tools+xextobin"], + commands=["{deps[0]} -i {ins[0]} -o {outs[0]} -b %d" % address], + label="XEXTOBIN", + ) + + +@Rule +def mkcpmfs( + self, + name, + format, + template: Target = None, + bootimage: Target = None, + size=None, + items: TargetsMap = {}, +): + cs = [] + if template: + cs += ["cp %s {outs[0]}" % filenameof(template)] + else: + mkfs = "mkfs.cpm -f %s" % format + if bootimage: + mkfs += " -b %s" % filenameof(bootimage) + mkfs += " {outs[0]}" + cs += [mkfs] + + ins = [] + for k, v in items.items(): + flags = None + if "@" in k: + k, flags = k.split("@") + cs += ["cpmcp -f %s {outs[0]} %s %s" % (format, filenameof(v), k)] + if flags: + cs += ["chpmchattr -f %s {outs[0]} %s %s" % (format, flags, k)] + ins += [v] + + if size: + cs += ["truncate -s %d {outs[0]}" % size] + + normalrule( + replaces=self, + ins=ins, + outs=[name + ".img"], + deps=["diskdefs"] + [bootimage] + if bootimage + else [] + [template] + if template + else [], + commands=cs, + label="MKCPMFS", + ) + + +@Rule +def mkdfs(self, name, out=None, title="DFS", opt=0, items: TargetsMap = {}): + cs = [] + ins = [] + for k, v in items.items(): + addr = None + if "@" in k: + k, addr = k.split("@") + + ins += [v] + cs += ["-f", filenameof(v), "-n", k] + if addr: + cs += ["-l", addr, "-e", addr] + + normalrule( + replaces=self, + ins=ins, + outs=[out], + deps=["tools+mkdfs"], + commands=[ + ("{deps[0]} -O {outs[0]} -B %d -N %s " % (opt, title)) + + " ".join(cs) + ], + label="MKDFS", + ) + + +@Rule +def shuffle( + self, name, src: Target = None, blocksize=256, blockspertrack=16, map="" +): + normalrule( + replaces=self, + ins=[src], + outs=[name + ".bin"], + deps=["tools+shuffle"], + commands=[ + "{deps[0]} -i {ins[0]} -o {outs[0]} -b %d -t %d -r -m %s" + % (blocksize, blockspertrack, map) + ], + label="SHUFFLE", + ) + + +@Rule +def fontconvert(self, name, src: Target = None): + normalrule( + replaces=self, + ins=[src], + outs=[name + ".inc"], + deps=["tools+fontconvert"], + commands=["{deps[0]} {ins[0]} > {outs[0]}"], + label="FONTCONVERT", + ) + + +@Rule +def mkoricdsk(self, name, src: Target = None): + normalrule( + replaces=self, + ins=[src], + outs=[name + ".img"], + deps=["tools+mkoricdsk"], + commands=["{deps[0]} -i {ins[0]} -o {outs[0]}"], + label="MKORICDSK", + ) diff --git a/tools/cpmemu/biosbdos.c b/tools/cpmemu/biosbdos.c index ee048868..d072a508 100644 --- a/tools/cpmemu/biosbdos.c +++ b/tools/cpmemu/biosbdos.c @@ -1,4 +1,3 @@ -#define _XOPEN_SOURCE 500 #include #include #include diff --git a/tools/cpmemu/build.py b/tools/cpmemu/build.py new file mode 100644 index 00000000..aec7798b --- /dev/null +++ b/tools/cpmemu/build.py @@ -0,0 +1,7 @@ +from build.c import cprogram + +cprogram( + name="cpmemu", + srcs=["./biosbdos.c", "./emulator.c", "./fileio.c", "./main.c"], + deps=["third_party/lib6502", "+libreadline"], +) diff --git a/tools/cpmemu/fileio.c b/tools/cpmemu/fileio.c index def5ce42..8557354e 100644 --- a/tools/cpmemu/fileio.c +++ b/tools/cpmemu/fileio.c @@ -1,5 +1,3 @@ -#define _XOPEN_SOURCE 500 -#define _POSIX_C_SOURCE 200809 #include #include #include diff --git a/tools/fontconvert.c b/tools/fontconvert.c index 870767a4..ae4f6e25 100644 --- a/tools/fontconvert.c +++ b/tools/fontconvert.c @@ -42,14 +42,14 @@ int main(int argc, const char* argv[]) printf( "\t.byte 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, " "0x%02x ; char %d\n", - p[0] | (p[0]>>4), - p[1] | (p[1]>>4), - p[2] | (p[2]>>4), - p[3] | (p[3]>>4), - p[4] | (p[4]>>4), - p[5] | (p[5]>>4), - p[6] | (p[6]>>4), - p[7] | (p[7]>>4), + p[0] | (p[0] >> 4), + p[1] | (p[1] >> 4), + p[2] | (p[2] >> 4), + p[3] | (p[3] >> 4), + p[4] | (p[4] >> 4), + p[5] | (p[5] >> 4), + p[6] | (p[6] >> 4), + p[7] | (p[7] >> 4), c); } diff --git a/tools/libbdf.c b/tools/libbdf.c index 46623345..bb3643c2 100644 --- a/tools/libbdf.c +++ b/tools/libbdf.c @@ -7,95 +7,99 @@ static bool startswith(const char* string, const char* prefix) { - return strncmp(prefix, string, strlen(prefix)) == 0; + return strncmp(prefix, string, strlen(prefix)) == 0; } BDF* bdf_load(const char* filename) { - BDF* bdf = calloc(1, sizeof(BDF)); - FILE* fp = fopen(filename, "rt"); + BDF* bdf = calloc(1, sizeof(BDF)); + FILE* fp = fopen(filename, "rt"); - char* ptr = NULL; - size_t size = 0; - Glyph* glyph = NULL; - for (;;) - { - if (getline(&ptr, &size, fp) == -1) - break; + char* ptr = NULL; + size_t size = 0; + Glyph* glyph = NULL; + for (;;) + { + if (getline(&ptr, &size, fp) == -1) + break; - int p1, p2, p3, p4; - if (startswith(ptr, "STARTCHAR ")) - { - glyph = calloc(1, sizeof(Glyph)); - glyph->data = calloc(bdf->height, sizeof(&glyph->data)); - } - else if (sscanf(ptr, "ENCODING %d\n", &p1) == 1) - bdf->glyphs[p1] = glyph; - else if (sscanf(ptr, "FONTBOUNDINGBOX %d %d %d %d\n", &p1, &p2, &p3, &p4) == 4) - { - bdf->width = p1; - bdf->height = p2; - } - else if (sscanf(ptr, "FONT_ASCENT %d\n", &p1) == 1) - bdf->ascent = p1; - else if (sscanf(ptr, "FONT_DESCENT %d\n", &p1) == 1) - bdf->descent = p1; - else if (sscanf(ptr, "BBX %d %d %d %d\n", &p1, &p2, &p3, &p4) == 4) - { - if (!glyph) - goto malformed; - glyph->width = p1; - glyph->height = p2; - glyph->dx = p3; - glyph->dy = p4; - } - else if (strcmp(ptr, "BITMAP\n") == 0) - { - int yo = bdf->ascent - glyph->dy - glyph->height; + int p1, p2, p3, p4; + if (startswith(ptr, "STARTCHAR ")) + { + glyph = calloc(1, sizeof(Glyph)); + glyph->data = calloc(bdf->height, sizeof(&glyph->data)); + } + else if (sscanf(ptr, "ENCODING %d\n", &p1) == 1) + bdf->glyphs[p1] = glyph; + else if (sscanf(ptr, + "FONTBOUNDINGBOX %d %d %d %d\n", + &p1, + &p2, + &p3, + &p4) == 4) + { + bdf->width = p1; + bdf->height = p2; + } + else if (sscanf(ptr, "FONT_ASCENT %d\n", &p1) == 1) + bdf->ascent = p1; + else if (sscanf(ptr, "FONT_DESCENT %d\n", &p1) == 1) + bdf->descent = p1; + else if (sscanf(ptr, "BBX %d %d %d %d\n", &p1, &p2, &p3, &p4) == 4) + { + if (!glyph) + goto malformed; + glyph->width = p1; + glyph->height = p2; + glyph->dx = p3; + glyph->dy = p4; + } + else if (strcmp(ptr, "BITMAP\n") == 0) + { + int yo = bdf->ascent - glyph->dy - glyph->height; - for (int y=0; yheight; y++) - { - if (getline(&ptr, &size, fp) == -1) - goto malformed; - if (sscanf(ptr, "%x\n", &p1) != 1) - goto malformed; - int yy = y + yo; - if ((yy >= 0) && (yy < bdf->height)) - glyph->data[yy] = p1 >> (glyph->dx); - } - } - } - free(ptr); + for (int y = 0; y < glyph->height; y++) + { + if (getline(&ptr, &size, fp) == -1) + goto malformed; + if (sscanf(ptr, "%x\n", &p1) != 1) + goto malformed; + int yy = y + yo; + if ((yy >= 0) && (yy < bdf->height)) + glyph->data[yy] = p1 >> (glyph->dx); + } + } + } + free(ptr); - fclose(fp); - return bdf; + fclose(fp); + return bdf; toobig: - fprintf(stderr, "libbdf: glyphs may be a maximum of 8x8\n"); - goto error; + fprintf(stderr, "libbdf: glyphs may be a maximum of 8x8\n"); + goto error; malformed: - fprintf(stderr, "libbdf: malformed BDF file\n"); + fprintf(stderr, "libbdf: malformed BDF file\n"); error: - bdf_free(bdf); - if (fp) - fclose(fp); - return NULL; + bdf_free(bdf); + if (fp) + fclose(fp); + return NULL; } void bdf_free(BDF* bdf) { - if (bdf) - { - for (int i=0; i<256; i++) - { - Glyph* g = bdf->glyphs[i]; - if (g) - { - free(g->data); - free(g); - } - } - free(bdf); - } + if (bdf) + { + for (int i = 0; i < 256; i++) + { + Glyph* g = bdf->glyphs[i]; + if (g) + { + free(g->data); + free(g); + } + } + free(bdf); + } } - diff --git a/tools/mkcombifs.cc b/tools/mkcombifs.cc index 44aa8176..d1121152 100644 --- a/tools/mkcombifs.cc +++ b/tools/mkcombifs.cc @@ -4,6 +4,7 @@ #include #include #include +#include /* Does the magic fixing up to make a combination 1541/CPMFS disk. * @@ -14,6 +15,9 @@ * blocks are in use. */ +static std::string infilename; +static bool verbose = false; + template void error(fmt::format_string fmt, T&&... args) { @@ -24,95 +28,140 @@ void error(fmt::format_string fmt, T&&... args) static int get1541TrackSize(int track) { - if (track <= 17) - return 21; - if (track <= 24) - return 19; - if (track <= 30) - return 18; - return 17; + if (track <= 17) + return 21; + if (track <= 24) + return 19; + if (track <= 30) + return 18; + return 17; } /* 1-offset track numbers! But 0-offset sector numbers... */ static int get1541LBA(int track, int sector) { - int offset = 0; + int offset = 0; - assert(track != 0); - for (int t = 1; t < track; t++) - offset += get1541TrackSize(t); + assert(track != 0); + for (int t = 1; t < track; t++) + offset += get1541TrackSize(t); - return offset + sector; + return offset + sector; } -int main(int argc, const char* argv[]) +static void syntaxError() { - std::fstream fs(argv[1], std::ios::binary | std::ios::in | std::ios::out); - if (!fs) - error("Cannot open input file: {}", strerror(errno)); - uint32_t size = std::filesystem::file_size(argv[1]); - - uint8_t bam[256]; - fs.seekg(get1541LBA(18, 0) * 256); - fs.read((char*) bam, sizeof(bam)); - - if (bam[2] != 0x41) - error("This doesn't look like a 1541 file system"); - - std::set usedSectors; - - for (int track=1;; track++) - { - int offset = get1541LBA(track, 0) * 256; - if (offset >= size) - break; - - uint8_t* bamp = &bam[5 + (track-1) * 4]; - uint32_t bitmap = bamp[0] | (bamp[1] << 8) | (bamp[2] << 16); - int sectorCount = get1541TrackSize(track); - - for (int sector=0; sector>= 1; - - if (allocated) - usedSectors.insert(get1541LBA(track, sector)); - } - - bamp[-1] = bamp[0] = bamp[1] = bamp[2] = 0; - } - fmt::print("1541 filesystem has {} allocated sectors\n", usedSectors.size()); - - std::set usedBlocks; - for (int sector : usedSectors) - usedBlocks.insert(sector/4); - - fmt::print("CP/M filesystem has {} allocated blocks\n", usedBlocks.size()); - - for (int i=0; i<64; i++) - { - fs.seekp(32*i); - for (int j=0; j<32; j++) - fs.put(0xe5); - } - - uint8_t dirent[32] = { - 0, 'C', 'B', 'M', 'F', 'S', ' ', ' ', ' ', 'S', 'Y', 'S', - /* EX */ 0, - /* S1 */ 0, - /* S2 */ 0, - /* RC */ (uint8_t)(usedBlocks.size() * 8) - }; - uint8_t* al = &dirent[16]; - for (int block : usedBlocks) - *al++ = block; - fs.seekp(0); - fs.write((const char*) dirent, sizeof(dirent)); - - fs.seekp(get1541LBA(18, 0) * 256); - fs.write((char*) bam, sizeof(bam)); - - return 0; + fmt::print(stderr, "Usage: mkcombifs [-v] \n"); + exit(1); } +static void parseArguments(int argc, char* const* argv) +{ + for (;;) + { + switch (getopt(argc, argv, "vf:")) + { + case -1: + if (infilename.empty() || argv[optind]) + syntaxError(); + + case 'f': + infilename = optarg; + return; + + case 'v': + verbose = true; + break; + + default: + syntaxError(); + } + } +} + +int main(int argc, char* const* argv) +{ + parseArguments(argc, argv); + + std::fstream fs( + infilename, std::ios::binary | std::ios::in | std::ios::out); + if (!fs) + error("Cannot open input file: {}", strerror(errno)); + uint32_t size = std::filesystem::file_size(infilename); + + uint8_t bam[256]; + fs.seekg(get1541LBA(18, 0) * 256); + fs.read((char*)bam, sizeof(bam)); + + if (bam[2] != 0x41) + error("This doesn't look like a 1541 file system"); + + std::set usedSectors; + + for (int track = 1;; track++) + { + int offset = get1541LBA(track, 0) * 256; + if (offset >= size) + break; + + uint8_t* bamp = &bam[5 + (track - 1) * 4]; + uint32_t bitmap = bamp[0] | (bamp[1] << 8) | (bamp[2] << 16); + int sectorCount = get1541TrackSize(track); + + for (int sector = 0; sector < sectorCount; sector++) + { + bool allocated = !(bitmap & 1); + bitmap >>= 1; + + if (allocated) + usedSectors.insert(get1541LBA(track, sector)); + } + + bamp[-1] = bamp[0] = bamp[1] = bamp[2] = 0; + } + if (verbose) + fmt::print( + "1541 filesystem has {} allocated sectors\n", usedSectors.size()); + + std::set usedBlocks; + for (int sector : usedSectors) + usedBlocks.insert(sector / 4); + + if (verbose) + fmt::print( + "CP/M filesystem has {} allocated blocks\n", usedBlocks.size()); + + for (int i = 0; i < 64; i++) + { + fs.seekp(32 * i); + for (int j = 0; j < 32; j++) + fs.put(0xe5); + } + + uint8_t dirent[32] = {0, + 'C', + 'B', + 'M', + 'F', + 'S', + ' ', + ' ', + ' ', + 'S', + 'Y', + 'S', + /* EX */ 0, + /* S1 */ 0, + /* S2 */ 0, + /* RC */ (uint8_t)(usedBlocks.size() * 8)}; + uint8_t* al = &dirent[16]; + for (int block : usedBlocks) + *al++ = block; + fs.seekp(0); + fs.write((const char*)dirent, sizeof(dirent)); + + fs.seekp(get1541LBA(18, 0) * 256); + fs.write((char*)bam, sizeof(bam)); + + return 0; +} diff --git a/tools/mkdfs.c b/tools/mkdfs.c index 0b9db11e..b4ad513b 100644 --- a/tools/mkdfs.c +++ b/tools/mkdfs.c @@ -3,7 +3,6 @@ * see the COPYING file in the root project directory for the full text. */ -#define _XOPEN_SOURCE 500 #include #include #include @@ -67,7 +66,7 @@ static void add_file(const char* filename) leaf = filename; else leaf++; - for (int i=0; i<7; i++) + for (int i = 0; i < 7; i++) { char c = leaf[i]; if ((c == '.') || (c == '\0')) @@ -100,18 +99,18 @@ static void write_byte(int fd, uint32_t pos, uint8_t value) static void write_word(int fd, uint32_t pos, uint16_t value) { write_byte(fd, pos, value); - write_byte(fd, pos+1, value>>8); + write_byte(fd, pos + 1, value >> 8); } static void write_quad(int fd, uint32_t pos, uint32_t value) { write_word(fd, pos, value); - write_word(fd, pos+2, value>>16); + write_word(fd, pos + 2, value >> 16); } static void write_disk(void) { - int fd = open(output_filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); + int fd = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { fprintf(stderr, "cannot open output file: %s\n", strerror(errno)); @@ -120,27 +119,27 @@ static void write_disk(void) ftruncate(fd, disk_size * 0x100); write_byte(fd, 0x107, disk_size); - write_byte(fd, 0x106, (boot_mode<<4) | (disk_size>>8)); + write_byte(fd, 0x106, (boot_mode << 4) | (disk_size >> 8)); write_byte(fd, 0x105, catalogue_pos << 3); - pwrite(fd, disk_name+0, 8, 0x000); - pwrite(fd, disk_name+8, 4, 0x100); + pwrite(fd, disk_name + 0, 8, 0x000); + pwrite(fd, disk_name + 8, 4, 0x100); - for (int i=0; idata, 0x100 * ce->sectors, ce->startsector * 0x100); - pwrite(fd, ce->name, 7, 8 + i*8); - write_byte(fd, 0x008 + i*8 + 7, ce->directory); - write_word(fd, 0x108 + i*8 + 0, ce->load_address); - write_word(fd, 0x108 + i*8 + 2, ce->exec_address); - write_word(fd, 0x108 + i*8 + 4, ce->length); - write_byte(fd, 0x108 + i*8 + 7, ce->startsector); - - write_byte(fd, 0x108 + i*8 + 6, + pwrite(fd, ce->name, 7, 8 + i * 8); + write_byte(fd, 0x008 + i * 8 + 7, ce->directory); + write_word(fd, 0x108 + i * 8 + 0, ce->load_address); + write_word(fd, 0x108 + i * 8 + 2, ce->exec_address); + write_word(fd, 0x108 + i * 8 + 4, ce->length); + write_byte(fd, 0x108 + i * 8 + 7, ce->startsector); + + write_byte(fd, + 0x108 + i * 8 + 6, (((ce->load_address >> 16) & 0x3) << 2) | - (((ce->exec_address >> 16) & 3) << 6) | - (((ce->length >> 16) & 3) << 4) | - (ce->startsector >> 8)); + (((ce->exec_address >> 16) & 3) << 6) | + (((ce->length >> 16) & 3) << 4) | (ce->startsector >> 8)); } close(fd); @@ -184,7 +183,7 @@ int main(int argc, char* const argv[]) optarg = optarg + 2; } memset(&lastfile->name, ' ', 7); - for (int i=0; i<7; i++) + for (int i = 0; i < 7; i++) { char c = optarg[i]; if (c == '\0') @@ -204,7 +203,8 @@ int main(int argc, char* const argv[]) break; default: - fprintf(stderr, "Usage: mkdfs -O -f ...\n"); + fprintf( + stderr, "Usage: mkdfs -O -f ...\n"); exit(1); } } diff --git a/tools/mkoricdsk.cc b/tools/mkoricdsk.cc index 57802677..e67a3966 100644 --- a/tools/mkoricdsk.cc +++ b/tools/mkoricdsk.cc @@ -207,7 +207,7 @@ int main(int argc, char* argv[]) buffer[2] = 0xa1; buffer[3] = 0xfb; inf.clear(); - inf.seekg((s + h*sectors + t*heads*sectors)*256); + inf.seekg((s + h * sectors + t * heads * sectors) * 256); if (inf) inf.read((char*)buffer + 4, 256); putbe16(&buffer[256 + 4], crc16(&buffer[0], 256 + 4)); diff --git a/tools/multilink.cc b/tools/multilink.cc index 74176fcc..61f3e5cf 100644 --- a/tools/multilink.cc +++ b/tools/multilink.cc @@ -4,6 +4,8 @@ */ #include +#include +#include #include #include #include @@ -11,6 +13,12 @@ #include #include +static std::string outfilename; +static std::string corefilename; +static std::string zpfilename; +static std::string memfilename; +static bool verbose = false; + template void error(fmt::format_string fmt, T&&... args) { @@ -93,38 +101,76 @@ unsigned roundup(unsigned value) return (value + 127) & ~127; } +static void syntaxError() +{ + fmt::print(stderr, + "Usage: multilink -o \n"); + exit(1); +} + +static void parseArguments(int argc, char* const* argv) +{ + for (;;) + { + switch (getopt(argc, argv, "vo:")) + { + case -1: + if (!argv[optind + 0] || !argv[optind + 1] || !argv[optind + 2]) + syntaxError(); + + corefilename = argv[optind + 0]; + zpfilename = argv[optind + 1]; + memfilename = argv[optind + 2]; + return; + + case 'o': + outfilename = optarg; + break; + + case 'v': + verbose = true; + break; + + default: + syntaxError(); + } + } +} + int main(int argc, char* const* argv) { - if ((argc != 6) || (std::string(argv[1]) != "-o")) - error("syntax: multilink -o "); + parseArguments(argc, argv); - auto outfile = std::string(argv[2]); - auto corefile = std::string(argv[3]); - auto zpfile = std::string(argv[4]); - auto memfile = std::string(argv[5]); + if (verbose) + { + fmt::print("core file: {}\n", corefilename); + fmt::print("zp file: {}\n", zpfilename); + fmt::print("mem file: {}\n", memfilename); + } - auto coreSize = std::filesystem::file_size(corefile); + auto coreSize = std::filesystem::file_size(corefilename); - auto [zpDifferences, zpMax] = compare(corefile, zpfile); + auto [zpDifferences, zpMax] = compare(corefilename, zpfilename); auto zpBytes = toBytestream(zpDifferences); - auto [memDifferences, memMax] = compare(corefile, memfile); + auto [memDifferences, memMax] = compare(corefilename, memfilename); auto memBytes = toBytestream(memDifferences); unsigned reloBytesSize = zpBytes.size() + 1 + memBytes.size(); - std::fstream outs(outfile, + std::fstream outs(outfilename, std::fstream::in | std::fstream::out | std::fstream::trunc | std::fstream::binary); - fmt::print("{} code bytes, {} zprelo bytes, {} memrelo bytes\n", - coreSize, - zpBytes.size(), - memBytes.size()); + if (verbose) + fmt::print("{} code bytes, {} zprelo bytes, {} memrelo bytes\n", + coreSize, + zpBytes.size(), + memBytes.size()); /* Write the actual code body. */ { auto memi = memDifferences.begin(); - std::ifstream is(corefile); + std::ifstream is(corefilename); unsigned pos = 0; for (;;) { @@ -162,11 +208,5 @@ int main(int argc, char* const* argv) for (uint8_t b : memBytes) outs.put(b); - /* Remove temporary files. */ - - std::filesystem::remove(corefile); - std::filesystem::remove(zpfile); - std::filesystem::remove(memfile); - return 0; } diff --git a/tools/shuffle.cc b/tools/shuffle.cc index 7524c1d3..510e33ec 100644 --- a/tools/shuffle.cc +++ b/tools/shuffle.cc @@ -9,6 +9,7 @@ #include #include #include +#include static int blocksize = 256; static int blockspertrack = 16; @@ -16,6 +17,7 @@ static std::string mappingstring = "0123456789abcdef"; static std::string infilename; static std::string outfilename; static bool reverse = false; +static bool verbose = false; static std::string readfile(std::ifstream& in) { @@ -26,51 +28,53 @@ static std::string readfile(std::ifstream& in) static int chartoint(char c) { - if (isdigit(c)) - return c - '0'; - c = tolower(c); - if (isalpha(c)) - return 10 + c - 'a'; - std::cerr << "bad mapping string\n"; - exit(1); + if (isdigit(c)) + return c - '0'; + c = tolower(c); + if (isalpha(c)) + return 10 + c - 'a'; + std::cerr << "bad mapping string\n"; + exit(1); } static void write_file() { std::ifstream ifs(infilename, std::ios::binary); - std::ofstream ofs(outfilename, std::ios::binary); + std::ofstream ofs(outfilename, std::ios::binary); std::string infile = readfile(ifs); - if (!ifs) - { + if (!ifs) + { perror("Could not read input file"); exit(1); } int inblocks = (infile.size() + blocksize - 1) / blocksize; int tracks = (inblocks + blockspertrack - 1) / blockspertrack; - std::cout << "file size: " << tracks << " tracks of " << blockspertrack - << " blocks\n"; + if (verbose) + fmt::print( + "file size: {} tracks of {} blocks\n", tracks, blockspertrack); infile.resize(tracks * blockspertrack * blocksize); - std::map mapping; - for (int i=0; i mapping; + for (int i = 0; i < mappingstring.size(); i++) + { + if (reverse) + mapping[i] = chartoint(mappingstring[i]); + else + mapping[chartoint(mappingstring[i])] = i; + } + + for (int track = 0; track < tracks; track++) + { + int baseblock = track * blockspertrack; + for (int block = 0; block < blockspertrack; block++) + ofs << infile.substr( + (baseblock + mapping[block]) * blocksize, blocksize); + } + + if (!ofs) + { perror("Could not write output file"); exit(1); } @@ -106,14 +110,18 @@ int main(int argc, char* const argv[]) outfilename = optarg; break; - case 'r': - reverse = true; - break; + case 'r': + reverse = true; + break; + + case 'v': + verbose = true; + break; default: fprintf(stderr, "Usage: shuffle -i -o -b -t " - " -m \n"); + " -m [-v] [-r]\n"); exit(1); } } diff --git a/tools/xextobin.cc b/tools/xextobin.cc index bad98403..db224d0d 100644 --- a/tools/xextobin.cc +++ b/tools/xextobin.cc @@ -16,6 +16,7 @@ static uint8_t ram[0x10000]; static uint16_t base = 0; static uint16_t himem = 0; static std::string outfilename; +static bool verbose = false; template void error(fmt::format_string fmt, T&&... args) @@ -36,7 +37,7 @@ static uint16_t readle16(std::istream& is) static void read_file(std::string filename) { std::ifstream ifs(filename, std::ios::binary); - if (!ifs) + if (!ifs) error("could not read input file: {}", strerror(errno)); for (;;) @@ -49,7 +50,7 @@ static void read_file(std::string filename) default: if ((header & 0xff00) == 0xff00) error("unsupported header 0x{:04x}\n", header); - ifs.seekg(ifs.tellg()-2L); + ifs.seekg(ifs.tellg() - 2L); /* fall through */ case 0xffff: { @@ -58,9 +59,11 @@ static void read_file(std::string filename) if (start == 0x0000) error("relocatable blocks are not supported"); uint16_t len = (end - start) + 1; - fmt::print("reading 0x{:04x} bytes to 0x{:04x}\n", len, start); + if (verbose) + fmt::print( + "reading 0x{:04x} bytes to 0x{:04x}\n", len, start); ifs.read((char*)(ram + start), len); - himem = std::max((int)himem, (int)end+1); + himem = std::max((int)himem, (int)end + 1); break; } } @@ -70,8 +73,9 @@ static void read_file(std::string filename) static void write_file() { uint16_t len = himem - base; - fmt::print("writing 0x{:04x} bytes from 0x{:04x}\n", len, base); - + if (verbose) + fmt::print("writing 0x{:04x} bytes from 0x{:04x}\n", len, base); + std::ofstream ofs(outfilename, std::ios::out | std::ios::binary); if (!ofs) error("failed to open output file: {}", strerror(errno)); @@ -100,6 +104,10 @@ int main(int argc, char* const argv[]) outfilename = optarg; break; + case 'v': + verbose = true; + break; + default: fmt::print(stderr, "Usage: xextobin -i -o -b \n"); @@ -107,4 +115,3 @@ int main(int argc, char* const argv[]) } } } -