Remove the hires loader since the LZSS loader doesn't care about hires gap
authorNick Downing <nick@ndcode.org>
Fri, 17 Jun 2022 12:34:46 +0000 (22:34 +1000)
committerNick Downing <nick@ndcode.org>
Fri, 17 Jun 2022 13:16:23 +0000 (23:16 +1000)
12 files changed:
disasm/Makefile
disasm/a2_hex2bin.py [new file with mode: 0755]
disasm/disasm.py
disasm/load.py [deleted file]
disasm/pack.py [deleted file]
disasm/shape_extract.py
disasm/star_blazer.txt
loader/Makefile
loader/hires_loader.asm [deleted file]
loader/hires_loader.py [deleted file]
loader/recrack.py [new file with mode: 0755]
loader/recrack_loader.asm [new file with mode: 0644]

index 09252c9..9f32605 100644 (file)
@@ -19,22 +19,22 @@ shape4.png \
 shape5.png \
 shape6.png
 
-star_blazer.dsk: ../util/bootable.dsk star_blazer_lzss_loader.bin
+star_blazer.dsk: ../util/bootable.dsk star_blazer_lzss.bin
        cp ../util/bootable.dsk $@
-       ${DOS33} $@ SAVE B star_blazer_lzss_loader.bin "STAR BLAZER LZSS LOADER"
+       ${DOS33} $@ SAVE B star_blazer_lzss.bin "STAR BLAZER LZSS"
 
-star_blazer_lzss_loader.bin: \
-star_blazer_hires_loader.bin \
+star_blazer_lzss.bin: \
+star_blazer.bin \
 ../loader/lzss_loader.bin \
-../loader/star_blazer_lzss_loader.bin
+../loader/star_blazer_recrack_lzss.bin
        ../loader/lzss_encode.py ${LZSS_LOADER} ../loader/lzss_loader.bin $< $@
-       -diff -q ../loader/star_blazer_lzss_loader.bin $@
+       -diff -q ../loader/star_blazer_recrack_lzss.bin $@
 
-star_blazer_hires_loader.bin: \
+star_blazer.bin: \
 star_blazer.ihx \
-../loader/star_blazer_hires_loader.bin
-       ./pack.py $< $@
-       -diff -q ../loader/star_blazer_hires_loader.bin $@
+../loader/star_blazer_recrack.bin
+       ./a2_hex2bin.py $< $@
+       -diff -q ../loader/star_blazer_recrack.bin $@
 
 star_blazer.ihx: star_blazer.rel
        # add for DHGR: -b data1=0xd000
@@ -43,7 +43,6 @@ star_blazer.ihx: star_blazer.rel
 -b udata0=0x200 \
 -b udata1=0x400 \
 -b text=0x9fd \
--b loader=0x2000 \
 -b data0=0x4000 \
 $@ $<
 
@@ -57,8 +56,12 @@ shape_index.inc \
 shape_data.inc
        ${AS6500} -l -o $<
 
-star_blazer.asm: trace.txt star_blazer.txt mem.bin star_blazer.asm.patch
-       ./disasm.py star_blazer.txt mem.bin $@ <trace.txt
+star_blazer.asm: \
+trace.txt \
+star_blazer.txt \
+../loader/star_blazer_recrack.bin \
+star_blazer.asm.patch
+       ./disasm.py star_blazer.txt ../loader/star_blazer_recrack.bin $@ <trace.txt
        cp $@ $@0
        patch $@ <$@.patch
 
@@ -88,7 +91,7 @@ shape_index.inc: shape.txt shape0.png
 shape_data.inc: shape.txt shape0.png
        ./shape_compile.py --data shape0.png <$< >$@
 
-shape0.png: mem.bin
+shape0.png: ../loader/star_blazer_recrack.bin
        ./shape_extract.py $< $@
 
 shape1.png: shape0.png
@@ -118,9 +121,6 @@ shape0b.png: shape0.png shape0a.png
 shape0c.png: shape_dhgr.png
        ./shape_color_to_mono.py $< $@
 
-mem.bin: ../loader/star_blazer_hires_loader.bin
-       ./load.py $^ $@
-
 .PHONY: clean
 clean:
        rm -f \
