splat64 0.34.3__py3-none-any.whl → 0.35.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- splat/__init__.py +1 -1
- splat/disassembler/spimdisasm_disassembler.py +7 -1
- splat/scripts/create_config.py +99 -19
- splat/scripts/split.py +55 -2
- splat/segtypes/common/group.py +23 -0
- splat/segtypes/common/textbin.py +8 -0
- splat/segtypes/linker_entry.py +1 -1
- splat/segtypes/segment.py +9 -0
- splat/util/__init__.py +1 -0
- splat/util/compiler.py +11 -6
- splat/util/file_presets.py +711 -0
- splat/util/n64/rominfo.py +83 -30
- splat/util/options.py +17 -0
- splat/util/relocs.py +1 -3
- {splat64-0.34.3.dist-info → splat64-0.35.1.dist-info}/METADATA +2 -2
- {splat64-0.34.3.dist-info → splat64-0.35.1.dist-info}/RECORD +19 -18
- {splat64-0.34.3.dist-info → splat64-0.35.1.dist-info}/WHEEL +0 -0
- {splat64-0.34.3.dist-info → splat64-0.35.1.dist-info}/entry_points.txt +0 -0
- {splat64-0.34.3.dist-info → splat64-0.35.1.dist-info}/licenses/LICENSE +0 -0
splat/__init__.py
CHANGED
|
@@ -7,7 +7,7 @@ from typing import Set
|
|
|
7
7
|
|
|
8
8
|
class SpimdisasmDisassembler(disassembler.Disassembler):
|
|
9
9
|
# This value should be kept in sync with the version listed on requirements.txt and pyproject.toml
|
|
10
|
-
SPIMDISASM_MIN = (1,
|
|
10
|
+
SPIMDISASM_MIN = (1, 36, 0)
|
|
11
11
|
|
|
12
12
|
def configure(self):
|
|
13
13
|
# Configure spimdisasm
|
|
@@ -93,9 +93,15 @@ class SpimdisasmDisassembler(disassembler.Disassembler):
|
|
|
93
93
|
)
|
|
94
94
|
spimdisasm.common.GlobalConfig.ASM_DATA_LABEL = options.opts.asm_data_macro
|
|
95
95
|
spimdisasm.common.GlobalConfig.ASM_TEXT_END_LABEL = options.opts.asm_end_label
|
|
96
|
+
spimdisasm.common.GlobalConfig.ASM_DATA_END_LABEL = (
|
|
97
|
+
options.opts.asm_data_end_label
|
|
98
|
+
)
|
|
96
99
|
spimdisasm.common.GlobalConfig.ASM_EHTBL_LABEL = (
|
|
97
100
|
options.opts.asm_ehtable_label_macro
|
|
98
101
|
)
|
|
102
|
+
spimdisasm.common.GlobalConfig.ASM_NM_LABEL = (
|
|
103
|
+
options.opts.asm_nonmatching_label_macro
|
|
104
|
+
)
|
|
99
105
|
|
|
100
106
|
if options.opts.asm_emit_size_directive is not None:
|
|
101
107
|
spimdisasm.common.GlobalConfig.ASM_EMIT_SIZE_DIRECTIVE = (
|
splat/scripts/create_config.py
CHANGED
|
@@ -6,7 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
|
|
7
7
|
from ..util.n64 import find_code_length, rominfo
|
|
8
8
|
from ..util.psx import psxexeinfo
|
|
9
|
-
from ..util import log
|
|
9
|
+
from ..util import log, file_presets, conf
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def main(file_path: Path):
|
|
@@ -70,10 +70,6 @@ options:
|
|
|
70
70
|
use_legacy_include_asm: False
|
|
71
71
|
mips_abi_float_regs: o32
|
|
72
72
|
|
|
73
|
-
asm_function_macro: glabel
|
|
74
|
-
asm_jtbl_label_macro: jlabel
|
|
75
|
-
asm_data_macro: dlabel
|
|
76
|
-
|
|
77
73
|
# section_order: [".text", ".data", ".rodata", ".bss"]
|
|
78
74
|
# auto_link_sections: [".data", ".rodata", ".bss"]
|
|
79
75
|
|
|
@@ -111,7 +107,7 @@ segments:
|
|
|
111
107
|
type: header
|
|
112
108
|
start: 0x0
|
|
113
109
|
|
|
114
|
-
- name:
|
|
110
|
+
- name: ipl3
|
|
115
111
|
type: bin
|
|
116
112
|
start: 0x40
|
|
117
113
|
|
|
@@ -122,7 +118,7 @@ segments:
|
|
|
122
118
|
subsegments:
|
|
123
119
|
- [0x1000, hasm]
|
|
124
120
|
"""
|
|
125
|
-
if rom.entrypoint_info.data_size
|
|
121
|
+
if rom.entrypoint_info.data_size is not None:
|
|
126
122
|
segments += f"""\
|
|
127
123
|
- [0x{0x1000 + rom.entrypoint_info.entry_size:X}, data]
|
|
128
124
|
"""
|
|
@@ -139,7 +135,7 @@ segments:
|
|
|
139
135
|
|
|
140
136
|
if rom.entrypoint_info.bss_size is not None:
|
|
141
137
|
segments += f"""\
|
|
142
|
-
bss_size: 0x{rom.entrypoint_info.bss_size:X}
|
|
138
|
+
bss_size: 0x{rom.entrypoint_info.bss_size.value:X}
|
|
143
139
|
"""
|
|
144
140
|
|
|
145
141
|
segments += f"""\
|
|
@@ -152,11 +148,13 @@ segments:
|
|
|
152
148
|
and rom.entrypoint_info.bss_start_address is not None
|
|
153
149
|
and first_section_end > main_rom_start
|
|
154
150
|
):
|
|
155
|
-
bss_start =
|
|
151
|
+
bss_start = (
|
|
152
|
+
rom.entrypoint_info.bss_start_address.value - rom.entry_point + 0x1000
|
|
153
|
+
)
|
|
156
154
|
# first_section_end points to the start of data
|
|
157
155
|
segments += f"""\
|
|
158
156
|
- [0x{first_section_end:X}, data]
|
|
159
|
-
- {{ type: bss, vram: 0x{rom.entrypoint_info.bss_start_address:08X} }}
|
|
157
|
+
- {{ type: bss, vram: 0x{rom.entrypoint_info.bss_start_address.value:08X} }}
|
|
160
158
|
"""
|
|
161
159
|
# Point next segment to the detected end of the main one
|
|
162
160
|
first_section_end = bss_start
|
|
@@ -174,12 +172,93 @@ segments:
|
|
|
174
172
|
- [0x{rom.size:X}]
|
|
175
173
|
"""
|
|
176
174
|
|
|
177
|
-
out_file = f"{cleaned_basename}.yaml"
|
|
178
|
-
with open(
|
|
175
|
+
out_file = Path(f"{cleaned_basename}.yaml")
|
|
176
|
+
with out_file.open("w", newline="\n") as f:
|
|
179
177
|
print(f"Writing config to {out_file}")
|
|
180
178
|
f.write(header)
|
|
181
179
|
f.write(segments)
|
|
182
180
|
|
|
181
|
+
# `file_presets` requires an initialized `opts`.
|
|
182
|
+
# A simple way to do that is to simply load the yaml we just generated.
|
|
183
|
+
conf.load([out_file])
|
|
184
|
+
file_presets.write_all_files()
|
|
185
|
+
|
|
186
|
+
# Write reloc_addrs.txt file
|
|
187
|
+
reloc_addrs = []
|
|
188
|
+
if rom.entrypoint_info.bss_start_address is not None:
|
|
189
|
+
reloc_addrs.append(
|
|
190
|
+
f"rom:0x{rom.entrypoint_info.bss_start_address.rom_hi:06X} reloc:MIPS_HI16 symbol:main_BSS_START"
|
|
191
|
+
)
|
|
192
|
+
reloc_addrs.append(
|
|
193
|
+
f"rom:0x{rom.entrypoint_info.bss_start_address.rom_lo:06X} reloc:MIPS_LO16 symbol:main_BSS_START"
|
|
194
|
+
)
|
|
195
|
+
reloc_addrs.append("")
|
|
196
|
+
if rom.entrypoint_info.bss_size is not None:
|
|
197
|
+
reloc_addrs.append(
|
|
198
|
+
f"rom:0x{rom.entrypoint_info.bss_size.rom_hi:06X} reloc:MIPS_HI16 symbol:main_BSS_SIZE"
|
|
199
|
+
)
|
|
200
|
+
reloc_addrs.append(
|
|
201
|
+
f"rom:0x{rom.entrypoint_info.bss_size.rom_lo:06X} reloc:MIPS_LO16 symbol:main_BSS_SIZE"
|
|
202
|
+
)
|
|
203
|
+
reloc_addrs.append("")
|
|
204
|
+
if rom.entrypoint_info.bss_end_address is not None:
|
|
205
|
+
reloc_addrs.append(
|
|
206
|
+
f"rom:0x{rom.entrypoint_info.bss_end_address.rom_hi:06X} reloc:MIPS_HI16 symbol:main_BSS_END"
|
|
207
|
+
)
|
|
208
|
+
reloc_addrs.append(
|
|
209
|
+
f"rom:0x{rom.entrypoint_info.bss_end_address.rom_lo:06X} reloc:MIPS_LO16 symbol:main_BSS_END"
|
|
210
|
+
)
|
|
211
|
+
reloc_addrs.append("")
|
|
212
|
+
if rom.entrypoint_info.stack_top is not None:
|
|
213
|
+
reloc_addrs.append(
|
|
214
|
+
'// This entry corresponds to the "stack top", which is the end of the array used as the stack for the main segment.'
|
|
215
|
+
)
|
|
216
|
+
reloc_addrs.append(
|
|
217
|
+
"// It is commented out because it was not possible to infer what the start of the stack symbol is, so you'll have to figure it out by yourself."
|
|
218
|
+
)
|
|
219
|
+
reloc_addrs.append(
|
|
220
|
+
"// Once you have found it you can properly name it and specify the length of this stack as the addend value here."
|
|
221
|
+
)
|
|
222
|
+
reloc_addrs.append(
|
|
223
|
+
f"// The address of the end of the stack is 0x{rom.entrypoint_info.stack_top.value:08X}."
|
|
224
|
+
)
|
|
225
|
+
reloc_addrs.append(
|
|
226
|
+
f"// A common size for this stack is 0x2000, so try checking for the address 0x{rom.entrypoint_info.stack_top.value-0x2000:08X}. Note the stack may have a different size."
|
|
227
|
+
)
|
|
228
|
+
reloc_addrs.append(
|
|
229
|
+
f"// rom:0x{rom.entrypoint_info.stack_top.rom_hi:06X} reloc:MIPS_HI16 symbol:main_stack addend:0xXXXX"
|
|
230
|
+
)
|
|
231
|
+
reloc_addrs.append(
|
|
232
|
+
f"// rom:0x{rom.entrypoint_info.stack_top.rom_lo:06X} reloc:MIPS_LO16 symbol:main_stack addend:0xXXXX"
|
|
233
|
+
)
|
|
234
|
+
reloc_addrs.append("")
|
|
235
|
+
if reloc_addrs:
|
|
236
|
+
with Path("reloc_addrs.txt").open("w", newline="\n") as f:
|
|
237
|
+
print("Writing reloc_addrs.txt")
|
|
238
|
+
f.write(
|
|
239
|
+
"// Visit https://github.com/ethteck/splat/wiki/Advanced-Reloc for documentation about this file\n"
|
|
240
|
+
)
|
|
241
|
+
f.write("// entrypoint relocs\n")
|
|
242
|
+
contents = "\n".join(reloc_addrs)
|
|
243
|
+
f.write(contents)
|
|
244
|
+
|
|
245
|
+
# Write symbol_addrs.txt file
|
|
246
|
+
symbol_addrs = []
|
|
247
|
+
symbol_addrs.append(f"entrypoint = 0x{rom.entry_point:08X}; // type:func")
|
|
248
|
+
if rom.entrypoint_info.main_address is not None:
|
|
249
|
+
symbol_addrs.append(
|
|
250
|
+
f"main = 0x{rom.entrypoint_info.main_address.value:08X}; // type:func"
|
|
251
|
+
)
|
|
252
|
+
if symbol_addrs:
|
|
253
|
+
symbol_addrs.append("")
|
|
254
|
+
with Path("symbol_addrs.txt").open("w", newline="\n") as f:
|
|
255
|
+
print("Writing symbol_addrs.txt")
|
|
256
|
+
f.write(
|
|
257
|
+
"// Visit https://github.com/ethteck/splat/wiki/Adding-Symbols for documentation about this file\n"
|
|
258
|
+
)
|
|
259
|
+
contents = "\n".join(symbol_addrs)
|
|
260
|
+
f.write(contents)
|
|
261
|
+
|
|
183
262
|
|
|
184
263
|
def create_psx_config(exe_path: Path, exe_bytes: bytes):
|
|
185
264
|
exe = psxexeinfo.PsxExe.get_info(exe_path, exe_bytes)
|
|
@@ -211,10 +290,6 @@ options:
|
|
|
211
290
|
o_as_suffix: True
|
|
212
291
|
use_legacy_include_asm: False
|
|
213
292
|
|
|
214
|
-
asm_function_macro: glabel
|
|
215
|
-
asm_jtbl_label_macro: jlabel
|
|
216
|
-
asm_data_macro: dlabel
|
|
217
|
-
|
|
218
293
|
section_order: [".rodata", ".text", ".data", ".bss"]
|
|
219
294
|
# auto_link_sections: [".data", ".rodata", ".bss"]
|
|
220
295
|
|
|
@@ -251,7 +326,7 @@ segments:
|
|
|
251
326
|
"""
|
|
252
327
|
text_offset = exe.text_offset
|
|
253
328
|
if text_offset != 0x800:
|
|
254
|
-
segments +=
|
|
329
|
+
segments += """\
|
|
255
330
|
- [0x800, rodata, 800]
|
|
256
331
|
"""
|
|
257
332
|
segments += f"""\
|
|
@@ -268,12 +343,17 @@ segments:
|
|
|
268
343
|
- [0x{exe.size:X}]
|
|
269
344
|
"""
|
|
270
345
|
|
|
271
|
-
out_file = f"{cleaned_basename}.yaml"
|
|
272
|
-
with open(
|
|
346
|
+
out_file = Path(f"{cleaned_basename}.yaml")
|
|
347
|
+
with out_file.open("w", newline="\n") as f:
|
|
273
348
|
print(f"Writing config to {out_file}")
|
|
274
349
|
f.write(header)
|
|
275
350
|
f.write(segments)
|
|
276
351
|
|
|
352
|
+
# `file_presets` requires an initialized `opts`.
|
|
353
|
+
# A simple way to do that is to simply load the yaml we just generated.
|
|
354
|
+
conf.load([out_file])
|
|
355
|
+
file_presets.write_all_files()
|
|
356
|
+
|
|
277
357
|
|
|
278
358
|
def add_arguments_to_parser(parser: argparse.ArgumentParser):
|
|
279
359
|
parser.add_argument(
|
splat/scripts/split.py
CHANGED
|
@@ -8,9 +8,9 @@ from pathlib import Path
|
|
|
8
8
|
|
|
9
9
|
from .. import __package_name__, __version__
|
|
10
10
|
from ..disassembler import disassembler_instance
|
|
11
|
-
from ..util import cache_handler, progress_bar, vram_classes, statistics
|
|
11
|
+
from ..util import cache_handler, progress_bar, vram_classes, statistics, file_presets
|
|
12
12
|
|
|
13
|
-
from colorama import
|
|
13
|
+
from colorama import Style
|
|
14
14
|
from intervaltree import Interval, IntervalTree
|
|
15
15
|
import sys
|
|
16
16
|
|
|
@@ -19,6 +19,7 @@ from ..segtypes.linker_entry import (
|
|
|
19
19
|
get_segment_vram_end_symbol_name,
|
|
20
20
|
)
|
|
21
21
|
from ..segtypes.segment import Segment
|
|
22
|
+
from ..segtypes.common.group import CommonSegGroup
|
|
22
23
|
from ..util import conf, log, options, palettes, symbols, relocs
|
|
23
24
|
|
|
24
25
|
linker_writer: LinkerWriter
|
|
@@ -38,6 +39,9 @@ def initialize_segments(config_segments: Union[dict, list]) -> List[Segment]:
|
|
|
38
39
|
segments_by_name: Dict[str, Segment] = {}
|
|
39
40
|
ret: List[Segment] = []
|
|
40
41
|
|
|
42
|
+
# Cross segment pairing can be quite expensive, so we try to avoid it if the user haven't requested it.
|
|
43
|
+
do_cross_segment_pairing = False
|
|
44
|
+
|
|
41
45
|
last_rom_end = 0
|
|
42
46
|
|
|
43
47
|
for i, seg_yaml in enumerate(config_segments):
|
|
@@ -80,6 +84,9 @@ def initialize_segments(config_segments: Union[dict, list]) -> List[Segment]:
|
|
|
80
84
|
|
|
81
85
|
segments_by_name[segment.name] = segment
|
|
82
86
|
|
|
87
|
+
if segment.pair_segment_name is not None:
|
|
88
|
+
do_cross_segment_pairing = True
|
|
89
|
+
|
|
83
90
|
ret.append(segment)
|
|
84
91
|
if (
|
|
85
92
|
isinstance(segment.rom_start, int)
|
|
@@ -112,6 +119,50 @@ def initialize_segments(config_segments: Union[dict, list]) -> List[Segment]:
|
|
|
112
119
|
"Last segment in config cannot be a pad segment; see https://github.com/ethteck/splat/wiki/Segments#pad"
|
|
113
120
|
)
|
|
114
121
|
|
|
122
|
+
if do_cross_segment_pairing:
|
|
123
|
+
# Do the cross segment pairing
|
|
124
|
+
for seg in ret:
|
|
125
|
+
if seg.pair_segment_name is not None:
|
|
126
|
+
found = False
|
|
127
|
+
for other_seg in ret:
|
|
128
|
+
if seg == other_seg:
|
|
129
|
+
continue
|
|
130
|
+
if seg.pair_segment_name == other_seg.name and isinstance(
|
|
131
|
+
other_seg, CommonSegGroup
|
|
132
|
+
):
|
|
133
|
+
# We found the other segment specified by `pair_segment`
|
|
134
|
+
|
|
135
|
+
if other_seg.pair_segment_name is not None:
|
|
136
|
+
log.error(
|
|
137
|
+
f"Both segments '{seg.name}' and '{other_seg.name}' have a `pair_segment` value, when only at most one of the cross-paired segments can have this attribute."
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Not user error, hopefully...
|
|
141
|
+
assert (
|
|
142
|
+
seg.paired_segment is None
|
|
143
|
+
), f"Somehow '{seg.name}' was already paired so something else? It is paired to '{seg.paired_segment.name}' instead of {other_seg.name}"
|
|
144
|
+
assert (
|
|
145
|
+
other_seg.paired_segment is None
|
|
146
|
+
), f"Somehow '{other_seg.name}' was already paired so something else? It is paired to '{other_seg.paired_segment.name}' instead of {seg.name}"
|
|
147
|
+
|
|
148
|
+
found = True
|
|
149
|
+
# Pair them
|
|
150
|
+
seg.paired_segment = other_seg
|
|
151
|
+
other_seg.paired_segment = seg
|
|
152
|
+
|
|
153
|
+
if isinstance(seg, CommonSegGroup) and isinstance(
|
|
154
|
+
other_seg, CommonSegGroup
|
|
155
|
+
):
|
|
156
|
+
# Pair the subsegments
|
|
157
|
+
seg.pair_subsegments_to_other_segment(other_seg)
|
|
158
|
+
|
|
159
|
+
break
|
|
160
|
+
|
|
161
|
+
if not found:
|
|
162
|
+
log.error(
|
|
163
|
+
f"Segment '{seg.pair_segment_name}' not found.\n It is referenced by segment '{seg.name}', because of the `pair_segment` attribute."
|
|
164
|
+
)
|
|
165
|
+
|
|
115
166
|
return ret
|
|
116
167
|
|
|
117
168
|
|
|
@@ -520,6 +571,8 @@ def main(
|
|
|
520
571
|
if options.opts.is_mode_active("code"):
|
|
521
572
|
dump_symbols()
|
|
522
573
|
|
|
574
|
+
file_presets.write_all_files()
|
|
575
|
+
|
|
523
576
|
|
|
524
577
|
def add_arguments_to_parser(parser: argparse.ArgumentParser):
|
|
525
578
|
parser.add_argument(
|
splat/segtypes/common/group.py
CHANGED
|
@@ -168,6 +168,10 @@ class CommonSegGroup(CommonSegment):
|
|
|
168
168
|
for sub in self.subsegments:
|
|
169
169
|
if sub.contains_vram(addr):
|
|
170
170
|
return sub
|
|
171
|
+
if isinstance(self.paired_segment, CommonSegGroup):
|
|
172
|
+
for sub in self.paired_segment.subsegments:
|
|
173
|
+
if sub.contains_vram(addr):
|
|
174
|
+
return sub
|
|
171
175
|
return None
|
|
172
176
|
|
|
173
177
|
def get_next_subsegment_for_ram(
|
|
@@ -187,3 +191,22 @@ class CommonSegGroup(CommonSegment):
|
|
|
187
191
|
if sub.vram_start > addr:
|
|
188
192
|
return sub
|
|
189
193
|
return None
|
|
194
|
+
|
|
195
|
+
def pair_subsegments_to_other_segment(
|
|
196
|
+
self,
|
|
197
|
+
other_segment: "CommonSegGroup",
|
|
198
|
+
):
|
|
199
|
+
# Pair cousins with the same name
|
|
200
|
+
for segment in self.subsegments:
|
|
201
|
+
for sibling in other_segment.subsegments:
|
|
202
|
+
if segment.name == sibling.name:
|
|
203
|
+
# Make them reference each other
|
|
204
|
+
segment.siblings[sibling.get_linker_section_linksection()] = sibling
|
|
205
|
+
sibling.siblings[segment.get_linker_section_linksection()] = segment
|
|
206
|
+
|
|
207
|
+
if segment.is_text():
|
|
208
|
+
sibling.sibling = segment
|
|
209
|
+
elif sibling.is_text():
|
|
210
|
+
segment.sibling = sibling
|
|
211
|
+
|
|
212
|
+
break
|
splat/segtypes/common/textbin.py
CHANGED
|
@@ -97,6 +97,8 @@ class CommonSegTextbin(CommonSegment):
|
|
|
97
97
|
|
|
98
98
|
if self.is_text() and options.opts.asm_end_label != "":
|
|
99
99
|
f.write(f"{options.opts.asm_end_label} {sym.name}\n")
|
|
100
|
+
elif self.is_data() and options.opts.asm_data_end_label != "":
|
|
101
|
+
f.write(f"{options.opts.asm_data_end_label} {sym.name}\n")
|
|
100
102
|
|
|
101
103
|
if sym.given_name_end is not None:
|
|
102
104
|
if (
|
|
@@ -106,6 +108,12 @@ class CommonSegTextbin(CommonSegment):
|
|
|
106
108
|
f.write(f"{asm_label} {sym.given_name_end}\n")
|
|
107
109
|
if asm_label == ".globl":
|
|
108
110
|
f.write(f"{sym.given_name_end}:\n")
|
|
111
|
+
if self.is_text() and options.opts.asm_end_label != "":
|
|
112
|
+
f.write(f"{options.opts.asm_end_label} {sym.given_name_end}\n")
|
|
113
|
+
elif self.is_data() and options.opts.asm_data_end_label != "":
|
|
114
|
+
f.write(
|
|
115
|
+
f"{options.opts.asm_data_end_label} {sym.given_name_end}\n"
|
|
116
|
+
)
|
|
109
117
|
|
|
110
118
|
def split(self, rom_bytes):
|
|
111
119
|
if self.rom_end is None:
|
splat/segtypes/linker_entry.py
CHANGED
|
@@ -522,7 +522,7 @@ class LinkerWriter:
|
|
|
522
522
|
)
|
|
523
523
|
|
|
524
524
|
def save_dependencies_file(self, output_path: Path, target_elf_path: Path):
|
|
525
|
-
output = f"{target_elf_path.as_posix()}:"
|
|
525
|
+
output = f"{clean_up_path(target_elf_path).as_posix()}:"
|
|
526
526
|
|
|
527
527
|
for entry in self.dependencies_entries:
|
|
528
528
|
if entry.object_path is None:
|
splat/segtypes/segment.py
CHANGED
|
@@ -274,6 +274,12 @@ class Segment:
|
|
|
274
274
|
return suggestion_rodata_section_start
|
|
275
275
|
return None
|
|
276
276
|
|
|
277
|
+
@staticmethod
|
|
278
|
+
def parse_pair_segment(yaml: Union[dict, list]) -> Optional[str]:
|
|
279
|
+
if isinstance(yaml, dict) and "pair_segment" in yaml:
|
|
280
|
+
return yaml["pair_segment"]
|
|
281
|
+
return None
|
|
282
|
+
|
|
277
283
|
def __init__(
|
|
278
284
|
self,
|
|
279
285
|
rom_start: Optional[int],
|
|
@@ -319,6 +325,9 @@ class Segment:
|
|
|
319
325
|
self.parent: Optional[Segment] = None
|
|
320
326
|
self.sibling: Optional[Segment] = None
|
|
321
327
|
self.siblings: Dict[str, Segment] = {}
|
|
328
|
+
self.pair_segment_name: Optional[str] = self.parse_pair_segment(yaml)
|
|
329
|
+
self.paired_segment: Optional[Segment] = None
|
|
330
|
+
|
|
322
331
|
self.file_path: Optional[Path] = None
|
|
323
332
|
|
|
324
333
|
self.args: List[str] = args
|
splat/util/__init__.py
CHANGED
splat/util/compiler.py
CHANGED
|
@@ -6,15 +6,18 @@ from typing import Optional, Dict
|
|
|
6
6
|
class Compiler:
|
|
7
7
|
name: str
|
|
8
8
|
asm_function_macro: str = "glabel"
|
|
9
|
-
asm_function_alt_macro: str = "
|
|
10
|
-
asm_jtbl_label_macro: str = "
|
|
11
|
-
asm_data_macro: str = "
|
|
12
|
-
asm_end_label: str = ""
|
|
9
|
+
asm_function_alt_macro: str = "alabel"
|
|
10
|
+
asm_jtbl_label_macro: str = "jlabel"
|
|
11
|
+
asm_data_macro: str = "dlabel"
|
|
12
|
+
asm_end_label: str = "endlabel"
|
|
13
|
+
asm_data_end_label: str = "enddlabel"
|
|
13
14
|
asm_ehtable_label_macro: str = "ehlabel"
|
|
15
|
+
asm_nonmatching_label_macro: str = "nonmatching"
|
|
14
16
|
c_newline: str = "\n"
|
|
15
17
|
asm_inc_header: str = ""
|
|
16
18
|
asm_emit_size_directive: Optional[bool] = None
|
|
17
19
|
j_as_branch: bool = False
|
|
20
|
+
uses_include_asm: bool = True
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
GCC = Compiler(
|
|
@@ -30,12 +33,14 @@ SN64 = Compiler(
|
|
|
30
33
|
asm_jtbl_label_macro=".globl",
|
|
31
34
|
asm_data_macro=".globl",
|
|
32
35
|
asm_end_label=".end",
|
|
36
|
+
asm_data_end_label="",
|
|
37
|
+
asm_nonmatching_label_macro="",
|
|
33
38
|
c_newline="\r\n",
|
|
34
39
|
asm_emit_size_directive=False,
|
|
35
40
|
j_as_branch=True,
|
|
36
41
|
)
|
|
37
42
|
|
|
38
|
-
IDO = Compiler("IDO", asm_emit_size_directive=False)
|
|
43
|
+
IDO = Compiler("IDO", asm_emit_size_directive=False, uses_include_asm=False)
|
|
39
44
|
|
|
40
45
|
KMC = Compiler(
|
|
41
46
|
"KMC",
|
|
@@ -55,7 +60,7 @@ PSYQ = Compiler(
|
|
|
55
60
|
)
|
|
56
61
|
|
|
57
62
|
# PS2
|
|
58
|
-
MWCCPS2 = Compiler("MWCCPS2")
|
|
63
|
+
MWCCPS2 = Compiler("MWCCPS2", uses_include_asm=False)
|
|
59
64
|
EEGCC = Compiler("EEGCC")
|
|
60
65
|
|
|
61
66
|
compiler_for_name: Dict[str, Compiler] = {
|