HEX2BIN=hex2bin.py
RLE_LOADER=0x800
+RLE2_LOADER=0x800
HIRES_LOADER=0x2000
.PHONY: all
star_blazer.bin \
star_blazer_dejunked0.bin \
star_blazer_dejunked1.bin \
+star_blazer_rle2_loader.bin \
star_blazer_rle_loader.bin
star_blazer.bin: ../orig/Star_Blazer_1981_Star_Craft.do
star_blazer_dejunked1.bin: star_blazer.bin
./dejunk.py $< $@ 0xff
+star_blazer_rle2_loader.bin: rle2_loader.bin star_blazer_hires_loader.bin
+ ./rle2_encode.py ${RLE2_LOADER} $^ $@
+
+rle2_loader.bin: rle2_loader.ihx
+ ${HEX2BIN} $< $@
+
+rle2_loader.ihx: rle2_loader.rel
+ ${ASLINK} -n -m -u -i -b text=${RLE2_LOADER} $@ $^
+
+rle2_loader.rel: rle2_loader.asm
+ ${AS6500} -l -o $<
+
star_blazer_rle_loader.bin: rle_loader.bin star_blazer_hires_loader.bin
./rle_encode.py ${RLE_LOADER} $^ $@
--- /dev/null
+#!/usr/bin/env python3
+
+import sys
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+# key byte is partitioned as follows
+KEY_EOF = 0
+KEY_LIT = 1 # literal lengths 01..a7
+KEY_RUN = 0xa8 # run lengths 02..49
+KEY_PAIR_RUN = 0xf0 # pair run lengths 03..12
+N_KEYS = 0x100
+
+if len(sys.argv) < 3:
+ print(f'usage: {sys.argv[0]:s} in.bin out.bin')
+ sys.exit(EXIT_FAILURE)
+in_bin = sys.argv[1]
+out_bin = sys.argv[2]
+
+with open(in_bin, 'rb') as fin:
+ data = list(fin.read())
+ hdr = data[:4]
+ rle2 = data[4:]
+load_addr = hdr[0] | (hdr[1] << 8)
+assert hdr[2] == len(rle2) & 0xff
+assert hdr[3] == len(rle2) >> 8
+
+assert rle2[0] == 0xa9 # lda #NN
+assert rle2[4] == 0xa9 # lda #NN
+src = rle2[1] | (rle2[5] << 8)
+assert src == load_addr + len(rle2) - 1
+
+assert rle2[8] == 0xa9 # lda #NN
+assert rle2[0xc] == 0xa9 # lda #NN
+dest = rle2[9] + (rle2[0xd] << 8)
+
+assert rle2[0x6b] == 0x4c # jmp NNNN
+start = rle2[0x6c] | (rle2[0x6d] << 8)
+
+bin = [0] * (dest + 1 - start)
+print(f'rle2 {len(rle2):04x} bin {len(bin):04x}')
+
+i = len(rle2)
+j = len(bin)
+while True:
+ i -= 1
+ assert i >= 0xa1
+ count = rle2[i]
+ if count == KEY_EOF:
+ break
+ if count < KEY_RUN:
+ i -= count
+ assert i >= 0xa1
+
+ j -= count
+ assert j >= 0
+
+ bin[j:j + count] = rle2[i:i + count]
+ elif count < KEY_PAIR_RUN:
+ count -= KEY_RUN - 2
+
+ i -= 1
+ assert i >= 0
+
+ j -= count
+ assert j >= 0
+
+ bin[j:j + count] = rle2[i:i + 1] * count
+ else:
+ count -= KEY_PAIR_RUN - 3
+
+ i -= 2
+ assert i >= 0
+
+ j -= count
+ assert j >= 0
+
+ bin[j:j + count] = (rle2[i:i + 2] * ((count + 1) >> 1))[-count:]
+assert i == 0xa1
+assert j == 0
+
+load_addr = start
+load_size = len(bin)
+hdr = [load_addr & 0xff, load_addr >> 8, load_size & 0xff, load_size >> 8]
+
+with open(out_bin, 'wb') as fout:
+ fout.write(bytes(hdr + bin))
--- /dev/null
+#!/usr/bin/env python3
+
+import sys
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+# key byte is partitioned as follows
+KEY_EOF = 0
+KEY_LIT = 1 # literal lengths 01..a7
+KEY_RUN = 0xa8 # run lengths 02..49
+KEY_PAIR_RUN = 0xf0 # pair run lengths 03..12
+N_KEYS = 0x100
+
+MAX_LIT = KEY_RUN - KEY_LIT # a7
+MAX_RUN = KEY_PAIR_RUN - KEY_RUN + 1 # 49
+MAX_PAIR_RUN = N_KEYS - KEY_PAIR_RUN + 2 # 12
+
+if len(sys.argv) < 5:
+ print(f'usage: {sys.argv[0]:s} load_addr rle2_loader.bin in.bin out.bin')
+ sys.exit(EXIT_FAILURE)
+load_addr = int(sys.argv[1], 0)
+rle2_loader_bin = sys.argv[2]
+in_bin = sys.argv[3]
+out_bin = sys.argv[4]
+
+with open(rle2_loader_bin, 'rb') as fin:
+ rle2_loader = list(fin.read())
+assert len(rle2_loader) == 0xa1
+
+with open(in_bin, 'rb') as fin:
+ data = list(fin.read())
+ hdr = data[:4]
+ bin = data[4:]
+start = hdr[0] | (hdr[1] << 8)
+assert hdr[2] == len(bin) & 0xff
+assert hdr[3] == len(bin) >> 8
+
+rle2 = [0] * (len(bin) + (len(bin) >> 7) + 2)
+
+i = len(bin)
+j = len(rle2)
+while i:
+ # look for a run
+ count = 1
+ while (
+ count < MAX_RUN and
+ i - count - 1 >= 0 and
+ bin[i - count - 1] == bin[i - 1]
+ ):
+ count += 1
+
+ # since we are in key mode we can output runs of at least 2
+ if count >= 2:
+ i -= count
+ assert i >= 0
+
+ j -= 1
+ assert j >= 0
+ rle2[j] = KEY_RUN + count - 2
+
+ j -= 1
+ assert j >= 0
+ rle2[j] = bin[i]
+ else:
+ # look for a run of pairs
+ count = 2
+ while (
+ count < MAX_PAIR_RUN and
+ i - count - 1 >= 0 and
+ bin[i - count - 1] == bin[i - 1 - (count & 1)]
+ ):
+ count += 1
+
+ # since we are in key mode we can output pair runs of at least 2
+ if count >= 3:
+ i -= count
+ assert i >= 0
+
+ j -= 1
+ assert j >= 0
+ rle2[j] = KEY_PAIR_RUN + count - 3
+
+ j -= 2
+ assert j >= 0
+ rle2[j:j + 2] = bin[i + count - 2:i + count]
+ else:
+ # we will have to start literal mode
+ # stop with a run of a least 3 or pair run of at least 4
+ count = 1
+ while (
+ count < MAX_LIT and
+ count < i and
+ (
+ i - count - 3 < 0 or
+ bin[i - count - 2] != bin[i - count - 1] or
+ bin[i - count - 3] != bin[i - count - 1]
+ )
+ and
+ (
+ i - count - 4 < 0 or
+ bin[i - count - 3] != bin[i - count - 1] or
+ bin[i - count - 4] != bin[i - count - 2]
+ )
+ ):
+ count += 1
+
+ # but do not stop in the middle of a pair
+ if (
+ count == MAX_LIT and
+ count + 1 <= i and
+ bin[i - count - 1] == bin[i - count]
+ ):
+ count -= 1
+
+ i -= count
+ assert i >= 0
+
+ j -= 1
+ assert j >= 0
+ rle2[j] = KEY_LIT + count - 1
+
+ j -= count
+ assert j >= 0
+ rle2[j:j + count] = bin[i:i + count]
+j -= 1
+assert j >= 0
+rle2[j] = KEY_EOF
+
+rle2 = rle2_loader + rle2[j:]
+print(f'bin {len(bin):04x} rle2 {len(rle2):04x}')
+
+src = load_addr + len(rle2) - 1
+assert rle2[0] == 0xa9 # lda #NN
+rle2[1] = src & 0xff
+assert rle2[4] == 0xa9 # lda #NN
+rle2[5] = src >> 8
+
+dest = start + len(bin) - 1
+assert rle2[8] == 0xa9 # lda #NN
+rle2[9] = dest & 0xff
+assert rle2[0xc] == 0xa9 # lda #NN
+rle2[0xd] = dest >> 8
+
+assert rle2[0x6b] == 0x4c # jmp NNNN
+rle2[0x6c] = start & 0xff
+rle2[0x6d] = start >> 8
+
+load_size = len(rle2)
+hdr = [load_addr & 0xff, load_addr >> 8, load_size & 0xff, load_size >> 8]
+
+with open(out_bin, 'wb') as fout:
+ fout.write(bytes(hdr + rle2))