From 39ea4c7a86197cf7a4bd244ee55520c0be051c52 Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Mon, 8 Feb 2021 19:57:56 +0900 Subject: [PATCH] git subrepo pull tools/splat subrepo: subdir: "tools/splat" merged: "3a66565988" upstream: origin: "https://github.com/ethteck/splat.git" branch: "master" commit: "3a66565988" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo" commit: "2f68596" --- tools/splat/.gitrepo | 4 +- tools/splat/CHANGELOG.md | 7 + tools/splat/segtypes/n64/bin.py | 3 +- tools/splat/segtypes/n64/code.py | 364 +++++++++++++++-------------- tools/splat/segtypes/n64/header.py | 3 +- tools/splat/segtypes/segment.py | 6 +- tools/splat/split.py | 109 +++++---- 7 files changed, 256 insertions(+), 240 deletions(-) diff --git a/tools/splat/.gitrepo b/tools/splat/.gitrepo index 548fd4514b..1911e298bb 100644 --- a/tools/splat/.gitrepo +++ b/tools/splat/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/ethteck/splat.git branch = master - commit = 7e40c55d56f779521350fa881aa4dbdf30032a8c - parent = 68e927503b880c53ebb03a74030479ca519eb9bc + commit = 3a66565988438d58d8c53449254a49f31ff2817c + parent = e578b7d90ac01d1e3f235fa6ebec09a0ddb5c415 method = merge cmdver = 0.4.3 diff --git a/tools/splat/CHANGELOG.md b/tools/splat/CHANGELOG.md index bf49629f2d..6ae663b00e 100644 --- a/tools/splat/CHANGELOG.md +++ b/tools/splat/CHANGELOG.md @@ -37,3 +37,10 @@ There's also a new option, `create_new_c_files`, which disables the creation of I am also working on adding bss support as well. It should almost be all set, aside from the changes needed in the linker script. **Breaking change**: The `files` field in `code` segments should now be renamed to `subsections`. + +### 0.6.3: More refactoring +**Breaking Change**: The command line args to split.py have changed. Currently, only the config path is now a required argument to splat. The old `rom` and `outdir` parameters are now optional (`--rom`, `--outdir`). Now, you can add rom and out directory paths in the yaml. + +The `out_dir` option specifies a directory relative to the config file. If your config file is in a subdirectory of the main repo, you can set `out_dir: ../`, for example. + +The `target_path` option spcifies a path to the binary file to split, relative to the `out_dir`. If your `baserom.z64` is in the top-level of the repo, you can set `target_path: baserom.z64`, for example. diff --git a/tools/splat/segtypes/n64/bin.py b/tools/splat/segtypes/n64/bin.py index 7b9e831a8f..4420493911 100644 --- a/tools/splat/segtypes/n64/bin.py +++ b/tools/splat/segtypes/n64/bin.py @@ -1,11 +1,12 @@ import os from segtypes.n64.segment import N64Segment from pathlib import Path +from segtypes.segment import Segment class N64SegBin(N64Segment): def split(self, rom_bytes, base_path): - out_dir = self.create_split_dir(base_path, self.options.get("assets_dir", "bin")) + out_dir = Segment.create_split_dir(base_path, self.options.get("assets_dir", "bin")) bin_path = os.path.join(out_dir, self.name + ".bin") Path(bin_path).parent.mkdir(parents=True, exist_ok=True) diff --git a/tools/splat/segtypes/n64/code.py b/tools/splat/segtypes/n64/code.py index 740e620126..c0e565d95a 100644 --- a/tools/splat/segtypes/n64/code.py +++ b/tools/splat/segtypes/n64/code.py @@ -1,9 +1,12 @@ -from typing import get_args from capstone import * from capstone.mips import * from collections import OrderedDict from segtypes.n64.segment import N64Segment +from segtypes.segment import Segment +from segtypes.n64.palette import N64SegPalette +from segtypes.n64.ci4 import N64SegCi4 +import png import os from pathlib import Path, PurePath import re @@ -11,41 +14,13 @@ import sys from util import floats from util.symbol import Symbol - -STRIP_C_COMMENTS_RE = re.compile( - r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', - re.DOTALL | re.MULTILINE -) - -C_FUNC_RE = re.compile( - r"^(static\s+)?[^\s]+\s+([^\s(]+)\(([^;)]*)\)[^;]+?{", - re.MULTILINE -) - double_mnemonics = ["ldc1", "sdc1"] word_mnemonics = ["addiu", "sw", "lw", "jtbl"] float_mnemonics = ["lwc1", "swc1"] short_mnemonics = ["addiu", "lh", "sh", "lhu"] byte_mnemonics = ["lb", "sb", "lbu"] -def strip_c_comments(text): - def replacer(match): - s = match.group(0) - if s.startswith("/"): - return " " - else: - return s - return re.sub(STRIP_C_COMMENTS_RE, replacer, text) - - -def get_funcs_defined_in_c(c_file): - with open(c_file, "r") as f: - text = strip_c_comments(f.read()) - - return set(m.group(2) for m in C_FUNC_RE.finditer(text)) - class Subsegment(): - def __init__(self, start, end, name, type, vram, args): self.rom_start = start self.rom_end = end @@ -104,8 +79,163 @@ class Subsegment(): def should_run(self, options): return self.type in options["modes"] or "all" in options["modes"] + def get_generic_out_path(self, base_path, options): + return os.path.join( + base_path, + self.get_out_subdir(options), + self.name + "." + self.get_ext() + ) + + def split_inner(self, segment, rom_bytes, base_path, generic_out_path): + pass + + def split(self, segment, rom_bytes, base_path): + if self.should_run(segment.options) and not self.name.startswith("."): + self.split_inner(segment, rom_bytes, base_path, self.get_generic_out_path(base_path, segment.options)) + + @staticmethod + def get_subclass(typ): + if typ in ["data", ".data", "rodata", ".rodata"]: + return DataSubsegment + elif typ in ["bss", ".bss"]: + return BssSubsegment + elif typ == "bin": + return BinSubsegment + elif typ in ["c", "asm", "hasm"]: + return CodeSubsegment + elif typ == "palette": + return PaletteSubsegment + else: + return Subsegment + +class CodeSubsegment(Subsegment): + md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN) + md.detail = True + md.skipdata = True + + STRIP_C_COMMENTS_RE = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE + ) + + C_FUNC_RE = re.compile( + r"^(static\s+)?[^\s]+\s+([^\s(]+)\(([^;)]*)\)[^;]+?{", + re.MULTILINE + ) + + def strip_c_comments(text): + def replacer(match): + s = match.group(0) + if s.startswith("/"): + return " " + else: + return s + return re.sub(CodeSubsegment.STRIP_C_COMMENTS_RE, replacer, text) + + @staticmethod + def get_funcs_defined_in_c(c_file): + with open(c_file, "r") as f: + text = CodeSubsegment.strip_c_comments(f.read()) + + return set(m.group(2) for m in CodeSubsegment.C_FUNC_RE.finditer(text)) + + @staticmethod + def get_asm_header(): + ret = [] + + ret.append(".include \"macro.inc\"") + ret.append("") + ret.append("# assembler directives") + ret.append(".set noat # allow manual use of $at") + ret.append(".set noreorder # don't insert nops after branches") + ret.append(".set gp=64 # allow use of 64-bit general purpose registers") + ret.append("") + ret.append(".section .text, \"ax\"") + ret.append("") + + return ret + + def split_inner(self, segment, rom_bytes, base_path, generic_out_path): + if not self.rom_start == self.rom_end: + asm_out_dir = Segment.create_split_dir(base_path, "asm") + + rom_addr = self.rom_start + + insns = [insn for insn in CodeSubsegment.md.disasm(rom_bytes[self.rom_start : self.rom_end], self.vram_start)] + + funcs = segment.process_insns(insns, rom_addr) + + # TODO: someday make func a subclass of symbol and store this disasm info there too + for func in funcs: + segment.get_symbol(func, type="func", create=True, define=True, local_only=True) + + funcs = segment.determine_symbols(funcs) + segment.gather_jumptable_labels(rom_bytes) + funcs_text = segment.add_labels(funcs) + + if self.type == "c": + if os.path.exists(generic_out_path): + defined_funcs = CodeSubsegment.get_funcs_defined_in_c(generic_out_path) + segment.mark_c_funcs_as_defined(defined_funcs) + else: + defined_funcs = set() + + asm_out_dir = Segment.create_split_dir(base_path, os.path.join("asm", "nonmatchings")) + + for func in funcs_text: + func_name = segment.get_symbol(func, type="func", local_only=True).name + + if func_name not in defined_funcs: + segment.create_c_asm_file(funcs_text, func, asm_out_dir, self, func_name) + + if not os.path.exists(generic_out_path) and self.options.get("create_new_c_files", True): + self.create_c_file(funcs_text, self, asm_out_dir, base_path, generic_out_path) + else: + out_lines = self.get_asm_header() + for func in funcs_text: + out_lines.extend(funcs_text[func][0]) + out_lines.append("") + + outpath = Path(os.path.join(asm_out_dir, self.name + ".s")) + outpath.parent.mkdir(parents=True, exist_ok=True) + + with open(outpath, "w", newline="\n") as f: + f.write("\n".join(out_lines)) + +class DataSubsegment(Subsegment): + def split_inner(self, segment, rom_bytes, base_path, generic_out_path): + asm_out_dir = Segment.create_split_dir(base_path, os.path.join("asm", "data")) + + outpath = Path(os.path.join(asm_out_dir, self.name + f".{self.type}.s")) + outpath.parent.mkdir(parents=True, exist_ok=True) + + file_text = segment.disassemble_data(self, rom_bytes) + if file_text: + with open(outpath, "w", newline="\n") as f: + f.write(file_text) + +class BssSubsegment(DataSubsegment): + def __init__(self, start, end, name, type, vram, args): + super().__init__(start, end, name, type, vram, args) + self.size = self.args[0] + self.vram_end = self.vram_start + self.size + +class BinSubsegment(Subsegment): + def split_inner(self, segment, rom_bytes, base_path, generic_out_path): + Path(generic_out_path).parent.mkdir(parents=True, exist_ok=True) + with open(generic_out_path, "wb") as f: + f.write(rom_bytes[self.rom_start : self.rom_end]) + +class PaletteSubsegment(Subsegment): + def split_inner(self, segment, rom_bytes, base_path, generic_out_path): + img_bytes = rom_bytes[self.rom_start : self.rom_end] + + palette = N64SegPalette.parse_palette(img_bytes) + segment.palettes[self.name] = palette class N64SegCode(N64Segment): + palettes = {} + def parse_subsegments(self, segment_yaml): prefix = self.name if self.name.endswith("/") else f"{self.name}_" @@ -141,7 +271,9 @@ class N64SegCode(N64Segment): vram = self.rom_to_ram(start) - ret.append(Subsegment(start, end, name, typ, vram, args)) + subsegment_class = Subsegment.get_subclass(typ) + + ret.append(subsegment_class(start, end, name, typ, vram, args)) prev_start = start return ret @@ -165,6 +297,22 @@ class N64SegCode(N64Segment): def get_default_name(addr): return f"code_{addr:X}" + def get_ld_files(self): + def transform(sub): + subdir = sub.get_out_subdir(self.options) + obj_type = sub.get_ld_obj_type(".text") + ext = sub.get_ext() + + return subdir, f"{sub.name}.{ext}", obj_type, sub.rom_start + + return [transform(file) for file in self.subsegments] + + def get_ld_section_name(self): + path = PurePath(self.name) + name = path.name if path.name != "" else path.parent + + return f"code_{name}" + def retrieve_symbol(self, d, k, t): if k not in d: return None @@ -239,21 +387,6 @@ class N64SegCode(N64Segment): return ret - def get_asm_header(self): - ret = [] - - ret.append(".include \"macro.inc\"") - ret.append("") - ret.append("# assembler directives") - ret.append(".set noat # allow manual use of $at") - ret.append(".set noreorder # don't insert nops after branches") - ret.append(".set gp=64 # allow use of 64-bit general purpose registers") - ret.append("") - ret.append(".section .text, \"ax\"") - ret.append("") - - return ret - def get_gcc_inc_header(self): ret = [] ret.append(".set noat # allow manual use of $at") @@ -276,6 +409,7 @@ class N64SegCode(N64Segment): def process_insns(self, insns, rom_addr): ret = OrderedDict() + func_addr = None func = [] end_func = False labels = [] @@ -781,149 +915,25 @@ class N64SegCode(N64Segment): print(f"Wrote {sub.name} to {c_path}") def split(self, rom_bytes, base_path): - md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN) - md.detail = True - md.skipdata = True - - palettes = {} - for sub in self.subsegments: - if sub.type in ["asm", "hasm", "c"]: - if not sub.should_run(self.options): - continue + sub.split(self, rom_bytes, base_path) - if sub.rom_start == sub.rom_end: - continue - - asm_out_dir = self.create_split_dir(base_path, "asm") - - rom_addr = sub.rom_start - - insns = [insn for insn in md.disasm(rom_bytes[sub.rom_start: sub.rom_end], sub.vram_start)] - - funcs = self.process_insns(insns, rom_addr) - - # TODO: someday make func a subclass of symbol and store this disasm info there too - for func in funcs: - self.get_symbol(func, type="func", create=True, define=True, local_only=True) - - funcs = self.determine_symbols(funcs) - self.gather_jumptable_labels(rom_bytes) - funcs_text = self.add_labels(funcs) - - if sub.type == "c": - c_path = os.path.join( - base_path, - sub.get_out_subdir(self.options), - sub.name + "." + sub.get_ext() - ) - - if os.path.exists(c_path): - defined_funcs = get_funcs_defined_in_c(c_path) - self.mark_c_funcs_as_defined(defined_funcs) - else: - defined_funcs = set() - - asm_out_dir = self.create_split_dir(base_path, os.path.join("asm", "nonmatchings")) - - for func in funcs_text: - func_name = self.get_symbol(func, type="func", local_only=True).name - - if func_name not in defined_funcs: - self.create_c_asm_file(funcs_text, func, asm_out_dir, sub, func_name) - - if not os.path.exists(c_path) and self.options.get("create_new_c_files", True): - self.create_c_file(funcs_text, sub, asm_out_dir, base_path, c_path) - else: - out_lines = self.get_asm_header() - for func in funcs_text: - out_lines.extend(funcs_text[func][0]) - out_lines.append("") - - outpath = Path(os.path.join(asm_out_dir, sub.name + ".s")) - outpath.parent.mkdir(parents=True, exist_ok=True) - - with open(outpath, "w", newline="\n") as f: - f.write("\n".join(out_lines)) - - elif sub.type in ["data", "rodata", "bss"] and sub.should_run(self.options): - asm_out_dir = self.create_split_dir(base_path, os.path.join("asm", "data")) - - outpath = Path(os.path.join(asm_out_dir, sub.name + f".{sub.type}.s")) - outpath.parent.mkdir(parents=True, exist_ok=True) - - file_text = self.disassemble_data(sub, rom_bytes) - if file_text: - with open(outpath, "w", newline="\n") as f: - f.write(file_text) - - elif sub.type == "bin" and sub.should_run(self.options): - bin_path = os.path.join( - base_path, - sub.get_out_subdir(self.options), - sub.name + "." + sub.get_ext() - ) - - Path(bin_path).parent.mkdir(parents=True, exist_ok=True) - with open(bin_path, "wb") as f: - f.write(rom_bytes[sub.rom_start : sub.rom_end]) - - elif sub.type in ["i4", "i8", "ia4", "ia8", "ia16", "rgba16", "rgba32", "ci4", "ci8"]: - pass - - elif sub.type == "palette": - from segtypes.n64.palette import N64SegPalette - - out_path = os.path.join( - base_path, - sub.get_out_subdir(self.options), - sub.name + "." + sub.get_ext() - ) + # TODO hack for images: move at some point + for sub in self.subsegments: + if sub.type == "ci4" and (sub.should_run(self.options) or "img" in self.options["modes"]): + generic_out_path = sub.get_generic_out_path(base_path, self.options) img_bytes = rom_bytes[sub.rom_start : sub.rom_end] - palette = N64SegPalette.parse_palette(img_bytes) - palettes[sub.name] = palette - - import png - - for sub in self.subsegments: - img_bytes = rom_bytes[sub.rom_start : sub.rom_end] - - out_path = os.path.join( - base_path, - sub.get_out_subdir(self.options), - sub.name + "." + sub.get_ext() - ) - - if sub.type == "ci4" and (sub.should_run(self.options) or "img" in self.options["modes"]): - from segtypes.n64.ci4 import N64SegCi4 - width, height = sub.args - palette = palettes[sub.name] + palette = self.palettes[sub.name] image = N64SegCi4.parse_image(img_bytes, width, height) w = png.Writer(width, height, palette=palette) - Path(out_path).parent.mkdir(parents=True, exist_ok=True) - with open(out_path, "wb") as f: + Path(generic_out_path).parent.mkdir(parents=True, exist_ok=True) + with open(generic_out_path, "wb") as f: w.write_array(f, image) # TODO other image types # TODO write orphaned palettes - - def get_ld_files(self): - def transform(sub): - subdir = sub.get_out_subdir(self.options) - obj_type = sub.get_ld_obj_type(".text") - ext = sub.get_ext() - - return subdir, f"{sub.name}.{ext}", obj_type, sub.rom_start - - return [transform(file) for file in self.subsegments] - - def get_ld_section_name(self): - path = PurePath(self.name) - name = path.name if path.name != "" else path.parent - - return f"code_{name}" diff --git a/tools/splat/segtypes/n64/header.py b/tools/splat/segtypes/n64/header.py index 4a4e3919a9..1256aa4dfc 100644 --- a/tools/splat/segtypes/n64/header.py +++ b/tools/splat/segtypes/n64/header.py @@ -1,6 +1,7 @@ import os from segtypes.n64.segment import N64Segment from pathlib import Path +from segtypes.segment import Segment class N64SegHeader(N64Segment): def should_run(self): @@ -18,7 +19,7 @@ class N64SegHeader(N64Segment): return f".{typ} {dstr} /* {comment} */" def split(self, rom_bytes, base_path): - out_dir = self.create_split_dir(base_path, "asm") + out_dir = Segment.create_split_dir(base_path, "asm") encoding = self.options.get("header_encoding", "ASCII") diff --git a/tools/splat/segtypes/segment.py b/tools/splat/segtypes/segment.py index 1516f6a3fa..baf4b1b060 100644 --- a/tools/splat/segtypes/segment.py +++ b/tools/splat/segtypes/segment.py @@ -94,12 +94,14 @@ class Segment: return self.rom_start + ram_addr - self.vram_start - def create_split_dir(self, base_path, subdir): + @staticmethod + def create_split_dir(base_path, subdir): out_dir = Path(base_path, subdir) out_dir.mkdir(parents=True, exist_ok=True) return out_dir - def create_parent_dir(self, base_path, filename): + @staticmethod + def create_parent_dir(base_path, filename): out_dir = Path(base_path, filename).parent out_dir.mkdir(parents=True, exist_ok=True) return out_dir diff --git a/tools/splat/split.py b/tools/splat/split.py index 92bd7ab16a..b582a0f66f 100755 --- a/tools/splat/split.py +++ b/tools/splat/split.py @@ -12,12 +12,13 @@ from segtypes.segment import parse_segment_type from segtypes.n64.code import N64SegCode from util import log from util.symbol import Symbol +import sys parser = argparse.ArgumentParser( description="Split a rom given a rom, a config, and output directory") -parser.add_argument("rom", help="path to a .z64 rom") parser.add_argument("config", help="path to a compatible config .yaml file") -parser.add_argument("outdir", help="a directory in which to extract the rom") +parser.add_argument("--rom", help="path to a .z64 rom") +parser.add_argument("--outdir", help="a directory in which to extract the rom") parser.add_argument("--modes", nargs="+", default="all") parser.add_argument("--verbose", action="store_true", help="Enable debug logging") @@ -133,20 +134,6 @@ def gather_symbols(symbol_addrs_path, undefined_syms_path): rom_addr = int(info.split(":")[1], 0) sym.rom = rom_addr symbols.append(sym) - - # Maybe let's not use this - if os.path.exists(undefined_syms_path): - with open(undefined_syms_path) as f: - us_lines = f.readlines() - - for line in us_lines: - line = line.strip() - if not line == "" and not line.startswith("//"): - line_split = line.split("=") - name = line_split[0].strip() - addr = int(line_split[1].strip()[:-1], 0) - symbols.append(Symbol(addr, given_name=name)) - return symbols @@ -196,11 +183,7 @@ def initialize_segments(options, config_path, config_segments): seen_segment_names = set() ret = [] - for i, segment in enumerate(config_segments): - if len(segment) == 1: - # We're at the end - continue - + for i, segment in enumerate(config_segments[:-1]): seg_type = parse_segment_type(segment) platform = get_platform(options) @@ -266,13 +249,7 @@ def get_segment_symbols(segment, all_symbols, all_segments): return seg_syms, other_syms -def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): - with open(rom_path, "rb") as f: - rom_bytes = f.read() - - # Create main output dir - Path(repo_path).mkdir(parents=True, exist_ok=True) - +def main(config_path, out_dir, target_path, modes, verbose, ignore_cache=False): # Load config with open(config_path) as f: config = yaml.safe_load(f.read()) @@ -281,10 +258,31 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): options["modes"] = modes options["verbose"] = verbose - symbol_addrs_path = get_symbol_addrs_path(repo_path, options) - undefined_syms_path = get_undefined_syms_path(repo_path, options) + if not out_dir: + out_dir = options.get("out_dir", None) + if not out_dir: + print("Error: Output dir not specified as a command line arg or via the config yaml (out_dir)") + sys.exit(2) + else: + out_dir = os.path.join(Path(config_path).parent, out_dir) + + if not target_path: + target_path = options.get("target_path", None) + if not target_path: + print("Error: Target binary path not specified as a command line arg or via the config yaml (target_path)") + sys.exit(2) + else: + target_path = os.path.join(out_dir, target_path) + + with open(target_path, "rb") as f: + rom_bytes = f.read() + + # Create main output dir + Path(out_dir).mkdir(parents=True, exist_ok=True) + + symbol_addrs_path = get_symbol_addrs_path(out_dir, options) + undefined_syms_path = get_undefined_syms_path(out_dir, options) all_symbols = gather_symbols(symbol_addrs_path, undefined_syms_path) - isolated_symbols = {} symbol_ranges = [s for s in all_symbols if s.size > 4] platform = get_platform(options) @@ -296,7 +294,7 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): seg_cached = {} # Load cache - cache_path = get_cache_path(repo_path, options) + cache_path = get_cache_path(out_dir, options) try: with open(cache_path, "rb") as f: cache = pickle.load(f) @@ -316,15 +314,15 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): segment.check() - tp = segment.type + typ = segment.type if segment.type == "bin" and segment.is_name_default(): - tp = "unk" + typ = "unk" - if tp not in seg_sizes: - seg_sizes[tp] = 0 - seg_split[tp] = 0 - seg_cached[tp] = 0 - seg_sizes[tp] += segment.size + if typ not in seg_sizes: + seg_sizes[typ] = 0 + seg_split[typ] = 0 + seg_cached[typ] = 0 + seg_sizes[typ] += segment.size if len(segment.errors) == 0: if segment.should_run(): @@ -332,18 +330,18 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): cached = segment.cache() if not ignore_cache and cached == cache.get(segment.unique_id()): # Cache hit - seg_cached[tp] += 1 + seg_cached[typ] += 1 else: # Cache miss; split cache[segment.unique_id()] = cached segment.did_run = True - segment.split(rom_bytes, repo_path) + segment.split(rom_bytes, out_dir) if len(segment.errors) == 0: processed_segments.append(segment) - seg_split[tp] += 1 + seg_split[typ] += 1 log.dot(status=segment.status()) ld_sections.append(segment.get_ld_section()) @@ -356,15 +354,13 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): if "ld" in options["modes"] or "all" in options["modes"]: if verbose: log.write(f"saving {config['basename']}.ld") - write_ldscript(config['basename'], repo_path, ld_sections, options) + write_ldscript(config['basename'], out_dir, ld_sections, options) undefined_syms_to_write = [s for s in all_symbols if s.referenced and not s.defined and not s.type == "func"] undefined_funcs_to_write = [s for s in all_symbols if s.referenced and not s.defined and s.type == "func"] # Write undefined_funcs_auto.txt - undefined_funcs_auto_path = get_undefined_funcs_auto_path(repo_path, options) - if verbose: - log.write(f"saving {undefined_funcs_auto_path}") + undefined_funcs_auto_path = get_undefined_funcs_auto_path(out_dir, options) to_write = undefined_funcs_to_write if len(to_write) > 0: @@ -373,9 +369,8 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") # write undefined_syms_auto.txt - undefined_syms_auto_path = get_undefined_syms_auto_path(repo_path, options) - if verbose: - log.write(f"saving {undefined_syms_auto_path}") + undefined_syms_auto_path = get_undefined_syms_auto_path(out_dir, options) + to_write = undefined_syms_to_write if len(to_write) > 0: with open(undefined_syms_auto_path, "w", newline="\n") as f: @@ -397,9 +392,9 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): rest_size = 0 total_size = len(rom_bytes) - for tp in seg_sizes: - if tp != "unk": - rest_size += seg_sizes[tp] + for typ in seg_sizes: + if typ != "unk": + rest_size += seg_sizes[typ] assert(unk_size + rest_size == total_size) @@ -407,11 +402,11 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): unk_ratio = unk_size / total_size log.write(f"Split {fmt_size(rest_size)} ({known_ratio:.2%}) in defined segments") - for tp in seg_sizes: - if tp != "unk": - tmp_size = seg_sizes[tp] + for typ in seg_sizes: + if typ != "unk": + tmp_size = seg_sizes[typ] tmp_ratio = tmp_size / total_size - log.write(f"{tp:>20}: {fmt_size(tmp_size):>8} ({tmp_ratio:.2%}) {Fore.GREEN}{seg_split[tp]} split{Style.RESET_ALL}, {Style.DIM}{seg_cached[tp]} cached") + log.write(f"{typ:>20}: {fmt_size(tmp_size):>8} ({tmp_ratio:.2%}) {Fore.GREEN}{seg_split[typ]} split{Style.RESET_ALL}, {Style.DIM}{seg_cached[typ]} cached") log.write(f"{'unknown':>20}: {fmt_size(unk_size):>8} ({unk_ratio:.2%}) from unknown bin files") # Save cache @@ -425,5 +420,5 @@ def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): if __name__ == "__main__": args = parser.parse_args() - error_code = main(args.rom, args.config, args.outdir, args.modes, args.verbose, not args.new) + error_code = main(args.config, args.outdir, args.rom, args.modes, args.verbose, not args.new) exit(error_code)