mirror of
https://github.com/valentderah/totk-pc-recomp.git
synced 2026-11-11 18:01:03 +00:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
2.7 KiB
C
54 lines
2.7 KiB
C
// Guest address -> host function lookup for indirect branches (rt_dispatch, declared in cpu.h).
|
|
//
|
|
// One flat table covers every module's code range: slot (pc - lo) >> 2 holds the host function for a guest
|
|
// function start, as a 32-bit offset from an anchor address. Lookup is one range check and one load. The table is
|
|
// built once by rt_dispatch_init and never written again, so threads read it without locks.
|
|
#pragma once
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#include "cpu.h"
|
|
|
|
// A lifted module: its place in the guest layout and the generator's sorted function table.
|
|
typedef struct RtModule {
|
|
const char *name;
|
|
uint64_t base, size; // guest image (layout.h MOD_<NAME>_BASE / _SIZE)
|
|
const uint64_t *addrs; // <mod>_fn_addrs: guest function starts, strictly ascending
|
|
const GuestFn *fns; // <mod>_fn_ptrs: the lifted function for each start
|
|
uint64_t count; // <mod>_fn_count
|
|
} RtModule;
|
|
|
|
// The module glue that tools/build_game.py writes for each build (build/<version>/modules.c), from layout.json and
|
|
// layout.h: every module of the layout, and the modules linked into this executable.
|
|
typedef struct RtLayoutEntry { const char *name; uint64_t base, size; } RtLayoutEntry;
|
|
extern const RtLayoutEntry rt_layout[];
|
|
extern const int rt_layout_count;
|
|
int rt_linked_modules(RtModule *out, int max);
|
|
|
|
// Register a host function at a guest address outside every module (HLE entry points). Allowed only before
|
|
// rt_dispatch_init; the registry is fixed afterwards.
|
|
void rt_register_host(uint64_t addr, GuestFn fn);
|
|
|
|
// Build the table from the modules (kept by pointer; they must outlive the process). Call it once, before any guest
|
|
// thread starts: thread creation publishes the table to the threads. Fatal on a malformed table:
|
|
// unsorted or duplicate starts, a start outside its module, overlapping modules, host code spread over 4 GiB.
|
|
void rt_dispatch_init(const RtModule *mods, int count);
|
|
|
|
// The host function for a guest address, or NULL when nothing is there. Does not run guest code.
|
|
GuestFn rt_dispatch_lookup(uint64_t pc);
|
|
|
|
// "0x7000001234 (main+0x1234)" for a guest address inside a module, else the bare address. Returns buf.
|
|
const char *rt_guest_name(uint64_t pc, char *buf, int size);
|
|
|
|
typedef struct RtDispatchStats {
|
|
uint64_t lo, hi; // guest range the table covers
|
|
uint64_t slots; // (hi - lo) / 4
|
|
uint64_t table_bytes; // reserved for the table
|
|
uint64_t functions; // filled slots
|
|
uint64_t host_fns; // rt_register_host entries
|
|
} RtDispatchStats;
|
|
RtDispatchStats rt_dispatch_stats(void);
|
|
|
|
// Runtime fatal error: message to stderr, then exit. Used by the dispatcher and the stubs.
|
|
void rt_fatal(const char *fmt, ...) __attribute__((noreturn, format(printf, 1, 2)));
|