From: Nick Downing Date: Sat, 25 Jun 2022 05:24:09 +0000 (+1000) Subject: New JSON-based shape extractor and compiler (the PNG-based scheme can be piggybacked... X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=ab6b41a3652fe857522b6ce6af541829de55ff47;p=star_disasm.git New JSON-based shape extractor and compiler (the PNG-based scheme can be piggybacked onto this later, avoiding having to deal with the detailed storage format) --- diff --git a/.gitignore b/.gitignore index fcbdcb0..0ff2e9d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,12 @@ *.rel *.rst *.seed +/disasm/shape.json +/disasm/shape_data.inc +/disasm/shape_index.inc +/disasm/shape_data_pixel.inc +/disasm/shape_index_pixel.inc +/disasm/shape_pixel.json /disasm/star_blazer.asm /disasm/star_blazer.asm0 /disasm/star_blazer.dsk diff --git a/disasm/Makefile b/disasm/Makefile index 4453351..a548ec8 100644 --- a/disasm/Makefile +++ b/disasm/Makefile @@ -50,14 +50,26 @@ star_blazer.asm \ ../shape/dhgr_pixel_shape_index.inc \ ../shape/dhgr_pixel_shape_data_main.inc \ ../shape/dhgr_pixel_shape_data_aux.inc \ -../shape/pixel_shape_index.inc \ -../shape/pixel_shape_data.inc \ -../shape/shape_index.inc \ -../shape/shape_data.inc \ +shape_index_pixel.inc \ +shape_data_pixel.inc \ +shape_index.inc \ +shape_data.inc \ ucode_defs.inc \ ucode_data.inc ${AS6500} -3 -l -o $< +shape_index_pixel.inc shape_data_pixel.inc: star_blazer.txt shape_pixel.json + ./shape_compile.py $^ shape_index_pixel.inc shape_data_pixel.inc + +shape_pixel.json: star_blazer.txt ../loader/star_blazer.ihx + ./shape_extract.py --pixel $^ $@ + +shape_index.inc shape_data.inc: star_blazer.txt shape.json + ./shape_compile.py $^ shape_index.inc shape_data.inc + +shape.json: star_blazer.txt ../loader/star_blazer.ihx + ./shape_extract.py $^ $@ + ucode_data.inc: star_blazer.asm sed -ne '/^ucode1080_countdown_30_pixel:/,/; 9dec/p' $< |\ ./ucode_disasm.py >$@ @@ -84,4 +96,10 @@ clean: *.rel \ *.rst \ star_blazer.asm \ -star_blazer.dsk +star_blazer.dsk \ +shape_index_pixel.inc \ +shape_data_pixel.inc \ +shape_pixel.json \ +shape_index.inc \ +shape_data.inc \ +shape.json diff --git a/disasm/shape_compile.py b/disasm/shape_compile.py new file mode 100755 index 0000000..44a0262 --- /dev/null +++ b/disasm/shape_compile.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +import json +import sys +from intelhex import IntelHex + +EXIT_SUCCESS = 0 +EXIT_FAILURE = 1 + +if len(sys.argv) < 5: + print(f'usage: {sys.argv[0]:s} addrs.txt in.json out_index.inc out_data.inc') + sys.exit(EXIT_FAILURE) +addrs_txt = sys.argv[1] +in_json = sys.argv[2] +out_index_inc = sys.argv[3] +out_data_inc = sys.argv[4] + +print('reading addrs') +shape_tables = {} +with open(addrs_txt, 'r') 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' and name[:6] == 'shape_': + shape_tables[name[6:]] = addr + fields = get_line() + continue + + # unknown section, skip + fields = get_line() + while len(fields) >= 2: + fields = get_line() + +print('reading json') +with open(in_json) as fin: + data = json.load(fin) + +print('writing index') + +with open(out_index_inc, 'w') as fout: + for table, addr in shape_tables.items(): + fout.write(f'shape_{table:s}:\n') + + prefix = '' + if table[-3:] == '_lo': + prefix = '<' + table = table[:-3] + elif table[-3:] == '_hi': + prefix = '>' + table = table[:-3] + + table_data = [data[i][table] for i in range(0x100)] + if table == 'data_ptr' or table == 'size_bytes': + for i in range(0x100): + name = data[i]['name'] + if name is not None: + size_bytes = int(data[i]['size_bytes'], 0) + if table == 'data_ptr': + table_data[i] = 'shape_' + name + if size_bytes: + width_bytes = int(data[i]['width_bytes'], 0) + height = int(data[i]['height'], 0) + assert size_bytes == width_bytes * height + if table == 'data_ptr': + table_data[i] += f' + 3 * {width_bytes:d} * {height:d}' + else: + table_data[i] = f'{width_bytes:d} * {height:d}' + fout.write(''.join([f'\t.db\t{prefix:s}{i:s}\n' for i in table_data])) + +print('writing data') + +# preserve ordering from the original executable, based on data_ptr +order = sorted( + [ + (int(data[i]['data_ptr'], 0), i) + for i in range(0x100) + if data[i]['name'] is not None + ] +) + +with open(out_data_inc, 'w') as fout: + for i in range(len(order)): + addr, index = order[i] + name = data[index]['name'] + fout.write(f'shape_{name:s}:\n') + + # check for reuse of same shape data in original executable + # if so, don't bother outputting the shape data, use next one + if i + 1 < len(order): + addr1, index1 = order[i + 1] + if addr1 == addr and data[index1]['data'] == data[index]['data']: + continue + + fout.write( + ''.join( + [ + ''.join(['\t.db\t{0:s}\n'.format(', '.join(j)) for j in i]) + '\n' + for i in data[index]['data'] + ] + ) + ) diff --git a/disasm/shape_extract.py b/disasm/shape_extract.py new file mode 100755 index 0000000..543cd12 --- /dev/null +++ b/disasm/shape_extract.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 + +import json +import sys +from intelhex import IntelHex + +EXIT_SUCCESS = 0 +EXIT_FAILURE = 1 + +pixel = False +if len(sys.argv) >= 2 and sys.argv[1] == '--pixel': + pixel = True + del sys.argv[1] +if len(sys.argv) < 4: + print(f'usage: {sys.argv[0]:s} [--pixel] 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') +shape_tables = {} +pixel_tables = {} +shapes = {} +with open(addrs_txt, 'r') 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': + if name[:6] == 'shape_': + shape_tables[name[6:]] = addr + elif name[:6] == 'pixel_': + pixel_tables[name[6:]] = addr + fields = get_line() + continue + + if section == 'shapes': + fields = get_line() + while len(fields) >= 2: + assert len(fields) == 2 + index = int(fields[0], 0) + name = fields[1] + # shape < 8 is a single pixel masked by the shape number + # ignore these lines in addrs file unless --pixel requested + if index >= 8 or pixel: + shapes[index] = name + fields = get_line() + continue + + # unknown section, skip + fields = get_line() + while len(fields) >= 2: + fields = get_line() + +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': None} for i in range(0x100)] + +i = 0 +shape_tables1 = list(shape_tables.items()) +while i < len(shape_tables1): + if ( + i + 2 <= len(shape_tables1) and + shape_tables1[i][0][-3:] == '_lo' and + shape_tables1[i + 1][0][-3:] == '_hi' + ): + table, addr_lo = shape_tables1[i] + _, addr_hi = shape_tables1[i + 1] + table = table[:-3] + for j in range(0x100): + value = intelhex[addr_lo + j] | (intelhex[addr_hi + j] << 8) + data[j][table] = f'0x{value:04x}' + i += 2 + else: + table, addr = shape_tables1[i] + for j in range(0x100): + value = intelhex[addr + j] + data[j][table] = str(value) + i += 1 + +# do this here so that item ordering is nicer in the json file +for i in range(0x100): + data[i]['data'] = None + +for index, name in shapes.items(): + data[index]['name'] = f'{index:02x}_{name:s}' + + # shape < 8 is a single pixel masked by the shape number + # transform the special data tables for pixel drawing into ordinary data + if index < 8: + data[index]['data_ptr'] = '0x0000' # make them be compiled first + data[index]['width_bytes'] = '2' + data[index]['height'] = '1' + data[index]['size_bytes'] = '2' + data[index]['width'] = '1' + + data_table_left = pixel_tables['data_table_left'] + data_table_right = pixel_tables['data_table_right'] + mask_table_left = pixel_tables['mask_table_left'] + mask_table_right = pixel_tables['mask_table_right'] + value = [ + [ + [ + f'0x{intelhex[data_table_left + ((i * 2) % 7)] & intelhex[mask_table_left + index]:02x}', + f'0x{intelhex[data_table_right + ((i * 2) % 7)] & intelhex[mask_table_right + index]:02x}' + ] + ] + for i in range(7) + ] + else: + addr = int(data[index]['data_ptr'], 0) + height = int(data[index]['height'], 0) + width_bytes = int(data[index]['width_bytes'], 0) + size_bytes = int(data[index]['size_bytes'], 0) + value = [ + [ + [ + f'0x{intelhex[addr + (i - 3) * size_bytes + j * width_bytes + k]:02x}' + for k in range(width_bytes) + ] + for j in range(height) + ] + for i in range(7 if size_bytes else 1) + ] + data[index]['data'] = value + +print('writing json') +with open(out_json, 'w') as fout: + json.dump(data, fout, indent = 2) diff --git a/disasm/star_blazer.asm.patch b/disasm/star_blazer.asm.patch index 6735757..b71aa50 100644 --- a/disasm/star_blazer.asm.patch +++ b/disasm/star_blazer.asm.patch @@ -1,10 +1,10 @@ ---- star_blazer.asm0 2022-06-25 13:01:14.395901396 +1000 -+++ star_blazer.asm 2022-06-25 13:03:26.391899763 +1000 +--- star_blazer.asm0 2022-06-25 14:50:24.743820370 +1000 ++++ star_blazer.asm 2022-06-25 15:16:37.251800919 +1000 @@ -1,3 +1,9 @@ +UNREACHABLE = 1 +DHGR = 0 +PIXEL_SHAPE = 0 -+SHAPE = 0 ++SHAPE = 1 +UCODE = 0 + HIRES_SCREEN = 0x2000 ; 2000 @@ -817,14 +817,14 @@ +.include "../shape/dhgr_pixel_shape_index.inc" +.else +.if PIXEL_SHAPE -+.include "../shape/pixel_shape_index.inc" ++.include "shape_index_pixel.inc" +.else +.if SHAPE -+.include "../shape/shape_index.inc" ++.include "shape_index.inc" +.else shape_data_ptr_lo: - .db <0x5d01 ; 4000 r - .db <0x5d01 ; 4001 r + .db