mirror of
https://github.com/zeldaret/ph
synced 2026-07-07 21:31:01 -04:00
Remove redundant Python scripts
This commit is contained in:
@@ -1,132 +0,0 @@
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
parser = argparse.ArgumentParser(description='Generates .inc files with external symbols used by Assembly code')
|
||||
parser.add_argument('files', nargs='+', help='.s file to generate .inc file for')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
tools_dir = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
as_path = tools_dir / 'mwccarm' / '2.0' / 'sp1p5' / 'mwasmarm.exe'
|
||||
root_dir = tools_dir.parent
|
||||
asm_dir = root_dir / 'asm'
|
||||
|
||||
MSG_UNKNOWN_IDENTIFIER = 'Unknown identifier,'
|
||||
MSG_DUPLICATE_DECLARATION = 'Incompatible duplicate declaration of'
|
||||
|
||||
if platform.system() == 'Windows': as_cmd = [str(as_path)]
|
||||
else: as_cmd = ['wine', str(as_path)]
|
||||
|
||||
as_cmd.extend([
|
||||
'-nolink',
|
||||
'-proc', 'arm5te',
|
||||
'-msgstyle', 'gcc',
|
||||
'-DEUR', '-DUSA',
|
||||
f'-I{asm_dir}',
|
||||
])
|
||||
|
||||
def get_unknown_symbols(file: Path):
|
||||
with tempfile.NamedTemporaryFile(delete=True) as tmp_obj_file:
|
||||
# Run assembler
|
||||
cmd = as_cmd.copy()
|
||||
cmd.extend(['-o', tmp_obj_file.name])
|
||||
cmd.append(str(file))
|
||||
try:
|
||||
output = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
|
||||
output = output.decode()
|
||||
except subprocess.CalledProcessError as e:
|
||||
output = e.stdout.decode()
|
||||
|
||||
# Get unknown identifiers
|
||||
lines = output.splitlines()
|
||||
symbol = ''
|
||||
symbols: set[str] = set()
|
||||
skip = False
|
||||
for line in lines:
|
||||
# print(line)
|
||||
if ':' not in line: continue
|
||||
line = line.rsplit(':', 1)[-1].strip()
|
||||
if line.startswith(MSG_DUPLICATE_DECLARATION):
|
||||
symbols.add(symbol)
|
||||
skip = True
|
||||
elif line.startswith(MSG_UNKNOWN_IDENTIFIER):
|
||||
symbols.add(symbol)
|
||||
skip = False
|
||||
symbol = line[len(MSG_UNKNOWN_IDENTIFIER):].strip()
|
||||
elif not skip:
|
||||
symbol += line.strip()
|
||||
symbols.add(symbol)
|
||||
if '' in symbols: symbols.remove('')
|
||||
if len(symbols) == 0:
|
||||
return []
|
||||
|
||||
return sorted(list(symbols))
|
||||
|
||||
files_updated = 0
|
||||
inc_files_created = 0
|
||||
|
||||
def generate_externs(file: Path):
|
||||
global inc_files_created
|
||||
|
||||
with tempfile.NamedTemporaryFile('w', suffix='.s', delete=True) as tmp_asm_file:
|
||||
file_name = file.name.rsplit('.', 1)[0]
|
||||
inc_file_name = f'{file_name}.inc'
|
||||
inc_path = file.parent / inc_file_name
|
||||
|
||||
# Comment out '.include ".../my_file.inc"
|
||||
with open(file, 'r') as f:
|
||||
contents = f.read()
|
||||
lines = contents.splitlines()
|
||||
has_inc_file = False
|
||||
for i in range(len(lines)):
|
||||
if not lines[i].strip().startswith('.include'): continue
|
||||
if inc_file_name not in lines[i]: continue
|
||||
lines[i] = f';{lines[i]}'
|
||||
has_inc_file = True
|
||||
break
|
||||
|
||||
# Get unknown symbols
|
||||
for line in lines:
|
||||
tmp_asm_file.write(line)
|
||||
tmp_asm_file.write('\n')
|
||||
tmp_asm_file.flush()
|
||||
symbols = get_unknown_symbols(tmp_asm_file.name)
|
||||
|
||||
# Create inc file
|
||||
with open(inc_path, 'w') as f:
|
||||
f.write('#pragma once\n')
|
||||
for i, symbol in enumerate(symbols):
|
||||
# Skip duplicates
|
||||
if symbol in symbols[:i]: continue
|
||||
f.write(f'.extern {symbol}\n')
|
||||
|
||||
# Add .include
|
||||
if not has_inc_file:
|
||||
relative_inc_path = inc_path.relative_to('asm/')
|
||||
lines.insert(0, f' .include "{relative_inc_path}"')
|
||||
with open(file, 'w') as f:
|
||||
for line in lines:
|
||||
f.write(line)
|
||||
f.write('\n')
|
||||
inc_files_created += 1
|
||||
|
||||
|
||||
for file in args.files:
|
||||
if not file.endswith('.s'): continue
|
||||
path = Path(file)
|
||||
if len(args.files) > 1:
|
||||
print(path)
|
||||
generate_externs(path)
|
||||
files_updated += 1
|
||||
|
||||
if len(args.files) > 1:
|
||||
print(f"Updated {files_updated} file(s)")
|
||||
print(f"Created {inc_files_created} .inc file(s)")
|
||||
-435
@@ -1,435 +0,0 @@
|
||||
class Overlay:
|
||||
def __init__(self, name: str = None, after = None, origin: int = None, objects: list[str] = None):
|
||||
self.name = name
|
||||
self.objects = objects
|
||||
self.after = after
|
||||
self.origin = origin
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def name(path: str): return path.split("/")[-1]
|
||||
|
||||
ARM9_OBJECTS = [
|
||||
'asm/main/main_02000000.s',
|
||||
|
||||
'src/Main/Actor/ActorType.cpp',
|
||||
|
||||
'asm/main/main_0203e8a0.s',
|
||||
|
||||
'libs/cpp/src/__register_global_object.c',
|
||||
|
||||
'asm/main/main_0204f8f4.s',
|
||||
]
|
||||
|
||||
ITCM_OBJECTS = [
|
||||
'asm/itcm.s'
|
||||
]
|
||||
|
||||
DTCM_OBJECTS = [
|
||||
'asm/dtcm.s'
|
||||
]
|
||||
|
||||
ov00 = Overlay(name='ov00', after='ARM9', objects=[
|
||||
'asm/ov00/ov00_020773c0.s',
|
||||
|
||||
'asm/ov00/Player/TouchControl.s',
|
||||
|
||||
'asm/ov00/ov00_0207afa0.s',
|
||||
|
||||
'asm/ov00/Map/Course.s',
|
||||
'asm/ov00/Map/MapBase.s',
|
||||
|
||||
'asm/ov00/ov00_0207da38.s',
|
||||
|
||||
'asm/ov00/Map/MapManager.s',
|
||||
|
||||
'asm/ov00/ov00_02086cd0.s',
|
||||
|
||||
'asm/ov00/Save/AdventureFlags.s',
|
||||
|
||||
'asm/ov00/ov00_020980f4.s',
|
||||
|
||||
'asm/ov00/Player/PlayerBase.s',
|
||||
'asm/ov00/Player/LinkStateBase.s',
|
||||
'asm/ov00/Player/LinkStateMove.s',
|
||||
'asm/ov00/Player/LinkStateFollow.s',
|
||||
'asm/ov00/Player/TouchGesture.s',
|
||||
|
||||
'asm/ov00/ov00_020a8e04.s',
|
||||
|
||||
'asm/ov00/Player/LinkStateInteract.s',
|
||||
'asm/ov00/Player/LinkStateItem.s',
|
||||
'asm/ov00/Player/LinkStateDamage.s',
|
||||
'asm/ov00/Item/Item.s',
|
||||
'src/00_Core/Item/ItemManager.cpp',
|
||||
'asm/ov00/Player/LinkStateRoll.s',
|
||||
'asm/ov00/Player/PlayerControl.s',
|
||||
|
||||
'asm/ov00/ov00_020b1498.s',
|
||||
|
||||
'asm/ov00/Actor/Actor.s',
|
||||
|
||||
'asm/ov00/ov00_020c3348.s',
|
||||
|
||||
'asm/ov00/Actor/ActorManager.s',
|
||||
|
||||
'asm/ov00/ov00_020c3e54.s',
|
||||
])
|
||||
ov01 = Overlay(name='ov01', after=[ov00], objects=[
|
||||
'asm/ov01.s'
|
||||
])
|
||||
ov02 = Overlay(name='ov02', after=[ov00], objects=[
|
||||
'asm/ov02.s'
|
||||
])
|
||||
ov03 = Overlay(name='ov03', after=[ov00], objects=[
|
||||
'asm/ov03.s'
|
||||
])
|
||||
ov04 = Overlay(name='ov04', after=[ov01, ov02, ov03], objects=[
|
||||
'asm/ov04.s'
|
||||
])
|
||||
ov05 = Overlay(name='ov05', after=[ov01, ov02, ov03], objects=[
|
||||
'asm/ov05.s'
|
||||
])
|
||||
ov06 = Overlay(name='ov06', after=[ov01, ov02, ov03], objects=[
|
||||
'asm/ov06.s'
|
||||
])
|
||||
ov07 = Overlay(name='ov07', after=[ov01, ov02, ov03], objects=[
|
||||
'asm/ov07.s'
|
||||
])
|
||||
ov08 = Overlay(name='ov08', after=[ov04, ov05, ov06, ov07], objects=[
|
||||
'asm/ov08.s'
|
||||
])
|
||||
ov09 = Overlay(name='ov09', after=[ov04, ov05, ov06, ov07], objects=[
|
||||
'asm/ov09.s'
|
||||
])
|
||||
ov10 = Overlay(name='ov10', after=[ov04, ov05, ov06, ov07], objects=[
|
||||
'asm/ov10.s'
|
||||
])
|
||||
ov11 = Overlay(name='ov11', after=[ov04, ov05, ov06, ov07], objects=[
|
||||
'asm/ov11.s'
|
||||
])
|
||||
ov12 = Overlay(name='ov12', after=[ov04, ov05, ov06, ov07], objects=[
|
||||
'asm/ov12.s'
|
||||
])
|
||||
ov13 = Overlay(name='ov13', after=[ov04, ov05, ov06, ov07], objects=[
|
||||
'asm/ov13.s'
|
||||
])
|
||||
ov14 = Overlay(name='ov14', after=[ov08, ov09, ov10, ov13], objects=[
|
||||
'asm/ov14/ov14_0211f640.s',
|
||||
|
||||
'asm/ov14/Actor/ActorRupee.s',
|
||||
|
||||
'asm/ov14/ov14_0213b778.s',
|
||||
])
|
||||
ov15 = Overlay(name='ov15', after=[ov08, ov09, ov10, ov13], objects=[
|
||||
'asm/ov15.s'
|
||||
])
|
||||
ov16 = Overlay(name='ov16', after=[ov08, ov09, ov10, ov13], objects=[
|
||||
'asm/ov16.s'
|
||||
])
|
||||
ov17 = Overlay(name='ov17', after=[ov14, ov16], objects=[
|
||||
'asm/ov17.s'
|
||||
])
|
||||
ov18 = Overlay(name='ov18', after=[ov14, ov16], objects=[
|
||||
'asm/ov18.s'
|
||||
])
|
||||
ov19 = Overlay(name='ov19', after=[ov17, ov18], objects=[
|
||||
'asm/ov19.s'
|
||||
])
|
||||
ov20 = Overlay(name='ov20', after=[ov17, ov18], objects=[
|
||||
'asm/ov20.s'
|
||||
])
|
||||
ov21 = Overlay(name='ov21', after=[ov17, ov18], objects=[
|
||||
'asm/ov21.s'
|
||||
])
|
||||
ov22 = Overlay(name='ov22', after=[ov17, ov18], objects=[
|
||||
'asm/ov22.s'
|
||||
])
|
||||
ov23 = Overlay(name='ov23', after=[ov17, ov18], objects=[
|
||||
'asm/ov23.s'
|
||||
])
|
||||
ov24 = Overlay(name='ov24', after=[ov17, ov18], objects=[
|
||||
'asm/ov24.s'
|
||||
])
|
||||
ov25 = Overlay(name='ov25', after=[ov17, ov18], objects=[
|
||||
'asm/ov25.s'
|
||||
])
|
||||
ov26 = Overlay(name='ov26', after=[ov17, ov18], objects=[
|
||||
'asm/ov26.s'
|
||||
])
|
||||
ov27 = Overlay(name='ov27', after=[ov17, ov18], objects=[
|
||||
'asm/ov27.s'
|
||||
])
|
||||
ov28 = Overlay(name='ov28', after=[ov17, ov18], objects=[
|
||||
'asm/ov28.s'
|
||||
])
|
||||
ov29 = Overlay(name='ov29', after=[ov17, ov18], objects=[
|
||||
'asm/ov29.s'
|
||||
])
|
||||
ov30 = Overlay(name='ov30', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov30.s'
|
||||
])
|
||||
ov31 = Overlay(name='ov31', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov31.s'
|
||||
])
|
||||
ov32 = Overlay(name='ov32', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov32.s'
|
||||
])
|
||||
ov33 = Overlay(name='ov33', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov33.s'
|
||||
])
|
||||
ov34 = Overlay(name='ov34', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov34.s'
|
||||
])
|
||||
ov35 = Overlay(name='ov35', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov35.s'
|
||||
])
|
||||
ov36 = Overlay(name='ov36', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov36.s'
|
||||
])
|
||||
ov37 = Overlay(name='ov37', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov37.s'
|
||||
])
|
||||
ov38 = Overlay(name='ov38', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov38.s'
|
||||
])
|
||||
ov39 = Overlay(name='ov39', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov39.s'
|
||||
])
|
||||
ov40 = Overlay(name='ov40', after=[ov19, ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29], objects=[
|
||||
'asm/ov40.s'
|
||||
])
|
||||
ov41 = Overlay(name='ov41', after=[ov30, ov31, ov32, ov33, ov34, ov35, ov36, ov37, ov38, ov39], objects=[
|
||||
'asm/ov41.s'
|
||||
])
|
||||
ov42 = Overlay(name='ov42', after=[ov30, ov31, ov32, ov33, ov34, ov35, ov36, ov37, ov38, ov39], objects=[
|
||||
'asm/ov42.s'
|
||||
])
|
||||
ov43 = Overlay(name='ov43', after=[ov30, ov31, ov32, ov33, ov34, ov35, ov36, ov37, ov38, ov39], objects=[
|
||||
'asm/ov43.s'
|
||||
])
|
||||
ov44 = Overlay(name='ov44', after=[ov30, ov31, ov32, ov33, ov34, ov35, ov36, ov37, ov38, ov39], objects=[
|
||||
'asm/ov44.s'
|
||||
])
|
||||
ov45 = Overlay(name='ov45', after=[ov30, ov31, ov32, ov33, ov34, ov35, ov36, ov37, ov38, ov39], objects=[
|
||||
'asm/ov45.s'
|
||||
])
|
||||
ov46 = Overlay(name='ov46', after=[ov41, ov42, ov43, ov44, ov45], objects=[
|
||||
'asm/ov46.s'
|
||||
])
|
||||
ov47 = Overlay(name='ov47', after=[ov41, ov42, ov43, ov44, ov45], objects=[
|
||||
'asm/ov47.s'
|
||||
])
|
||||
ov48 = Overlay(name='ov48', after=[ov41, ov42, ov43, ov44, ov45], objects=[
|
||||
'asm/ov48.s'
|
||||
])
|
||||
ov49 = Overlay(name='ov49', after=[ov46, ov47, ov48], objects=[
|
||||
'asm/ov49.s'
|
||||
])
|
||||
ov50 = Overlay(name='ov50', after=[ov46, ov47, ov48], objects=[
|
||||
'asm/ov50.s'
|
||||
])
|
||||
ov51 = Overlay(name='ov51', after=[ov46, ov47, ov48], objects=[
|
||||
'asm/ov51.s'
|
||||
])
|
||||
ov52 = Overlay(name='ov52', after=[ov46, ov47, ov48], objects=[
|
||||
'asm/ov52.s'
|
||||
])
|
||||
ov53 = Overlay(name='ov53', after=[ov49, ov50, ov51, ov52], objects=[
|
||||
'asm/ov53.s'
|
||||
])
|
||||
ov54 = Overlay(name='ov54', after=[ov49, ov50, ov51, ov52], objects=[
|
||||
'asm/ov54.s'
|
||||
])
|
||||
ov55 = Overlay(name='ov55', after=[ov49, ov50, ov51, ov52], objects=[
|
||||
'asm/ov55.s'
|
||||
])
|
||||
ov56 = Overlay(name='ov56', after=[ov49, ov50, ov51, ov52], objects=[
|
||||
'asm/ov56.s'
|
||||
])
|
||||
ov57 = Overlay(name='ov57', after=[ov49, ov50, ov51, ov52], objects=[
|
||||
'asm/ov57.s'
|
||||
])
|
||||
ov58 = Overlay(name='ov58', after=[ov49, ov50, ov51, ov52], objects=[
|
||||
'asm/ov58.s'
|
||||
])
|
||||
ov59 = Overlay(name='ov59', after=[ov49, ov50, ov51, ov52], objects=[
|
||||
'asm/ov59.s'
|
||||
])
|
||||
ov60 = Overlay(name='ov60', after=[ov11, ov12], objects=[
|
||||
'asm/ov60.s'
|
||||
])
|
||||
ov61 = Overlay(name='ov61', after=[ov11, ov12], objects=[
|
||||
'asm/ov61.s'
|
||||
])
|
||||
|
||||
OVERLAYS = [
|
||||
ov00, ov01, ov02, ov03, ov04, ov05, ov06, ov07, ov08, ov09,
|
||||
ov10, ov11, ov12, ov13, ov14, ov15, ov16, ov17, ov18, ov19,
|
||||
ov20, ov21, ov22, ov23, ov24, ov25, ov26, ov27, ov28, ov29,
|
||||
ov30, ov31, ov32, ov33, ov34, ov35, ov36, ov37, ov38, ov39,
|
||||
ov40, ov41, ov42, ov43, ov44, ov45, ov46, ov47, ov48, ov49,
|
||||
ov50, ov51, ov52, ov53, ov54, ov55, ov56, ov57, ov58, ov59,
|
||||
ov60, ov61
|
||||
]
|
||||
|
||||
BUILD = 'build/'
|
||||
|
||||
with open(f'{BUILD}arm9_linker_script.lcf', 'w') as file:
|
||||
file.write('MEMORY {\n')
|
||||
file.write(' ARM9 : ORIGIN = 0x2000000 > arm9.bin\n')
|
||||
file.write(' ITCM : ORIGIN = 0x1ff8000 >> arm9.bin\n')
|
||||
file.write(' DTCM : ORIGIN = 0x27e0000 >> arm9.bin\n')
|
||||
file.write(' AUTOLOADS : ORIGIN = 0 >> arm9.bin\n')
|
||||
file.write(' FOOTER : ORIGIN = 0 > arm9_footer.bin\n')
|
||||
file.write(' METADATA : ORIGIN = 0 > arm9_metadata.bin\n')
|
||||
file.write('\n')
|
||||
file.write(' OV_TABLE : ORIGIN = 0 > arm9_ovt.bin\n')
|
||||
file.write('\n')
|
||||
for ov in OVERLAYS:
|
||||
file.write(f' {ov.name} : ORIGIN = ')
|
||||
if ov.origin is not None:
|
||||
file.write(hex(ov.origin))
|
||||
elif type(ov.after) is list:
|
||||
file.write('AFTER(')
|
||||
file.write(','.join(map(str, ov.after)))
|
||||
file.write(')')
|
||||
else:
|
||||
file.write(f'AFTER({str(ov.after)})')
|
||||
|
||||
file.write(f' > overlays/{ov.name}.bin\n')
|
||||
file.write('\n')
|
||||
file.write(' HEAP : ORIGIN = AFTER(ARM9,')
|
||||
file.write(','.join(map(str, OVERLAYS)))
|
||||
file.write(')\n')
|
||||
file.write('}\n')
|
||||
file.write('\n')
|
||||
file.write('SECTIONS {\n')
|
||||
file.write(' .arm9 : {\n')
|
||||
file.write(' gHeap = ADDR(HEAP);\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
for obj in ARM9_OBJECTS: file.write(f' {name(obj)}.o(.text)\n')
|
||||
for obj in ARM9_OBJECTS: file.write(f' {name(obj)}.o(.init)\n')
|
||||
for obj in ARM9_OBJECTS: file.write(f' {name(obj)}.o(.rodata)\n')
|
||||
for obj in ARM9_OBJECTS: file.write(f' {name(obj)}.o(.ctor)\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
for obj in ARM9_OBJECTS: file.write(f' {name(obj)}.o(.data)\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' arm9_bss_start = .;\n')
|
||||
for obj in ARM9_OBJECTS: file.write(f' {name(obj)}.o(.bss)\n')
|
||||
for obj in ARM9_OBJECTS: file.write(f' {name(obj)}.o(.sbss)\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' arm9_bss_end = .;\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' } > ARM9\n')
|
||||
file.write('\n')
|
||||
file.write(' .itcm : {\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' itcm_start = .;\n')
|
||||
for obj in ITCM_OBJECTS: file.write(f' {name(obj)}.o(.text)\n')
|
||||
for obj in ITCM_OBJECTS: file.write(f' {name(obj)}.o(.rodata)\n')
|
||||
file.write(' itcm_end = .;\n')
|
||||
file.write(' itcm_size = itcm_end - itcm_start;\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
for obj in ITCM_OBJECTS: file.write(f' {name(obj)}.o(.bss)\n')
|
||||
for obj in ITCM_OBJECTS: file.write(f' {name(obj)}.o(.sbss)\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' } > ITCM\n')
|
||||
file.write('\n')
|
||||
file.write(' .dtcm : {\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' dtcm_start = .;\n')
|
||||
for obj in DTCM_OBJECTS: file.write(f' {name(obj)}.o(.data)\n')
|
||||
file.write(' dtcm_end = .;\n')
|
||||
file.write(' dtcm_size = dtcm_end - dtcm_start;\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' dtcm_end = .;\n')
|
||||
file.write(' dtcm_aligned_size = dtcm_end - dtcm_start;\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
for obj in DTCM_OBJECTS: file.write(f' {name(obj)}.o(.bss)\n')
|
||||
for obj in DTCM_OBJECTS: file.write(f' {name(obj)}.o(.sbss)\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' } > DTCM\n')
|
||||
file.write('\n')
|
||||
file.write(' .autoloads : {\n')
|
||||
file.write(' autoloads_start = arm9_bss_start + itcm_size + dtcm_size;\n')
|
||||
file.write(' WRITEW ADDR(ITCM); WRITEW itcm_size; WRITEW 0;\n')
|
||||
file.write(' WRITEW ADDR(DTCM); WRITEW dtcm_size; WRITEW 0xec0;\n')
|
||||
file.write(' autoloads_end = . + autoloads_start;\n')
|
||||
file.write(' } > AUTOLOADS\n')
|
||||
file.write('\n')
|
||||
file.write(' .footer : {\n')
|
||||
file.write(' WRITEW 0xdec00621;\n')
|
||||
file.write(' WRITEW spAutoloadBlockInfosStart - ADDR(ARM9);\n')
|
||||
file.write(' WRITEW 0;\n')
|
||||
file.write(' } > FOOTER\n')
|
||||
file.write('\n')
|
||||
file.write(' .metadata : {\n')
|
||||
file.write(' WRITEW AutoloadDoneCallback;\n')
|
||||
file.write(' WRITEW spAutoloadBlockInfosStart - ADDR(ARM9);\n')
|
||||
file.write(' WRITEW Entry;\n')
|
||||
file.write(' WRITEW ADDR(ARM9);\n')
|
||||
file.write(' WRITEW autoloads_start;\n')
|
||||
file.write(' WRITEW autoloads_end;\n')
|
||||
file.write(' WRITEW arm9_bss_start;\n')
|
||||
file.write(' WRITEW arm9_bss_start;\n')
|
||||
file.write(' WRITEW arm9_bss_end;\n')
|
||||
file.write(' } > METADATA\n')
|
||||
file.write('\n')
|
||||
for ov in OVERLAYS:
|
||||
file.write(f' .{ov.name} : ' + '{\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(f' {ov.name}_start = .;\n')
|
||||
for obj in ov.objects: file.write(f' {name(obj)}.o(.text)\n')
|
||||
for obj in ov.objects: file.write(f' {name(obj)}.o(.rodata)\n')
|
||||
for obj in ov.objects: file.write(f' {name(obj)}.o(.init)\n')
|
||||
file.write('\n')
|
||||
file.write(f' {ov.name}_sinit_start = .;\n')
|
||||
for obj in ov.objects: file.write(f' {name(obj)}.o(.ctor)\n')
|
||||
file.write(' WRITEW 0;\n')
|
||||
file.write(f' {ov.name}_sinit_end = .;\n')
|
||||
file.write('\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
for obj in ov.objects: file.write(f' {name(obj)}.o(.data)\n')
|
||||
file.write('\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(f' {ov.name}_end = .;\n')
|
||||
file.write(f' {ov.name}_size = {ov.name}_end - {ov.name}_start;\n')
|
||||
file.write('\n')
|
||||
file.write(f' {ov.name}_bss_start = .;\n')
|
||||
for obj in ov.objects: file.write(f' {name(obj)}.o(.bss)\n')
|
||||
for obj in ov.objects: file.write(f' {name(obj)}.o(.sbss)\n')
|
||||
file.write(f' {ov.name}_bss_end = .;\n')
|
||||
file.write(f' {ov.name}_bss_size = {ov.name}_bss_end - {ov.name}_bss_start;\n')
|
||||
file.write(' . = ALIGN(32);\n')
|
||||
file.write(' } > ' + ov.name + '\n')
|
||||
file.write('\n')
|
||||
file.write(' .arm9_ovt : {\n')
|
||||
for (index, ov) in enumerate(OVERLAYS):
|
||||
file.write(' ')
|
||||
file.write(f'WRITEW {index}; ')
|
||||
file.write(f'WRITEW {ov.name}_start; ')
|
||||
file.write(f'WRITEW {ov.name}_size; ')
|
||||
file.write(f'WRITEW {ov.name}_bss_size; ')
|
||||
file.write(f'WRITEW {ov.name}_sinit_start; ')
|
||||
file.write(f'WRITEW {ov.name}_sinit_end; ')
|
||||
file.write('WRITEW 0; ') # file id will be inserted later
|
||||
file.write('WRITEW 0; ') # compression flags, overlay is compressed later
|
||||
file.write('\n')
|
||||
file.write(' } > OV_TABLE\n')
|
||||
file.write('\n')
|
||||
file.write(' .heap : {\n')
|
||||
file.write(' gHeap = .;\n')
|
||||
file.write(' } > HEAP\n')
|
||||
file.write('}\n')
|
||||
|
||||
with open(f'{BUILD}arm9_objects.txt', 'w') as file:
|
||||
for obj in ARM9_OBJECTS: file.write(f'{obj}.o\n')
|
||||
for obj in ITCM_OBJECTS: file.write(f'{obj}.o\n')
|
||||
for obj in DTCM_OBJECTS: file.write(f'{obj}.o\n')
|
||||
file.write('\n')
|
||||
for ov in OVERLAYS:
|
||||
file.write(f'-og {ov.name},0 -ol {ov.name}\n')
|
||||
for obj in ov.objects: file.write(f' {obj}.o\n')
|
||||
file.write('\n')
|
||||
@@ -1,88 +0,0 @@
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import os
|
||||
import json
|
||||
|
||||
parser = argparse.ArgumentParser(description='Generates objdiff.json for configuring objdiff')
|
||||
parser.add_argument('region', help='Game region, defaults to EUR', default='EUR')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
tools_dir = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
root_dir = tools_dir.parent
|
||||
config_path = root_dir / 'objdiff.json'
|
||||
src_dir = root_dir / 'src'
|
||||
asm_dir = root_dir / 'asm'
|
||||
|
||||
|
||||
def find_asm_path(src_path: Path) -> Path | None:
|
||||
first_dir = src_path.parents[-2]
|
||||
subdirs = src_path.relative_to(first_dir)
|
||||
if first_dir.name == 'Main':
|
||||
asm_dir = 'main'
|
||||
elif first_dir.name == 'ITCM':
|
||||
asm_dir = 'itcm'
|
||||
elif first_dir.name == 'DTCM':
|
||||
asm_dir = 'dtcm'
|
||||
else:
|
||||
try: ov_num = int(first_dir.name[:2], 10)
|
||||
except: return None
|
||||
asm_dir = f'ov{ov_num:02d}'
|
||||
|
||||
file_name, _ = src_path.name.rsplit('.', 1)
|
||||
asm_file = file_name + '.s'
|
||||
asm_path: Path = asm_dir / subdirs.parent / asm_file
|
||||
return asm_path
|
||||
|
||||
|
||||
def get_build_path(path: Path, extension='.o') -> Path:
|
||||
region = args.region.lower()
|
||||
return Path('build') / region / path.parent / (path.name + extension)
|
||||
|
||||
|
||||
config = dict()
|
||||
config["custom_make"] = "make"
|
||||
config["custom_args"] = [
|
||||
"-B",
|
||||
f"REGION={args.region}"
|
||||
]
|
||||
config["build_target"] = True
|
||||
config["watch_patterns"] = [
|
||||
"*.c",
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"*.hpp",
|
||||
"*.s"
|
||||
]
|
||||
config["objects"] = []
|
||||
|
||||
for (root, dirs, files) in os.walk(src_dir):
|
||||
for file in files:
|
||||
if not file.endswith('.cpp') and not file.endswith('.c'): continue
|
||||
src_path = Path(f'{root}/{file}')
|
||||
src_path = src_path.relative_to(src_dir)
|
||||
asm_path = find_asm_path(src_path)
|
||||
src_path = 'src' / src_path
|
||||
|
||||
if asm_path: asm_path = 'asm' / asm_path
|
||||
|
||||
name, _ = str(src_path).rsplit('.', 1)
|
||||
|
||||
obj = dict()
|
||||
obj["name"] = name
|
||||
if asm_path.exists(): obj["target_path"] = str(get_build_path(asm_path))
|
||||
obj["base_path"] = str(get_build_path(src_path))
|
||||
obj["reverse_fn_order"] = False
|
||||
|
||||
scratch = dict()
|
||||
scratch["platform"] = "nds_arm9"
|
||||
scratch["compiler"] = "mwcc_30_131"
|
||||
scratch["ctx_path"] = str(get_build_path(src_path, '.ctx'))
|
||||
scratch["build_ctx"] = True
|
||||
|
||||
obj["scratch"] = scratch
|
||||
|
||||
config["objects"].append(obj)
|
||||
|
||||
with open(config_path, 'w') as f:
|
||||
f.write(json.dumps(config, indent=4))
|
||||
@@ -1,51 +0,0 @@
|
||||
import hashlib
|
||||
import sys
|
||||
|
||||
class Patch:
|
||||
def __init__(self, name: str, version: str, sha1: str, desc: str, offset: int, write: list[int]) -> None:
|
||||
self.name = name
|
||||
self.version = version
|
||||
self.sha1 = sha1
|
||||
self.desc = desc
|
||||
self.offset = offset
|
||||
self.write = write
|
||||
|
||||
VERSION = '1.0'
|
||||
PATCHES = [
|
||||
Patch(
|
||||
'mwasmarm', '2.0/sp1p5', '448cb0c7f1ace4393e9a9562f819f7a9f049be83',
|
||||
'Fix 2-aligned Thumb BLX where ARM call target was off by 1',
|
||||
offset=0x1b45b, write=[0xc2]
|
||||
),
|
||||
]
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print(f'patch_mwcc {VERSION}')
|
||||
print()
|
||||
print(f'Usage: {sys.argv[0]} <exe>')
|
||||
print(' <exe>\tPath to mwasmarm.exe')
|
||||
exit()
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
with open(filename, 'rb', buffering=0) as file:
|
||||
sha1 = hashlib.file_digest(file, 'sha1').hexdigest()
|
||||
file.seek(0, 2)
|
||||
length = file.tell()
|
||||
file.seek(0, 0)
|
||||
file_bytes = bytearray(file.read(length))
|
||||
|
||||
num_patches = 0
|
||||
for patch in PATCHES:
|
||||
if sha1 == patch.sha1:
|
||||
num_patches += 1
|
||||
print(f'{patch.name} version {patch.version}')
|
||||
print(patch.desc)
|
||||
for i in range(len(patch.write)):
|
||||
file_bytes[patch.offset + i] = patch.write[i]
|
||||
print()
|
||||
|
||||
with open(filename, 'wb') as file:
|
||||
file.write(file_bytes)
|
||||
|
||||
print(f'Applied {num_patches} patch(es)')
|
||||
@@ -1,65 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
tools_dir = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
root_dir = tools_dir.parent
|
||||
asm_dir = root_dir / 'asm'
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
def read_lines() -> list[str]:
|
||||
lines: list[str] = []
|
||||
while True:
|
||||
line = sys.stdin.readline().strip()
|
||||
if len(line) == 0: break
|
||||
lines.append(line)
|
||||
return lines
|
||||
|
||||
eprint("Paste the current symbol names (empty line moves on to the next step):")
|
||||
current_names = read_lines()
|
||||
|
||||
eprint("Paste the new symbol names:")
|
||||
new_names = read_lines()
|
||||
|
||||
if len(current_names) != len(new_names):
|
||||
eprint("Error: number of names must match")
|
||||
eprint(f"Received {len(current_names)} current name(s)")
|
||||
eprint(f"Received {len(new_names)} new name(s)")
|
||||
exit(1)
|
||||
|
||||
symbols_to_rename = {current: new for (current, new) in zip(current_names, new_names)}
|
||||
files_updated = 0
|
||||
lines_updated = 0
|
||||
|
||||
def rename_in_file(file: Path):
|
||||
global files_updated, lines_updated
|
||||
with open(file, 'r') as f:
|
||||
contents = f.read()
|
||||
has_symbol = any(contents.find(symbol) >= 0 for symbol in symbols_to_rename.keys())
|
||||
if not has_symbol: return
|
||||
print(f'{file}:')
|
||||
lines = contents.splitlines()
|
||||
for i in range(len(lines)):
|
||||
for current, new in symbols_to_rename.items():
|
||||
if lines[i].find(current) < 0: continue
|
||||
lines[i] = lines[i].replace(current, new)
|
||||
print(f'\t{i + 1}: {lines[i]}')
|
||||
lines_updated += 1
|
||||
print()
|
||||
files_updated += 1
|
||||
with open(file, 'w') as f:
|
||||
for line in lines:
|
||||
f.write(line)
|
||||
f.write('\n')
|
||||
|
||||
|
||||
for (root, dirs, files) in os.walk(asm_dir):
|
||||
for file in files:
|
||||
if not file.endswith('.s') and not file.endswith('.inc'): continue
|
||||
path = Path(f'{root}/{file}')
|
||||
path = path.relative_to(root_dir)
|
||||
rename_in_file(path)
|
||||
|
||||
print(f'Updated {lines_updated} line(s) in {files_updated} file(s)')
|
||||
Reference in New Issue
Block a user