Skip to content

CPUState

MIPS R3000A register file, GTE registers and memory callbacks.

The recompiled game is C that reads and writes these fields where the original instructions read and wrote registers; there is no interpreter and no other copy of the state. One instance exists for the session, owned by the sim thread. An override receives a pointer to it at the entry of the function it overrides and the pointer is valid until the override returns: keep no copy of it, and touch it from no other thread.

Calling convention (MIPS o32, as the game was compiled): arguments in a0..a3, a fifth and later argument in the caller's frame at sp + 16, sp + 20, ... at entry, read through read_word. The return value is in v0, with v1 carrying the high word of a 64-bit return. ra is the return address, written by the caller before the call, and sp at entry is the caller's stack pointer: the overridden function has not yet built its frame.

Preservation: the recompiled function saves and restores exactly the registers its original code did, so at return s0..s7, sp, fp and gp hold their entry values and every other register is clobbered. An override that runs around api->base(cpu) sees this too: read the arguments before base(), the result after it, and expect a0..a3, t0..t9, v0, v1 and ra to have changed across it. The natural-signature wrappers save and restore a0..a3, v0, v1 and ra around the calls they make and nothing else. An override that calls api->call itself and then returns into the original must restore the argument registers it overwrote.

pc is written by the recompiled code only in a build regenerated with per-instruction PC tracking (OPENPETE_REGEN_PC_TRACKING=1) and at indirect jumps; in a stock build it is stale and not a way to find where the game is. cop0 is carried for completeness: the game executes no coprocessor-0 instruction. The GTE arrays are live: every recompiled COP2 instruction executes against them.

The memory callbacks translate a guest vaddr in kuseg, kseg0 or kseg1 to the 2 MB RAM, the 1 KB scratchpad or a registered region (the mod arena included) and access it at the requested width; an unmapped read returns 0 and an unmapped write is dropped. Addresses are naturally aligned, as the game's are. api->guest resolves the same map to a host pointer, so the two are interchangeable for bulk work.

Savestates, rewind and runahead carry the register file, from zero through gte_ctrl, with guest RAM; the callback pointers are bound once at boot and are not timeline state.

Declared in psx_runtime.h, shipped in sdk/; include it beside openpete_mod_api.h, which only forward-declares the type.

Fields

Field Type Meaning
zero uint32_t Hard-wired 0.
at uint32_t Assembler temporary.
v0 uint32_t Return value; the low word of a 64-bit return.
v1 uint32_t High word of a 64-bit return; otherwise scratch.
a0 uint32_t First argument.
a1 uint32_t Second argument.
a2 uint32_t Third argument.
a3 uint32_t Fourth argument; later ones are on the stack at sp + 16 and up.
t0 uint32_t Caller-saved temporaries.
t1 uint32_t Caller-saved temporaries.
t2 uint32_t Caller-saved temporaries.
t3 uint32_t Caller-saved temporaries.
t4 uint32_t Caller-saved temporaries.
t5 uint32_t Caller-saved temporaries.
t6 uint32_t Caller-saved temporaries.
t7 uint32_t Caller-saved temporaries.
s0 uint32_t Callee-saved; a function returns them as it found them.
s1 uint32_t Callee-saved; a function returns them as it found them.
s2 uint32_t Callee-saved; a function returns them as it found them.
s3 uint32_t Callee-saved; a function returns them as it found them.
s4 uint32_t Callee-saved; a function returns them as it found them.
s5 uint32_t Callee-saved; a function returns them as it found them.
s6 uint32_t Callee-saved; a function returns them as it found them.
s7 uint32_t Callee-saved; a function returns them as it found them.
t8 uint32_t Caller-saved temporaries.
t9 uint32_t Caller-saved temporaries.
k0 uint32_t Kernel reserved; unused by the game.
k1 uint32_t Kernel reserved; unused by the game.
gp uint32_t Global pointer: base of the game's small-data area, constant across the session.
sp uint32_t Stack pointer; the caller's frame at override entry.
fp uint32_t Frame pointer (s8); callee-saved.
ra uint32_t Return address of the current call.
pc uint32_t Program counter; maintained only under PC-tracking regeneration.
hi uint32_t Multiply/divide result, high word or remainder.
lo uint32_t Multiply/divide result, low word or quotient.
cop0[32] uint32_t System coprocessor registers; the game never touches them.
gte_data[32] uint32_t GTE data registers (VXY0..LZCR), live.
gte_ctrl[32] uint32_t GTE control registers (rotation matrix, translation, screen offsets, flags), live.
uint32_t (*read_word)(uint32_t addr) Aligned 32-bit load.
void (*write_word)(uint32_t addr, uint32_t value) Aligned 32-bit store.
uint16_t (*read_half)(uint32_t addr) Aligned 16-bit load.
void (*write_half)(uint32_t addr, uint16_t value) Aligned 16-bit store.
uint8_t (*read_byte)(uint32_t addr) 8-bit load.
void (*write_byte)(uint32_t addr, uint8_t value) 8-bit store.
uint32_t (*lwl)(uint32_t addr, uint32_t rt_value) Unaligned load, left part, merged into the rt_value word.
uint32_t (*lwr)(uint32_t addr, uint32_t rt_value) Unaligned load, right part, merged into the rt_value word.
void (*swl)(uint32_t addr, uint32_t rt_value) Unaligned store, left part.
void (*swr)(uint32_t addr, uint32_t rt_value) Unaligned store, right part.