diff --git a/disasm/a2_hex2bin.py b/disasm/a2_hex2bin.py
new file mode 100755 (executable)
index 0000000..b885d7f
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+
+import bisect
+import sys
+from intelhex import IntelHex
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+if len(sys.argv) < 3:
+  print(f'usage: {sys.argv[0]:s} in.ihx out.bin')
+  sys.exit(EXIT_FAILURE)
+in_ihx = sys.argv[1]
+out_bin = sys.argv[2]
+
+intelhex = IntelHex(in_ihx)
+segments = [j for i in intelhex.segments() for j in i]
+for i in range(0, len(segments), 2):
+  print(f'[{segments[i]:04x}, {segments[i + 1]:04x})')
+
+load_addr = segments[0] #intelhex.minaddr()
+load_size = segments[-1] - load_addr #intelhex.maxaddr() + 1 - load_addr
+
+intelhex.padding = 0
+bin = list(intelhex.tobinstr(load_addr, load_addr + load_size - 1))
+
+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))
index e6615bd..77f3328 100755 (executable)
@@ -77,12 +77,10 @@ for line in sys.stdin:
   pc1 = int(line[8:12], 16)
 
   # hacks so I don't have to redo the trace
-  if pc0 >= 0x2000 and pc0 < 0x200f:
+  if pc0 == 0x9fd:
+    pc1 = 0x9ded
+  if pc0 >= 0x2000 and pc0 < 0x4000:
     continue
-  if pc0 >= 0x200f and pc0 < 0x2100:
-    pc0 -= 0xf
-  if pc1 >= 0x200f and pc0 < 0x2100:
-    pc1 -= 0xf
 
   if pc0 not in trace_nexts:
     trace_nexts[pc0] = set()
@@ -217,8 +215,15 @@ with open(addrs_txt, 'r') as fin:
 
 print('reading image')
 with open(in_bin, 'rb') as fin:
-  mem = list(fin.read())
-assert len(mem) == 0x10000
+  data = list(fin.read())
+  hdr = data[:4]
+  bin = data[4:]
+load_addr = hdr[0] | (hdr[1] << 8)
+load_size = hdr[2] | (hdr[3] << 8)
+assert load_size == len(bin)
+
+mem = [0] * 0x10000
+mem[load_addr:load_addr + load_size] = bin
 
 mpu = py65.devices.mpu65c02.MPU(mem, 0)
 disassembler = py65.disassembler.Disassembler(mpu)
