mirror of
https://github.com/zeldaret/mm.git
synced 2024-11-24 05:19:53 +00:00
7743e5a2c4
* wip * fix * add disassembler * Disasm builds OK * Variable addends * More wip * Rodata migration implemented * Cleanup old tools * Try fix submodule -> subrepo merge * git subrepo pull --force --remote=https://github.com/zeldaret/ZAPD.git tools/ZAPD subrepo: subdir: "tools/ZAPD" merged: "602e609" upstream: origin: "https://github.com/zeldaret/ZAPD.git" branch: "master" commit: "602e609" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo" commit: "2f68596" * Builds again but assets are totally broken * git subrepo pull --force tools/asm-processor subrepo: subdir: "tools/asm-processor" merged: "1ffdb08a" upstream: origin: "https://github.com/simonlindholm/asm-processor.git" branch: "master" commit: "1ffdb08a" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo" commit: "2f68596" * More cleanup, move functions.txt and variables.txt to tools/disasm and rm tables * rm z64compress in preparation for subrepo * git subrepo clone (merge) https://github.com/z64me/z64compress.git tools/z64compress subrepo: subdir: "tools/z64compress" merged: "eb11085c" upstream: origin: "https://github.com/z64me/z64compress.git" branch: "main" commit: "eb11085c" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo" commit: "2f68596" * Fix asset extraction * Fix diff-init make rule * Split code bss * Split assumed linker bug padding from assembly files * add filelists for mm.us.rev1 * Maybe working, but I'm not sure * add overlays to spec * Add rodata to actos * Everything compiles * Make a lot of C files for code * Add almost every file in code to spec * whoops * 3 code files left * add scenes to spec * More progress on progress.py * Fix skelanime in spec * audio files! * Fix merge issues * Fix some C files in code * Fix remaining code files * Use existing O1 C files in spec * reorder boot order in spec * update spec * fault.c * Convert relocs on completed actors, fixbaserom uses current rom name * more boot files * Add VT macros and script * finish already existing boot files * most of libultra * fix 64bits libultra files * Use C files for libultra, wrap some functions in NON_MATCHING * Remove duplicate of OS_CLOCK_RATE from fault.c * C files for fbdemos * delete dumb files * bootstrap C files, still need to add them to the spec * update fixbaserom * boot OK? * I forgot to commit the spec * C for gamestates * C for kaleido * Change all includes to "" * copy actor sizes script from oot * I forgot to delete those files * Basic C files for effects * Add effects initvars names * Remove mislabelled boot functions from header/txt * Begin porting bootstrap_fx, some sizes * Fix <> * Fix enum * Fix diff.py * fix libultra stuff * update regconvert * update setup warnings * add some missing ; * Fix some makefile stuff and other fixes on some non_matching functions * add executable flag in extract_baserom and fixbaserom * fix relative path * copy assist from oot * fix map path * another assist path fix * Delete C files for handwritten files * add code_801A51F0 to spec * add gfxbuffers to spec * Move rodata to top of each file when possible * UNK_TYPEs for func_801A51F0 * Remove kaleido rodata from spec * Update spec and undefined_syms for recent merge * GCC warnings and fix errors in nonmatchings, * round percentage numbers * progress script: format changes * progress: error on non-existing files * fix warning in z_scene_table * Match 2 nonmatchings in z_actor * Warnings in lightswitch and invadepoh * Fix warning in z_actor_dlftbls * I though I fixed this one * whoops * Comment out CC_CHECK * Removed redundant ultra64.h includes * Update asm_processor, sorted boot_O1 into other folders, completed the fbdemo bootstrap, cleaned up undefined_syms * Completed gamestates bootstrap * Split kaleido_scope * Remove section.h and segment.h, move keep object externs to a common location in variables.h * Completed effects bootstrap * Segmented address externs for effects, fbdemos, gamestates and kaleido * Move actor data externs out of the if 0 * Segmented address externs for actors * Prepare actionfunc detection * fix script, how did it even work before * Fix actionfunc script again, re-introduce some more intermediate prints to the disassembler * Automated actionFunc detection in actors * Segmented addresses from player .text * rm old segment addrs script and fix build * Move sizes folder to tools * Make build.py executable * New Jenkinsfile Prayge * Remove numpy dependencies * Add warnings_disasm_current.txt * my bad * Update spec and undefined_syms * Add z_eff_ss_hahen to pametfrog * git subrepo pull (merge) --force tools/z64compress subrepo: subdir: "tools/z64compress" merged: "163ca2af" upstream: origin: "https://github.com/z64me/z64compress.git" branch: "main" commit: "163ca2af" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo" commit: "2f68596" * Make z64compress print to stdout * sneeky commit to update warnings tooling * test * Another test * Mark fixing overlay reloc generating as a TODO * Update warnings stuff * Communicate the return code from running z64compress back to the Makefile through the wrapper * Run formatter, remove extra commented copy of function * Re-fix some includes * Convert atan to hex to conform to decided style * Some tidying up, remove c for fp and the other two handwritten code files * BSS in z_collision_check & z_scene_proc * add static back in * Fix timerintr bss, add file to spec, some cleanup * Remove externs * Newline * Readd enums * Typo * Colours * Comments for hitmark enum values Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com> * Improvements and suggestions * Organize and remove unused imports and use env for python3 scripts, delete unused overlay.py Co-authored-by: angie <angheloalf95@gmail.com> Co-authored-by: Elliptic Ellipsis <elliptic.ellipsis@gmail.com> Co-authored-by: engineer124 <engineer124engineer124@gmail.com> Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com>
205 lines
6.4 KiB
Python
Executable File
205 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import hashlib, io, struct, sys
|
|
from os import path
|
|
|
|
from libyaz0 import decompress
|
|
|
|
UNCOMPRESSED_SIZE = 0x2F00000
|
|
|
|
def as_word(b, off=0):
|
|
return struct.unpack(">I", b[off:off+4])[0]
|
|
|
|
def as_word_list(b):
|
|
return [i[0] for i in struct.iter_unpack(">I", b)]
|
|
|
|
def calc_crc(rom_data, cic_type):
|
|
start = 0x1000
|
|
end = 0x101000
|
|
|
|
unsigned_long = lambda i: i & 0xFFFFFFFF
|
|
rol = lambda i, b: unsigned_long(i << b) | (i >> (-b & 0x1F))
|
|
|
|
if cic_type == 6101 or cic_type == 6102:
|
|
seed = 0xF8CA4DDC
|
|
elif cic_type == 6103:
|
|
seed = 0xA3886759
|
|
elif cic_type == 6105:
|
|
seed = 0xDF26F436
|
|
elif cic_type == 6106:
|
|
seed = 0x1FEA617A
|
|
else:
|
|
assert False , f"Unknown cic type: {cic_type}"
|
|
|
|
t1 = t2 = t3 = t4 = t5 = t6 = seed
|
|
|
|
for pos in range(start, end, 4):
|
|
d = as_word(rom_data, pos)
|
|
r = rol(d, d & 0x1F)
|
|
|
|
t6d = unsigned_long(t6 + d)
|
|
if t6d < t6:
|
|
t4 = unsigned_long(t4 + 1)
|
|
t6 = t6d
|
|
t3 ^= d
|
|
t5 = unsigned_long(t5 + r)
|
|
|
|
if t2 > d:
|
|
t2 ^= r
|
|
else:
|
|
t2 ^= t6 ^ d
|
|
|
|
if cic_type == 6105:
|
|
t1 = unsigned_long(t1 + (as_word(rom_data, 0x0750 + (pos & 0xFF)) ^ d))
|
|
else:
|
|
t1 = unsigned_long(t1 + (t5 ^ d))
|
|
|
|
chksum = [0,0]
|
|
|
|
if cic_type == 6103:
|
|
chksum[0] = unsigned_long((t6 ^ t4) + t3)
|
|
chksum[1] = unsigned_long((t5 ^ t2) + t1)
|
|
elif cic_type == 6106:
|
|
chksum[0] = unsigned_long((t6 * t4) + t3)
|
|
chksum[1] = unsigned_long((t5 * t2) + t1)
|
|
else:
|
|
chksum[0] = t6 ^ t4 ^ t3
|
|
chksum[1] = t5 ^ t2 ^ t1
|
|
|
|
return struct.pack(">II", chksum[0], chksum[1])
|
|
|
|
def read_dmadata_entry(addr):
|
|
return as_word_list(fileContent[addr:addr+0x10])
|
|
|
|
def read_dmadata(start):
|
|
dmadata = []
|
|
addr = start
|
|
entry = read_dmadata_entry(addr)
|
|
i = 0
|
|
while any([e != 0 for e in entry]):
|
|
# print(f"0x{addr:08X} " + str([f"{e:08X}" for e in entry]))
|
|
dmadata.append(entry)
|
|
addr += 0x10
|
|
i += 1
|
|
entry = read_dmadata_entry(addr)
|
|
# print(f"0x{addr:08X} " + str([f"{e:08X}" for e in entry]))
|
|
return dmadata
|
|
|
|
def update_crc(decompressed):
|
|
print("Recalculating crc...")
|
|
new_crc = calc_crc(decompressed.getbuffer(), 6105)
|
|
|
|
decompressed.seek(0x10)
|
|
decompressed.write(new_crc)
|
|
return decompressed
|
|
|
|
def decompress_rom(dmadata_addr, dmadata):
|
|
rom_segments = {} # vrom start : data s.t. len(data) == vrom_end - vrom_start
|
|
new_dmadata = bytearray() # new dmadata: {vrom start , vrom end , vrom start , 0}
|
|
|
|
decompressed = io.BytesIO(b"")
|
|
|
|
for v_start, v_end, p_start, p_end in dmadata:
|
|
if p_start == 0xFFFFFFFF and p_end == 0xFFFFFFFF:
|
|
new_dmadata.extend(struct.pack(">IIII", v_start, v_end, p_start, p_end))
|
|
continue
|
|
if p_end == 0: # uncompressed
|
|
rom_segments.update({v_start : fileContent[p_start:p_start + v_end - v_start]})
|
|
else: # compressed
|
|
rom_segments.update({v_start : decompress(fileContent[p_start:p_end])})
|
|
new_dmadata.extend(struct.pack(">IIII", v_start, v_end, v_start, 0))
|
|
|
|
# write rom segments to vaddrs
|
|
for vrom_st,data in rom_segments.items():
|
|
decompressed.seek(vrom_st)
|
|
decompressed.write(data)
|
|
# write new dmadata
|
|
decompressed.seek(dmadata_addr)
|
|
decompressed.write(new_dmadata)
|
|
# pad to size
|
|
decompressed.seek(UNCOMPRESSED_SIZE-1)
|
|
decompressed.write(bytearray([0]))
|
|
# re-calculate crc
|
|
return update_crc(decompressed)
|
|
|
|
correct_str_hash = "f46493eaa0628827dbd6ad3ecd8d65d6"
|
|
|
|
def get_str_hash(byte_array):
|
|
return str(hashlib.md5(byte_array).hexdigest())
|
|
|
|
# If the baserom exists and is correct, we don't need to change anything
|
|
if path.exists("baserom_uncompressed.z64"):
|
|
with open("baserom_uncompressed.z64", mode="rb") as file:
|
|
fileContent = bytearray(file.read())
|
|
if get_str_hash(fileContent) == correct_str_hash:
|
|
print("Found valid baserom - exiting early")
|
|
sys.exit(0)
|
|
|
|
# Determine if we have a ROM file
|
|
romFileName = ""
|
|
if path.exists("baserom.mm.us.rev1.z64"):
|
|
romFileName = "baserom.mm.us.rev1.z64"
|
|
elif path.exists("baserom.mm.us.rev1.n64"):
|
|
romFileName = "baserom.mm.us.rev1.n64"
|
|
elif path.exists("baserom.mm.us.rev1.v64"):
|
|
romFileName = "baserom.mm.us.rev1.v64"
|
|
else:
|
|
print("Error: Could not find baserom.mm.us.rev1.z64/baserom.mm.us.rev1.n64/baserom.mm.us.rev1.v64.")
|
|
sys.exit(1)
|
|
|
|
# Read in the original ROM
|
|
print("File '" + romFileName + "' found.")
|
|
with open(romFileName, mode="rb") as file:
|
|
fileContent = bytearray(file.read())
|
|
|
|
fileContentLen = len(fileContent)
|
|
|
|
# Check if ROM needs to be byte/word swapped
|
|
# Little-endian
|
|
if fileContent[0] == 0x40:
|
|
# Word Swap ROM
|
|
print("ROM needs to be word swapped...")
|
|
words = str(int(fileContentLen/4))
|
|
little_byte_format = "<" + words + "I"
|
|
big_byte_format = ">" + words + "I"
|
|
tmp = struct.unpack_from(little_byte_format, fileContent, 0)
|
|
struct.pack_into(big_byte_format, fileContent, 0, *tmp)
|
|
|
|
print("Word swapping done.")
|
|
|
|
# Byte-swapped
|
|
elif fileContent[0] == 0x37:
|
|
# Byte Swap ROM
|
|
print("ROM needs to be byte swapped...")
|
|
halfwords = str(int(fileContentLen/2))
|
|
little_byte_format = "<" + halfwords + "H"
|
|
big_byte_format = ">" + halfwords + "H"
|
|
tmp = struct.unpack_from(little_byte_format, fileContent, 0)
|
|
struct.pack_into(big_byte_format, fileContent, 0, *tmp)
|
|
|
|
print("Byte swapping done.")
|
|
|
|
# Decompress
|
|
FILE_TABLE_OFFSET = 0x1A500 # 0x1C110 for JP1.0, 0x1C050 for JP1.1, 0x24F60 for debug
|
|
if any([b != 0 for b in fileContent[FILE_TABLE_OFFSET + 0x9C:FILE_TABLE_OFFSET + 0x9C + 0x4]]):
|
|
print("Decompressing rom...")
|
|
fileContent = decompress_rom(FILE_TABLE_OFFSET, read_dmadata(FILE_TABLE_OFFSET)).getbuffer()
|
|
|
|
# FF Padding (TODO is there an automatic way we can find where to start padding from? Largest dmadata file end maybe?)
|
|
for i in range(0x2EE8000,UNCOMPRESSED_SIZE):
|
|
fileContent[i] = 0xFF
|
|
|
|
# Check to see if the ROM is a "vanilla" ROM
|
|
str_hash = get_str_hash(bytearray(fileContent))
|
|
if str_hash != correct_str_hash:
|
|
print("Error: Expected a hash of " + correct_str_hash + " but got " + str_hash + ". " +
|
|
"The baserom has probably been tampered, find a new one")
|
|
sys.exit(1)
|
|
|
|
# Write out our new ROM
|
|
print("Writing new ROM 'baserom_uncompressed.z64'.")
|
|
with open("baserom_uncompressed.z64", "wb") as file:
|
|
file.write(bytes(fileContent))
|
|
|
|
print("Done!")
|