From a2381ce957e4c4d54fe39540a2c635f12bb8851b Mon Sep 17 00:00:00 2001 From: octorock <79596758+octorock@users.noreply.github.com> Date: Tue, 9 Mar 2021 09:21:17 +0100 Subject: [PATCH] Remove script_disassembler script --- .gitignore | 1 + tools/script_disassembler/.gitignore | 1 - tools/script_disassembler/definitions.py | 334 ------------------ .../script_disassembler.py | 219 ------------ .../script_disassembler/split_script_data.py | 117 ------ tools/script_disassembler/utils.py | 21 -- 6 files changed, 1 insertion(+), 692 deletions(-) delete mode 100644 tools/script_disassembler/.gitignore delete mode 100644 tools/script_disassembler/definitions.py delete mode 100644 tools/script_disassembler/script_disassembler.py delete mode 100644 tools/script_disassembler/split_script_data.py delete mode 100644 tools/script_disassembler/utils.py diff --git a/.gitignore b/.gitignore index a4960ad2..f7c4e9e2 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ types_*.taghl !calcrom.pl !sound/programmable_wave_samples/*.pcm _Deparsed_XSubs.pm +*.py *.sna __pycache__ .vscode/settings.json diff --git a/tools/script_disassembler/.gitignore b/tools/script_disassembler/.gitignore deleted file mode 100644 index 9289883f..00000000 --- a/tools/script_disassembler/.gitignore +++ /dev/null @@ -1 +0,0 @@ -labels.txt \ No newline at end of file diff --git a/tools/script_disassembler/definitions.py b/tools/script_disassembler/definitions.py deleted file mode 100644 index d71d5040..00000000 --- a/tools/script_disassembler/definitions.py +++ /dev/null @@ -1,334 +0,0 @@ -from utils import barray_to_u16_hex, barray_to_u32_hex, barray_to_s16 -import struct - -ROM_OFFSET = 0x08000000 -SCRIPTS_START = 0x08008B5C -SCRIPTS_END = 0x08016984 - -# A list of all the commands, their correspondingScriptCommand_ functions and what kind of parameters they take -commands = [ - {'fun': 'ScriptCommandNop', 'params': ''}, - {'fun': 'ScriptCommand_BeginBlock', 'params': ''}, - {'fun': 'ScriptCommand_EndBlock', 'params': ''}, - {'fun': 'ScriptCommand_Jump', 'params': 'j'}, - {'fun': 'ScriptCommand_JumpIf', 'params': 'j'}, - {'fun': 'ScriptCommand_JumpIfNot', 'params': 'j'}, - {'fun': 'ScriptCommand_JumpTable', 'params': ['jj', 'jjj', 'jjjj', 'jjjjjjj', 'jjjjjjjjj']}, - {'fun': 'ScriptCommand_JumpAbsolute', 'params': 'x'}, - {'fun': 'ScriptCommand_JumpAbsoluteIf', 'params': 'x'}, - {'fun': 'ScriptCommand_JumpAbsoluteIfNot', 'params': 'x'}, - {'fun': 'ScriptCommand_JumpAbsoluteTable', 'params': 'xx'}, - {'fun': 'ScriptCommand_Call', 'params': 'p'}, - {'fun': 'ScriptCommand_CallWithArg', 'params': ['px', 'p']}, - {'fun': 'ScriptCommand_LoadRoomEntityList', 'params': 'd'}, - {'fun': 'ScriptCommand_TestBit', 'params': 'w'}, - {'fun': 'ScriptCommand_CheckInventory1', 'params': 's'}, - {'fun': 'ScriptCommand_CheckInventory2', 'params': 's'}, - {'fun': 'ScriptCommand_HasRoomItemForSale', 'params': ''}, - {'fun': 'ScriptCommand_CheckLocalFlag', 'params': 's'}, - {'fun': 'ScriptCommand_CheckLocalFlagByOffset', 'params': 'ss'}, - {'fun': 'ScriptCommand_CheckGlobalFlag', 'params': 's'}, - {'fun': 'ScriptCommand_CheckRoomFlag', 'params': 's'}, - {'fun': 'ScriptCommand_CheckPlayerInRegion', 'params': 'sss'}, - {'fun': 'ScriptCommand_CheckPlayerInRegion2', 'params': 's'}, - {'fun': 'ScriptCommand_CheckEntityInteractType', 'params': ''}, - {'fun': 'ScriptCommand_0807E30C', 'params': ''}, - {'fun': 'ScriptCommand_HasRupees', 'params': 's'}, - {'fun': 'ScriptCommand_0807E3BC', 'params': 's'}, - {'fun': 'ScriptCommand_0807E3E8', 'params': ''}, - {'fun': 'ScriptCommand_CheckKinstoneFused', 'params': 's'}, - {'fun': 'ScriptCommand_BuyItem', 'params': 'ss'}, - {'fun': 'ScriptCommand_0807E48C', 'params': 's'}, - {'fun': 'ScriptCommand_0807E4CC', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E4EC', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E514', 'params': 'w'}, - {'fun': 'ScriptCommand_CheckPlayerFlags', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E564', 'params': ''}, - {'fun': 'ScriptCommand_EntityHasHeight', 'params': ''}, - {'fun': 'ScriptCommand_ComparePlayerAction', 'params': 's'}, - {'fun': 'ScriptCommand_ComparePlayerAnimationState', 'params': 's'}, - {'fun': 'ScriptCommand_0807E5F8', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E610', 'params': 'w'}, - {'fun': 'ScriptCommand_SetLocalFlag', 'params': 's'}, - {'fun': 'ScriptCommand_SetLocalFlagByOffset', 'params': 'ss'}, - {'fun': 'ScriptCommand_ClearLocalFlag', 'params': 's'}, - {'fun': 'ScriptCommand_SetGlobalFlag', 'params': 's'}, - {'fun': 'ScriptCommand_ClearGlobalFlag', 'params': 's'}, - {'fun': 'ScriptCommand_SetRoomFlag', 'params': 's'}, - {'fun': 'ScriptCommand_ClearRoomFlag', 'params': 's'}, - {'fun': 'ScriptCommand_Wait', 'params': 's'}, - {'fun': 'ScriptCommand_WaitForSomething', 'params': 'w'}, - {'fun': 'ScriptCommand_WaitForSomething2', 'params': 'w'}, - {'fun': 'ScriptCommand_WaitPlayerAction8', 'params': ''}, - {'fun': 'ScriptCommand_WaitForPlayerAction0x17', 'params': ''}, - {'fun': 'ScriptCommand_WaitFor_1', 'params': ''}, - {'fun': 'ScriptCommand_WaitFor_2', 'params': ''}, - {'fun': 'ScriptCommand_0807E778', 'params': 's'}, - {'fun': 'ScriptCommand_0807E788', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E79C', 'params': ''}, - {'fun': 'ScriptCommandNop2', 'params': 's'}, - {'fun': 'ScriptCommand_DoFade4', 'params': ''}, - {'fun': 'ScriptCommand_DoFade5', 'params': ''}, - {'fun': 'ScriptCommand_DoFade6', 'params': ''}, - {'fun': 'ScriptCommand_DoFade7', 'params': ''}, - {'fun': 'ScriptCommand_0807E800', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E80C', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E858', 'params': ['s', '']}, - {'fun': 'ScriptCommand_0807E864', 'params': ''}, - {'fun': 'ScriptCommand_0807E878', 'params': ''}, - {'fun': 'ScriptCommand_0807E888', 'params': ''}, - {'fun': 'ScriptCommand_SetPlayerAction', 'params': 'w'}, - {'fun': 'ScriptCommand_StartPlayerScript', 'params': 'x'}, - {'fun': 'ScriptCommand_0807E8D4', 'params': 's'}, - {'fun': 'ScriptCommand_0807E8E4_0', 'params': ''}, # duplicate - {'fun': 'ScriptCommand_0807E8E4_1', 'params': ''}, # duplicate - {'fun': 'ScriptCommand_0807E8E4_2', 'params': ''}, # duplicate - {'fun': 'ScriptCommand_0807E8E4_3', 'params': ''}, # duplicate - {'fun': 'ScriptCommand_0807E908', 'params': 's'}, - {'fun': 'ScriptCommand_SetIntVariable', 'params': 'w'}, - {'fun': 'ScriptCommand_0807E924', 'params': ''}, - {'fun': 'ScriptCommand_0807E930', 'params': 's'}, - {'fun': 'ScriptCommand_0807E944', 'params': ''}, - {'fun': 'ScriptCommand_0807E974', 'params': 's'}, - {'fun': 'ScriptCommand_0807E9D4', 'params': ''}, - {'fun': 'ScriptCommand_0807E9DC', 'params': ''}, - {'fun': 'ScriptCommand_0807E9E4', 'params': 's'}, - {'fun': 'ScriptCommand_0807E9F0', 'params': ''}, - {'fun': 'ScriptCommand_0807EA4C', 'params': ''}, - {'fun': 'ScriptCommand_0807EA88', 'params': 's'}, - {'fun': 'ScriptCommand_0807EA94', 'params': ''}, - {'fun': 'ScriptCommand_TextboxNoOverlapFollow', 'params': 's'}, - {'fun': 'ScriptCommand_TextboxNoOverlap', 'params': 's'}, - {'fun': 'ScriptCommand_TextboxNoOverlapFollowPos', 'params': ['ss', 's']}, - {'fun': 'ScriptCommand_TextboxNoOverlapFollowTable', 'params': ['ss', 'sss', 'ssss']}, - {'fun': 'ScriptCommand_TextboxNoOverlapVar', 'params': ''}, - {'fun': 'ScriptCommand_0807EB28', 'params': 's'}, - {'fun': 'ScriptCommand_0807EB38', 'params': ''}, - {'fun': 'ScriptCommand_0807EB44', 'params': 's'}, - {'fun': 'ScriptCommand_0807EB4C', 'params': 'ss'}, - {'fun': 'ScriptCommand_0807EB74', 'params': ''}, - {'fun': 'ScriptCommand_0807EB8C', 'params': ''}, - {'fun': 'ScriptCommand_SetEntityDirection', 'params': 's'}, - {'fun': 'ScriptCommand_SetEntityDirectionWithAnimationState', 'params': 's'}, - {'fun': 'ScriptCommand_SetEntityNonPlanarMovement', 'params': 's'}, - {'fun': 'ScriptCommand_SetEntity0x20', 'params': 'w'}, - {'fun': 'ScriptCommand_SetEntityPositionRelative', 'params': 'ss'}, - {'fun': 'ScriptCommand_SetEntityPosition', 'params': 'ss'}, - {'fun': 'ScriptCommand_MoveEntityToPlayer', 'params': ''}, - {'fun': 'ScriptCommandNop3', 'params': ''}, - {'fun': 'ScriptCommand_0807EC1C', 'params': 's'}, - {'fun': 'ScriptCommand_0807EC64', 'params': 's'}, - {'fun': 'ScriptCommand_0807EC94', 'params': 's'}, - {'fun': 'ScriptCommand_0807ECC4', 'params': 's'}, - {'fun': 'ScriptCommand_0807ECF4', 'params': 's'}, - {'fun': 'ScriptCommand_0807ED24', 'params': 'sss'}, - {'fun': 'ScriptCommand_0807EDD4', 'params': 'ss'}, - {'fun': 'ScriptCommand_0807EE04', 'params': 'ss'}, - {'fun': 'ScriptCommand_0807EE30', 'params': ''}, - {'fun': 'ScriptCommand_0807EEB4', 'params': ''}, - {'fun': 'ScriptCommand_0807EEF4', 'params': 'ss'}, - {'fun': 'ScriptCommand_0807EF3C', 'params': 'ss'}, - {'fun': 'ScriptCommandDoPostScriptAction', 'params': 's'}, - {'fun': 'ScriptCommandDoPostScriptAction2', 'params': 's'}, - {'fun': 'ScriptCommand_SoundReq', 'params': 's'}, - {'fun': 'ScriptCommand_SoundReq2', 'params': 's'}, - {'fun': 'ScriptCommand_SoundReq3', 'params': 'w'}, - {'fun': 'ScriptCommand_SoundReq0x80100000', 'params': ''}, - {'fun': 'ScriptCommand_ModRupees', 'params': 's'}, - {'fun': 'ScriptCommand_ModHealth', 'params': 's'}, - {'fun': 'ScriptCommand_IncreaseMaxHealth', 'params': 's'}, - {'fun': 'ScriptCommand_0807F034', 'params': 's'}, - {'fun': 'ScriptCommand_0807F050', 'params': 's'}, - {'fun': 'ScriptCommand_GetInventoryValue', 'params': 's'}, - {'fun': 'ScriptCommand_0807F078', 'params': 'ss'}, - {'fun': 'ScriptCommand_0807F088', 'params': 's'}, - {'fun': 'ScriptCommand_CameraTargetEntity', 'params': ''}, - {'fun': 'ScriptCommand_CameraTargetPlayer', 'params': ''}, - {'fun': 'ScriptCommand_0807F0B4', 'params': 's'}, - {'fun': 'ScriptCommand_0807F0C8', 'params': 'ss'} -] - -# Functions that have already been renamed -POINTER_MAP = { - 'sub_08095458': 'nullsub_527', - 'sub_0805EBCC': 'DeleteAllEnemies', - 'sub_0806C23C': 'Simon_CreateChest', - 'sub_0801637C': 'script_0801637C+1', - 'sub_08016383': 'script_08016384', - 'sub_0806C598': 'sub_0806C598', - 'sub_080A2138': 'Windcrest_Unlock', - 'sub_080A29BC': 'CreateDust' -} - - -def get_pointer(barray): - # tries to directly reference the function this is pointing to - integers = struct.unpack('I', barray) - pointer = 'sub_' + (struct.pack('>I', integers[0]-1).hex()).upper() - if pointer in POINTER_MAP: - return POINTER_MAP[pointer] - return pointer - - -# Data pointers that actually point to a script location -DATA_MAP = { - 'gUnk_08016384': 'script_08016384' -} - -def get_data_pointer(barray): - integers = struct.unpack('I', barray) - pointer = 'gUnk_' + (struct.pack('>I', integers[0]).hex()).upper() - if pointer in DATA_MAP: - return DATA_MAP[pointer] - return pointer - - -def get_script_pointer(barray): - integers = struct.unpack('I', barray) - val = integers[0] - if val >= SCRIPTS_START and val <= SCRIPTS_END: - return use_script_label(val) -# return 'script_' + (struct.pack('>I', val).hex()).upper() - else: - return '0x'+struct.pack('>I', val).hex() - - -def get_script_label(u32): - return hex(u32).upper().replace('0X', 'script_0') - -# Collects a set of all the labels that were jumped to -used_labels = set() -def use_script_label(u32): - global used_labels - used_labels.add(u32) - label = get_script_label(u32) - return label - - -# definitions for parameter types -parameters = { - '': { - 'length': 0, - 'param': '', - 'expr': '', - 'read': lambda ctx: '' - }, - 's': { - 'length': 1, - 'param': 's', - 'expr': ' .2byte \s', - 'read': lambda ctx: barray_to_u16_hex(ctx.data[ctx.ptr + 2:ctx.ptr + 4])[0] - }, - 'ss': { - 'length': 2, - 'param': 'a,b', - 'expr': ' .2byte \\a\n .2byte \\b', - 'read': lambda ctx: ', '.join(barray_to_u16_hex(ctx.data[ctx.ptr + 2:ctx.ptr + 6])) - }, - 'sss': { - 'length': 3, - 'param': 'a,b,c', - 'expr': ' .2byte \\a\n .2byte \\b\n .2byte \\c', - 'read': lambda ctx: ', '.join(barray_to_u16_hex(ctx.data[ctx.ptr + 2:ctx.ptr + 8])) - }, - 'ssss': { - 'length': 4, - 'param': 'a,b,c,d', - 'expr': ' .2byte \\a\n .2byte \\b\n .2byte \\c\n .2byte \\d', - 'read': lambda ctx: ', '.join(barray_to_u16_hex(ctx.data[ctx.ptr + 2:ctx.ptr + 10])) - }, - - 'w': { - 'length': 2, - 'param': 'w', - 'expr': ' .4byte \w', - 'read': lambda ctx: barray_to_u32_hex(ctx.data[ctx.ptr + 2:ctx.ptr + 6])[0] - }, - 'ww': { - 'length': 4, - 'param': 'a,b', - 'expr': ' .4byte \\a\n .4byte \\b', - 'read': lambda ctx: ', '.join(barray_to_u32_hex(ctx.data[ctx.ptr + 2:ctx.ptr + 10])) - }, - - 'j': { # Relative jump target - 'length': 1, - 'param': 's', - 'expr': '1: .2byte \s - 1b', - 'read': lambda ctx: use_script_label(ctx.script_addr + ctx.ptr + 2 + barray_to_s16(ctx.data[ctx.ptr + 2:ctx.ptr + 4])) - }, - 'jj': { - 'length': 2, - 'param': 'a,b', - 'expr': '1: .2byte \\a - 1b\n .2byte \\b - 1b - 2', - 'read': lambda ctx: ', '.join([use_script_label(ctx.script_addr + ctx.ptr + 2 + barray_to_s16(ctx.data[ctx.ptr + x * 2 + 2:ctx.ptr + x * 2 + 4]) + x * 2) for x in range(0, 2)]) - }, - 'jjj': { - 'length': 3, - 'param': 'a,b,c', - 'expr': '1: .2byte \\a - 1b\n .2byte \\b - 1b - 2\n .2byte \\c - 1b - 4', - 'read': lambda ctx: ', '.join([use_script_label(ctx.script_addr + ctx.ptr + 2 + barray_to_s16(ctx.data[ctx.ptr + x * 2 + 2:ctx.ptr + x * 2 + 4]) + x*2) for x in range(0, 3)]) - }, - 'jjjj': { - 'length': 4, - 'param': 'a,b,c,d', - 'expr': '1: .2byte \\a - 1b\n .2byte \\b - 1b - 2\n .2byte \\c - 1b - 4\n .2byte \\d - 1b - 6', - 'read': lambda ctx: ', '.join([use_script_label(ctx.script_addr + ctx.ptr + 2 + barray_to_s16(ctx.data[ctx.ptr + x * 2 + 2:ctx.ptr + x * 2 + 4]) + x*2) for x in range(0, 4)]) - }, - 'jjjjjjj': { - 'length': 7, - 'param': 'a,b,c,d,e,f,g', - 'expr': '1: .2byte \\a - 1b\n .2byte \\b - 1b - 2\n .2byte \\c - 1b - 4\n .2byte \\d - 1b - 6\n .2byte \\e - 1b - 8\n .2byte \\f - 1b - 10\n .2byte \\g - 1b - 12', - 'read': lambda ctx: ', '.join([use_script_label(ctx.script_addr + ctx.ptr + 2 + barray_to_s16(ctx.data[ctx.ptr + x * 2 + 2:ctx.ptr + x * 2 + 4]) + x*2) for x in range(0, 7)]) - }, - 'jjjjjjjjj': { - 'length': 9, - 'param': 'a,b,c,d,e,f,g,h,i', - 'expr': '1: .2byte \\a - 1b\n .2byte \\b - 1b - 2\n .2byte \\c - 1b - 4\n .2byte \\d - 1b - 6\n .2byte \\e - 1b - 8\n .2byte \\f - 1b - 10\n .2byte \\g - 1b - 12\n .2byte \\h - 1b - 14\n .2byte \\i - 1b - 16', - 'read': lambda ctx: ', '.join([use_script_label(ctx.script_addr + ctx.ptr + 2 + barray_to_s16(ctx.data[ctx.ptr + x * 2 + 2:ctx.ptr + x * 2 + 4]) + x*2) for x in range(0, 9)]) - }, - 'p': { - 'length': 2, - 'param': 'w', - 'expr': ' .4byte \w', - 'read': lambda ctx: get_pointer(ctx.data[ctx.ptr + 2:ctx.ptr + 6]) - }, - - 'px': { - 'length': 4, - 'param': 'a,b', - 'expr': ' .4byte \\a\n .4byte \\b', - 'read': lambda ctx: get_pointer(ctx.data[ctx.ptr + 2:ctx.ptr + 6]) + ', ' + get_script_pointer(ctx.data[ctx.ptr + 6:ctx.ptr + 10]) - }, - 'd': { # Data pointer - 'length': 2, - 'param': 'w', - 'expr': ' .4byte \w', - 'read': lambda ctx: get_data_pointer(ctx.data[ctx.ptr + 2:ctx.ptr + 6]) - }, - 'x': { # Script pointer - 'length': 2, - 'param': 'w', - 'expr': ' .4byte \w', - 'read': lambda ctx: get_script_pointer(ctx.data[ctx.ptr + 2:ctx.ptr + 6]) - }, - 'xx': { - 'length': 4, - 'param': 'a, b', - 'expr': ' .4byte \\a\n .4byte \\b', - 'read': lambda ctx: get_script_pointer(ctx.data[ctx.ptr + 2:ctx.ptr + 6]) + ', ' + get_script_pointer(ctx.data[ctx.ptr + 6:ctx.ptr + 10]) - }, - # Commands with variable parameter count are now handled by explicitely defining all used parameter configurations - # 'v': { - # 'length': -1, - # 'param': '', - # 'expr': '', - # 'read': lambda ctx: '' - # }, - # 'pv': { - # 'length': -2, - # 'param': 'w', - # 'expr': ' .4byte \w', - # 'read': lambda ctx: '' - # }, -} diff --git a/tools/script_disassembler/script_disassembler.py b/tools/script_disassembler/script_disassembler.py deleted file mode 100644 index 3b7094d8..00000000 --- a/tools/script_disassembler/script_disassembler.py +++ /dev/null @@ -1,219 +0,0 @@ -from dataclasses import dataclass -import struct -from utils import barray_to_u16_hex, u16_to_hex -from definitions import get_pointer, commands, parameters, get_script_label, used_labels - - -# Disassembler for tmc scripts -# Input 'macros' to generate the macros for the script commands -# Input the script bytes as hex to disassemble the script - -# Build macros: echo "macros" | python script_disassembler.py > ~/git/tmc/github/asm/macros/scripts.inc - -@dataclass -class Context: - ptr: int - data: bytes - script_addr: int - - -# Remove the ScriptCommand_ prefix for the asm macros -def build_script_command(name: str): - name = name.replace("ScriptCommand_", "") - if name[0].isdigit(): # asm macros cannot start with an _ - return f'_{name}' - return name - - -def print_rest_bytes(ctx): - print('\n'.join(['.byte ' + hex(x) for x in ctx.data[ctx.ptr:]])) - - -def disassemble_command(ctx: Context, add_all_annotations=False): - global used_labels - if (add_all_annotations or ctx.script_addr + ctx.ptr in used_labels) and ctx.ptr != 0: - # print offsets to debug when manually inserting labels - print(f'{get_script_label(ctx.script_addr + ctx.ptr)}:') - cmd = struct.unpack('H', ctx.data[ctx.ptr:ctx.ptr + 2])[0] - if cmd == 0: - # this does not need to be the end of the script - print('\t.2byte 0x0000') - ctx.ptr += 2 - return 1 - - if cmd == 0xffff: - ctx.ptr += 2 - print('SCRIPT_END') - cmd = struct.unpack('H', ctx.data[ctx.ptr:ctx.ptr + 2])[0] - if cmd == 0x0000: - # This is actually the end of the script - print('\t.2byte 0x0000') - ctx.ptr += 2 - return 2 - return 3 # There is a SCRIPT_END without 0x0000 afterwards, but still split into a new file, please - - commandSize = cmd >> 0xA - if commandSize == 0: - raise Exception(f'Zero commandSize not allowed') - commandId = cmd & 0x3FF - if commandId >= len(commands): - raise Exception(f'Invalid commandId {commandId} / {len(commands)} {cmd}') - command = commands[commandId] - param_length = commandSize - 1 - if commandSize > 1: - if ctx.ptr + 2 * commandSize > len(ctx.data): - raise Exception(f'Not enough data to fetch {commandSize-1} params') - - # Handle parameters - if not 'params' in command: - raise Exception(f'Parameters not defined for {command["fun"]}. Should be of length {str(param_length)}') - - params = None - suffix = '' - # When there are multiple variants of parameters, choose the one with the correct count for this - if isinstance(command['params'], list): - for i, param in enumerate(command['params']): - if not param in parameters: - raise Exception(f'Parameter configuration {param} not defined') - candidate = parameters[param] - if candidate['length'] == commandSize - 1: - params = candidate - if i != 0: - # We need to add a suffix to distinguish the correct parameter variant - suffix = f'_{params["length"]}' - break - if params is None: - raise Exception( - f'No suitable parameter configuration with length {commandSize-1} found for {command["fun"]}') - else: - if not command['params'] in parameters: - raise Exception(f'Parameter configuration {command["params"]} not defined') - params = parameters[command['params']] - - command_name = f'{command["fun"]}{suffix}' - - if params['length'] == -1: # variable parameter length - print(f'\t.2byte {u16_to_hex(cmd)} @ {build_script_command(command_name)} with {commandSize-1} parameters') - if commandSize > 1: - print('\n'.join(['\t.2byte ' + x for x in barray_to_u16_hex(ctx.data[ctx.ptr + 2:ctx.ptr + commandSize * 2])])) - print(f'@ End of parameters') - ctx.ptr += commandSize * 2 - return 1 - elif params['length'] == -2: # point and var - print(f'\t.2byte {u16_to_hex(cmd)} @ {build_script_command(command_name)} with {commandSize-3} parameters') - - print('\t.4byte ' + get_pointer(ctx.data[ctx.ptr + 2:ctx.ptr + 6])) - if commandSize > 3: - print('\n'.join(['\t.2byte ' + x for x in barray_to_u16_hex(ctx.data[ctx.ptr + 6:ctx.ptr + commandSize * 2])])) - print(f'@ End of parameters') - ctx.ptr += commandSize * 2 - return 1 - - if commandSize-1 != params['length']: - raise Exception(f'Call {command_name} with {commandSize-1} length, while length of {params["length"]} defined') - - print(f'\t{build_script_command(command_name)} {params["read"](ctx)}') - - # Execute script - ctx.ptr += commandSize * 2 - return 1 - - -def disassemble_script(input_bytes, script_addr, add_all_annotations=False): - ctx = Context(0, input_bytes, script_addr) - - foundEnd = False - while True: - # End of file (there need to be at least two bytes remaining for the next operation id) - if ctx.ptr >= len(ctx.data) - 1: - break - res = disassemble_command(ctx, add_all_annotations) - if res == 0: - break - elif res == 2: - foundEnd = True - break - elif res == 3: - # End in the middle of the script, please create a new file - return ctx.ptr - - # Print rest (did not manage to get there) - if ctx.ptr < len(ctx.data): - if (len(ctx.data) - ctx.ptr) % 2 != 0: - print_rest_bytes(ctx) - raise Exception(f'There is extra data at the end {ctx.ptr} / {len(ctx.data)}') - print('\n'.join(['.2byte ' + x for x in barray_to_u16_hex(ctx.data[ctx.ptr:])])) - raise Exception(f'There is extra data at the end {ctx.ptr} / {len(ctx.data)}') - - if not foundEnd: - # Sadly, there are script files without and end? - return 0 - #print('\033[93mNo end found\033[0m') - return 0 - - -def generate_macros(): - print('@ All the macro functions for scripts') - print('@ Generated by disassemble_script.py') - - print('.macro SCRIPT_START name') - print(' .globl \\name') - print(' .section .text') - print('\\name:') - print('.endm') - - print('.macro SCRIPT_END') - print(' .2byte 0xffff') - print('.endm') - - print('') - for num, command in enumerate(commands): - if not 'params' in command: - raise Exception(f'Parameters not defined for {command["fun"]}') - - def emit_macro(command_name, id, params): - print(f'.macro {command_name} {params["param"]}') - print(f' .2byte {u16_to_hex(id)}') - if params['expr'] != '': - print(params['expr']) - print('.endm') - print('') - - if isinstance(command['params'], list): - # emit macros for all variants - for i, variant in enumerate(command['params']): - if not variant in parameters: - raise Exception(f'Parameter configuration {variant} not defined') - params = parameters[variant] - id = ((params['length'] + 1) << 0xA) + num - suffix = '' - if i != 0: - suffix = f'_{params["length"]}' - emit_macro(f'{build_script_command(command["fun"])}{suffix}', id, params) - else: - if not command['params'] in parameters: - raise Exception(f'Parameter configuration {command["params"]} not defined') - params = parameters[command['params']] - id = ((params['length'] + 1) << 0xA) + num - - if params['length'] < 0: # Don't emit anything for variable parameters - continue - - emit_macro(build_script_command(command['fun']), id, params) - - print('') - - -def main(): - - # Read input - input_data = input() - - if input_data.strip() == 'macros': - generate_macros() - return - disassemble_script(bytearray.fromhex(input_data)) - - -if __name__ == '__main__': - main() diff --git a/tools/script_disassembler/split_script_data.py b/tools/script_disassembler/split_script_data.py deleted file mode 100644 index 8d99df3b..00000000 --- a/tools/script_disassembler/split_script_data.py +++ /dev/null @@ -1,117 +0,0 @@ -from definitions import ROM_OFFSET, SCRIPTS_END, SCRIPTS_START -from script_disassembler import disassemble_script, generate_macros -import sys - -# Reads a section from the baserom, splits the residing scripts into seperate files and disassembles them -# Should only be run before any manual changes to the script files are done! - -TMC_FOLDER = '../..' - - - -# Create labels for these additional script instructions -# Currently done by splitting the script at that point -LABEL_BREAKS = [0x0800A088, 0x0800ACE0, 0x0800AD54, 0x0800B41C, 0x0800B7C4, 0x0800C8C8, 0x0800D190, 0x800D3EC, 0x0800E9F4, 0x0800FD80, - 0x08012AC8, 0x08012F0C, 0x080130E4, 0x08013B70, 0x080142B0, 0x080147DC, 0x08014A80, 0x08014B10, 0x0801635C, 0x08016384, 0x080165D8] - -# Whether to output a label for every line -PRINT_ALL_LABELS = False - - -def read_baserom(): - # read baserom data - with open(f'{TMC_FOLDER}/baserom.gba', 'rb') as baserom: - return bytearray(baserom.read()) - - -def get_label(addr): - return hex(addr).upper().replace('0X', 'script_0') - - -def disassemble_scripts(baserom_data): - script_start = SCRIPTS_START-ROM_OFFSET - - scripts = ''' .include "asm/macros.inc" - .include "constants/constants.inc" - - .include "asm/macros/scripts.inc" - - .syntax unified - - .text - -''' - label_break = 0 - - while script_start < SCRIPTS_END-ROM_OFFSET: - if label_break < len(LABEL_BREAKS) and script_start + ROM_OFFSET >= LABEL_BREAKS[label_break]: - label_break += 1 - - label = get_label(script_start + ROM_OFFSET) - print(f"Disassembling \033[1;34m{label}\033[0m ({script_start} / { SCRIPTS_END-ROM_OFFSET} bytes converted)...") - # find end of the script signified by 0xffff0000 - script_end = baserom_data.index(b'\xff\xff\x00\x00', script_start) + 4 - - if script_end > SCRIPTS_END-ROM_OFFSET: - script_end = SCRIPTS_END-ROM_OFFSET - - # break at a predefined label into a new file - if label_break < len(LABEL_BREAKS) and script_end + ROM_OFFSET > LABEL_BREAKS[label_break]: - script_end = LABEL_BREAKS[label_break]-ROM_OFFSET - - # read data from rom - data = baserom_data[script_start:script_end] - - scripts += f' .include "data/scripts/{label}.inc"\n' - stdout = sys.stdout - - with open(f'{TMC_FOLDER}/data/scripts/{label}.inc', 'w') as out: - sys.stdout = out - - if script_start == 0x1637C: # This function is actually assembly - print('''thumb_func_start script_0801637C -script_0801637C: - push {lr} - bl CreateDust - pop {pc}''') - sys.stdout = stdout - script_start = script_end - continue - - print(f'SCRIPT_START {label}') - res = disassemble_script(data, script_start + ROM_OFFSET, PRINT_ALL_LABELS) - if res != 0: - # Script ended in the middle, need to create a new file - script_end = script_start + res - sys.stdout = stdout - - script_start = script_end - return scripts - - -def main(): - baserom_data = read_baserom() - - # Do two passes, in the first pass not all labels that are jumped to are known, so those labels are recorded in the first pass - # This is not necessary when all labels are printed - if not PRINT_ALL_LABELS: - print('Collecting labels...') - disassemble_scripts(baserom_data) - print('Writing scripts with labels...') - scripts = disassemble_scripts(baserom_data) - - print('Writing scripts.s file...') - with open(f'{TMC_FOLDER}/data/scripts.s', 'w') as out: - out.write(scripts) - print('Generating asm macros...') - stdout = sys.stdout - with open(f'{TMC_FOLDER}/asm/macros/scripts.inc', 'w') as out: - sys.stdout = out - generate_macros() - sys.stdout = stdout - - print('\033[1;92mDone\033[0m\n') - - -if __name__ == '__main__': - main() diff --git a/tools/script_disassembler/utils.py b/tools/script_disassembler/utils.py deleted file mode 100644 index b0501e5a..00000000 --- a/tools/script_disassembler/utils.py +++ /dev/null @@ -1,21 +0,0 @@ -import struct - -def barray_to_s16(barray): - integers = struct.unpack('h', barray) - return integers[0] - -def u16_to_hex(value): - return '0x' + (struct.pack('>H', value).hex()) - -def barray_to_u16_hex(barray): - count = len(barray)//2 - integers = struct.unpack('H'*count, barray) - return [u16_to_hex(x) for x in integers] - -def u32_to_hex(value): - return '0x' + (struct.pack('>I', value).hex()) - -def barray_to_u32_hex(barray): - count = len(barray)//4 - integers = struct.unpack('I'*count, barray) - return [u32_to_hex(x) for x in integers] \ No newline at end of file