diff --git a/disasm/load.py b/disasm/load.py
deleted file mode 100755 (executable)
index 71d119f..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-
-EXIT_SUCCESS = 0
-EXIT_FAILURE = 1
-
-HIRES_SCREEN = 0x2000
-HIRES_SCREEN_SIZE = 0x2000
-
-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]
-  bin = data[4:]
-load_addr = hdr[0] + (hdr[1] << 8)
-load_size = hdr[2] + (hdr[3] << 8)
-assert len(bin) == load_size
-
-# load
-mem = [0] * 0x10000
-mem[load_addr:load_addr + load_size] = bin
-
-# initialize needed udata 
-addr = HIRES_SCREEN
-while addr < HIRES_SCREEN + 0x32:
-  assert mem[addr] == 0xa9 # lda #$nn
-  data = mem[addr + 1]
-  if mem[addr + 2] == 0x85: # sta $nn
-    dest = mem[addr + 3]
-    addr += 4
-  elif mem[addr + 2] == 0x8d: # sta $nnnn
-    dest = mem[addr + 3] + (mem[addr + 4] << 8)
-    addr += 5
-  else:
-    assert False
-  mem[dest] = data
-
-# relocate
-relocate_addr = HIRES_SCREEN + 0x4e
-assert mem[relocate_addr - 3:relocate_addr] == \
-  [0x6c, 0x20, 0x00] # jmp [vec_start]
-relocate_size = HIRES_SCREEN + HIRES_SCREEN_SIZE - relocate_addr
-assert mem[0x2039] == 0x9d # sta end_of_image - hires_screen_size
-end_of_image = mem[0x203a] + (mem[0x203b] << 8) + HIRES_SCREEN_SIZE
-mem[end_of_image - relocate_size:end_of_image] = \
-  mem[relocate_addr:relocate_addr + relocate_size]
-mem[relocate_addr:relocate_addr + relocate_size] = \
-  [0] * relocate_size
-
-with open(out_bin, 'wb') as fout:
-  fout.write(bytes(mem))
diff --git a/disasm/pack.py b/disasm/pack.py
deleted file mode 100755 (executable)
index 7d4b788..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env python3
-
-import bisect
-import sys
-from intelhex import IntelHex
-
-EXIT_SUCCESS = 0
-EXIT_FAILURE = 1
-
-HIRES_SCREEN = 0x2000
-HIRES_SCREEN_SIZE = 0x2000
-
-defeat = False
-if len(sys.argv) >= 2 and sys.argv[1] == '--defeat':
-  defeat = True
-  del sys.argv[1]
-if len(sys.argv) < 3:
-  print(f'usage: {sys.argv[0]:s} [--defeat] in.ihx out.bin')
-  sys.exit(EXIT_FAILURE)
-in_ihx = sys.argv[1]
-out_bin = sys.argv[2]
-
-intelhex = IntelHex(in_ihx)
-intelhex.padding = 0
-load_addr = intelhex.minaddr()
-bin = list(intelhex.tobinstr(load_addr, intelhex.maxaddr()))
-segments = [j for i in intelhex.segments() for j in i]
-for i in range(0, len(segments), 2):
-  print(f'[{segments[i]:04x}, {segments[i + 1]:04x})')
-
-# language-card version of relocator is slightly larger
-relocator = HIRES_SCREEN + 0x32
-if (
-  bin[relocator - load_addr:relocator + 6 - load_addr] ==
-    [0xad, 0x87, 0xc0] * 2 # lda hw_lc_bank1_ram_we twice
-):
-  relocator += 6
-
-# what will be relocated at runtime
-assert bin[relocator - load_addr] == 0xa2 # ldx #NN
-assert bin[relocator + 4 - load_addr] == 0xbd # lda MM00,x
-assert bin[relocator + 5 - load_addr] == 0x00
-addr = (
-  bin[relocator + 1 - load_addr] |
-    (bin[relocator + 6 - load_addr] << 8)
-) # MMNN
-assert bin[addr - 3 - load_addr] == 0x6c # jmp [vec_start]
-assert bin[addr - 2 - load_addr] == 0x20
-assert bin[addr - 1 - load_addr] == 0x00
-
-# how much will be copied at runtime
-size = HIRES_SCREEN + HIRES_SCREEN_SIZE - addr
-rounding = ((size + 0xff) & 0xff00) - size # >0 if first block is partial
-assert bin[relocator + 2 - load_addr] == 0xa0 # ldy #NN
-assert bin[relocator + 3 - load_addr] == (size + rounding) >> 8
-
-# where it will be copied to
-dest = load_addr + len(bin) - size
-assert bin[relocator + 7 - load_addr] == 0x9d # sta MM00,x
-assert bin[relocator + 8 - load_addr] == (dest - rounding) & 0xff
-assert bin[relocator + 9 - load_addr] == (dest - rounding) >> 8
-
-print(f'addr {addr:04x} size {size:04x} dest {dest:04x}')
-
-# if dest falls between segments, adjust up to start of next segment
-i = bisect.bisect_right(segments, dest)
-if (i & 1) == 0:
-  diff = segments[i] - dest
-  i += 1
-
-  addr += diff
-  bin[relocator + 1 - load_addr] = addr & 0xff
-  bin[relocator + 6 - load_addr] = addr >> 8
-  size -= diff
-  rounding = ((size + 0xff) & 0xff00) - size # >0 if first block is partial
-  bin[relocator + 3 - load_addr] = (size + rounding) >> 8
-  dest += diff
-  bin[relocator + 8 - load_addr] = (dest - rounding) & 0xff
-  bin[relocator + 9 - load_addr] = (dest - rounding) >> 8
-
-  print(f'diff {diff:04x} addr {addr:04x} size {size:04x} dest {dest:04x}')
-
-# relocate
-if defeat: # just nop out the relocation code
-  bin[0x2033 - load_addr:0x2049 - load_addr] = [0xff] + [0xea] * 0x15
-else:
-  bin[addr - load_addr:addr + size - load_addr] = bin[dest - load_addr:]
-  del bin[dest - load_addr:]
-
-  # if (adjusted) dest falls at start of segment, trim off padding
-  if dest == segments[i - 1]:
-    trim = segments[i - 2]
-    print(f'trim {trim:04x}')
-    assert bin[trim - load_addr:] == [0] * (load_addr + len(bin) - trim)
-    del bin[trim - load_addr:]
-
-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))
index a4d9fc9..4dc0a13 100755 (executable)
@@ -40,8 +40,15 @@ in_bin = sys.argv[1]
 out_png = sys.argv[2]
 
 with open(in_bin, 'rb') as fin:
