Range measured: all 27 levels' overlays. The overlay carries the game's profiler menu definition -- a run of 8-byte padded names (normal, camera, cam+chr, volume, bars, render, mobys, ties, shrubs, cpu/gpu, occl, ...) followed by runs of absolute RAM addresses that point back at those same names. On every level the four addresses after normal/camera/cam+chr/volume, each minus its target name's overlay offset, give the same number: 1,735,792. That is field_00 - 16, where field_00 is the header word that read 1,735,808 on all 27 levels with nothing attached to it. The overlay is loaded with its 16-byte header stripped, so overlay offset X sits at RAM X + 1,735,792. OverlayHeader::ram_address carries it, and the disc test asserts the derivation holds on all 27 levels. Confirmed, not only derived: level 0's RAM 0x1acf80 holds "normal\0camera\0cam+chr\0volume\0", byte-identical to overlay 0x5310, and 0x5310 + 1735792 == 0x1acf80. All four names land where the overlay's own table says. `gc-trace verify-overlay-base` runs that check, savestate-gated the same way as the tie and tfrag ones. The overlay is relocated, not copied: only 37.67% of level 0's is byte-identical at the base, and the 256-entry sine table -- at overlay 0xb650c -- is not at 0xb650c + base. So the base locates the overlay's image, but individual tables inside it move. That is the shape of a loader applying relocations, and it means the base is necessary but not sufficient for reading the game's tables. The value of the base is that any overlay offset can now be carried to a RAM address, which is the prerequisite for reading the game's live level state -- the thing the tie relocation and tfrag lighting checks had to work around. Two things get deleted rather than finished. The collision u16 table was probed four ways -- magnitude distribution, level-independence, run starts, run lengths -- and every one came back level-dependent: the run-start pattern is identical on 1 of 19 levels. So the first 1024 bytes of the collision payload are data, not a fixed table, and nothing was decoded. Recorded as the negative it is rather than left as four half-findings.
38 lines
1.5 KiB
Rust
38 lines
1.5 KiB
Rust
//! `gc-trace` — the PCSX2 ground-truth harness.
|
|
//!
|
|
//! This crate is a **dev tool**. It never ships and no shipped crate depends
|
|
//! on it; the dependency direction is the other way round (`tools/` may read
|
|
//! what the engine computes). Its job is the one the rest of the suite cannot
|
|
//! do: compare what the real game does against what we compute, from the same
|
|
//! disc data.
|
|
//!
|
|
//! Inputs, in order of convenience:
|
|
//!
|
|
//! * **PINE** — the live emulator, over its unix socket. Needs PCSX2 running
|
|
//! with PINE enabled. No savestate, no files.
|
|
//! * **a PCSX2 savestate** (`.p2s`) — a zip with zstd/deflate entries holding
|
|
//! `eeMemory.bin` and friends. Repeatable input: the file can be kept,
|
|
//! but it is personal data and is never committed.
|
|
//! * **a raw EE RAM dump** — 32 MiB, whatever produced it.
|
|
//!
|
|
//! The one comparison that exists so far is
|
|
//! [`compare-tfrag-light`](tfrag_cmp::compare): the game's lit per-vertex
|
|
//! tfrag colours in EE RAM against [`gc_engine::tfrag_light::light_tfrag`] over
|
|
//! the same disc data. See `docs/plan/pcsx2-verification.md`.
|
|
//!
|
|
//! **Findings reach tests only as numbers.** A test never reads a savestate, a
|
|
//! dump or a live emulator; when a comparison becomes a regression, distil the
|
|
//! facts it needs into a small fixture and test against that.
|
|
|
|
pub mod ee;
|
|
pub mod overlay_base;
|
|
pub mod p2s;
|
|
pub mod pine;
|
|
pub mod tfrag_cmp;
|
|
pub mod tie_verify;
|
|
pub mod zip;
|
|
|
|
pub use ee::EeRam;
|
|
pub use p2s::Savestate;
|
|
pub use tfrag_cmp::{compare, print_report, LevelInputs, Report};
|