splat64 0.32.2__py3-none-any.whl → 0.33.0__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 +1 -1
- splat/scripts/split.py +20 -55
- splat/segtypes/common/asm.py +3 -33
- splat/segtypes/common/asmtu.py +3 -3
- splat/segtypes/common/bss.py +3 -1
- splat/segtypes/common/c.py +20 -9
- splat/segtypes/common/code.py +2 -0
- splat/segtypes/common/codesubsegment.py +55 -2
- splat/segtypes/common/data.py +8 -20
- splat/segtypes/common/group.py +11 -2
- splat/segtypes/common/hasm.py +5 -13
- splat/segtypes/common/textbin.py +7 -1
- splat/segtypes/linker_entry.py +5 -5
- splat/segtypes/segment.py +3 -1
- splat/util/compiler.py +1 -0
- splat/util/conf.py +96 -0
- splat/util/options.py +21 -8
- {splat64-0.32.2.dist-info → splat64-0.33.0.dist-info}/METADATA +2 -2
- {splat64-0.32.2.dist-info → splat64-0.33.0.dist-info}/RECORD +23 -22
- {splat64-0.32.2.dist-info → splat64-0.33.0.dist-info}/WHEEL +0 -0
- {splat64-0.32.2.dist-info → splat64-0.33.0.dist-info}/entry_points.txt +0 -0
- {splat64-0.32.2.dist-info → splat64-0.33.0.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, 33, 0)
|
|
11
11
|
|
|
12
12
|
def configure(self):
|
|
13
13
|
# Configure spimdisasm
|
splat/scripts/split.py
CHANGED
|
@@ -10,10 +10,6 @@ from .. import __package_name__, __version__
|
|
|
10
10
|
from ..disassembler import disassembler_instance
|
|
11
11
|
from ..util import cache_handler, progress_bar, vram_classes, statistics
|
|
12
12
|
|
|
13
|
-
# This unused import makes the yaml library faster. don't remove
|
|
14
|
-
import pylibyaml # pyright: ignore
|
|
15
|
-
import yaml
|
|
16
|
-
|
|
17
13
|
from colorama import Fore, Style
|
|
18
14
|
from intervaltree import Interval, IntervalTree
|
|
19
15
|
import sys
|
|
@@ -23,7 +19,7 @@ from ..segtypes.linker_entry import (
|
|
|
23
19
|
get_segment_vram_end_symbol_name,
|
|
24
20
|
)
|
|
25
21
|
from ..segtypes.segment import Segment
|
|
26
|
-
from ..util import log, options, palettes, symbols, relocs
|
|
22
|
+
from ..util import conf, log, options, palettes, symbols, relocs
|
|
27
23
|
|
|
28
24
|
linker_writer: LinkerWriter
|
|
29
25
|
config: Dict[str, Any]
|
|
@@ -142,34 +138,6 @@ def assign_symbols_to_segments():
|
|
|
142
138
|
seg.add_symbol(symbol)
|
|
143
139
|
|
|
144
140
|
|
|
145
|
-
def merge_configs(main_config, additional_config):
|
|
146
|
-
# Merge rules are simple
|
|
147
|
-
# For each key in the dictionary
|
|
148
|
-
# - If list then append to list
|
|
149
|
-
# - If a dictionary then repeat merge on sub dictionary entries
|
|
150
|
-
# - Else assume string or number and replace entry
|
|
151
|
-
|
|
152
|
-
for curkey in additional_config:
|
|
153
|
-
if curkey not in main_config:
|
|
154
|
-
main_config[curkey] = additional_config[curkey]
|
|
155
|
-
elif type(main_config[curkey]) != type(additional_config[curkey]):
|
|
156
|
-
log.error(f"Type for key {curkey} in configs does not match")
|
|
157
|
-
else:
|
|
158
|
-
# keys exist and match, see if a list to append
|
|
159
|
-
if type(main_config[curkey]) == list:
|
|
160
|
-
main_config[curkey] += additional_config[curkey]
|
|
161
|
-
elif type(main_config[curkey]) == dict:
|
|
162
|
-
# need to merge sub areas
|
|
163
|
-
main_config[curkey] = merge_configs(
|
|
164
|
-
main_config[curkey], additional_config[curkey]
|
|
165
|
-
)
|
|
166
|
-
else:
|
|
167
|
-
# not a list or dictionary, must be a number or string, overwrite
|
|
168
|
-
main_config[curkey] = additional_config[curkey]
|
|
169
|
-
|
|
170
|
-
return main_config
|
|
171
|
-
|
|
172
|
-
|
|
173
141
|
def brief_seg_name(seg: Segment, limit: int, ellipsis="…") -> str:
|
|
174
142
|
s = seg.name.strip()
|
|
175
143
|
if len(s) > limit:
|
|
@@ -203,25 +171,6 @@ def calc_segment_dependences(
|
|
|
203
171
|
return vram_class_to_follows_segments
|
|
204
172
|
|
|
205
173
|
|
|
206
|
-
def initialize_config(
|
|
207
|
-
config_path: List[str],
|
|
208
|
-
modes: Optional[List[str]],
|
|
209
|
-
verbose: bool,
|
|
210
|
-
disassemble_all: bool = False,
|
|
211
|
-
) -> Dict[str, Any]:
|
|
212
|
-
config: Dict[str, Any] = {}
|
|
213
|
-
for entry in config_path:
|
|
214
|
-
with open(entry) as f:
|
|
215
|
-
additional_config = yaml.load(f.read(), Loader=yaml.SafeLoader)
|
|
216
|
-
config = merge_configs(config, additional_config)
|
|
217
|
-
|
|
218
|
-
vram_classes.initialize(config.get("vram_classes"))
|
|
219
|
-
|
|
220
|
-
options.initialize(config, config_path, modes, verbose, disassemble_all)
|
|
221
|
-
|
|
222
|
-
return config
|
|
223
|
-
|
|
224
|
-
|
|
225
174
|
def read_target_binary() -> bytes:
|
|
226
175
|
rom_bytes = options.opts.target_path.read_bytes()
|
|
227
176
|
|
|
@@ -493,20 +442,27 @@ def dump_symbols() -> None:
|
|
|
493
442
|
|
|
494
443
|
|
|
495
444
|
def main(
|
|
496
|
-
config_path: List[
|
|
445
|
+
config_path: List[Path],
|
|
497
446
|
modes: Optional[List[str]],
|
|
498
447
|
verbose: bool,
|
|
499
448
|
use_cache: bool = True,
|
|
500
449
|
skip_version_check: bool = False,
|
|
501
450
|
stdout_only: bool = False,
|
|
502
451
|
disassemble_all: bool = False,
|
|
452
|
+
make_full_disasm_for_code=False,
|
|
503
453
|
):
|
|
504
454
|
if stdout_only:
|
|
505
455
|
progress_bar.out_file = sys.stdout
|
|
506
456
|
|
|
507
457
|
# Load config
|
|
508
458
|
global config
|
|
509
|
-
config =
|
|
459
|
+
config = conf.load(
|
|
460
|
+
config_path,
|
|
461
|
+
modes,
|
|
462
|
+
verbose,
|
|
463
|
+
disassemble_all,
|
|
464
|
+
make_full_disasm_for_code,
|
|
465
|
+
)
|
|
510
466
|
|
|
511
467
|
disassembler_instance.create_disassembler_instance(skip_version_check, __version__)
|
|
512
468
|
|
|
@@ -565,7 +521,10 @@ def main(
|
|
|
565
521
|
|
|
566
522
|
def add_arguments_to_parser(parser: argparse.ArgumentParser):
|
|
567
523
|
parser.add_argument(
|
|
568
|
-
"config",
|
|
524
|
+
"config",
|
|
525
|
+
help="path to a compatible config .yaml file",
|
|
526
|
+
nargs="+",
|
|
527
|
+
type=Path,
|
|
569
528
|
)
|
|
570
529
|
parser.add_argument("--modes", nargs="+", default="all")
|
|
571
530
|
parser.add_argument("--verbose", action="store_true", help="Enable debug logging")
|
|
@@ -585,6 +544,11 @@ def add_arguments_to_parser(parser: argparse.ArgumentParser):
|
|
|
585
544
|
help="Disasemble matched functions and migrated data",
|
|
586
545
|
action="store_true",
|
|
587
546
|
)
|
|
547
|
+
parser.add_argument(
|
|
548
|
+
"--make-full-disasm-for-code",
|
|
549
|
+
help="Emit a full `.s` file for each `c`/`cpp` segment besides the generated `nonmatchings` individual functions",
|
|
550
|
+
action="store_true",
|
|
551
|
+
)
|
|
588
552
|
|
|
589
553
|
|
|
590
554
|
def process_arguments(args: argparse.Namespace):
|
|
@@ -596,6 +560,7 @@ def process_arguments(args: argparse.Namespace):
|
|
|
596
560
|
args.skip_version_check,
|
|
597
561
|
args.stdout_only,
|
|
598
562
|
args.disassemble_all,
|
|
563
|
+
args.make_full_disasm_for_code,
|
|
599
564
|
)
|
|
600
565
|
|
|
601
566
|
|
splat/segtypes/common/asm.py
CHANGED
|
@@ -14,9 +14,6 @@ class CommonSegAsm(CommonSegCodeSubsegment):
|
|
|
14
14
|
def get_section_flags(self) -> Optional[str]:
|
|
15
15
|
return "ax"
|
|
16
16
|
|
|
17
|
-
def out_path(self) -> Optional[Path]:
|
|
18
|
-
return options.opts.asm_path / self.dir / f"{self.name}.s"
|
|
19
|
-
|
|
20
17
|
def scan(self, rom_bytes: bytes):
|
|
21
18
|
if (
|
|
22
19
|
self.rom_start is not None
|
|
@@ -25,35 +22,8 @@ class CommonSegAsm(CommonSegCodeSubsegment):
|
|
|
25
22
|
):
|
|
26
23
|
self.scan_code(rom_bytes)
|
|
27
24
|
|
|
28
|
-
def get_file_header(self) -> List[str]:
|
|
29
|
-
ret = []
|
|
30
|
-
|
|
31
|
-
ret.append('.include "macro.inc"')
|
|
32
|
-
ret.append("")
|
|
33
|
-
ret.append(".set noat") # allow manual use of $at
|
|
34
|
-
ret.append(".set noreorder") # don't insert nops after branches
|
|
35
|
-
if options.opts.add_set_gp_64:
|
|
36
|
-
ret.append(".set gp=64") # allow use of 64-bit general purpose registers
|
|
37
|
-
ret.append("")
|
|
38
|
-
preamble = options.opts.generated_s_preamble
|
|
39
|
-
if preamble:
|
|
40
|
-
ret.append(preamble)
|
|
41
|
-
ret.append("")
|
|
42
|
-
|
|
43
|
-
ret.append(self.get_section_asm_line())
|
|
44
|
-
ret.append("")
|
|
45
|
-
|
|
46
|
-
return ret
|
|
47
|
-
|
|
48
25
|
def split(self, rom_bytes: bytes):
|
|
49
|
-
if
|
|
50
|
-
|
|
51
|
-
if out_path:
|
|
52
|
-
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
53
|
-
|
|
54
|
-
self.print_file_boundaries()
|
|
26
|
+
if self.rom_start == self.rom_end:
|
|
27
|
+
return
|
|
55
28
|
|
|
56
|
-
|
|
57
|
-
for line in self.get_file_header():
|
|
58
|
-
f.write(line + "\n")
|
|
59
|
-
f.write(self.spim_section.disassemble())
|
|
29
|
+
self.split_as_asm_file(self.out_path())
|
splat/segtypes/common/asmtu.py
CHANGED
|
@@ -24,7 +24,7 @@ class CommonSegAsmtu(CommonSegAsm):
|
|
|
24
24
|
|
|
25
25
|
with open(out_path, "w", newline="\n") as f:
|
|
26
26
|
# Write `.text` contents
|
|
27
|
-
for line in self.
|
|
27
|
+
for line in self.get_asm_file_header():
|
|
28
28
|
f.write(line + "\n")
|
|
29
29
|
f.write(self.spim_section.disassemble())
|
|
30
30
|
|
|
@@ -40,7 +40,7 @@ class CommonSegAsmtu(CommonSegAsm):
|
|
|
40
40
|
if (
|
|
41
41
|
isinstance(sibling, CommonSegCodeSubsegment)
|
|
42
42
|
and sibling.spim_section is not None
|
|
43
|
-
and not sibling.
|
|
43
|
+
and not sibling.should_self_split()
|
|
44
44
|
):
|
|
45
45
|
f.write("\n")
|
|
46
46
|
f.write(f"{sibling.get_section_asm_line()}\n\n")
|
|
@@ -58,7 +58,7 @@ class CommonSegAsmtu(CommonSegAsm):
|
|
|
58
58
|
if (
|
|
59
59
|
isinstance(sibling, CommonSegCodeSubsegment)
|
|
60
60
|
and sibling.spim_section is not None
|
|
61
|
-
and not sibling.
|
|
61
|
+
and not sibling.should_self_split()
|
|
62
62
|
):
|
|
63
63
|
f.write("\n")
|
|
64
64
|
f.write(f"{sibling.get_section_asm_line()}\n\n")
|
splat/segtypes/common/bss.py
CHANGED
|
@@ -60,7 +60,9 @@ class CommonSegBss(CommonSegData):
|
|
|
60
60
|
f"Segment '{self.name}' (type '{self.type}') requires a vram address. Got '{self.vram_start}'"
|
|
61
61
|
)
|
|
62
62
|
|
|
63
|
-
next_subsegment = self.parent.get_next_subsegment_for_ram(
|
|
63
|
+
next_subsegment = self.parent.get_next_subsegment_for_ram(
|
|
64
|
+
self.vram_start, self.index_within_group
|
|
65
|
+
)
|
|
64
66
|
if next_subsegment is None:
|
|
65
67
|
bss_end = self.get_most_parent().vram_end
|
|
66
68
|
else:
|
splat/segtypes/common/c.py
CHANGED
|
@@ -276,6 +276,14 @@ class CommonSegC(CommonSegCodeSubsegment):
|
|
|
276
276
|
spim_rodata_sym, asm_out_dir, rodata_sym
|
|
277
277
|
)
|
|
278
278
|
|
|
279
|
+
if options.opts.make_full_disasm_for_code:
|
|
280
|
+
# Disable gpRelHack since this file is expected to be built with modern gas
|
|
281
|
+
section = self.spim_section.get_section()
|
|
282
|
+
old_value = section.getGpRelHack()
|
|
283
|
+
section.setGpRelHack(False)
|
|
284
|
+
self.split_as_asm_file(self.asm_out_path())
|
|
285
|
+
section.setGpRelHack(old_value)
|
|
286
|
+
|
|
279
287
|
def get_c_preamble(self):
|
|
280
288
|
ret = []
|
|
281
289
|
|
|
@@ -380,13 +388,16 @@ class CommonSegC(CommonSegCodeSubsegment):
|
|
|
380
388
|
# IDO uses the asm processor to embeed assembly, and it doesn't require a special directive to include symbols
|
|
381
389
|
asm_outpath = asm_out_dir / self.name / f"{sym.filename}.s"
|
|
382
390
|
rel_asm_outpath = os.path.relpath(asm_outpath, options.opts.base_path)
|
|
383
|
-
|
|
391
|
+
final_path = Path(rel_asm_outpath).as_posix()
|
|
392
|
+
return f'#pragma GLOBAL_ASM("{final_path}")'
|
|
384
393
|
|
|
385
394
|
if options.opts.use_legacy_include_asm:
|
|
386
395
|
rel_asm_out_dir = asm_out_dir.relative_to(options.opts.nonmatchings_path)
|
|
387
|
-
|
|
396
|
+
final_path = (rel_asm_out_dir / self.name).as_posix()
|
|
397
|
+
return f'{macro_name}(const s32, "{final_path}", {sym.filename});'
|
|
388
398
|
|
|
389
|
-
|
|
399
|
+
final_path = (asm_out_dir / self.name).as_posix()
|
|
400
|
+
return f'{macro_name}("{final_path}", {sym.filename});'
|
|
390
401
|
|
|
391
402
|
def get_c_lines_for_function(
|
|
392
403
|
self,
|
|
@@ -448,7 +459,7 @@ class CommonSegC(CommonSegCodeSubsegment):
|
|
|
448
459
|
c_lines += self.get_c_lines_for_rodata_sym(rodata_sym, asm_out_dir)
|
|
449
460
|
|
|
450
461
|
c_path.parent.mkdir(parents=True, exist_ok=True)
|
|
451
|
-
with c_path.open("w") as f:
|
|
462
|
+
with c_path.open("w", newline=options.opts.c_newline) as f:
|
|
452
463
|
f.write("\n".join(c_lines))
|
|
453
464
|
log.write(f"Wrote {self.name} to {c_path}")
|
|
454
465
|
|
|
@@ -472,12 +483,12 @@ class CommonSegC(CommonSegCodeSubsegment):
|
|
|
472
483
|
|
|
473
484
|
dep_path = build_path / c_path.with_suffix(".asmproc.d")
|
|
474
485
|
dep_path.parent.mkdir(parents=True, exist_ok=True)
|
|
475
|
-
with dep_path.open("w") as f:
|
|
486
|
+
with dep_path.open("w", newline=options.opts.c_newline) as f:
|
|
476
487
|
if options.opts.use_o_as_suffix:
|
|
477
488
|
o_path = build_path / c_path.with_suffix(".o")
|
|
478
489
|
else:
|
|
479
490
|
o_path = build_path / c_path.with_suffix(c_path.suffix + ".o")
|
|
480
|
-
f.write(f"{o_path}:")
|
|
491
|
+
f.write(f"{o_path.as_posix()}:")
|
|
481
492
|
depend_list = []
|
|
482
493
|
for entry in symbols_entries:
|
|
483
494
|
if entry.function is not None:
|
|
@@ -488,7 +499,7 @@ class CommonSegC(CommonSegCodeSubsegment):
|
|
|
488
499
|
outpath.parent.mkdir(parents=True, exist_ok=True)
|
|
489
500
|
|
|
490
501
|
depend_list.append(outpath)
|
|
491
|
-
f.write(f" \\\n {outpath}")
|
|
502
|
+
f.write(f" \\\n {outpath.as_posix()}")
|
|
492
503
|
else:
|
|
493
504
|
for rodata_sym in entry.rodataSyms:
|
|
494
505
|
rodata_name = rodata_sym.getName()
|
|
@@ -498,9 +509,9 @@ class CommonSegC(CommonSegCodeSubsegment):
|
|
|
498
509
|
outpath.parent.mkdir(parents=True, exist_ok=True)
|
|
499
510
|
|
|
500
511
|
depend_list.append(outpath)
|
|
501
|
-
f.write(f" \\\n {outpath}")
|
|
512
|
+
f.write(f" \\\n {outpath.as_posix()}")
|
|
502
513
|
|
|
503
514
|
f.write("\n")
|
|
504
515
|
|
|
505
516
|
for depend_file in depend_list:
|
|
506
|
-
f.write(f"{depend_file}:\n")
|
|
517
|
+
f.write(f"{depend_file.as_posix()}:\n")
|
splat/segtypes/common/code.py
CHANGED
|
@@ -270,6 +270,8 @@ class CommonSegCode(CommonSegGroup):
|
|
|
270
270
|
sibling.siblings[segment.get_linker_section_linksection()] = segment
|
|
271
271
|
|
|
272
272
|
ret = self._insert_all_auto_sections(ret, base_segments, readonly_before)
|
|
273
|
+
for i, seg in enumerate(ret):
|
|
274
|
+
seg.index_within_group = i
|
|
273
275
|
|
|
274
276
|
return ret
|
|
275
277
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional, List
|
|
2
3
|
|
|
3
4
|
import spimdisasm
|
|
4
5
|
import rabbitizer
|
|
@@ -60,7 +61,7 @@ class CommonSegCodeSubsegment(Segment):
|
|
|
60
61
|
section.isHandwritten = self.is_hasm
|
|
61
62
|
section.instrCat = self.instr_category
|
|
62
63
|
section.detectRedundantFunctionEnd = self.detect_redundant_function_end
|
|
63
|
-
section.
|
|
64
|
+
section.setGpRelHack(not self.use_gp_rel_macro)
|
|
64
65
|
|
|
65
66
|
def scan_code(self, rom_bytes, is_hasm=False):
|
|
66
67
|
self.is_hasm = is_hasm
|
|
@@ -194,3 +195,55 @@ class CommonSegCodeSubsegment(Segment):
|
|
|
194
195
|
return (
|
|
195
196
|
self.extract and options.opts.is_mode_active("code") and self.should_scan()
|
|
196
197
|
) # only split if the segment was scanned first
|
|
198
|
+
|
|
199
|
+
def should_self_split(self) -> bool:
|
|
200
|
+
return self.should_split()
|
|
201
|
+
|
|
202
|
+
def get_asm_file_header(self) -> List[str]:
|
|
203
|
+
ret = []
|
|
204
|
+
|
|
205
|
+
ret.append('.include "macro.inc"')
|
|
206
|
+
ret.append("")
|
|
207
|
+
|
|
208
|
+
ret.extend(self.get_asm_file_extra_directives())
|
|
209
|
+
|
|
210
|
+
preamble = options.opts.generated_s_preamble
|
|
211
|
+
if preamble:
|
|
212
|
+
ret.append(preamble)
|
|
213
|
+
ret.append("")
|
|
214
|
+
|
|
215
|
+
ret.append(self.get_section_asm_line())
|
|
216
|
+
ret.append("")
|
|
217
|
+
|
|
218
|
+
return ret
|
|
219
|
+
|
|
220
|
+
def get_asm_file_extra_directives(self) -> List[str]:
|
|
221
|
+
ret = []
|
|
222
|
+
|
|
223
|
+
ret.append(".set noat") # allow manual use of $at
|
|
224
|
+
ret.append(".set noreorder") # don't insert nops after branches
|
|
225
|
+
if options.opts.add_set_gp_64:
|
|
226
|
+
ret.append(".set gp=64") # allow use of 64-bit general purpose registers
|
|
227
|
+
ret.append("")
|
|
228
|
+
|
|
229
|
+
return ret
|
|
230
|
+
|
|
231
|
+
def asm_out_path(self) -> Path:
|
|
232
|
+
return options.opts.asm_path / self.dir / f"{self.name}.s"
|
|
233
|
+
|
|
234
|
+
def out_path(self) -> Optional[Path]:
|
|
235
|
+
return self.asm_out_path()
|
|
236
|
+
|
|
237
|
+
def split_as_asm_file(self, out_path: Optional[Path]):
|
|
238
|
+
if self.spim_section is None:
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
if out_path:
|
|
242
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
243
|
+
|
|
244
|
+
self.print_file_boundaries()
|
|
245
|
+
|
|
246
|
+
with open(out_path, "w", newline="\n") as f:
|
|
247
|
+
for line in self.get_asm_file_header():
|
|
248
|
+
f.write(line + "\n")
|
|
249
|
+
f.write(self.spim_section.disassemble())
|
splat/segtypes/common/data.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Optional, List
|
|
3
3
|
from ...util import options, symbols, log
|
|
4
4
|
|
|
5
5
|
from .codesubsegment import CommonSegCodeSubsegment
|
|
@@ -38,33 +38,21 @@ class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup):
|
|
|
38
38
|
if self.rom_start is not None and self.rom_end is not None:
|
|
39
39
|
self.disassemble_data(rom_bytes)
|
|
40
40
|
|
|
41
|
+
def get_asm_file_extra_directives(self) -> List[str]:
|
|
42
|
+
return []
|
|
43
|
+
|
|
41
44
|
def split(self, rom_bytes: bytes):
|
|
42
45
|
super().split(rom_bytes)
|
|
43
46
|
|
|
44
|
-
if self.type.startswith(".") and not options.opts.disassemble_all:
|
|
45
|
-
return
|
|
46
|
-
|
|
47
47
|
if self.spim_section is None or not self.should_self_split():
|
|
48
48
|
return
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
path.parent.mkdir(parents=True, exist_ok=True)
|
|
53
|
-
|
|
54
|
-
self.print_file_boundaries()
|
|
55
|
-
|
|
56
|
-
with path.open("w", newline="\n") as f:
|
|
57
|
-
f.write('.include "macro.inc"\n\n')
|
|
58
|
-
preamble = options.opts.generated_s_preamble
|
|
59
|
-
if preamble:
|
|
60
|
-
f.write(preamble + "\n")
|
|
61
|
-
|
|
62
|
-
f.write(f"{self.get_section_asm_line()}\n\n")
|
|
63
|
-
|
|
64
|
-
f.write(self.spim_section.disassemble())
|
|
50
|
+
self.split_as_asm_file(self.asm_out_path())
|
|
65
51
|
|
|
66
52
|
def should_self_split(self) -> bool:
|
|
67
|
-
return options.opts.is_mode_active("data")
|
|
53
|
+
return options.opts.is_mode_active("data") and (
|
|
54
|
+
not self.type.startswith(".") or options.opts.disassemble_all
|
|
55
|
+
)
|
|
68
56
|
|
|
69
57
|
def should_scan(self) -> bool:
|
|
70
58
|
return True
|
splat/segtypes/common/group.py
CHANGED
|
@@ -110,11 +110,16 @@ class CommonSegGroup(CommonSegment):
|
|
|
110
110
|
self.special_vram_segment = True
|
|
111
111
|
segment.is_auto_segment = is_auto_segment
|
|
112
112
|
|
|
113
|
+
segment.index_within_group = len(ret)
|
|
114
|
+
|
|
113
115
|
ret.append(segment)
|
|
114
116
|
prev_start = start
|
|
115
117
|
if end is not None:
|
|
116
118
|
last_rom_end = end
|
|
117
119
|
|
|
120
|
+
for i, seg in enumerate(ret):
|
|
121
|
+
seg.index_within_group = i
|
|
122
|
+
|
|
118
123
|
return ret
|
|
119
124
|
|
|
120
125
|
@property
|
|
@@ -165,13 +170,17 @@ class CommonSegGroup(CommonSegment):
|
|
|
165
170
|
return sub
|
|
166
171
|
return None
|
|
167
172
|
|
|
168
|
-
def get_next_subsegment_for_ram(
|
|
173
|
+
def get_next_subsegment_for_ram(
|
|
174
|
+
self, addr: int, current_subseg_index: Optional[int]
|
|
175
|
+
) -> Optional[Segment]:
|
|
169
176
|
"""
|
|
170
177
|
Returns the first subsegment which comes after the specified address,
|
|
171
178
|
or None in case this address belongs to the last subsegment of this group
|
|
172
179
|
"""
|
|
173
180
|
|
|
174
|
-
|
|
181
|
+
start = current_subseg_index if current_subseg_index is not None else 0
|
|
182
|
+
|
|
183
|
+
for sub in self.subsegments[start:]:
|
|
175
184
|
if sub.vram_start is None:
|
|
176
185
|
continue
|
|
177
186
|
assert isinstance(sub.vram_start, int)
|
splat/segtypes/common/hasm.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
3
|
from .asm import CommonSegAsm
|
|
5
4
|
|
|
@@ -7,11 +6,11 @@ from ...util import options
|
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
class CommonSegHasm(CommonSegAsm):
|
|
10
|
-
def
|
|
9
|
+
def asm_out_path(self) -> Path:
|
|
11
10
|
if options.opts.hasm_in_src_path:
|
|
12
11
|
return options.opts.src_path / self.dir / f"{self.name}.s"
|
|
13
12
|
|
|
14
|
-
return super().
|
|
13
|
+
return super().asm_out_path()
|
|
15
14
|
|
|
16
15
|
def scan(self, rom_bytes: bytes):
|
|
17
16
|
if (
|
|
@@ -22,14 +21,7 @@ class CommonSegHasm(CommonSegAsm):
|
|
|
22
21
|
self.scan_code(rom_bytes, is_hasm=True)
|
|
23
22
|
|
|
24
23
|
def split(self, rom_bytes: bytes):
|
|
25
|
-
if
|
|
26
|
-
|
|
27
|
-
if out_path and not out_path.exists():
|
|
28
|
-
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
24
|
+
if self.rom_start == self.rom_end:
|
|
25
|
+
return
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
with open(out_path, "w", newline="\n") as f:
|
|
33
|
-
for line in self.get_file_header():
|
|
34
|
-
f.write(line + "\n")
|
|
35
|
-
f.write(self.spim_section.disassemble())
|
|
27
|
+
self.split_as_asm_file(self.out_path())
|
splat/segtypes/common/textbin.py
CHANGED
|
@@ -83,9 +83,13 @@ class CommonSegTextbin(CommonSegment):
|
|
|
83
83
|
|
|
84
84
|
if sym is not None:
|
|
85
85
|
f.write(f"{asm_label} {sym.name}\n")
|
|
86
|
+
if asm_label == ".globl":
|
|
87
|
+
if self.is_text():
|
|
88
|
+
f.write(f".ent {sym.name}\n")
|
|
89
|
+
f.write(f"{sym.name}:\n")
|
|
86
90
|
sym.defined = True
|
|
87
91
|
|
|
88
|
-
f.write(f'.incbin "{binpath}"\n')
|
|
92
|
+
f.write(f'.incbin "{binpath.as_posix()}"\n')
|
|
89
93
|
|
|
90
94
|
if sym is not None:
|
|
91
95
|
if self.is_text() and options.opts.asm_end_label != "":
|
|
@@ -97,6 +101,8 @@ class CommonSegTextbin(CommonSegment):
|
|
|
97
101
|
or sym.given_size == self.rom_end - self.rom_start
|
|
98
102
|
):
|
|
99
103
|
f.write(f"{asm_label} {sym.given_name_end}\n")
|
|
104
|
+
if asm_label == ".globl":
|
|
105
|
+
f.write(f"{sym.given_name_end}:\n")
|
|
100
106
|
|
|
101
107
|
def split(self, rom_bytes):
|
|
102
108
|
if self.rom_end is None:
|
splat/segtypes/linker_entry.py
CHANGED
|
@@ -51,7 +51,7 @@ def write_file_if_different(path: Path, new_content: str):
|
|
|
51
51
|
|
|
52
52
|
if old_content != new_content:
|
|
53
53
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
54
|
-
with path.open("w") as f:
|
|
54
|
+
with path.open("w", newline=options.opts.c_newline) as f:
|
|
55
55
|
f.write(new_content)
|
|
56
56
|
|
|
57
57
|
|
|
@@ -522,18 +522,18 @@ 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}:"
|
|
525
|
+
output = f"{target_elf_path.as_posix()}:"
|
|
526
526
|
|
|
527
527
|
for entry in self.dependencies_entries:
|
|
528
528
|
if entry.object_path is None:
|
|
529
529
|
continue
|
|
530
|
-
output += f" \\\n {entry.object_path}"
|
|
530
|
+
output += f" \\\n {entry.object_path.as_posix()}"
|
|
531
531
|
|
|
532
532
|
output += "\n"
|
|
533
533
|
for entry in self.dependencies_entries:
|
|
534
534
|
if entry.object_path is None:
|
|
535
535
|
continue
|
|
536
|
-
output += f"{entry.object_path}:\n"
|
|
536
|
+
output += f"{entry.object_path.as_posix()}:\n"
|
|
537
537
|
write_file_if_different(output_path, output)
|
|
538
538
|
|
|
539
539
|
def _writeln(self, line: str):
|
|
@@ -561,7 +561,7 @@ class LinkerWriter:
|
|
|
561
561
|
self.header_symbols.add(symbol)
|
|
562
562
|
|
|
563
563
|
def _write_object_path_section(self, object_path: Path, section: str):
|
|
564
|
-
self._writeln(f"{object_path}({section});")
|
|
564
|
+
self._writeln(f"{object_path.as_posix()}({section});")
|
|
565
565
|
|
|
566
566
|
def _begin_segment(
|
|
567
567
|
self, segment: Segment, seg_name: str, noload: bool, is_first: bool
|
splat/segtypes/segment.py
CHANGED
|
@@ -255,7 +255,7 @@ class Segment:
|
|
|
255
255
|
|
|
256
256
|
@staticmethod
|
|
257
257
|
def parse_suggestion_rodata_section_start(
|
|
258
|
-
yaml: Union[dict, list]
|
|
258
|
+
yaml: Union[dict, list],
|
|
259
259
|
) -> Optional[bool]:
|
|
260
260
|
if isinstance(yaml, dict):
|
|
261
261
|
suggestion_rodata_section_start = yaml.get(
|
|
@@ -354,6 +354,8 @@ class Segment:
|
|
|
354
354
|
# Is an automatic segment, generated automatically or declared on the yaml by the user
|
|
355
355
|
self.is_auto_segment: bool = False
|
|
356
356
|
|
|
357
|
+
self.index_within_group: Optional[int] = None
|
|
358
|
+
|
|
357
359
|
if self.rom_start is not None and self.rom_end is not None:
|
|
358
360
|
if self.rom_start > self.rom_end:
|
|
359
361
|
log.error(
|
splat/util/compiler.py
CHANGED
splat/util/conf.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module is used to load splat configuration from a YAML file.
|
|
3
|
+
|
|
4
|
+
A config dict can be loaded using `load`.
|
|
5
|
+
|
|
6
|
+
config = conf.load("path/to/splat.yaml")
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
# This unused import makes the yaml library faster. don't remove
|
|
13
|
+
import pylibyaml # pyright: ignore
|
|
14
|
+
import yaml
|
|
15
|
+
|
|
16
|
+
from . import log, options, vram_classes
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _merge_configs(main_config, additional_config, additional_config_path):
|
|
20
|
+
# Merge rules are simple
|
|
21
|
+
# For each key in the dictionary
|
|
22
|
+
# - If list then append to list
|
|
23
|
+
# - If a dictionary then repeat merge on sub dictionary entries
|
|
24
|
+
# - Else assume string or number and replace entry
|
|
25
|
+
|
|
26
|
+
for curkey in additional_config:
|
|
27
|
+
if curkey not in main_config:
|
|
28
|
+
main_config[curkey] = additional_config[curkey]
|
|
29
|
+
elif type(main_config[curkey]) != type(additional_config[curkey]):
|
|
30
|
+
raise TypeError(
|
|
31
|
+
f"Could not merge {str(additional_config_path)}: type for key '{curkey}' in configs does not match"
|
|
32
|
+
)
|
|
33
|
+
else:
|
|
34
|
+
# keys exist and match, see if a list to append
|
|
35
|
+
if type(main_config[curkey]) == list:
|
|
36
|
+
main_config[curkey] += additional_config[curkey]
|
|
37
|
+
elif type(main_config[curkey]) == dict:
|
|
38
|
+
# need to merge sub areas
|
|
39
|
+
main_config[curkey] = _merge_configs(
|
|
40
|
+
main_config[curkey],
|
|
41
|
+
additional_config[curkey],
|
|
42
|
+
additional_config_path,
|
|
43
|
+
)
|
|
44
|
+
else:
|
|
45
|
+
# not a list or dictionary, must be a number or string, overwrite
|
|
46
|
+
main_config[curkey] = additional_config[curkey]
|
|
47
|
+
|
|
48
|
+
return main_config
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def load(
|
|
52
|
+
config_path: List[Path],
|
|
53
|
+
modes: Optional[List[str]] = None,
|
|
54
|
+
verbose: bool = False,
|
|
55
|
+
disassemble_all: bool = False,
|
|
56
|
+
make_full_disasm_for_code=False,
|
|
57
|
+
) -> Dict[str, Any]:
|
|
58
|
+
"""
|
|
59
|
+
Returns a `dict` with resolved splat config.
|
|
60
|
+
|
|
61
|
+
Multiple configuration files can be passed in ``config_path`` with each subsequent file merged into the previous.
|
|
62
|
+
|
|
63
|
+
`modes` specifies which modes are active (all, code, img, gfx, vtx, etc.). The default is all.
|
|
64
|
+
|
|
65
|
+
`verbose` may be used to determine whether or not to display additional output.
|
|
66
|
+
|
|
67
|
+
`disassemble_all` determines whether functions which are already compiled will be disassembled. This is OR-ed with
|
|
68
|
+
the `disassemble_all` key in a config file, if present.
|
|
69
|
+
|
|
70
|
+
After all files are merged, static validation is done on the configuration.
|
|
71
|
+
|
|
72
|
+
The returned `dict` represents the merged and validated YAML config.
|
|
73
|
+
|
|
74
|
+
As a side effect, the global `splat.util.options.opts` is set.
|
|
75
|
+
|
|
76
|
+
Config with invalid options may raise an error.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
config: Dict[str, Any] = {}
|
|
80
|
+
for entry in config_path:
|
|
81
|
+
with entry.open() as f:
|
|
82
|
+
additional_config = yaml.load(f.read(), Loader=yaml.SafeLoader)
|
|
83
|
+
config = _merge_configs(config, additional_config, entry)
|
|
84
|
+
|
|
85
|
+
vram_classes.initialize(config.get("vram_classes"))
|
|
86
|
+
|
|
87
|
+
options.initialize(
|
|
88
|
+
config,
|
|
89
|
+
config_path,
|
|
90
|
+
modes,
|
|
91
|
+
verbose,
|
|
92
|
+
disassemble_all,
|
|
93
|
+
make_full_disasm_for_code,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return config
|
splat/util/options.py
CHANGED
|
@@ -220,6 +220,8 @@ class SplatOpts:
|
|
|
220
220
|
detect_redundant_function_end: bool
|
|
221
221
|
# Don't skip disassembling already matched functions and migrated sections
|
|
222
222
|
disassemble_all: bool
|
|
223
|
+
# Emit a full `.s` file for each `c`/`cpp` segment besides the generated `nonmatchings` individual functions
|
|
224
|
+
make_full_disasm_for_code: bool
|
|
223
225
|
# Allow specifying that the global memory range may be larger than what was automatically detected.
|
|
224
226
|
# Useful for projects where splat is used in multiple individual files, meaning the expected global segment may not be properly detected because each instance of splat can't see the info from other files.
|
|
225
227
|
global_vram_start: Optional[int]
|
|
@@ -344,10 +346,11 @@ class OptParser:
|
|
|
344
346
|
|
|
345
347
|
def _parse_yaml(
|
|
346
348
|
yaml: Dict,
|
|
347
|
-
config_paths: List[
|
|
349
|
+
config_paths: List[Path],
|
|
348
350
|
modes: List[str],
|
|
349
351
|
verbose: bool = False,
|
|
350
352
|
disasm_all: bool = False,
|
|
353
|
+
make_full_disasm_for_code: bool = False,
|
|
351
354
|
) -> SplatOpts:
|
|
352
355
|
p = OptParser(yaml)
|
|
353
356
|
|
|
@@ -356,7 +359,7 @@ def _parse_yaml(
|
|
|
356
359
|
comp = compiler.for_name(p.parse_opt("compiler", str, "IDO"))
|
|
357
360
|
|
|
358
361
|
base_path = Path(
|
|
359
|
-
os.path.normpath(
|
|
362
|
+
os.path.normpath(config_paths[0].parent / p.parse_opt("base_path", str))
|
|
360
363
|
)
|
|
361
364
|
asm_path: Path = p.parse_path(base_path, "asm_path", "asm")
|
|
362
365
|
|
|
@@ -554,10 +557,12 @@ def _parse_yaml(
|
|
|
554
557
|
detect_redundant_function_end=p.parse_opt(
|
|
555
558
|
"detect_redundant_function_end", bool, True
|
|
556
559
|
),
|
|
557
|
-
#
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
),
|
|
560
|
+
# Setting either option will produce a full disassembly,
|
|
561
|
+
# but we still have to check the yaml option first to avoid leaving option unparsed,
|
|
562
|
+
# because splat would complain about an unrecognized yaml option otherwise.
|
|
563
|
+
disassemble_all=p.parse_opt("disassemble_all", bool, False) or disasm_all,
|
|
564
|
+
make_full_disasm_for_code=p.parse_opt("make_full_disasm_for_code", bool, False)
|
|
565
|
+
or make_full_disasm_for_code,
|
|
561
566
|
global_vram_start=p.parse_optional_opt("global_vram_start", int),
|
|
562
567
|
global_vram_end=p.parse_optional_opt("global_vram_end", int),
|
|
563
568
|
use_gp_rel_macro_nonmatching=p.parse_opt(
|
|
@@ -574,14 +579,22 @@ def _parse_yaml(
|
|
|
574
579
|
|
|
575
580
|
def initialize(
|
|
576
581
|
config: Dict,
|
|
577
|
-
config_paths: List[
|
|
582
|
+
config_paths: List[Path],
|
|
578
583
|
modes: Optional[List[str]] = None,
|
|
579
584
|
verbose=False,
|
|
580
585
|
disasm_all=False,
|
|
586
|
+
make_full_disasm_for_code=False,
|
|
581
587
|
):
|
|
582
588
|
global opts
|
|
583
589
|
|
|
584
590
|
if not modes:
|
|
585
591
|
modes = ["all"]
|
|
586
592
|
|
|
587
|
-
opts = _parse_yaml(
|
|
593
|
+
opts = _parse_yaml(
|
|
594
|
+
config["options"],
|
|
595
|
+
config_paths,
|
|
596
|
+
modes,
|
|
597
|
+
verbose,
|
|
598
|
+
disasm_all,
|
|
599
|
+
make_full_disasm_for_code,
|
|
600
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splat64
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.33.0
|
|
4
4
|
Summary: A binary splitting tool to assist with decompilation and modding projects
|
|
5
5
|
Project-URL: Repository, https://github.com/ethteck/splat
|
|
6
6
|
Project-URL: Issues, https://github.com/ethteck/splat/issues
|
|
@@ -76,7 +76,7 @@ The brackets corresponds to the optional dependencies to install while installin
|
|
|
76
76
|
If you use a `requirements.txt` file in your repository, then you can add this library with the following line:
|
|
77
77
|
|
|
78
78
|
```txt
|
|
79
|
-
splat64[mips]>=0.
|
|
79
|
+
splat64[mips]>=0.33.0,<1.0.0
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
### Optional dependencies
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
splat/__init__.py,sha256=
|
|
1
|
+
splat/__init__.py,sha256=BC3Ztd-mFegTEbtIJhxdClCWjIA8qw5qhS8jZNWQ-ec,291
|
|
2
2
|
splat/__main__.py,sha256=T333dHDgr-2HYYhtARnYMEjdECnYiNIKfcXDD99o22A,732
|
|
3
3
|
splat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
splat/disassembler/__init__.py,sha256=IubLMnm_F5cZ7WUPBfk1VJ7vdj6i1if5GG6RBvEoBEA,226
|
|
@@ -6,7 +6,7 @@ splat/disassembler/disassembler.py,sha256=2ynehZRz1P6UnaBk6DWRy4c3ynRnnWApMhf0K9
|
|
|
6
6
|
splat/disassembler/disassembler_instance.py,sha256=09GW7QYoNolgE2wnO7ALngw_CxgF-mfyLiXBsyv22jA,916
|
|
7
7
|
splat/disassembler/disassembler_section.py,sha256=J9jtplQVDVeGBmyEOcMpC3Hv3DyecqaNjlYc7zqEqDI,7459
|
|
8
8
|
splat/disassembler/null_disassembler.py,sha256=jYuDMtfPiBifwz0H-ZHLMWtpGa19X_iLgy4K-dQhPYY,328
|
|
9
|
-
splat/disassembler/spimdisasm_disassembler.py,sha256=
|
|
9
|
+
splat/disassembler/spimdisasm_disassembler.py,sha256=Lj6zp2g7Jo4sRlZ7CavLb7qM4alzEG1n7AhFYLiskqU,5685
|
|
10
10
|
splat/platforms/__init__.py,sha256=qjqKi63k5N3DUdILNfuk6qpJJkVeAWpjAs36L97vvP4,100
|
|
11
11
|
splat/platforms/n64.py,sha256=kgWr6nesGC0X-qVydmu8tSq48NbqVf9mF6EyqvUuoUM,421
|
|
12
12
|
splat/platforms/ps2.py,sha256=QI_8Ve43LZeNqpuk8_CFxIqsNJpMTacRHXdZVh3iY6c,336
|
|
@@ -15,25 +15,25 @@ splat/platforms/psx.py,sha256=YxQERdOBr4p3ab9Wk80FNhVYi-uvmh7p_jeykSFp23M,40
|
|
|
15
15
|
splat/scripts/__init__.py,sha256=OY0nHg6a7JB437Sb96qLbZ_7ByVsal1gStj35wJAI_Y,101
|
|
16
16
|
splat/scripts/capy.py,sha256=svbOfLO34-QN3xLiBy9vk2RGs_To8TWMWEKBw6yx2xQ,3674
|
|
17
17
|
splat/scripts/create_config.py,sha256=nFwIt1UWzlWE9C3i-2dGsVyGX2cuXzIqkp2kur2-pdE,7670
|
|
18
|
-
splat/scripts/split.py,sha256=
|
|
18
|
+
splat/scripts/split.py,sha256=EJLpvwGurQZEe-FE3hfNcMFIbxLToB4SX95OXdL_qoE,19285
|
|
19
19
|
splat/segtypes/__init__.py,sha256=-upUw_4JGQtvyp6IfTMzOq_CK3xvVaT_0K0_EipHyOo,208
|
|
20
|
-
splat/segtypes/linker_entry.py,sha256=
|
|
21
|
-
splat/segtypes/segment.py,sha256=
|
|
20
|
+
splat/segtypes/linker_entry.py,sha256=e2IzjAWC1B_JCx5pxBdKJrzOCse4SYUBrLHM8l3AR3o,24765
|
|
21
|
+
splat/segtypes/segment.py,sha256=Y8OaNle09VeQ8pghzMQtxu8I2sWKy8fWPdfRH1zkUXU,28820
|
|
22
22
|
splat/segtypes/common/__init__.py,sha256=mnq0acScilSCCo6q2PvkDk0Or3V8qitA7I8QMVw8haI,631
|
|
23
|
-
splat/segtypes/common/asm.py,sha256=
|
|
24
|
-
splat/segtypes/common/asmtu.py,sha256=
|
|
23
|
+
splat/segtypes/common/asm.py,sha256=k3p4vgbQJP40iyTgQkIci1j3CpKkWksqoWBx2Pb2oh8,703
|
|
24
|
+
splat/segtypes/common/asmtu.py,sha256=5FOVAXjqhM-kynm-nOuS1k7E9048WAW2eNHdKYtR5m8,2288
|
|
25
25
|
splat/segtypes/common/bin.py,sha256=6rxYRXTdAVEs3AFMgmhelOwOmKMg3bbkl-j4k4wqql4,1229
|
|
26
|
-
splat/segtypes/common/bss.py,sha256=
|
|
27
|
-
splat/segtypes/common/c.py,sha256=
|
|
28
|
-
splat/segtypes/common/code.py,sha256=
|
|
29
|
-
splat/segtypes/common/codesubsegment.py,sha256=
|
|
26
|
+
splat/segtypes/common/bss.py,sha256=nktRbKrDivweyLdsUQkL5guSayqpwn7NK5j3gq3arKc,3084
|
|
27
|
+
splat/segtypes/common/c.py,sha256=FBcEQ6GB5-F5wZQCahh2FjkqLkWFHBTehql8SuLVQyY,20419
|
|
28
|
+
splat/segtypes/common/code.py,sha256=CFDbn2YCoRIpUT07vTW0rUQtG58X0sxTtp17VPbrZsc,10706
|
|
29
|
+
splat/segtypes/common/codesubsegment.py,sha256=_fpQF7O5pq4CBclhqcR4_KbiY8Oo2p7gaMEnkICBfQ4,8558
|
|
30
30
|
splat/segtypes/common/cpp.py,sha256=p-duowCt4czrmaWgj1LuFw5LGfdyB_uaeLTKVmH80Cg,180
|
|
31
|
-
splat/segtypes/common/data.py,sha256=
|
|
31
|
+
splat/segtypes/common/data.py,sha256=r9G_vYieNlRze-5wGOKFazvFjpuodfSLad6iCNsBOAU,5665
|
|
32
32
|
splat/segtypes/common/databin.py,sha256=ucbbsc_M1332KifjExuDsf1wqm4-GZAiLqOwwrUwUpQ,1194
|
|
33
33
|
splat/segtypes/common/eh_frame.py,sha256=MzL373ej2E38leM47py3T5beLq2IolsYszLZM8PYS2Y,913
|
|
34
34
|
splat/segtypes/common/gcc_except_table.py,sha256=-ZrQL5dCcRu7EPFFPgL8lIJwWL5FsEeeQoSUVfTkyIg,2112
|
|
35
|
-
splat/segtypes/common/group.py,sha256=
|
|
36
|
-
splat/segtypes/common/hasm.py,sha256=
|
|
35
|
+
splat/segtypes/common/group.py,sha256=4g8jrpUjlsvxFuFRauS4rdxTvAAePebc941fQj96qEA,6197
|
|
36
|
+
splat/segtypes/common/hasm.py,sha256=0sU00X0Ax-DK2y8-lKt1ZowjaVKX-5bdiKnjnX_cKGA,703
|
|
37
37
|
splat/segtypes/common/header.py,sha256=NspQdk-L69j9dOBzBtDKb7bc11Gwa0WDWIVCd2P4mfE,1257
|
|
38
38
|
splat/segtypes/common/lib.py,sha256=WaJH0DH0B8iJvhYQWYBjThbNeEXz3Yh7E8ZyONe5JtQ,2349
|
|
39
39
|
splat/segtypes/common/linker_offset.py,sha256=IaEXMXq62BS2g95I4lS0wax5Ehjfi3O3C-uSDUbMjvI,767
|
|
@@ -44,7 +44,7 @@ splat/segtypes/common/rodatabin.py,sha256=uqp60QuwHwvlMwHq0nZrU3y3yYcHbv2twT0PID
|
|
|
44
44
|
splat/segtypes/common/sbss.py,sha256=blIEuVYie4qNEOYMmlSdltn5f4MvgJu3AV8vqVD8Nh4,131
|
|
45
45
|
splat/segtypes/common/sdata.py,sha256=dnLzNSNtSyclLZiNUmFTv0e0BWN8glxB1km1MSRq6xY,136
|
|
46
46
|
splat/segtypes/common/segment.py,sha256=vVFyFjs-gS5qIWO8Pd0pMJYxboP-iBRKvxcDV8YxdYM,94
|
|
47
|
-
splat/segtypes/common/textbin.py,sha256=
|
|
47
|
+
splat/segtypes/common/textbin.py,sha256=Xj-PxEDTN8f0DLgdZ2uA26SYCcXD3rqqr2r6-pEiA4Y,4578
|
|
48
48
|
splat/segtypes/n64/__init__.py,sha256=tf2yWlijeKmOp1OhEEL-aW88mU-mWQRC2lSjQ5Ww1eI,569
|
|
49
49
|
splat/segtypes/n64/ci.py,sha256=An7wIHcoZ89KiGCKpCRbM7IrmDNYBidXT-6kjKn2vH0,2400
|
|
50
50
|
splat/segtypes/n64/ci4.py,sha256=ZP8e12CpV8U7r8oLnb9uHc-MkmBbxjXBbJxROFvOjiM,184
|
|
@@ -78,9 +78,10 @@ splat/segtypes/psx/header.py,sha256=2S8XG_6zfLGzmEA0XpFqs0-4nf52YD9Erk6SbMUlVzo,
|
|
|
78
78
|
splat/util/__init__.py,sha256=3-jgYUssL84IgaR_JF1hSb-lN4ru0gJQTrjP_UGEWu8,470
|
|
79
79
|
splat/util/cache_handler.py,sha256=N0SggmvYwh0k-0fngHXoHG1CosC2rCsnlCTDsG8z5aE,1852
|
|
80
80
|
splat/util/color.py,sha256=FSmy0dAQJ9FzRBc99Yt4kBEyB62MC_YiVkqoWgPMsRU,371
|
|
81
|
-
splat/util/compiler.py,sha256=
|
|
81
|
+
splat/util/compiler.py,sha256=xDDNdnutmkB7T21j-BccBMdkA2leU3GzXuTYEWgVgNw,1530
|
|
82
|
+
splat/util/conf.py,sha256=aM6O2QikosjL95pCxI2FcCxrwDsLP8T8sRf2Uev_Pac,3236
|
|
82
83
|
splat/util/log.py,sha256=GguW9AolH-EXGBmh-8aZXgUeBFJthqAOb3qKtRYUSj8,999
|
|
83
|
-
splat/util/options.py,sha256=
|
|
84
|
+
splat/util/options.py,sha256=JHyZnBuB86tbZN_HvhAvOH8oZGsppIc9KmgRVRkBWvg,28632
|
|
84
85
|
splat/util/palettes.py,sha256=d3KoZnwt-zunI9eNwb3txysXg4DY3xnF0O5aQRxM4so,2920
|
|
85
86
|
splat/util/progress_bar.py,sha256=41VehpIFK1cphENaXV_Aq6_3mFx25eQ8V7Z51SKFPeM,166
|
|
86
87
|
splat/util/relocs.py,sha256=cgQYSaAtNpLlUZQdhEfa7ZpI8i0HqoDhwB88QtFqdJs,4212
|
|
@@ -93,8 +94,8 @@ splat/util/n64/find_code_length.py,sha256=uUoPoUORAjsAvH8oGqwnGvw6j8I_NnSrZtA-x9
|
|
|
93
94
|
splat/util/n64/rominfo.py,sha256=U6TieblUAmxhZsn7u8nbjOKkbC6ygsC_7IiLLaOWwUE,14646
|
|
94
95
|
splat/util/psx/__init__.py,sha256=kCCaR-KB1mNlIcXB4OuuSQ2zVLbWg_SnIZIUeyjeBBI,39
|
|
95
96
|
splat/util/psx/psxexeinfo.py,sha256=MrxY28nes0uzpFmCz0o9JFbF8s1eQRQNOpC_82wsMVI,5725
|
|
96
|
-
splat64-0.
|
|
97
|
-
splat64-0.
|
|
98
|
-
splat64-0.
|
|
99
|
-
splat64-0.
|
|
100
|
-
splat64-0.
|
|
97
|
+
splat64-0.33.0.dist-info/METADATA,sha256=5nOsSDJcmC7QQQzzzQGbGFjTCIT_xlq9q2AAgt04PhI,3830
|
|
98
|
+
splat64-0.33.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
99
|
+
splat64-0.33.0.dist-info/entry_points.txt,sha256=O7Xy-qNOHcI87-OQrWJ-OhRDws74SuwVb_4rtnp0eLo,52
|
|
100
|
+
splat64-0.33.0.dist-info/licenses/LICENSE,sha256=97VMVzjG8yQvsf8NG2M9IFSbh7R8cifJnc6QK1cZqj8,1070
|
|
101
|
+
splat64-0.33.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|