-  mem = list(fin.read())
-assert len(mem) == 0x10000
+  data = list(fin.read())
+  hdr = data[:4]
+  bin = data[4:]
+load_addr = hdr[0] | (hdr[1] << 8)
+load_size = hdr[2] | (hdr[3] << 8)
+assert load_size == len(bin)
+
+mem = [0] * 0x10000
+mem[load_addr:load_addr + load_size] = bin
 
 image_out = numpy.zeros((PITCH_Y * 32, PITCH_X * 8), numpy.uint8)
 
index ffe52ed..0eb2a08 100644 (file)
@@ -3,12 +3,10 @@ areas
 0x0200,0x0002,udata0,uninit
 0x0400,0x03f0,udata1,uninit
 0x09fd,0x1603,text,init
-0x2000,0x004e,loader,init
-0x4000,0x5ded,data0,init
+0x4000,0x5e1e,data0,init
 0xa800,0x0d80,udata2,uninit
 
 items
-0x0020,0x0002,vec_start,word
 0x0022,0x0002,vec_init_game,word
 0x0024,0x0002,vec_start_game,word
 0x0028,0x0002,vec_calculate_object_shape,word
@@ -75,6 +73,7 @@ items
 0x00f1,0x0001,button_state,byte
 # >= 0x80 = key waiting (uses lsr to clear it)
 0x00f2,0x0001,key_state,byte
+0x0200,0x0002,vec_restart,word
 0x0400,0x0070,object1080_onscreen,byte
 0x0480,0x0070,object1080_onscreen_clipped,byte
 0x0500,0x0070,object1080_onscreen_x0,byte
@@ -171,7 +170,7 @@ items
 0x16fd,0x0001,inc_mission,code
 0x1708,0x0001,init_game,code
 0x1719,0x0001,start_game_demo,code
-0x171b,0x0001,start_game_entry,code
+0x171b,0x0001,start_game,code
 0x1750,0x0001,test_key,code
 0x1797,0x0001,read_buttons,code
 0x17b1,0x0001,vector_to_start_game,code
@@ -209,10 +208,7 @@ items
 0x1db6,0x0008,draw_misc_mask_table,byte
 0x1dbe,0x0008,draw_misc_mask_xor_table,byte
 0x1e03,0x0001,test_player_fire,code # returns cf=1 if firing (random for demo mode)
-0x2036,0x0001,,code_ign # relocator source (don't merge source instructions)
-0x2037,0x0002,,word
-0x2039,0x0001,,code_ign # relocator destination (don't create a label for it)
-0x203a,0x0002,,word
+0x2000,0x2000,hires_screen,byte
 0x4000,0x0100,shape_data_ptr_lo,byte
 0x4100,0x0100,shape_data_ptr_hi,byte
 0x4200,0x0100,shape_width_bytes,byte
@@ -919,6 +915,7 @@ items
 0x9dd9,0x0001,microcode_table_55c6_data_9dd9,byte
 0x9dde,0x0001,microcode_table_5658_data_9dde,byte
 0x9de0,0x0001,microcode_table_5758_data_9de0,byte
+0x9ded,0x0001,recrack_loader,byte
 0xa800,0x0001,x_table_times2_div7_plus_5b,byte
 0xa900,0x0001,x_table_times2_mod7_minus_03,byte
 0xaa00,0x0001,video_line_table_lo,byte
index 63e46bc..67318c8 100755 (executable)
@@ -10,14 +10,14 @@ ASLINK=../asxv5pxx/asxmak/linux/exe/aslink
 HEX2BIN=hex2bin.py
 
 LZSS_LOADER=0x800
-HIRES_LOADER=0x2000
+RECRACK_LOADER=0x9ded
 
 .PHONY: all
 all: \
 star_blazer.bin \
 star_blazer_dejunked0.bin \
 star_blazer_dejunked1.bin \
-star_blazer_lzss_loader.bin
+star_blazer_recrack_lzss.bin
 
 star_blazer.bin: ../orig/Star_Blazer_1981_Star_Craft.do
        ${DOS33} ../orig/Star_Blazer_1981_Star_Craft.do LOAD "STAR BLAZER" $@
