mirror of
https://github.com/zeldaret/af.git
synced 2026-10-02 15:50:23 -04:00
632ff4b2ab
* git subrepo clone (merge) --branch=5da3132606e4fd427a8d72b8428e4f921cd6e56f git@github.com:z64tools/z64compress.git tools/z64compress subrepo: subdir: "tools/z64compress" merged: "5da3132" upstream: origin: "git@github.com:z64tools/z64compress.git" branch: "5da3132606e4fd427a8d72b8428e4f921cd6e56f" commit: "5da3132" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * z64compress_wrapper.py * fixes * dmadata.c * readme * git subrepo pull tools/splat subrepo: subdir: "tools/splat" merged: "01ac556" upstream: origin: "git@github.com:ethteck/splat.git" branch: "master" commit: "01ac556" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * segment_end_before_align: True * Add compressed step to jenkinsfile * TODO * format * remove from boot_variables.h * simplify * Change makefile to match MM
134 lines
4.1 KiB
Python
Executable File
134 lines
4.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# SPDX-FileCopyrightText: © 2023 ZeldaRET
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import itertools
|
|
from pathlib import Path
|
|
import spimdisasm
|
|
import subprocess
|
|
import yaml
|
|
|
|
|
|
QUIET = False
|
|
|
|
def printVerbose(*args, **kwargs):
|
|
if QUIET:
|
|
return
|
|
print(*args, **kwargs)
|
|
|
|
|
|
def ranges(i):
|
|
for _, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
|
|
b = list(b)
|
|
yield b[0][1], b[-1][1]
|
|
|
|
|
|
def getCompressedSegmentIndices(yamlPath: Path):
|
|
printVerbose("Finding compressed segments...")
|
|
with yamlPath.open() as f:
|
|
yamlObj = yaml.load(f, Loader=yaml.SafeLoader)
|
|
|
|
indices = []
|
|
currentIndex = 0
|
|
for segment in yamlObj["segments"]:
|
|
if not isinstance(segment, dict):
|
|
continue
|
|
|
|
notInDma = segment.get("notdma", False)
|
|
if notInDma:
|
|
continue
|
|
|
|
shouldCompress = segment.get("compress", False)
|
|
if shouldCompress:
|
|
indices.append(currentIndex)
|
|
currentIndex += 1
|
|
return list(ranges(indices))
|
|
|
|
|
|
def getDmaStartLen(elfPath: Path) -> tuple[int, int]:
|
|
printVerbose("Retrieving dmadata address...")
|
|
|
|
start = -1
|
|
end = -1
|
|
|
|
elfFile = spimdisasm.elf32.Elf32File(spimdisasm.common.Utils.readFileAsBytearray(elfPath))
|
|
|
|
assert elfFile.symtab is not None, f"Invalid Elf file, it is missing the symtab"
|
|
assert elfFile.strtab is not None, f"Invalid Elf file, it is missing the strtab"
|
|
|
|
for entry in elfFile.symtab:
|
|
symName = elfFile.strtab[entry.name]
|
|
|
|
if "dmadata_ROM_START" == symName:
|
|
start = entry.value
|
|
elif "dmadata_ROM_END" == symName:
|
|
end = entry.value
|
|
|
|
assert start > 0, f"Could not find 'dmadata_ROM_START' in Elf file"
|
|
assert end > 0, f"Could not find 'dmadata_ROM_END' in Elf file"
|
|
|
|
return start, (end - start) // 0x10
|
|
|
|
|
|
def main():
|
|
# Args from command line
|
|
parser = argparse.ArgumentParser(description="Compress ROM")
|
|
|
|
parser.add_argument("in_rom", help="Uncompressed input ROM filename", type=Path)
|
|
parser.add_argument("out_rom", help="Compressed output ROM filename", type=Path)
|
|
parser.add_argument("elf", help="Path to the uncompressed ROM elf file", type=Path)
|
|
parser.add_argument("yaml", help="Path to the yaml file", type=Path)
|
|
parser.add_argument("--cache", help="Cache directory")
|
|
parser.add_argument("--threads", help="Number of threads to run compression on, 0 disables multithreading", type=int, default=0)
|
|
parser.add_argument("--mb", help="compressed ROM size in MB, default is the smallest multiple of 8mb fitting the whole ROM")
|
|
parser.add_argument("--matching", help="matching compression, forfeits some useful optimizations", action="store_true")
|
|
parser.add_argument("--stderr", help="z64compress will write its output messages to stderr instead of stdout", action="store_true")
|
|
|
|
args = parser.parse_args()
|
|
|
|
dmaAddr, dmaLen = getDmaStartLen(args.elf)
|
|
|
|
compressed_ranges = getCompressedSegmentIndices(args.yaml)
|
|
indicesList = []
|
|
for start, end in compressed_ranges:
|
|
if start != end:
|
|
indicesList.append(f"{start}-{end}")
|
|
else:
|
|
indicesList.append(f"{start}")
|
|
|
|
command = f"./tools/z64compress/z64compress "
|
|
command += f"--in {args.in_rom} "
|
|
command += f"--out {args.out_rom} "
|
|
command += f"--codec yaz "
|
|
command += f"--dma 0x{dmaAddr:06X},{dmaLen} "
|
|
command += f"--compress {','.join(indicesList)} "
|
|
|
|
if args.matching:
|
|
command += f"--matching "
|
|
if args.mb is not None:
|
|
command += f"--mb {args.mb} "
|
|
if args.cache:
|
|
command += f"--cache {args.cache} "
|
|
if args.threads > 0:
|
|
command += f"--threads {args.threads} "
|
|
if not args.stderr:
|
|
command += f"--only-stdout "
|
|
|
|
|
|
print(command)
|
|
try:
|
|
subprocess.check_call(command, shell=True)
|
|
except subprocess.CalledProcessError as e:
|
|
# Return the same error code for the wrapper if z64compress fails
|
|
return e.returncode
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
exit(main())
|