mirror of
https://github.com/odiecay/chronicle-ps4.git
synced 2026-10-29 04:02:28 +01:00
* Name the discs by region and put every build input and output under a region directory The disc images are rom/Dark Cloud (NTSC).iso and rom/Dark Cloud (PAL).iso; each region's checksums and extracted files live under rom/ntsc and rom/pal. scripts/build/region.py turns REGION (NTSC by default, or PAL) into the paths every script and CMake use: config/<region> holds the split configuration, symbol lists, fixups and linker script, splat writes asm/<region>, and CMake builds into build/<region>. The overlay headers and pads are splat pad segments, so no assets/ tree is written, and the unused config/reference_asm and reference_asm.py are gone. overlay_private.sh places a private-repository file still kept under rom/extracted/ in rom/ntsc/extracted/. * Carry PR 40's PAL source differences; NTSC unchanged The PAL prototype's small divergences sit inline under #ifdef PAL in 30 units; common.h gains the per-region screen geometry and GS Y offset, clsmes.hpp the message window width and ClsMes size. The twenty PAL-only functions stand as stubs at their retail positions, dataread's four tree-building functions are NTSC-only, and PAL compiler-state pragma blocks sit beside NTSC's. config/pal/splice.txt lists the 213 functions whose PAL bytes are not yet expressed in C. Every unit compiles with -DPAL; every NTSC object is byte-identical. Co-authored-by: Alessandro Suha <plarpoon@zandark.eu> * Generate the PAL split configuration from NTSC's scripts/build/splat_config.py writes a release's symbol lists from its own executable and carries NTSC's yaml, linker script and object fixups over to another release by symbol and relocation pairing: the overlay entry points by the retail name they note, _gp from .reginfo, @ORDER comments and the dun text start, and function-local statics through the function that owns them. The carried files are written once and maintained by hand; --check compares the symbol lists and, on NTSC, proves the carry is the identity. region.paths() names any release's files. config/pal holds the PAL prototype's yaml, symbol lists, linker script, fixups and expression-node overrides. NTSC unchanged. Co-authored-by: Alessandro Suha <plarpoon@zandark.eu> * Supply the PAL prototype's undecompiled functions from INCLUDE_ASM markers Each PAL function not yet in C is `#ifdef PAL INCLUDE_ASM("asm/pal/nonmatchings/ <unit>", <symbol>)` beside its NTSC body (207 markers); include_asm.h and the mwccgap marker path are back for PAL, with the name counter pinned where a marker stands so later compiler constants keep their names. PAL-differing data is C under #ifdef PAL in the owning units. datacheck.py reads a relocation's target section from the REL entry's info field. docs/PAL.md describes the PAL build. NTSC is byte-identical; PAL links with 120 functions and 2 data bytes still to reconcile. Co-authored-by: Alessandro Suha <plarpoon@zandark.eu> * Carry PR 40's PAL data and layout; every PAL image verifies The PAL linker script places EditGaijiTbl at 0x0025f02c, aligns _dun_end to 128, drops dngmessageman's small-data line (PAL's LanguageStr is in hitvalue.cpp) and aligns editmapscript's .sbss to 16 over retail's unnamed pad at 0x002a9f3c. title/op_c loads the Chara__3 entries NTSC does in OpC_InitProcess2/5; battlemenu loads wepstatus and reloads DrawAallWeapon's textures from BtlMenuExtBlock under PAL. datacheck.py resolves retail's name__N spellings (Names), scores each voted anchor on its own layout and resolves a pointer word by its exact name. PAL: SCUS_971.11 3048 perfect / 154 asm, TITLE.BIN 126 / 44, DUN.BIN 52 / 9, data perfect. NTSC unchanged. Co-authored-by: Alessandro Suha <plarpoon@zandark.eu> * PAL: 29 main-executable functions in C from PR 40; NTSC unchanged battle_globals, battlemenu (9), memcard (2), menu_dungeon, shot_freefuncs, clsmes, dataread (2), edit, editloop, fireomni, frame, mglib, texture (3), stockitem, chararead, dungeonmap and spritetable express their PAL differences under #ifdef PAL instead of INCLUDE_ASM markers; editloop's PAL argument-flag indices follow. mglib.hpp declares PAL's mgTopVRAM and mgZBufferAdr. Co-authored-by: Alessandro Suha <plarpoon@zandark.eu> * PAL: 10 title-overlay functions in C from PR 40; NTSC unchanged op_a (2), op_b, op_c (2), op_d, opening, rushmovi (2) and title express their PAL differences under #ifdef PAL. A string retail shares with a function still supplied by a marker is reached through PAL_POOLED, so the compiled function does not emit a second copy. Co-authored-by: Alessandro Suha <plarpoon@zandark.eu> * PAL: dun, gamepad, eastking, menu_draw and collisiondata functions in C from PR 40 dun/gameloop (2), gamepad (3), eastking (2), menu_draw (2) and collisiondata express their PAL differences under #ifdef PAL; dun/gameloop takes PR 40's PAL argument-flag block, InitEastKingEvent returns int under PAL, and the PAL expression-node overrides carry PR 40's five entries. The PAL fixups follow every unit's renumbered statics. All three PAL images verify with 158 functions still supplied by markers; NTSC unchanged. Co-authored-by: Alessandro Suha <plarpoon@zandark.eu> * Make decompile.sh's m2c context parse again m2ctx.py spells a C++ template-id as a plain identifier, and now declares each one it spells as an opaque struct, so CDataAlloc<1, 1690000> no longer breaks m2c's C parser. decompile.sh generates a missing context with the container's venv Python, which has libclang's bindings. * Work on the PAL version --------- Co-authored-by: Alessandro Suha <plarpoon@zandark.eu>
141 lines
4.7 KiB
Python
141 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Create a decomp.me scratch for one function.
|
|
|
|
decompme.py <symbol> [main|title|dun]
|
|
|
|
Posts what https://decomp.me/new would: the function's reference disassembly as
|
|
the target, build/ctx.cpp as the context, and this project's compiler and flags
|
|
plus -lang=c++. decomp.me assembles with the same binutils and a prelude that
|
|
already defines glabel/alabel/jlabel, so the dumps go over nearly as they are.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import ref_index # noqa: E402 (needs the script's own directory on the path)
|
|
|
|
API = "https://decomp.me/api/scratch"
|
|
SCRATCH_URL = "https://decomp.me/scratch/%s"
|
|
|
|
# mwcc 2.3.3 is what this project builds with; see the top of the README.
|
|
COMPILER = "mwcps2-2.3.3-000906"
|
|
PLATFORM = "ps2"
|
|
|
|
# The C++ amalgamation, not the C rendering: decomp.me compiles the context
|
|
# with mwcc rather than parsing it, so it wants the project's own language.
|
|
# ctx.c is the one m2c reads; see scripts/diff/m2ctx.py.
|
|
CTX = "build/ntsc/ctx.cpp"
|
|
FLAGS = "build/ntsc/compiler_flags.txt"
|
|
|
|
# mwcc infers the language from the file extension, and decomp.me names the
|
|
# scratch's source after the platform rather than after this project, so the
|
|
# language has to be stated. Without it the C++ context is parsed as C.
|
|
EXTRA_FLAGS = ["-lang=c++"]
|
|
|
|
# decomp.me's own cc line already passes these, and the include paths point at
|
|
# a tree it does not have -- the context is what stands in for the headers.
|
|
DROP_FLAGS = {"-c", "-nostdinc", "-stderr"}
|
|
DROP_FLAGS_WITH_ARG = {"-i", "-I"}
|
|
|
|
|
|
def compiler_flags():
|
|
"""This build's mwcc flags, less the ones decomp.me supplies or cannot use."""
|
|
with open(FLAGS, encoding="utf-8") as f:
|
|
raw = f.read().split()
|
|
|
|
out = []
|
|
skip = False
|
|
for flag in raw:
|
|
if skip:
|
|
skip = False
|
|
continue
|
|
if flag in DROP_FLAGS_WITH_ARG:
|
|
skip = True
|
|
continue
|
|
if flag in DROP_FLAGS:
|
|
continue
|
|
out.append(flag)
|
|
return " ".join(out + EXTRA_FLAGS)
|
|
|
|
|
|
def prepare_asm(path):
|
|
"""The dump as decomp.me wants it.
|
|
|
|
Only the `.include "macro.inc"` has to go: that resolves against this
|
|
tree, and decomp.me prepends its own prelude defining the same macros.
|
|
"""
|
|
with open(path, encoding="utf-8") as f:
|
|
lines = f.read().splitlines()
|
|
return "\n".join(l for l in lines if not l.strip().startswith(".include")) + "\n"
|
|
|
|
|
|
def create(symbol, section=None):
|
|
for path, what in ((CTX, "C++ context"), (FLAGS, "compiler flags")):
|
|
if not os.path.exists(path):
|
|
raise SystemExit(
|
|
"decompme: %s is missing (the %s).\n"
|
|
" Build first: cmake --build build" % (path, what))
|
|
|
|
located = ref_index.lookup(symbol, section)
|
|
if located is None:
|
|
raise SystemExit("decompme: %s is in no reference index" % symbol)
|
|
|
|
with open(CTX, encoding="utf-8") as f:
|
|
context = f.read()
|
|
|
|
payload = {
|
|
"name": symbol,
|
|
"compiler": COMPILER,
|
|
"platform": PLATFORM,
|
|
"compiler_flags": compiler_flags(),
|
|
"context": context,
|
|
"source_code": "// %s\n// Paste an attempt here, or start from decompile.sh.\n" % symbol,
|
|
"diff_label": symbol,
|
|
"target_asm": prepare_asm(located.source),
|
|
}
|
|
|
|
req = urllib.request.Request(
|
|
API,
|
|
data=json.dumps(payload).encode("utf-8"),
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
# decomp.me sits behind Cloudflare, which rejects the default
|
|
# urllib agent outright.
|
|
"User-Agent": "dcdecomp-diff.sh (+https://github.com/Adubbz/DCDecomp)",
|
|
},
|
|
method="POST",
|
|
)
|
|
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
body = json.load(resp)
|
|
except urllib.error.HTTPError as e:
|
|
detail = e.read().decode("utf-8", "replace")[:500]
|
|
raise SystemExit("decompme: POST failed (HTTP %d)\n%s" % (e.code, detail))
|
|
except urllib.error.URLError as e:
|
|
raise SystemExit("decompme: could not reach decomp.me: %s" % e.reason)
|
|
|
|
slug = body.get("slug")
|
|
if not slug:
|
|
raise SystemExit("decompme: no slug in the response: %s" % json.dumps(body)[:300])
|
|
|
|
print(SCRATCH_URL % slug)
|
|
token = body.get("claim_token")
|
|
if token:
|
|
print("Claim it (once, while logged in): %s/claim?token=%s"
|
|
% (SCRATCH_URL % slug, token), file=sys.stderr)
|
|
|
|
|
|
def main():
|
|
if not 1 <= len(sys.argv) - 1 <= 2:
|
|
raise SystemExit("usage: decompme.py <symbol> [main|title|dun]")
|
|
create(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|