Skip to content

fntrace: add fntrace_mark_game_started() for compiled-flow entry - #99

Merged
mstan merged 2 commits into
mstan:masterfrom
Alexbeav:codex/centralised-game-start-latch
Aug 8, 2026
Merged

fntrace: add fntrace_mark_game_started() for compiled-flow entry#99
mstan merged 2 commits into
mstan:masterfrom
Alexbeav:codex/centralised-game-start-latch

Conversation

@Alexbeav

@Alexbeav Alexbeav commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Some titles reach their entry point through compiled code flow rather than a dispatcher round-trip, so \ ntrace_record()\ never sees the \entry_pc\ dispatch and the game-start latch (which drives widescreen engagement, CD speed switch, and boot turbo exit) remains false forever.

Problem

\s_game_started\ is only set inside \ ntrace_record()\ when the dispatcher targets either:

  1. The exact \entry_pc, OR
  2. Any game-text address with matching native bytes (secondary path)

The secondary path has a chicken-and-egg: the dirty baseline is only cleared after the primary latch fires.

For titles like Tenchu 2 (SLUS-00939) where the BIOS-to-game handoff bypasses the dispatcher, \s_game_started\ remains 0 forever.

Fix

Add \ ntrace_mark_game_started(CPUState* cpu)\ — a centralised, idempotent transition that performs all handoff side effects:

  • \dirty_ram_clear_image_baseline()\
  • \memory_clear_low_boot_scratch()\
  • \cdrom_notify_game_started()\
  • \�oot_state_trigger_capture()\

Refactor \ ntrace_record()\ to call the same function, removing the inlined copy. Generated entry-point functions can call \ ntrace_mark_game_started(cpu)\ directly to latch game-start regardless of how they were reached (dispatcher or compiled flow).

Safety

  • Timing: Must be called from the generated entry-point function, not during init. This ensures BIOS boot stays at 1x CD speed, 4:3, and with boot-shell skipping intact.
  • Idempotent: Checks \s_game_started\ and returns early if already set.
  • Complete: Performs the full transition, not just the latch bit.
  • Existing path preserved: The dispatcher-based detection in \ ntrace_record()\ now delegates to the same function — no behavioural change for titles where it already works.

Testing

  • Tenchu 2 (SLUS-00939): Adding \ ntrace_mark_game_started(cpu)\ at the top of \ unc_8002E4BC\ correctly engages widescreen, 2x CD speed, and exits boot turbo on first entry.
  • Existing titles: No regression — \ ntrace_record()\ uses the same function with identical semantics.

Companion generator change

A follow-up PR to \ ull_function_emitter.cpp\ would emit the call automatically for the entry-point function, removing the need for manual per-title patches.


Developed with AI assistance; validated as described (test evidence in PR body). AI writes the code and the PR, but I always test before I send something up. Happy to iterate on this process with your feedback.

@mstan
mstan self-requested a review August 6, 2026 02:25
@mstan

mstan commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Hiya! Thanks for the PR. It looks like the changes in this branch are beyond the scope of the description. Would you mind to factor out the excess changes and put them into their own PRs, if applicable? Some of them I think already superseded by changes on master as well, so they may be redundant.

Thank you in advance!

@Alexbeav

Alexbeav commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Hello! Sure thing, doing it now. Thank you!

@Alexbeav
Alexbeav force-pushed the codex/centralised-game-start-latch branch from d9ede05 to bdb8248 Compare August 6, 2026 06:50
@Alexbeav

Alexbeav commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Done — rebased onto current master and slimmed the branch to exactly the described change (the two fntrace commits). The SPU/IP2/audio-pump commits are gone since #104 supersedes them, and the CD fixes + SCPH1001 seeds will come as their own small PRs. Thanks for the pointer, and for carrying the #102 work forward with the IP2 second-latch-site and turbo-mute gating fixes.

Some titles reach their entry point through compiled code flow
rather than a dispatcher round-trip, so fntrace_record() never
sees the entry_pc dispatch and the game-start latch never fires.

Add fntrace_mark_game_started(CPUState*) — a centralised, idempotent
transition that performs all handoff side effects:
- dirty_ram_clear_image_baseline()
- memory_clear_low_boot_scratch()
- cdrom_notify_game_started()
- boot_state_trigger_capture()

Refactor fntrace_record() to call the same function, removing the
inlined copy. Generated entry-point functions can call this directly
to latch game-start regardless of how they were reached.

Tested with Tenchu 2 (SLUS-00939): adding the call at the top of
func_8002E4BC engages widescreen, 2x CD speed, and boot turbo exit
correctly on first entry without requiring a dispatcher round-trip.
@Alexbeav
Alexbeav force-pushed the codex/centralised-game-start-latch branch from bdb8248 to 9939514 Compare August 6, 2026 08:19
@Alexbeav

Alexbeav commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Important correction pushed: the interpreter-path trigger commit originally latched on the first dispatch to any phys >= 0x10000. That fires during BIOS boot (the shell/kernel execute relocated RAM code above 0x10000), and the handoff's baseline/scratch clears then corrupt the boot — found when Medal of Honor (SLUS-00974) regressed from playable to a frame-~700 garbage-jump/VBLANK-wedge, bisected to exactly this commit pair on top of current master. The branch now latches only on the exact game entry pc armed via fntrace_set_game_range (same semantics as the compiled path), verified: MoH boots 1500+ frames with the fix, and a no-range-armed title simply never latches (previous behavior). Worth knowing for review: the failure mode is title-dependent — GT/007/C-12 happened to survive the broad match, MoH did not.

@mstan
mstan merged commit 483a0d4 into mstan:master Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants