summaryrefslogtreecommitdiff
path: root/tools/script_disassembler/split_script_data.py
blob: 8d99df3b0c6f6625e49c0c9cdce021a050f41809 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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()