all: \
galaxian_shape.png \
galaxian.asm \
+alien_rain_shape.png \
+alien_rain.asm \
alien_typhoon_shape.png \
alien_typhoon.asm \
galaxian0_segments.txt \
Apple\ II+\ -\ 341-0020\ -\ Applesoft\ BASIC\ Autostart\ Monitor\ F800\ -\ 2716.bin
../utils/a2_load.py \
---f8_rom="Apple II+ - 341-0020 - Applesoft BASIC Autostart Monitor F800 - 2716.bin" \
-0x9707 $< $@ <galaxian0_segments.txt
+--f8-rom="Apple II+ - 341-0020 - Applesoft BASIC Autostart Monitor F800 - 2716.bin" \
+--segments=galaxian0_segments.txt \
+0x9707 \
+$< \
+$@
galaxian0.a2bin: ../orig/Galaxian_1980_Starcraft.do
${DOS33} $< LOAD "GALAXIAN" $@
+alien_rain_shape.png: alien_rain_shape.json
+ ./shape_extract_png.py $^ $@
+
+alien_rain_shape.json: alien_rain.txt alien_rain0.ihx
+ ./shape_extract.py $^ $@
+
+alien_rain.asm: \
+alien_rain_trace.txt \
+alien_rain.txt \
+alien_rain0.ihx
+ ../utils/disasm.py --trace=$^ $@
+
+alien_rain0.ihx: \
+../orig/Alien_Rain_1981_Broderbund_DOS.nib \
+alien_rain0_segments.txt \
+../orig/Apple\ Disk\ II\ 16\ Sector\ Interface\ Card\ ROM\ P5\ -\ 341-0027.bin \
+Apple\ II+\ -\ 341-0020\ -\ Applesoft\ BASIC\ Autostart\ Monitor\ F800\ -\ 2716.bin
+ ../utils/a2_load.py \
+--c6-rom=../orig/Apple\ Disk\ II\ 16\ Sector\ Interface\ Card\ ROM\ P5\ -\ 341-0027.bin \
+--f8-rom=../galaxian/Apple\ II+\ -\ 341-0020\ -\ Applesoft\ BASIC\ Autostart\ Monitor\ F800\ -\ 2716.bin \
+--trace=26 \
+0x9788 \
+$< \
+$@
+
+alien_rain0.a2bin: ../orig/Alien_Typhoon_1981_Starcraft.do
+ ${DOS33} $< LOAD "ALIEN TYPHOON" $@
+
alien_typhoon_shape.png: alien_typhoon_shape.json
./shape_extract_png.py $^ $@
alien_typhoon0.ihx: \
alien_typhoon0.a2bin \
alien_typhoon0_segments.txt
- ../utils/a2_load.py 0x8f98 $< $@ <alien_typhoon0_segments.txt
+ ../utils/a2_load.py \
+--segments=alien_typhoon0_segments.txt \
+0x8f98 \
+$< \
+$@
alien_typhoon0.a2bin: ../orig/Alien_Typhoon_1981_Starcraft.do
${DOS33} $< LOAD "ALIEN TYPHOON" $@
galaxian_shape.png \
galaxian_shape.json \
galaxian.asm \
+alien_rain_shape.png \
+alien_rain_shape.json \
+alien_rain.asm \
alien_typhoon_shape.png \
alien_typhoon_shape.json \
alien_typhoon.asm
EXIT_SUCCESS = 0
EXIT_FAILURE = 1
+in_c6_rom = None
in_f8_rom = None
-if len(sys.argv) >= 2 and sys.argv[1][:9] == '--f8_rom=':
- in_f8_rom = sys.argv[1][9:]
+segments_txt = None
+trace = -1 # track to trace from
+while len(sys.argv) >= 2:
+ if sys.argv[1][:9] == '--c6-rom=':
+ in_c6_rom = sys.argv[1][9:]
+ elif sys.argv[1][:9] == '--f8-rom=':
+ in_f8_rom = sys.argv[1][9:]
+ elif sys.argv[1][:11] == '--segments=':
+ segments_txt = sys.argv[1][11:]
+ elif sys.argv[1] == '--trace':
+ trace = 0
+ elif sys.argv[1][:8] == '--trace=':
+ trace = int(sys.argv[1][8:], 0)
+ else:
+ break
del sys.argv[1]
if len(sys.argv) < 4:
- print(f'usage: {sys.argv[0]:s} [--f8_rom=rom.bin] entry_point in.a2bin out.ihx <segments.txt')
+ print(f'usage: {sys.argv[0]:s} [--c6-rom=rom.bin] [--f8-rom=rom.bin] [--segments=segments.txt] [--trace[=disk2_track]] entry_point in.(a2bin|nib) out.ihx')
sys.exit(EXIT_FAILURE)
entry_point = int(sys.argv[1], 0)
-in_a2bin = sys.argv[2]
+in_a2bin_nib = sys.argv[2]
out_ihx = sys.argv[3]
-segments0 = []
-for line in sys.stdin:
- i = line.find('#')
- if i != -1:
- line = line[:i]
- line = line.rstrip()
- if len(line):
- assert line[:1] == '[' and line[-1:] == ')'
- fields = line[1:-1].split(',')
- assert len(fields) == 2
- segments0.extend([int(i, 0) for i in fields])
-if len(segments0) == 0:
- segments0 = [0, 0x10000]
-
-with open(in_a2bin, 'rb') as fin:
- a2bin = list(fin.read())
- hdr = a2bin[:4]
- bin = a2bin[4:]
-load_addr = hdr[0] | (hdr[1] << 8)
-load_size = hdr[2] | (hdr[3] << 8)
-assert len(bin) == load_size
+segments0 = [0, 0x10000]
+if segments_txt is not None:
+ with open(segments_txt) as fin:
+ segments0 = []
+ for line in fin:
+ i = line.find('#')
+ if i != -1:
+ line = line[:i]
+ line = line.rstrip()
+ if len(line):
+ assert line[:1] == '[' and line[-1:] == ')'
+ fields = line[1:-1].split(',')
+ assert len(fields) == 2
+ segments0.extend([int(i, 0) for i in fields])
mem = [0] * 0x10000
mem_used = [False] * 0x10000
+if in_c6_rom is not None:
+ with open(in_c6_rom, 'rb') as fin:
+ c6_rom = list(fin.read())
+ assert len(c6_rom) == 0x100
+ mem[0xc600:0xc700] = c6_rom
+
+start_addr = -1
if in_f8_rom is not None:
with open(in_f8_rom, 'rb') as fin:
f8_rom = list(fin.read())
assert len(f8_rom) == 0x800
mem[0xf800:] = f8_rom
-mem[load_addr:load_addr + load_size] = bin
-mem_used[load_addr:load_addr + load_size] = [True] * load_size
+disk2_data = []
+if in_a2bin_nib[-6:] == '.a2bin':
+ with open(in_a2bin_nib, 'rb') as fin:
+ a2bin = list(fin.read())
+ hdr = a2bin[:4]
+ bin = a2bin[4:]
+ load_addr = hdr[0] | (hdr[1] << 8)
+ load_size = hdr[2] | (hdr[3] << 8)
+ assert len(bin) == load_size
+ mem[load_addr:load_addr + load_size] = bin
+ mem_used[load_addr:load_addr + load_size] = [True] * load_size
+elif in_a2bin_nib[-4:] == '.nib':
+ with open(in_a2bin_nib, 'rb') as fin:
+ nib = list(fin.read())
+ assert len(nib) % 6656 == 0
+ disk2_data = [
+ nib[i:i + 6656] + nib[i:i + 11]
+ for i in range(0, len(nib), 6656)
+ ]
+ load_addr = mem[0xfffc] | (mem[0xfffd] << 8) # boot autostart monitor
+else:
+ assert False
+
+disk2_phase = 0
+disk2_track = 0
+disk2_index = 0
+disk2_address = [0xd5, 0xaa, 0x96]
+def disk2(addr, data):
+ global disk2_phase, disk2_track, disk2_index
+
+ if (addr & 9) == 1:
+ phase = (addr >> 1) & 3
+ track = disk2_track + (((phase - disk2_phase) + 2) & 3) - 2
+ disk2_phase = phase
+ if track >= 0 and track < 80:
+ disk2_track = track
+ print('disk2_track', disk2_track)
+ elif addr == 0xc:
+ if (disk2_track & 1) or disk2_track >= 35:
+ data = 0
+ else:
+ i = disk2_track >> 1
+ if disk2_data[i][disk2_index:disk2_index + 3] == disk2_address:
+ address = [
+ (disk2_data[i][disk2_index + j] << 1) &
+ disk2_data[i][disk2_index + j + 1]
+ for j in range(3, 11, 2)
+ ]
+ print(
+ 'volume',
+ address[0],
+ 'track',
+ address[1],
+ 'sector',
+ address[2],
+ 'checksum',
+ address[3]
+ )
+ data = disk2_data[i][disk2_index]
+ disk2_index = (disk2_index + 1) % 6656
+ return data
class Mem:
def __init__(self, mem, mem_used):
self.mem_used = mem_used
def __getitem__(self, addr):
+ if (addr & 0xfff0) == 0xc0e0:
+ #print('rd', hex(addr), hex(self.mem[addr]))
+ return disk2(addr & 0xf, 0)
#self.mem_used[addr] = False
return self.mem[addr]
def __setitem__(self, addr, data):
+ if (addr & 0xfff0) == 0xc0e0:
+ #print('wr', hex(addr), hex(data))
+ disk2(addr & 0xf, data)
self.mem[addr] = data
self.mem_used[addr] = True
mpu = py65.devices.mpu65c02.MPU(Mem(mem, mem_used), load_addr)
while mpu.pc != entry_point:
+ if disk2_track == trace and mem[mpu.pc] == 0x4c:
+ addr = mem[mpu.pc + 1] | (mem[mpu.pc + 2] << 8)
+ print(f'{mpu.pc:04x}: jmp {addr:04x}')
+ #print('pc', hex(mpu.pc))
mpu.step()
if mpu.p & 8:
print('warning: d = 1')