mirror of https://github.com/zeldaret/mm.git
81 lines
2.1 KiB
Python
Executable File
81 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# SPDX-FileCopyrightText: © 2024 ZeldaRET
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import ipl3checksum
|
|
from pathlib import Path
|
|
import struct
|
|
from typing import BinaryIO
|
|
|
|
|
|
def round_up(n: int, shift: int) -> int:
|
|
mod = 1 << shift
|
|
return (n + mod - 1) >> shift << shift
|
|
|
|
|
|
def pad_rom(f: BinaryIO, rom_len: int):
|
|
fill_00 = round_up(rom_len, 12)
|
|
fill_FF = round_up(fill_00, 17)
|
|
|
|
f.seek(rom_len)
|
|
|
|
if fill_00 > rom_len:
|
|
f.write(b"\0" * (fill_00 - rom_len))
|
|
if fill_FF > fill_00:
|
|
f.write(b"\xFF" * (fill_FF - fill_00))
|
|
|
|
|
|
def update_checksum(f: BinaryIO, detect: bool):
|
|
rom_bytes = f.read(0x101000)
|
|
assert len(rom_bytes) == 0x101000, "Small ROM?"
|
|
|
|
# Detect CIC
|
|
if detect:
|
|
cicKind = ipl3checksum.detectCIC(rom_bytes)
|
|
if cicKind is None:
|
|
print("Not able to detect CIC, defaulting to 6105")
|
|
cicKind = ipl3checksum.CICKind.CIC_X105
|
|
else:
|
|
cicKind = ipl3checksum.CICKind.CIC_X105
|
|
|
|
# Calculate checksum
|
|
calculatedChecksum = cicKind.calculateChecksum(rom_bytes)
|
|
assert calculatedChecksum is not None, "Not able to calculate checksum"
|
|
|
|
# Write checksum
|
|
checksum_bytes = struct.pack(f">II", calculatedChecksum[0], calculatedChecksum[1])
|
|
f.seek(0x10)
|
|
f.write(checksum_bytes)
|
|
|
|
|
|
def checksummer_main():
|
|
description = "Pads a rom in-place and updates its header checksum"
|
|
parser = argparse.ArgumentParser(description=description)
|
|
|
|
parser.add_argument("rom", help="input rom filename")
|
|
parser.add_argument(
|
|
"-d",
|
|
"--detect",
|
|
action="store_true",
|
|
help="Try to detect the IPL3 binary on the ROM instead of assuming the 6105 is being used. If not able to detect the IPL3 binary then this program will default to 6105",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
rom_path = Path(args.rom)
|
|
detect: bool = args.detect
|
|
|
|
rom_len = rom_path.stat().st_size
|
|
|
|
with rom_path.open("rb+") as f:
|
|
update_checksum(f, detect)
|
|
pad_rom(f, rom_len)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
checksummer_main()
|