--- /dev/null
+#!/usr/bin/env python3
+
+import json
+import sys
+from intelhex import IntelHex
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+if len(sys.argv) < 6:
+ print(
+ f'usage: {sys.argv[0]:s} load_addr addrs.txt in.json out_index.inc out_data.inc'
+ )
+ sys.exit(EXIT_FAILURE)
+load_addr = int(sys.argv[1], 0)
+addrs_txt = sys.argv[2]
+in_json = sys.argv[3]
+out_index_inc = sys.argv[4]
+out_data_inc = sys.argv[5]
+
+print('reading addrs')
+object_tables = {}
+with open(addrs_txt) as fin:
+ def get_line():
+ while True:
+ line = fin.readline()
+ if len(line) == 0:
+ return []
+ i = line.find('#')
+ if i >= 0:
+ line = line[:i]
+ fields = line.strip().split(',')
+ if fields != ['']:
+ #print('fields', fields)
+ return fields
+
+ fields = get_line()
+ while len(fields):
+ assert len(fields) == 1
+ section = fields[0]
+ print(section)
+
+ if section == 'items':
+ fields = get_line()
+ while len(fields) >= 2:
+ assert len(fields) >= 4
+ addr = int(fields[0], 0)
+ name = fields[2]
+ _type = fields[3]
+ if (
+ (_type == 'byte' or _type == 'word') and
+ name[:6] == 'object' and
+ name[6:7] in '0123456789abcdef' and
+ name[7:8] in '0123456789abcdef' and
+ name[8:9] in '0123456789abcdef' and
+ name[9:10] in '0123456789abcdef' and
+ name[10:11] == '_'
+ ):
+ object_tables[name[11:]] = (
+ addr,
+ int(name[6:8], 16),
+ int(name[8:10], 16),
+ _type == 'word'
+ )
+ fields = get_line()
+ continue
+
+ # unknown section, skip
+ fields = get_line()
+ while len(fields) >= 2:
+ fields = get_line()
+
+byte_tables = {
+ 'ucode_animate_shape',
+ 'ucode_collision_test',
+ 'ucode_homing',
+ 'ucode_test_fire_in_state_f0',
+ 'ucode_test_fire_in_state_f1',
+ 'ucode_test_fire_in_state_f2',
+ 'ucode_test_fire_in_state_f3',
+}
+object0 = min([i for _, i, _, _ in object_tables.values()])
+object1 = max([i for _, _, i, _ in object_tables.values()])
+
+print('reading json')
+with open(in_json) as fin:
+ data = json.load(fin)
+
+print('writing index')
+dot = load_addr
+with open(out_index_inc, 'w') as fout:
+ for table, (addr, index0, index1, word) in object_tables.items():
+ # only if we have some data for the table (otherwise it's udata)
+ if any([table in data[i - object0] for i in range(index0, index1)]):
+ if addr > dot:
+ i = addr - dot
+ fout.write(f'\t.ds\t0x{i:x}\n' if i >= 0x10 else f'\t.ds\t{i:d}\n')
+ dot = addr
+ fout.write(f'object{index0:02x}{index1:02x}_{table:s}: ; {addr:04x}\n')
+
+ if table[-4:] == '_ptr':
+ table1 = table[:-4]
+ table_data = []
+ for i in range(index0, index1):
+ value = '0'
+ if data[i - object0][table1] is not None:
+ name = data[i - object0]['name']
+ if name is None:
+ name = f'{i:02x}'
+ value = f'object{index0:02x}{index1:02x}_{table1:s}_{name:s}'
+ table_data.append(value)
+ else:
+ table_data = [
+ data[i - object0][table]
+ for i in range(index0, index1)
+ ]
+
+ op = '.dw' if word else '.db'
+ fout.write(''.join([f'\t{op:s}\t{i:s}\n' for i in table_data]))
+
+ dot += (index1 - index0) * 2 if word else index1 - index0
+print('writing data')
+
+# generate output
+out = []
+for table, (addr, index0, index1, word) in object_tables.items():
+ if table[-4:] == '_ptr':
+ table1 = table[:-4]
+ for i in range(index0, index1):
+ value = data[i - object0][table1]
+ if value is not None:
+ name = data[i - object0]['name']
+ if name is None:
+ name = f'{i:02x}'
+ addr = int(data[i - object0][table], 0)
+ text = f'object{index0:02x}{index1:02x}_{table1:s}_{name:s}: ; {addr:04x}\n'
+
+ op = '.db' if table1 in byte_tables else '.dw'
+ text += ''.join([f'\t{op:s}\t{i:s}\n' for i in value]) + '\t.db\t0\n'
+
+ out.append((addr, i, text))
+
+# write output in order of address in original executable
+with open(out_data_inc, 'w') as fout:
+ for _, _, text in sorted(out):
+ fout.write(text)
--- /dev/null
+#!/usr/bin/env python3
+
+import bisect
+import json
+import sys
+from intelhex import IntelHex
+
+EXIT_SUCCESS = 0
+EXIT_FAILURE = 1
+
+if len(sys.argv) < 4:
+ print(f'usage: {sys.argv[0]:s} addrs.txt in.ihx out.json')
+ sys.exit(EXIT_FAILURE)
+addrs_txt = sys.argv[1]
+in_ihx = sys.argv[2]
+out_json = sys.argv[3]
+
+print('reading addrs')
+object_tables = {}
+objects = {}
+with open(addrs_txt) as fin:
+ def get_line():
+ while True:
+ line = fin.readline()
+ if len(line) == 0:
+ return []
+ i = line.find('#')
+ if i >= 0:
+ line = line[:i]
+ fields = line.strip().split(',')
+ if fields != ['']:
+ #print('fields', fields)
+ return fields
+
+ fields = get_line()
+ while len(fields):
+ assert len(fields) == 1
+ section = fields[0]
+ print(section)
+
+ if section == 'items':
+ fields = get_line()
+ while len(fields) >= 2:
+ assert len(fields) >= 4
+ addr = int(fields[0], 0)
+ name = fields[2]
+ _type = fields[3]
+ if (
+ (_type == 'byte' or _type == 'word') and
+ name[:6] == 'object' and
+ name[6:7] in '0123456789abcdef' and
+ name[7:8] in '0123456789abcdef' and
+ name[8:9] in '0123456789abcdef' and
+ name[9:10] in '0123456789abcdef' and
+ name[10:11] == '_'
+ ):
+ object_tables[name[11:]] = (
+ addr,
+ int(name[6:8], 16),
+ int(name[8:10], 16),
+ _type == 'word'
+ )
+ fields = get_line()
+ continue
+
+ if section == 'objects':
+ fields = get_line()
+ while len(fields) >= 2:
+ assert len(fields) == 2
+ index = int(fields[0], 0)
+ name = fields[1]
+ objects[index] = name
+ fields = get_line()
+ continue
+
+ # unknown section, skip
+ fields = get_line()
+ while len(fields) >= 2:
+ fields = get_line()
+
+byte_tables = {
+ 'ucode_animate_shape',
+ 'ucode_collision_test',
+ 'ucode_homing',
+ 'ucode_test_fire_in_state_f0',
+ 'ucode_test_fire_in_state_f1',
+ 'ucode_test_fire_in_state_f2',
+ 'ucode_test_fire_in_state_f3',
+}
+object0 = min([i for _, i, _, _ in object_tables.values()])
+object1 = max([i for _, _, i, _ in object_tables.values()])
+
+print('reading ihx')
+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})')
+
+print('extracting')
+data = [
+ {'name': f'{i:02x}_{objects[i]}' if i in objects else None}
+ for i in range(object0, object1)
+]
+
+for table, (addr, index0, index1, word) in object_tables.items():
+ i = bisect.bisect_right(segments, addr) - 1
+ if (i & 1) == 0: # if initialized in ihx file
+ #for i in range(object0, object1):
+ # data[i - object0][table] = None
+ if word:
+ addr -= index0 * 2
+ for i in range(index0, index1):
+ value = intelhex[addr + 2 * i] | (intelhex[addr + 2 * i + 1] << 8)
+ data[i - object0][table] = f'0x{value:04x}'
+ else:
+ addr -= index0
+ for i in range(index0, index1):
+ value = intelhex[addr + i]
+ data[i - object0][table] = str(value)
+
+ # extract pointed-to data if applicable
+ if table[-4:] == '_ptr':
+ table1 = table[:-4]
+ for i in range(index0, index1):
+ addr1 = int(data[i - object0][table], 0)
+ value = None
+ if addr1:
+ value = []
+ if table1 in byte_tables:
+ while intelhex[addr1]:
+ value1 = intelhex[addr1]
+ value.append(f'0x{value1:02x}')
+ addr1 += 1
+ else:
+ while intelhex[addr1]:
+ value1 = intelhex[addr1] | (intelhex[addr1 + 1] << 8)
+ value.append(f'0x{value1:04x}')
+ addr1 += 2
+ data[i - object0][table1] = value
+
+print('writing json')
+with open(out_json, 'w') as fout:
+ json.dump(data, fout, indent = 2)
0x1800,0x05c6,text1,init
0x1e00,0x0139,text2,init
0x1f80,0x0080,data1,init
-0x4000,0x1bc0,data2,init
-0x5c00,0x3008,data3,init
-0x8e00,0x0fed,data4,init
+0x4000,0x0800,data2,init
+0x4800,0x13c0,data3,init
+0x5c00,0x3008,data4,init
+0x8e00,0x0fed,data5,init
0xa800,0x0d80,udata1,uninit
items
0x00c9,0x0001,ucode_x_save_c9,byte
0x00ca,0x0001,ucode_y_save_ca,byte
# seems to preserve a value from one of:
-# object6080_b500 (execute_ucode6080_fire_state_f0)
-# object6080_b520 (execute_ucode6080_fire_state_f1)
-# object6080_b540 (execute_ucode6080_fire_state_f2)
-# object6080_b560 (execute_ucode6080_fire_state_f3)
+# object6080_b500 (execute_object6080_ucode_fire_in_state_f0)
+# object6080_b520 (execute_object6080_ucode_fire_in_state_f1)
+# object6080_b540 (execute_object6080_ucode_fire_in_state_f2)
+# object6080_b560 (execute_object6080_ucode_fire_in_state_f3)
# and also used as an index into ucode in ucode_execute_10d1
0x00cb,0x0001,ucode_state_save,byte
# may contain a value from object1080_ucode_start_sentinel (basically
0x0d38,0x0001,maybe_copy_one_of_arr_52a0_52e0_5320_5360_to_arr_b480,code
0x0d5e,0x0001,calculate_object_direction,code
0x0d6c,0x0001,calculate_object_shape,code
-# example: ucode1080_animate_shape_4d_headquarters_radar_icbm
+# example: object1080_ucode_animate_shape_4d_headquarters_radar_icbm
# -> implied start of section 0xf0
# .db 0x72 headquarters shape
# .db 0xf2 -> start of section 0xf2
0x11b2,0x0001,make_object_inactive_and_erase,code
# called from update_object, when:
# object1080_countdown_b120 or object1080_countdown_b190 expires
-0x11bd,0x0001,execute_ucode1080_countdown,code
+0x11bd,0x0001,execute_object1080_ucode_countdown,code
# called from update_object, when:
# test_object_collision returns cf=1
-0x11cd,0x0001,execute_ucode1080_collision,code
+0x11cd,0x0001,execute_object1080_ucode_collision,code
# called from update_object for objects >= 40, when:
# object1080_x_hi outside [object4080_x_hi_min, object4080_x_hi_max)
-0x11dd,0x0001,execute_ucode4080_x_outside,code
+0x11dd,0x0001,execute_object4080_ucode_x_outside,code
# called from update_object for objects >= 40, when:
# object1080_y_hi outside [object4080_y_hi_min, object4080_y_hi_max)
-0x11ed,0x0001,execute_ucode4080_y_outside,code
+0x11ed,0x0001,execute_object4080_ucode_y_outside,code
# called from update_object for objects >= 60, when:
# object1080_start_sentinel == 0xf0
-# and then test_object_fire_state_f0 returns cf=1
-0x11fd,0x0001,execute_ucode6080_fire_state_f0,code
+# and then test_object_fire_in_state_f0 returns cf=1
+0x11fd,0x0001,execute_object6080_ucode_fire_in_state_f0,code
# called from update_object for objects >= 60, when:
# object1080_start_sentinel == 0xf1
-# and then test_object_fire_state_f1 returns cf=1
-0x1222,0x0001,execute_ucode6080_fire_state_f1,code
+# and then test_object_fire_in_state_f1 returns cf=1
+0x1222,0x0001,execute_object6080_ucode_fire_in_state_f1,code
# called from update_object for objects >= 60, when:
# object1080_start_sentinel == 0xf2
-# and then test_object_fire_state_f2 returns cf=1
-0x1247,0x0001,execute_ucode6080_fire_state_f2,code
+# and then test_object_fire_in_state_f2 returns cf=1
+0x1247,0x0001,execute_object6080_ucode_fire_in_state_f2,code
# called from update_object for objects >= 60, when:
# object1080_start_sentinel == 0xf3
-# and then test_object_fire_state_f3 returns cf=1
-0x126c,0x0001,execute_ucode6080_fire_state_f3,code
+# and then test_object_fire_in_state_f3 returns cf=1
+0x126c,0x0001,execute_object6080_ucode_fire_in_state_f3,code
# called from accelerate_object_towards_another
# seems to have a chance to intervene in the homing logic
-0x1291,0x0001,execute_ucode6080_homing,code
+0x1291,0x0001,execute_object6080_ucode_homing,code
0x12e1,0x0001,accelerate_object_towards_another,code
0x133f,0x0001,sign_extend_a_to_ya_asl_by_4,code
0x1350,0x0001,accelerate_object_somehow,code
0x1388,0x0001,move_object_by_velocity,code
0x13d0,0x0001,test_object_collision,code
0x1447,0x0001,accelerate_object_anyhow,code
-0x14ef,0x0001,test_object_fire_state_f0,code
-0x150f,0x0001,test_object_fire_state_f1,code
+0x14ef,0x0001,test_object_fire_in_state_f0,code
+0x150f,0x0001,test_object_fire_in_state_f1,code
0x152c,0x0001,test_object_fire_entry,code
0x153f,0x0001,test_object_fire_false,code
0x1542,0x0001,test_object_fire_player,code
-0x1549,0x0001,test_object_fire_state_f2,code
-0x1569,0x0001,test_object_fire_state_f3,code
+0x1549,0x0001,test_object_fire_in_state_f2,code
+0x1569,0x0001,test_object_fire_in_state_f3,code
0x1589,0x0001,objects_init,code
0x1595,0x0001,objects_init_entry,code
0x15d7,0x0001,maybe_calculate_object_shape_and_update,code
0x4990,0x0070,object1080_animate1,byte
0x4a00,0x0001,score_var_4a00,byte
0x4a01,0x000f,score_table_4a01,byte
-# 4a10 not referenced, spare?
+# 0x4a10 spare
0x4a80,0x0001,score_var_4a80,byte
0x4a81,0x000f,score_table_4a81,byte
-# 4a90 not referenced, spare?
+# 0x4a90 spare
0x4b00,0x0001,score_var_4b00,byte
0x4b01,0x000f,score_table_4b01,byte
0x4b10,0x0070,object1080_4b10,byte
0x4c70,0x0070,object1080_velocity_x_random_range,byte
0x4ce0,0x0070,object1080_velocity_y_random_base,byte
0x4d50,0x0070,object1080_velocity_y_random_range,byte
-# gap, spares?
+# 0x4dc0 spare
0x4ed0,0x0030,object4070_4ed0,byte # might be bigger
-# 4f00 not referenced, spare?
+# 0x4f00 spare
0x4f40,0x0040,object4080_4f40,byte
0x4f80,0x0040,object4080_x_random_base,byte
0x4fc0,0x0040,object4080_x_random_range,byte
0x5270,0x0030,object5080_difference_5270,byte
0x52a0,0x0030,object5080_difference_52a0,byte
0x52d0,0x0030,object5080_difference_52d0,byte
-0x5300,0x0020,object6080_fire_count_init_state_f0,byte
-# used from execute_ucode6080_fire_state_f0
+0x5300,0x0020,object6080_fire_count_init_in_state_f0,byte
+# used from execute_object6080_ucode_fire_in_state_f0
0x5320,0x0020,object6080_5320,byte
-0x5340,0x0020,object6080_fire_count_init_state_f1,byte
-# used from execute_ucode6080_fire_state_f1
+0x5340,0x0020,object6080_fire_count_init_in_state_f1,byte
+# used from execute_object6080_ucode_fire_in_state_f1
0x5360,0x0020,object6080_5360,byte
-0x5380,0x0020,object6080_fire_count_init_state_f2,byte
-# used from execute_ucode6080_fire_state_f2
+0x5380,0x0020,object6080_fire_count_init_in_state_f2,byte
+# used from execute_object6080_ucode_fire_in_state_f2
0x53a0,0x0020,object6080_53a0,byte
-0x53c0,0x0020,object6080_fire_count_init_state_f3,byte
-# used from execute_ucode6080_fire_state_f2
+0x53c0,0x0020,object6080_fire_count_init_in_state_f3,byte
+# used from execute_object6080_ucode_fire_in_state_f2
0x53e0,0x0020,object6080_53e0,byte
# the partitioning below is approximate and just tries to cover everything
0x5400,0x0020,,word
-0x5420,0x00e0,ucode1080_animate_shape,word
-0x5500,0x0020,ucode0010_init_or_zero,word
-0x5520,0x00e0,ucode1080_countdown,word
+0x5420,0x00e0,object1080_ucode_animate_shape_ptr,word
+0x5500,0x0020,object0010_ucode_init_or_zero_ptr,word
+0x5520,0x00e0,object1080_ucode_countdown_ptr,word
0x5600,0x0020,,word
-0x5620,0x00e0,ucode1080_collision_test,word
+0x5620,0x00e0,object1080_ucode_collision_test_ptr,word
0x5700,0x0020,,word
-0x5720,0x00e0,ucode1080_collision,word
-0x5800,0x0080,ucode4080_x_outside,word
-0x5880,0x0080,ucode4080_y_outside,word
+0x5720,0x00e0,object1080_ucode_collision_ptr,word
+0x5800,0x0080,object4080_ucode_x_outside_ptr,word
+0x5880,0x0080,object4080_ucode_y_outside_ptr,word
0x5900,0x0020,,word
-0x5920,0x0030,ucode6080_homing,word
+0x5920,0x0030,object6080_ucode_homing_ptr,word
0x5950,0x0070,,word
-0x59c0,0x0040,ucode6080_test_fire_state_f0,word
-0x5a00,0x0040,ucode6080_fire_state_f0,word
-0x5a40,0x0040,ucode6080_test_fire_state_f1,word
-0x5a80,0x0040,ucode6080_fire_state_f1,word
-0x5ac0,0x0040,ucode6080_test_fire_state_f2,word
-0x5b00,0x0040,ucode6080_fire_state_f2,word
-0x5b40,0x0040,ucode6080_test_fire_state_f3,word
-0x5b80,0x0040,ucode6080_fire_state_f3,word
+0x59c0,0x0040,object6080_ucode_test_fire_in_state_f0_ptr,word
+0x5a00,0x0040,object6080_ucode_fire_in_state_f0_ptr,word
+0x5a40,0x0040,object6080_ucode_test_fire_in_state_f1_ptr,word
+0x5a80,0x0040,object6080_ucode_fire_in_state_f1_ptr,word
+0x5ac0,0x0040,object6080_ucode_test_fire_in_state_f2_ptr,word
+0x5b00,0x0040,object6080_ucode_fire_in_state_f2_ptr,word
+0x5b40,0x0040,object6080_ucode_test_fire_in_state_f3_ptr,word
+0x5b80,0x0040,object6080_ucode_fire_in_state_f3_ptr,word
# 0x5bc0 padding
# 0x5c00 shape data
# 0x8c08 padding
0xb480,0x0030,object5080_abs_difference_b480,byte
0xb4b0,0x0030,object5080_abs_difference_b4b0,byte
0xb4e0,0x0020,object6080_fire_count,byte
-# used from execute_ucode6080_fire_state_f0
+# used from execute_object6080_ucode_fire_in_state_f0
0xb500,0x0020,object6080_b500,byte
-# used from execute_ucode6080_fire_state_f1
+# used from execute_object6080_ucode_fire_in_state_f1
0xb520,0x0020,object6080_b520,byte
-# used from execute_ucode6080_fire_state_f2
+# used from execute_object6080_ucode_fire_in_state_f2
0xb540,0x0020,object6080_b540,byte
-# used from execute_ucode6080_fire_state_f3
+# used from execute_object6080_ucode_fire_in_state_f3
0xb560,0x0020,object6080_b560,byte
0xc000,0x0001,HW_KBD,byte
0xc010,0x0001,HW_KBDSTRB,byte
0x13,exhaust
0x14,parachute
0x15,parachute
-0x16,parachute_open
+0x16,parachute
0x17,fuel
0x18,supply_plane
0x1c,tank