Files
psxrecomp/recompiler/include/mips_decoder.h
T
Matthew Stanley 7c40d33db3 Phase 1 complete: recompiler proven correct on SCPH1001.BIN
Phase 1a (boot slice): 30 instructions at 0xBFC00000, compiles clean.
Phase 1b (instruction coverage): 54 opcodes implemented in strict_translator,
  44,629 walker-reachable instructions covered, 0 missing.
Phase 1c (function discovery): 76 functions from 2 seeds, 2,988 instructions,
  199 call edges, 27 indirect jumps. All validated through StrictTranslator.
Phase 1d (indirect control flow): 27 sites classified — 21 A0/B0/C0 dispatch
  stubs, 4 computed calls, 2 computed tail calls. Ghidra cross-referenced
  with 0 disagreements.
Phase 1e (relocation): ROM-to-RAM copy at FUN_bfc00420 proven with both
  Ghidra (static) and DuckStation (runtime). 69 address aliases, 68/69
  function entries match byte-for-byte in RAM. Normalization rule documented.

Includes PRINCIPLES.md and DEBUG.md adapted from recomp-template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 21:26:04 -07:00

99 lines
3.7 KiB
C++

#pragma once
#include <cstdint>
#include <vector>
#include <string>
#include "ps1_exe_parser.h"
namespace PSXRecomp {
// MIPS R3000 instruction format types
enum class InstrFormat {
R, // Register: op[31:26]=0 rs rt rd shamt funct
I, // Immediate: op rs rt imm16
J, // Jump: op target26
SPECIAL, // SPECIAL opcode (funct field determines op) - alias for R
REGIMM, // REGIMM opcode (rt field determines op)
COP0, // Coprocessor 0
COP2, // GTE coprocessor
UNKNOWN // Unrecognized/invalid
};
// Fully decoded MIPS R3000 instruction
struct DecodedInstruction {
uint32_t raw; // Original instruction word
uint32_t address; // PC address where this was fetched
InstrFormat format;
// Register fields (R-type and I-type)
uint8_t rs; // Source register [25:21]
uint8_t rt; // Target register [20:16]
uint8_t rd; // Destination register [15:11]
uint8_t shamt; // Shift amount [10:6]
uint8_t funct; // Function code [5:0]
// Immediate fields (I-type)
int16_t imm16; // Sign-extended immediate [15:0]
uint16_t uimm16; // Zero-extended immediate [15:0]
// Jump field (J-type)
uint32_t target26; // 26-bit jump target [25:0]
// Derived fields
uint8_t opcode; // Top 6 bits [31:26]
uint32_t jump_target; // Full computed jump address (for J/JAL/JR/JALR)
uint32_t branch_target; // Full computed branch target (for beq/bne/etc)
int32_t sign_ext_imm; // Sign-extended 16-bit immediate as int32
// Classification flags
bool is_branch; // BEQ/BNE/BLEZ/BGTZ/BLTZ/BGEZ/BLTZAL/BGEZAL
bool is_jump; // J/JAL/JR/JALR
bool is_load; // LB/LH/LW/LBU/LHU/LWL/LWR/LWC2
bool is_store; // SB/SH/SW/SWL/SWR/SWC2
bool is_alu; // Arithmetic/logic (not load/store/branch/jump)
bool is_nop; // raw == 0 (SLL $zero,$zero,0)
bool is_syscall; // SYSCALL instruction
bool is_break; // BREAK instruction
bool is_jr_ra; // JR $ra specifically (function return)
bool is_delay_slot_user; // This instruction is followed by a delay slot
// Mnemonic for debugging/display
const char* mnemonic; // e.g. "ADDIU", "LW", "JAL"
};
class MipsDecoder {
public:
// Decode a single instruction word at a given address
// address is used to compute branch/jump targets
static DecodedInstruction decode(uint32_t instr, uint32_t address = 0);
// Decode all instructions in a PS1 executable sequentially
static std::vector<DecodedInstruction> decode_executable(
const PS1Executable& exe
);
// Compute branch target: address + 4 + (imm16 << 2)
static uint32_t compute_branch_target(uint32_t address, int16_t imm16);
// Compute jump target: (address & 0xF0000000) | (target26 << 2)
static uint32_t compute_jump_target(uint32_t address, uint32_t target26);
// Check if instruction is a NOP (0x00000000 = SLL $zero,$zero,0)
static bool is_nop(uint32_t instr);
// Get MIPS register name string ("$zero", "$at", "$v0", etc.)
static const char* register_name(uint8_t reg);
// Get mnemonic string for a decoded instruction
static const char* get_mnemonic(const DecodedInstruction& instr);
private:
static void decode_special(DecodedInstruction& out);
static void decode_regimm(DecodedInstruction& out);
static void decode_cop0(DecodedInstruction& out);
static void decode_cop2(DecodedInstruction& out);
static void set_classification_flags(DecodedInstruction& out);
};
} // namespace PSXRecomp