Files
AC6_recomp/src/ac6_pac_decoder_probe.h
T

74 lines
3.8 KiB
C

#pragma once
#include <rex/ppc/types.h>
// Mid-asm hook on the AC6 PAC stream-worker's work-item dispatch site.
//
// Wired to `0x82343E78` in `rex_sub_82343E18` (the streamer's `bctrl` that
// dispatches the next queued work item). At the moment of the call,
// `ctr` holds the guest function pointer about to run (the work item's
// virtual method[1]) and `r28` holds the work item itself.
//
// Gated by env var `AC6_TRACE_PAC_WORK_ITEMS=1`. When enabled, each
// distinct dispatch target is logged once. The decoder we are hunting for
// will appear here as a target that runs after a compressed PAC entry
// has been fully streamed.
void ac6PacWorkerDispatchHook(PPCRegister& r28, PPCRegister& ctr);
// Second-level dispatch probe, installed at the first `bctrl` inside each of
// the five non-error PAC stream-worker state handlers (rex_sub_82345608,
// _738, _860, _A00, _B28). Each handler invokes a different vtable slot on
// the same streaming sub-class; this hook records the target function each
// slot resolves to. The mode-1 decoder is reached through one of these slots.
//
// All five sites share this single hook; cross-reference the captured target
// addresses against `[AC6 PAC] compressed entry written` lines to identify
// the decoder.
void ac6PacWorkerL2DispatchHook(PPCRegister& r3, PPCRegister& r4, PPCRegister& r5,
PPCRegister& r6, PPCRegister& ctr);
// Mid-asm hook on the AC6 mode-1 decoder's post-decode site.
//
// Wired to `0x821CCC5C` in the streamer's per-entry processing function,
// immediately after `add r11,r9,r11` resolves the compress-table entry
// record pointer. At this point the prior `bl 0x822CF510` has decompressed
// the entry, `r4` holds the destination buffer's guest VA, `r11` points at
// the entry record (codec_mode at +1, csize at +8, usize at +12), `r10`
// has the entry tag (low 16 bits), and `*(r31+22888)` holds the source
// offset. Captured originally as a hand-edit in the Apr 23 build that
// produced FHM-magic'd dumps; re-introduced here as a proper midasm hook
// so codegen regeneration doesn't lose it.
void ac6PacDecoderDumpHook(PPCRegister& r4, PPCRegister& r10, PPCRegister& r11,
PPCRegister& r31);
// Forward decl for the dumper sink (defined in src/ac6_pac_decode_dump.cpp).
void Ac6DumpPacDecodedEntry(uint16_t entry_index, uint8_t codec_mode,
uint32_t compressed_size, uint32_t decompressed_size,
uint32_t source_offset, const uint8_t* host_data);
// ---------------------------------------------------------------------------
// Codec-internals tracing probes.
//
// Each probe is a mid-asm hook on a specific PPC function entry inside the
// mode-1 decoder pipeline. All probes are gated by env var
// AC6_TRACE_CODEC_INTERNALS=1 and rate-limited to the first 3 mode-1 decoder
// invocations so log volume stays manageable.
//
// Decoder pipeline (top-down):
// sub_822CF510 codec dispatcher -> ac6PacCodecDispatchProbe
// sub_822CF2F8 mode-1 entry -> ac6PacMode1EntryProbe (one-shot ROM dump)
// sub_822CCB50 bit fetcher -> ac6PacBitFetcherProbe
// sub_822CEAC0 dynamic header -> ac6PacDynamicHeaderProbe
// sub_822CDB38 tree builder -> ac6PacTreeBuilderProbe
// sub_822CD068 / sub_822CD758 -> ac6PacBlockConsumerProbe
//
// The bit-fetcher probe is the highest-value: it logs every byte the codec
// consumes, which lets us verify whether the .compressed.bin bytes are read
// verbatim or transformed before reaching the bit buffer.
void ac6PacCodecDispatchProbe(PPCRegister& r3);
void ac6PacMode1EntryProbe(PPCRegister& r3);
void ac6PacBitFetcherProbe(PPCRegister& r3, PPCRegister& r4, PPCRegister& r5);
void ac6PacDynamicHeaderProbe(PPCRegister& r3, PPCRegister& r4);
void ac6PacTreeBuilderProbe(PPCRegister& r3);
void ac6PacBlockConsumerProbe(PPCRegister& r3);