diff --git a/recompiler/src/pgxp_hook_emitter.cpp b/recompiler/src/pgxp_hook_emitter.cpp index 1455983c..5c54b8f5 100644 --- a/recompiler/src/pgxp_hook_emitter.cpp +++ b/recompiler/src/pgxp_hook_emitter.cpp @@ -30,6 +30,13 @@ inline int16_t get_imm16(uint32_t i) { return (int16_t)(i & 0xFFFF); } * return early above translate_instruction's main dispatch and are likewise * unhooked (they are cull compares, not vertex moves; validation covers). */ void append_pgxp_hooks(uint32_t instr, std::string& code) { + /* A translation ending in a preprocessor directive (the block-cycles + * muldiv wrappers end in `#endif`) would swallow an appended hook: the + * preprocessor discards tokens after #endif (the "extra tokens at end of + * #endif" warning class), so the MULT/DIV/MFLO/MFHI hooks silently never + * ran. Give the hook its own line. */ + if (code.size() >= 6 && code.compare(code.size() - 6, 6, "#endif") == 0) + code += "\n "; const uint32_t opcode = (instr >> 26) & 0x3F; const uint32_t rs = get_rs(instr); const uint32_t rt = get_rt(instr); diff --git a/runtime/include/overlay_dispatch_preamble.c.inc b/runtime/include/overlay_dispatch_preamble.c.inc index c2acb8e7..eee589b7 100644 --- a/runtime/include/overlay_dispatch_preamble.c.inc +++ b/runtime/include/overlay_dispatch_preamble.c.inc @@ -211,6 +211,23 @@ int psx_ws_cull_vxrange(uint32_t x, uint32_t imm) { return (((x + (uint32_t)margin) & 0xFFFFu) < (bound + 2u * (uint32_t)margin)) ? 1 : 0; } +/* [[widescreen.cull.widen]] SLT-family helpers. The emitter writes these at + * explicitly configured cull sites, INCLUDING in overlay-resident code, so + * the DLL must define them or the shard fails to link (undefined reference -> + * no native shard -> that mod-patched page runs interpreted forever). Same + * contract as the funnel helpers above: self-contained on psx_ws_x_margin(), + * identity at margin 0 (4:3), MUST stay byte-for-byte identical to the gpu.c + * implementations. */ +int psx_ws_cull_slti_lower(uint32_t sx, uint32_t imm) { + int32_t bound = (int32_t)(int16_t)(uint16_t)imm; + return ((int32_t)sx < bound - psx_ws_x_margin()) ? 1 : 0; +} +int psx_ws_cull_slt_widen(uint32_t rs, uint32_t rt, int bound_is_rt) { + const int32_t m = psx_ws_x_margin(); + const int32_t a = (int32_t)rs, b = (int32_t)rt; + return bound_is_rt ? ((a < b + m) ? 1 : 0) + : ((a + m < b) ? 1 : 0); +} void psx_ws_sprite_tag(CPUState *cpu) { if (g_cbs.ws_sprite_tag) g_cbs.ws_sprite_tag(cpu); }