mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-27 18:52:11 -04:00
77d036bfb6
Make the repo approachable for outside contributors and an IDE integrator:
- New contributor docs:
- docs/EXECUTION_MODEL.md — semi-technical tour of the static / native-overlay
/ interpreter execution model and how coverage gaps get plugged.
- docs/ARCHITECTURE.md — component-level view (recompiler, runtime, LLE+HLE
BIOS, overlay backend static->gcc->tcc, renderers, oracle model).
- docs/BUILDING.md — accurate dependency table, per-platform prereqs, build
steps, and the submodule + local-junction framework-linking setup.
- CONTRIBUTING.md — distilled core rules, verification expectations, PR flow.
- Declutter root: move ~14 internal dev-logs into docs/internal/ (history
preserved via rename) with an index README; repoint CLAUDE.md references.
- README: correct build recipe, LLE+HLE + overlay-backend summary, links to the
new docs.
- code_provider.c: update the stale backend comment to the real static->gcc->tcc
resolution (dead SLJIT.md reference removed).
- config_schema.md: drop the obsolete "once Phase A2/A3 ships --config" note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
92 lines
4.5 KiB
C
92 lines
4.5 KiB
C
/* code_provider.c — the CodeProvider implementations + active selection.
|
|
* See code_provider.h for the abstraction.
|
|
*
|
|
* The "spawn compiler" provider is a thin pass-through over the validated
|
|
* autocompile_* path (compile emitted overlay C to a DLL and load it); it backs
|
|
* BOTH the gcc and tcc tiers, which differ only in which compiler the pipeline
|
|
* invokes. The in-process JIT provider (code_provider_sljit) is a separate,
|
|
* legacy path. Which provider is active is decided once at init by
|
|
* overlay_backend_resolve() in overlay_backend.c (env PSX_OVERLAY_BACKEND >
|
|
* [runtime] overlay_backend > auto). The auto tier order is:
|
|
* static -> gcc (if gcc on PATH) -> tcc (bundled toolchain-free fallback). */
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "code_provider.h"
|
|
#include "autocompile.h"
|
|
#include "overlay_sljit.h"
|
|
#include "overlay_backend.h"
|
|
|
|
/* ---- gcc provider: pass-through to the validated spawn->DLL->rescan path --- */
|
|
/* The hook signatures match autocompile_* exactly, so we point straight at
|
|
* them — no wrappers, no behavior change. compile_fragment stays NULL: a
|
|
* compiler spawn is orders of magnitude too slow for the dispatch path, so gcc
|
|
* never produces a fragment synchronously (it self-improves via the batch path
|
|
* + autocapture instead). */
|
|
static const CodeProvider s_gcc = {
|
|
/* name */ "gcc",
|
|
/* available */ autocompile_configured,
|
|
/* request */ autocompile_request,
|
|
/* busy */ autocompile_busy,
|
|
/* poll_main */ autocompile_poll_main,
|
|
/* compile_fragment */ NULL,
|
|
};
|
|
|
|
/* ---- sljit provider: in-process JIT (sync on-miss only, v1) ---------------- */
|
|
/* No batch/async path: sljit produces synchronously at a dispatch miss, so
|
|
* request/busy/poll_main are inert. compile_fragment delegates to the MIPS->sljit
|
|
* emitter (overlay_sljit_try_compile), which compiles the supported instruction
|
|
* classes and declines the rest (fn=NULL) — safe by construction (precision over
|
|
* recall). The returned shard is validated via the same-state diff before live. */
|
|
static int sljit_request(void) { return 0; }
|
|
static int sljit_busy(void) { return 0; }
|
|
static void sljit_poll_main(void) { }
|
|
|
|
static void sljit_compile_fragment(uint32_t entry, const uint8_t *bytes,
|
|
uint32_t size, uint32_t image_base_vram,
|
|
CompiledFragment *out) {
|
|
OverlaySljitResult r = {0};
|
|
overlay_sljit_try_compile(entry, bytes, size, image_base_vram, &r);
|
|
/* OverlaySljitFn and CodeProviderFn are the same void fn(CPUState*) type. */
|
|
out->fn = (CodeProviderFn)r.fn;
|
|
out->code_lo = r.code_lo;
|
|
out->code_len = r.code_len;
|
|
out->serialized = r.serialized; /* for the persisted shard cache */
|
|
out->serialized_size = r.serialized_size;
|
|
}
|
|
|
|
static const CodeProvider s_sljit = {
|
|
/* name */ "sljit",
|
|
/* available */ overlay_sljit_available,
|
|
/* request */ sljit_request,
|
|
/* busy */ sljit_busy,
|
|
/* poll_main */ sljit_poll_main,
|
|
/* compile_fragment */ sljit_compile_fragment,
|
|
};
|
|
|
|
/* ---- active selection ------------------------------------------------------ */
|
|
/* Default to gcc so any caller before code_provider_init() (there should be
|
|
* none — init runs at overlay-cache setup) gets the proven path. */
|
|
static const CodeProvider *s_active = &s_gcc;
|
|
|
|
void code_provider_init(const char *cfg_backend, int gcc_configured) {
|
|
/* overlay_backend_resolve resolves AUTO to GCC or SLJIT and never returns
|
|
* AUTO, so this maps cleanly to one of the two providers. It also logs the
|
|
* decision (surfaced via the sljit_status debug command). */
|
|
OverlayBackend b = overlay_backend_resolve(cfg_backend, gcc_configured);
|
|
/* The "gcc" provider is really the spawn-a-compiler->DLL->rescan path; it is
|
|
* compiler-agnostic (the actual compiler is whatever overlay_autocompile_cmd
|
|
* runs — gcc OR tcc, selected in main.cpp by the resolved backend). So BOTH
|
|
* gcc and tcc map to it. Only the deprecated in-process sljit producer is
|
|
* separate. */
|
|
s_active = (b == OVERLAY_BACKEND_SLJIT) ? &s_sljit : &s_gcc;
|
|
}
|
|
|
|
const CodeProvider *code_provider_active(void) { return s_active; }
|
|
|
|
/* sljit provider for the synchronous JIT-on-miss gap-fill, regardless of which
|
|
* provider is "active". NULL when sljit isn't available so callers fall to interp. */
|
|
const CodeProvider *code_provider_sljit(void) {
|
|
return (s_sljit.available && s_sljit.available()) ? &s_sljit : NULL;
|
|
}
|