diff --git a/include/recomp.h b/include/recomp.h index 73f3e73..2fbe6c9 100644 --- a/include/recomp.h +++ b/include/recomp.h @@ -1,6 +1,8 @@ #ifndef __RECOMP_H__ #define __RECOMP_H__ +#include + #include #include #include @@ -468,6 +470,24 @@ void recomp_syscall_handler(uint8_t* rdram, recomp_context* ctx, int32_t instruc void pause_self(uint8_t *rdram); +/* Tolerant-emit runtime entry points. The engine emits calls to these + * for instructions/branches/calls it can't translate at compile time; + * consumers implement them in a runtime hook file (e.g. extras.c). + * See src/recompilation.cpp for the emit sites and PRINCIPLES.md #12 + * for why these exist (loud runtime aborts, NOT stubs). */ +void recomp_unhandled_branch(uint8_t *rdram, recomp_context *ctx, + uint32_t instr_vram, uint32_t branch_target); +void recomp_unhandled_call(uint8_t *rdram, recomp_context *ctx, + uint32_t instr_vram, uint32_t target); +void recomp_unhandled_jalr(uint8_t *rdram, recomp_context *ctx, + uint32_t instr_vram, uint64_t target_value, int rd); +uint64_t recomp_unhandled_cop0_read(uint8_t *rdram, recomp_context *ctx, + uint32_t instr_vram, int cop0_reg); +void recomp_unhandled_cop0_write(uint8_t *rdram, recomp_context *ctx, + uint32_t instr_vram, int cop0_reg, uint64_t value); +void recomp_unhandled_instruction(uint8_t *rdram, recomp_context *ctx, + uint32_t instr_vram, const char *opcode_name); + #ifdef __cplusplus } #endif diff --git a/src/recompilation.cpp b/src/recompilation.cpp index c29bd2e..6aeb4da 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -387,7 +387,21 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con return true; } - fmt::print(stderr, "[Warn] Function {} is branching outside of the function (to 0x{:08X})\n", func.name, branch_target); + // Branch out of function with no symbol at target. Emit a + // runtime abort instead of `goto L_` to a label that + // never exists. Per project principles: no stub, an + // unimplementable hole surfaced loudly at runtime. + fmt::print(stderr, "[Warn] Function {} is branching outside of the function (to 0x{:08X}) — emitting runtime abort\n", func.name, branch_target); + if (!process_delay_slot(true)) { + return false; + } + print_indent(); + print_indent(); + fmt::print(output_file, "recomp_unhandled_branch(rdram, ctx, 0x{:08X}u, 0x{:08X}u);\n", instr_vram, branch_target); + print_indent(); + print_indent(); + generator.emit_return(context, func_index); + return true; } if (!process_delay_slot(true)) {