Stage-2 foundation. Adds cranelift-jit/frontend/module/codegen 0.128.4 (the 1.90-compatible line; 0.133 needs Rust 1.94) and a new crates/xenia-cpu/src/jit.rs. Jit owns a JITModule (and thus all compiled code memory). compile(&DecodedBlock) lowers a block to native code ONLY if every opcode is covered() — otherwise returns None and the caller interprets the whole block (coverage grows opcode-by-opcode). ABI: extern "C" fn(*mut PpcContext, *const MemEnv) -> u32 (StepResult discriminant); guest registers are loaded/stored directly from the #[repr(C)] PpcContext at offset_of! offsets. A covered block is straight-line and always runs to completion, so pc advances to end_pc and cycle_count/timebase bump by the instruction count once — matching the interpreter's per-instruction bump. Covered set so far: addi, addis. Unit test jit_matches_interpreter_addi_block compiles a 32x addi block and asserts the JIT's r3/pc/cycle_count/timebase match the interpreter exactly — proves module setup, offset_of register access, IR emission, the extern "C" calling convention, and cycle/pc accounting end-to-end. Not yet wired into run_superblock (needs a compiled-block cache + routing); every future opcode will be validated against the interpreter via the M0 XENIA_JIT_DIFF harness before it counts as covered. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
134 KiB
134 KiB