@@ -28,7 +28,7 @@ star_blazer_dejunked0.bin: star_blazer.bin
 star_blazer_dejunked1.bin: star_blazer.bin
        ./dejunk.py $< $@ 0xff
 
-star_blazer_lzss_loader.bin: lzss_loader.bin star_blazer_hires_loader.bin
+star_blazer_recrack_lzss.bin: lzss_loader.bin star_blazer_recrack.bin
        ./lzss_encode.py ${LZSS_LOADER} $^ $@
 
 lzss_loader.bin: lzss_loader.ihx
@@ -40,16 +40,16 @@ lzss_loader.ihx: lzss_loader.rel
 lzss_loader.rel: lzss_loader.asm
        ${AS6500} -l -o $<
 
-star_blazer_hires_loader.bin: hires_loader.bin star_blazer_dejunked0.bin
-       ./hires_loader.py $^ $@
+star_blazer_recrack.bin: recrack_loader.bin star_blazer_dejunked0.bin
+       ./recrack.py $^ $@
 
-hires_loader.bin: hires_loader.ihx
+recrack_loader.bin: recrack_loader.ihx
        ${HEX2BIN} $< $@
 
-hires_loader.ihx: hires_loader.rel
-       ${ASLINK} -n -m -u -i -b text=${HIRES_LOADER} $@ $^
+recrack_loader.ihx: recrack_loader.rel
+       ${ASLINK} -n -m -u -i -b text=${RECRACK_LOADER} $@ $^
 
-hires_loader.rel: hires_loader.asm
+recrack_loader.rel: recrack_loader.asm
        ${AS6500} -l -o $<
 
 clean:
