Files
Matthew Stanley ec4306fbb3 mmx6 framework: CD/DMA/MDEC + codegen fixes (Tomba builds+plays, MMX6 boots to intro)
Framework work on codex/mmx6-support that makes Tomba build and play
(title screen, 0 dispatch misses) and MMX6 boot through BIOS to its
intro. Touches recompiler codegen (code_generator, function_analysis)
and runtime CD-ROM/DMA/MDEC/GPU/SIO timing (cdrom, dma, mdec, gpu,
psx_cycles, traps, fntrace, debug_server) + headers + runtime.cmake.

Milestone snapshot for collapsing onto master. Build dir excluded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 12:06:02 -07:00

74 lines
2.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* fntrace.h — always-on call ring for recomp psx_dispatch.
*
* Records every entry into psx_dispatch with the caller's argument
* registers and return address. Mirrors beetle_libretro.cpp's fntrace
* ring (same wire commands: fntrace_arm / fntrace_dump / fntrace_clear)
* so cross-process tools that already speak Beetle's protocol work
* unchanged against psx-runtime.
*
* Why "always-on" rather than arm-then-record: see CLAUDE.md global
* rule "Never time/attach for observability". The ring captures every
* dispatch from boot; arming only narrows what the dump command
* reports, never what is recorded. To investigate a window of
* interest, fntrace_dump it after the fact.
*
* Coverage: every psx_dispatch entry — both static-recompiled targets
* (ROM functions, shell-relocated functions) and dirty-RAM dispatches.
* dirty_ram_block_log overlaps with the dirty-RAM subset; this ring is
* the superset.
*/
#ifndef PSXRECOMP_FNTRACE_H
#define PSXRECOMP_FNTRACE_H
#include <stdint.h>
#include "cpu_state.h"
#ifdef __cplusplus
extern "C" {
#endif
/* 4M entries × 32 bytes = 128 MB. At ~580K dispatches/s peak (boot)
* that's ~7s; at ~10K/s during modal idle, ~400s. Sized for press-
* window retrospectives without per-second eviction. */
#define FNTRACE_RING_CAP (1u << 22)
typedef struct {
uint32_t frame; /* s_frame_count at dispatch */
uint32_t target; /* psx_dispatch addr argument (virtual) */
uint32_t ra; /* cpu->gpr[31] at dispatch — caller's return PC */
uint32_t a0; /* cpu->gpr[4] */
uint32_t a1; /* cpu->gpr[5] */
uint32_t a2; /* cpu->gpr[6] */
uint32_t a3; /* cpu->gpr[7] */
uint32_t s3; /* cpu->gpr[19] — callee-saved, useful for arg-passing chains */
} FntraceEntry;
extern FntraceEntry g_fntrace_ring[FNTRACE_RING_CAP];
extern uint64_t g_fntrace_seq; /* monotonic; index into ring = seq % CAP */
/* Hot path. Called from psx_dispatch on every entry. Inlinable. */
void fntrace_record(CPUState* cpu, uint32_t target);
/* Register the game's text range for one-shot game-start detection.
* First dispatch into [lo, hi) calls cdrom_notify_game_started(). */
void fntrace_set_game_range(uint32_t lo, uint32_t hi);
int fntrace_is_game_started(void);
/* Arm a target filter. arm_count == 0 means "record all" (default).
* When arm_count > 0, only dispatches whose target matches one of the
* armed entries are recorded. Use for noise reduction on a hot ring. */
#define FNTRACE_ARM_MAX 32
void fntrace_arm(uint32_t target); /* add to arm list, or 0 to clear */
void fntrace_arm_clear(void);
uint32_t fntrace_arm_count(void);
uint32_t fntrace_arm_get(uint32_t i);
void fntrace_arm_from_env(const char *env_name);
/* Reset ring (clears seq, leaves storage in place). */
void fntrace_clear(void);
#ifdef __cplusplus
}
#endif
#endif /* PSXRECOMP_FNTRACE_H */