diff --git a/loader/hires_loader.asm b/loader/hires_loader.asm
deleted file mode 100644 (file)
index 101c0ea..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-vec_start = 0x20
-start = 0x17d1
-
-vec_init_game = 0x22
-init_game = 0x1708
-
-vec_start_game = 0x24
-start_game = 0x171b
-
-vec_calculate_object_shape = 0x28
-calculate_object_shape = 0x0d6c
-
-vec_draw_miscellaneous_from_table = 0x4e
-draw_miscellaneous_from_table = 0x1d1c
-
-vec_unknown = 0x0200
-unknown = 0x1999
-
-; also address of loader
-hires_screen = 0x2000
-hires_screen_size = 0x2000
-
-; points after last byte initialized by loader
-end_of_image = 0x9ded
-
-       .r65c02
-
-       .area   text
-
-       lda     #<start
-       sta     vec_start
-       lda     #>start
-       sta     vec_start + 1
-
-       lda     #<init_game
-       sta     vec_init_game
-       lda     #>init_game
-       sta     vec_init_game + 1
-
-       lda     #<start_game
-       sta     vec_start_game
-       lda     #>start_game
-       sta     vec_start_game + 1
-
-       lda     #<calculate_object_shape
-       sta     vec_calculate_object_shape
-       lda     #>calculate_object_shape
-       sta     vec_calculate_object_shape + 1
-
-       lda     #<draw_miscellaneous_from_table
-       sta     vec_draw_miscellaneous_from_table
-       lda     #>draw_miscellaneous_from_table
-       sta     vec_draw_miscellaneous_from_table + 1
-
-       lda     #<unknown
-       sta     vec_unknown
-       lda     #>unknown
-       sta     vec_unknown + 1
-
-       ldx     #<2$ ; skip loader size in first 0x100-byte block
-       ldy     #>hires_screen_size ; number of 0x100-byte blocks
-1$:    lda     hires_screen,x
-       sta     end_of_image - hires_screen_size,x
-       inx
-       bne     1$
-       inc     1$+2
-       inc     1$+5
-       dey
-       bne     1$
-
-       dex
-       txs
-       cld
-       jmp     [vec_start]
-
-2$:    ; start of data relocated by loader
diff --git a/loader/hires_loader.py b/loader/hires_loader.py
deleted file mode 100755 (executable)
index 9039338..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-
-EXIT_SUCCESS = 0
-EXIT_FAILURE = 1
-
-if len(sys.argv) < 4:
-  print(f'usage: {sys.argv[0]:s} my_loader.bin in.bin out.bin')
-  sys.exit(EXIT_FAILURE)
-my_loader_bin = sys.argv[1]
-in_bin = sys.argv[2]
-out_bin = sys.argv[3]
-
-with open(my_loader_bin, 'rb') as fin:
-  my_loader = list(fin.read())
-
-with open(in_bin, 'rb') as fin:
-  data = list(fin.read())
-  hdr = data[:4]
-  bin = data[4:]
-assert len(bin) == 0x9300
-
-bin = bin[0x06fd:0x9300] + bin[0x1d00:0x24ed]
-assert len(bin) == 0x93f0 # [0x09fd:0x9ded)
-
-load_addr = 0x09fd
-hires_screen = 0x2000 - load_addr
-hires_screen_size = 0x2000
-
-relocate_start = hires_screen + len(my_loader)
-relocate_size = hires_screen_size - len(my_loader)
-bin[hires_screen:relocate_start] = my_loader
-bin[relocate_start:hires_screen + hires_screen_size] = bin[-relocate_size:]
-bin[-relocate_size:] = []
-load_size = len(bin)
-
-bin[:3] = [0x4c, 0x00, 0x20] # jmp 0x2000
-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))
diff --git a/loader/recrack.py b/loader/recrack.py
new file mode 100755 (executable)
index 0000000..d0e975f
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+import sys
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+if len(sys.argv) < 4:
+  print(f'usage: {sys.argv[0]:s} recrack_loader.bin in.bin out.bin')
+  sys.exit(EXIT_FAILURE)
+recrack_loader_bin = sys.argv[1]
+in_bin = sys.argv[2]
+out_bin = sys.argv[3]
+
+with open(recrack_loader_bin, 'rb') as fin:
+  recrack_loader = list(fin.read())
+
+with open(in_bin, 'rb') as fin:
+  data = list(fin.read())
+  hdr = data[:4]
+  bin = data[4:]
+load_addr = hdr[0] | (hdr[1] << 8)
+load_size = hdr[2] | (hdr[3] << 8)
+assert load_size == len(bin)
+
+assert load_size == 0x9300
+entry_point = 0x9ded
+
+bin = (
+  [0x4c, 0xed, 0x9d] + # jmp 0x9ded, end of image
+    bin[0x0a00 - load_addr:0x2000 - load_addr] + # [0x0a00, 0x2000)
+    [0] * 0x2000 + # [0x2000, 0x4000)
+    bin[0x4000 - load_addr:0x9600 - load_addr] + # [0x4000, 0x9600)
+    bin[0x2000 - load_addr:0x27ed - load_addr] + # [0x9600, 0x9ded)
+    recrack_loader
+)
+load_addr = 0x09fd
+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))
diff --git a/loader/recrack_loader.asm b/loader/recrack_loader.asm
new file mode 100644 (file)
index 0000000..aee5ab5
--- /dev/null
@@ -0,0 +1,58 @@
+vec_start = 0x20
+start = 0x17d1
+
+vec_init_game = 0x22
+init_game = 0x1708
+
+vec_start_game = 0x24
+start_game = 0x171b
+
+vec_calculate_object_shape = 0x28
+calculate_object_shape = 0x0d6c
+
+vec_draw_misc_from_table = 0x4e
+draw_misc_from_table = 0x1d1c
+
+vec_restart = 0x0200
+restart = 0x1999
+
+       .r65c02
+
+       .area   text
+
+       ldx     #0xff
+       txs
+       cld
+
+       ; this doesn't seem to be referenced after start
+       ;lda    #<start
+       ;sta    vec_start
+       ;lda    #>start
+       ;sta    vec_start + 1
+
+       lda     #<init_game
+       sta     vec_init_game
+       lda     #>init_game
+       sta     vec_init_game + 1
+
+       lda     #<start_game
+       sta     vec_start_game
+       lda     #>start_game
+       sta     vec_start_game + 1
+
+       lda     #<calculate_object_shape
+       sta     vec_calculate_object_shape
+       lda     #>calculate_object_shape
+       sta     vec_calculate_object_shape + 1
+
+       lda     #<draw_misc_from_table
+       sta     vec_draw_misc_from_table
+       lda     #>draw_misc_from_table
+       sta     vec_draw_misc_from_table + 1
+
+       lda     #<restart
+       sta     vec_restart
+       lda     #>restart
+       sta     vec_restart + 1
+
+       jmp     start