pub mod register;
pub mod memory;
use anyhow::{Result, Context};
use crate::recompiler::decoder::{DecodedInstruction, InstructionType, Operand};
use crate::recompiler::analysis::FunctionMetadata;
use std::collections::HashMap;
pub struct CodeGenerator {
indent_level: usize,
register_map: HashMap<u8, String>,
next_temp: usize,
register_values: HashMap<u8, RegisterValue>,
label_counter: usize,
optimize: bool,
function_calls: Vec<u32>, basic_block_map: HashMap<u32, usize>, }
#[derive(Debug, Clone)]
enum RegisterValue {
Constant(u32),
Variable(String),
Unknown,
}
impl CodeGenerator {
pub fn new() -> Self {
Self {
indent_level: 0,
register_map: HashMap::new(),
next_temp: 0,
register_values: HashMap::new(),
label_counter: 0,
optimize: true,
function_calls: Vec::new(),
basic_block_map: HashMap::new(),
}
}
pub fn with_optimizations(mut self, optimize: bool) -> Self {
self.optimize = optimize;
self
}
pub fn generate_function(
&mut self,
metadata: &FunctionMetadata,
instructions: &[DecodedInstruction],
) -> Result<String> {
let mut code = String::new();
code.push_str(&self.generate_function_signature(metadata)?);
code.push_str(" {\n");
self.indent_level += 1;
code.push_str(&self.generate_function_body(instructions)?);
self.indent_level -= 1;
code.push_str("}\n");
Ok(code)
}
fn generate_function_signature(&self, metadata: &FunctionMetadata) -> Result<String> {
let mut sig = String::new();
let func_name = if metadata.name.is_empty() || metadata.name.starts_with("sub_") {
format!("func_0x{:08X}", metadata.address)
} else {
format!("{}_{:08X}", self.sanitize_identifier(&metadata.name), metadata.address)
};
sig.push_str("pub fn ");
sig.push_str(&func_name);
sig.push_str("(");
sig.push_str("ctx: &mut CpuContext, memory: &mut MemoryManager");
sig.push_str(") -> Result<Option<u32>>");
Ok(sig)
}
fn generate_function_body(&mut self, instructions: &[DecodedInstruction]) -> Result<String> {
let cfg = crate::recompiler::analysis::control_flow::ControlFlowAnalyzer::build_cfg(instructions, 0)
.unwrap_or_else(|_| {
crate::recompiler::analysis::control_flow::ControlFlowGraph {
nodes: vec![],
edges: vec![],
entry_block: 0,
}
});
let def_use_chains = crate::recompiler::analysis::data_flow::DataFlowAnalyzer::build_def_use_chains(instructions);
let live_analysis = if !cfg.nodes.is_empty() {
Some(crate::recompiler::analysis::data_flow::DataFlowAnalyzer::live_variable_analysis(&cfg))
} else {
None
};
let optimized_instructions = if let Some(ref live) = live_analysis {
crate::recompiler::analysis::data_flow::DataFlowAnalyzer::eliminate_dead_code(instructions, live)
} else {
instructions.to_vec()
};
self.generate_function_body_impl(&optimized_instructions)
}
fn generate_function_body_impl(&mut self, instructions: &[DecodedInstruction]) -> Result<String> {
let mut code = String::new();
code.push('\n');
if !instructions.is_empty() {
code.push_str(&self.indent());
code.push_str("// Stack frame setup\n");
code.push_str(&self.indent());
code.push_str("let stack_base = ctx.get_register(1); // r1 is stack pointer\n");
code.push('\n');
}
let mut basic_blocks: Vec<Vec<DecodedInstruction>> = Vec::new();
let mut current_block: Vec<DecodedInstruction> = Vec::new();
for inst in instructions {
current_block.push(inst.clone());
if matches!(inst.instruction.instruction_type, InstructionType::Branch) {
basic_blocks.push(current_block);
current_block = Vec::new();
}
}
if !current_block.is_empty() {
basic_blocks.push(current_block);
}
for (block_idx, block) in basic_blocks.iter().enumerate() {
if block_idx > 0 {
code.push_str(&self.indent());
code.push_str(&format!("// Basic block {}\n", block_idx));
}
for (inst_idx, instruction) in block.iter().enumerate() {
match self.generate_instruction(instruction) {
Ok(inst_code) => {
code.push_str(&inst_code);
}
Err(e) => {
code.push_str(&self.indent());
code.push_str(&format!(
"// Error generating instruction {}: {}\n",
inst_idx, e
));
code.push_str(&self.indent());
code.push_str(&format!("// Raw instruction: 0x{:08X}\n", instruction.raw));
code.push_str(&self.indent());
code.push_str(&format!("// Instruction type: {:?}\n", instruction.instruction.instruction_type));
code.push_str(&self.indent());
code.push_str("// Fallback: generating generic instruction handler\n");
code.push_str(&self.indent());
code.push_str(&format!(
"// TODO: Implement proper handling for opcode 0x{:02X}\n",
instruction.instruction.opcode
));
code.push_str(&self.indent());
code.push_str("// Continuing with next instruction...\n");
if let Ok(fallback) = self.generate_generic(instruction) {
code.push_str(&fallback);
}
}
}
}
}
if !instructions.is_empty() {
code.push('\n');
code.push_str(&self.indent());
code.push_str("// Stack frame teardown\n");
code.push_str(&self.indent());
code.push_str("ctx.set_register(1, stack_base);\n");
}
code.push_str(&self.indent());
code.push_str("// Return value is in r3 (PowerPC calling convention)\n");
code.push_str(&self.indent());
code.push_str("Ok(Some(ctx.get_register(3)))\n");
Ok(code)
}
fn build_basic_blocks<'a>(&self, instructions: &'a [DecodedInstruction]) -> Result<Vec<Vec<&'a DecodedInstruction>>> {
let mut blocks = Vec::new();
let mut current_block = Vec::new();
for inst in instructions {
current_block.push(inst);
if matches!(inst.instruction.instruction_type, InstructionType::Branch) {
blocks.push(current_block);
current_block = Vec::new();
}
}
if !current_block.is_empty() {
blocks.push(current_block);
}
Ok(blocks)
}
fn generate_instruction(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if self.optimize {
code.push_str(&self.indent());
code.push_str(&format!("// 0x{:08X}: ", inst.raw));
}
match inst.instruction.instruction_type {
InstructionType::Arithmetic => {
code.push_str(&self.generate_arithmetic(inst)?);
}
InstructionType::Load => {
code.push_str(&self.generate_load(inst)?);
}
InstructionType::Store => {
code.push_str(&self.generate_store(inst)?);
}
InstructionType::Branch => {
code.push_str(&self.generate_branch(inst)?);
}
InstructionType::Compare => {
code.push_str(&self.generate_compare(inst)?);
}
InstructionType::Move => {
code.push_str(&self.generate_move(inst)?);
}
InstructionType::System => {
code.push_str(&self.generate_system(inst)?);
}
InstructionType::FloatingPoint => {
code.push_str(&self.generate_floating_point(inst)?);
}
InstructionType::ConditionRegister => {
code.push_str(&self.generate_condition_register(inst)?);
}
InstructionType::Shift => {
code.push_str(&self.generate_shift(inst)?);
}
InstructionType::Rotate => {
code.push_str(&self.generate_rotate(inst)?);
}
_ => {
code.push_str(&self.generate_generic(inst)?);
}
}
Ok(code)
}
fn generate_arithmetic(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.len() < 2 {
anyhow::bail!("Arithmetic instruction requires at least 2 operands");
}
let rt_reg = match &inst.instruction.operands[0] {
Operand::Register(r) => *r,
_ => anyhow::bail!("First operand must be a register"),
};
let ra_reg = match &inst.instruction.operands[1] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Second operand must be a register"),
};
let (op, update_cr) = match inst.instruction.opcode {
14 => ("+", false), 15 => ("-", false), 12 => ("&", false), 13 => ("|", false), 10 => ("^", false), 11 => ("&", false), 31 => {
let ext_opcode = (inst.raw >> 1) & 0x3FF;
match ext_opcode {
266 => ("+", false), 40 => ("-", false), 28 => ("&", false), 444 => ("|", false), 316 => ("^", false), 235 => ("*", false), 233 => ("*", false), 104 => ("/", false), 536 => ("<<", false), 824 => (">>", false), 792 => (">>", false), _ => ("+", false),
}
}
_ => ("+", false),
};
let (rb_expr, rb_value) = if inst.instruction.operands.len() > 2 {
match &inst.instruction.operands[2] {
Operand::Register(r) => {
let reg_val = self.get_register_value(*r);
(format!("ctx.get_register({})", r), reg_val)
}
Operand::Immediate(i) => {
let val = *i as u32;
(format!("{}u32", val), Some(RegisterValue::Constant(val)))
}
Operand::Immediate32(i) => {
let val = *i as u32;
(format!("{}u32", val), Some(RegisterValue::Constant(val)))
}
_ => ("0u32".to_string(), Some(RegisterValue::Constant(0))),
}
} else {
("0u32".to_string(), Some(RegisterValue::Constant(0)))
};
let operation_code = if op == "<<" || op == ">>" {
if op == "<<" {
format!("ctx.get_register({}) << ({} & 0x1F)", ra_reg, rb_expr)
} else {
format!("ctx.get_register({}) >> ({} & 0x1F)", ra_reg, rb_expr)
}
} else {
format!("ctx.get_register({}) {} {}", ra_reg, op, rb_expr)
};
let ra_value = self.get_register_value(ra_reg);
if let (Some(RegisterValue::Constant(a)), Some(RegisterValue::Constant(b))) = (ra_value, rb_value) {
let result = match op {
"+" => a.wrapping_add(b),
"-" => a.wrapping_sub(b),
"*" => a.wrapping_mul(b),
"&" => a & b,
"|" => a | b,
"^" => a ^ b,
"<<" => a << (b & 0x1F),
">>" => a >> (b & 0x1F),
_ => a,
};
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.set_register({}, {}u32); // Optimized: constant folding\n",
rt_reg, result
));
self.set_register_value(rt_reg, RegisterValue::Constant(result));
} else {
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.set_register({}, {});\n",
rt_reg, operation_code
));
self.set_register_value(rt_reg, RegisterValue::Unknown);
}
if update_cr {
code.push_str(&self.indent());
code.push_str(&format!(
"let result = ctx.get_register({});\n",
rt_reg
));
code.push_str(&self.indent());
code.push_str("let cr_field = if result == 0 { 0x2u8 } else if (result as i32) < 0 { 0x8u8 } else { 0x4u8 };\n");
code.push_str(&self.indent());
code.push_str("ctx.set_cr_field(0, cr_field);\n");
}
Ok(code)
}
fn get_register_value(&self, reg: u8) -> Option<RegisterValue> {
self.register_values.get(®).cloned()
}
fn set_register_value(&mut self, reg: u8, value: RegisterValue) {
self.register_values.insert(reg, value);
}
fn generate_load(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.len() < 3 {
anyhow::bail!("Load instruction requires 3 operands");
}
let rt_reg = match &inst.instruction.operands[0] {
Operand::Register(r) => *r,
_ => anyhow::bail!("First operand must be a register"),
};
let ra_reg = match &inst.instruction.operands[1] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Second operand must be a register"),
};
let offset = match &inst.instruction.operands[2] {
Operand::Immediate(i) => *i as i32,
_ => 0,
};
let base_value = self.get_register_value(ra_reg);
if let Some(RegisterValue::Constant(base)) = base_value {
let addr = base.wrapping_add(offset as u32);
code.push_str(&self.indent());
code.push_str(&format!(
"let value = memory.read_u32(0x{:08X}u32).unwrap_or(0u32); // Optimized: constant address\n",
addr
));
} else {
code.push_str(&self.indent());
code.push_str(&format!(
"let addr = ctx.get_register({}) as u32 + {}i32 as u32;\n",
ra_reg, offset
));
code.push_str(&self.indent());
code.push_str("let value = memory.read_u32(addr).unwrap_or(0u32);\n");
}
code.push_str(&self.indent());
code.push_str(&format!("ctx.set_register({}, value);\n", rt_reg));
self.set_register_value(rt_reg, RegisterValue::Unknown);
Ok(code)
}
fn generate_store(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.len() < 3 {
anyhow::bail!("Store instruction requires 3 operands");
}
let rs_reg = match &inst.instruction.operands[0] {
Operand::Register(r) => *r,
_ => anyhow::bail!("First operand must be a register"),
};
let ra_reg = match &inst.instruction.operands[1] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Second operand must be a register"),
};
let offset = match &inst.instruction.operands[2] {
Operand::Immediate(i) => *i as i32,
_ => 0,
};
let base_value = self.get_register_value(ra_reg);
let value_expr = if let Some(RegisterValue::Constant(val)) = self.get_register_value(rs_reg) {
format!("{}u32", val)
} else {
format!("ctx.get_register({})", rs_reg)
};
if let Some(RegisterValue::Constant(base)) = base_value {
let addr = base.wrapping_add(offset as u32);
code.push_str(&self.indent());
code.push_str(&format!(
"memory.write_u32(0x{:08X}u32, {}).unwrap_or(()); // Optimized: constant address\n",
addr, value_expr
));
} else {
code.push_str(&self.indent());
code.push_str(&format!(
"let addr = ctx.get_register({}) as u32 + {}i32 as u32;\n",
ra_reg, offset
));
code.push_str(&self.indent());
code.push_str(&format!("memory.write_u32(addr, {}).unwrap_or(());\n", value_expr));
}
Ok(code)
}
fn generate_branch(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.is_empty() {
anyhow::bail!("Branch instruction requires operands");
}
match inst.instruction.operands.len() {
1 => {
let target = match &inst.instruction.operands[0] {
Operand::Immediate32(li) => *li,
Operand::Address(addr) => *addr as i32,
_ => anyhow::bail!("Branch target must be immediate or address"),
};
let is_call = inst.instruction.opcode == 18 && (inst.raw & 1) != 0;
if is_call {
self.function_calls.push(target as u32);
code.push_str(&self.indent());
code.push_str(&format!(
"// Function call to 0x{:08X}\n",
target
));
code.push_str(&self.indent());
code.push_str("// Save return address in link register\n");
code.push_str(&self.indent());
code.push_str("let saved_lr = ctx.lr;\n");
code.push_str(&self.indent());
code.push_str("ctx.lr = ctx.pc + 4;\n");
code.push_str(&self.indent());
code.push_str("// Call recompiled function via dispatcher\n");
code.push_str(&self.indent());
code.push_str(&format!(
"match call_function_by_address(0x{:08X}u32, ctx, memory) {{\n",
target
));
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str("Ok(result) => {\n");
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str("// Function call succeeded, result in r3 (PowerPC calling convention)\n");
code.push_str(&self.indent());
code.push_str("if let Some(ret_val) = result {\n");
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str("ctx.set_register(3, ret_val); // Return value in r3\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("}\n");
code.push_str(&self.indent());
code.push_str("ctx.lr = saved_lr; // Restore link register\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("}\n");
code.push_str(&self.indent());
code.push_str("Err(e) => {\n");
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str(&format!(
"log::warn!(\"Function call to 0x{:08X} failed: {{:?}}\", e);\n",
target
));
code.push_str(&self.indent());
code.push_str("ctx.lr = saved_lr; // Restore link register\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("}\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("}\n");
} else {
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.pc = 0x{:08X}u32; // Unconditional branch\n",
target
));
code.push_str(&self.indent());
code.push_str("return; // Branch out of function\n");
}
}
3..=5 => {
let bo = match &inst.instruction.operands[0] {
Operand::Condition(c) => *c,
_ => anyhow::bail!("First operand must be condition"),
};
let bi = if inst.instruction.operands.len() > 1 {
match &inst.instruction.operands[1] {
Operand::Condition(c) => *c,
_ => anyhow::bail!("Second operand must be condition"),
}
} else {
0
};
let target = if inst.instruction.operands.len() > 2 {
match &inst.instruction.operands[2] {
Operand::Immediate(bd) => *bd as i32,
Operand::Address(addr) => *addr as i32,
_ => 0,
}
} else {
0
};
let _label = self.next_label();
code.push_str(&self.indent());
code.push_str(&format!(
"let cr_bit = (ctx.get_cr_field({}) >> {}) & 1;\n",
bi / 4, bi % 4
));
code.push_str(&self.indent());
code.push_str("if cr_bit != 0 {\n");
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.pc = ctx.pc + {}i32 as u32; // Conditional branch\n",
target
));
code.push_str(&self.indent());
code.push_str("return; // Branch taken\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("}\n");
}
_ => {
code.push_str(&self.indent());
code.push_str("// Complex branch instruction\n");
}
}
Ok(code)
}
fn next_label(&mut self) -> String {
let label = format!("label_{}", self.label_counter);
self.label_counter += 1;
label
}
fn generate_compare(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.len() < 2 {
anyhow::bail!("Compare instruction requires at least 2 operands");
}
let bf = match &inst.instruction.operands[0] {
Operand::Condition(c) => *c,
_ => 0, };
let ra_reg = match &inst.instruction.operands[1] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Second operand must be a register"),
};
let compare_value = if inst.instruction.operands.len() > 2 {
match &inst.instruction.operands[2] {
Operand::Register(rb) => {
format!("ctx.get_register({})", rb)
}
Operand::Immediate(i) => {
let val = *i as i32;
format!("{}i32", val)
}
_ => "0i32".to_string(),
}
} else {
"0i32".to_string()
};
let is_unsigned = inst.instruction.opcode == 10;
code.push_str(&self.indent());
code.push_str(&format!(
"let ra_val = ctx.get_register({}) as {};\n",
ra_reg,
if is_unsigned { "u32" } else { "i32" }
));
code.push_str(&self.indent());
code.push_str(&format!(
"let rb_val = {} as {};\n",
compare_value,
if is_unsigned { "u32" } else { "i32" }
));
code.push_str(&self.indent());
code.push_str("let cr_field = if ra_val < rb_val {\n");
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str("0x8u8 // Less than\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("} else if ra_val > rb_val {\n");
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str("0x4u8 // Greater than\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("} else {\n");
self.indent_level += 1;
code.push_str(&self.indent());
code.push_str("0x2u8 // Equal\n");
self.indent_level -= 1;
code.push_str(&self.indent());
code.push_str("};\n");
code.push_str(&self.indent());
code.push_str(&format!("ctx.set_cr_field({}, cr_field);\n", bf));
Ok(code)
}
fn generate_move(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.is_empty() {
anyhow::bail!("Move instruction requires at least one operand");
}
if inst.instruction.operands.len() == 1 {
let reg = match &inst.instruction.operands[0] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Move operand must be a register"),
};
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.set_register({}, ctx.lr); // Move from/to link register\n",
reg
));
}
Ok(code)
}
fn generate_floating_point(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.is_empty() {
anyhow::bail!("Floating point instruction requires operands");
}
match inst.instruction.operands.len() {
3 => {
let frt = match &inst.instruction.operands[0] {
Operand::FpRegister(r) => *r,
_ => anyhow::bail!("First operand must be FP register"),
};
let fra = match &inst.instruction.operands[1] {
Operand::FpRegister(r) => *r,
_ => anyhow::bail!("Second operand must be FP register"),
};
let frb = match &inst.instruction.operands[2] {
Operand::FpRegister(r) => *r,
_ => anyhow::bail!("Third operand must be FP register"),
};
let ext_opcode = (inst.raw >> 1) & 0x3FF;
let op = match ext_opcode {
21 => "+", 20 => "-", 25 => "*", 18 => "/", 14 => "+", 15 => "-", 28 => "-", 29 => "-", _ => "+", };
if ext_opcode == 14 || ext_opcode == 15 || ext_opcode == 28 || ext_opcode == 29 {
if inst.instruction.operands.len() >= 4 {
let frc = match &inst.instruction.operands[2] {
Operand::FpRegister(r) => *r,
_ => anyhow::bail!("Third operand must be FP register for multiply-add"),
};
code.push_str(&self.indent());
code.push_str(&format!(
"let mul_result = ctx.get_fpr({}) * ctx.get_fpr({});\n",
fra, frc
));
code.push_str(&self.indent());
if ext_opcode == 28 || ext_opcode == 29 {
code.push_str("let mul_result = -mul_result;\n");
}
code.push_str(&self.indent());
code.push_str(&format!(
"let result = mul_result {} ctx.get_fpr({});\n",
if ext_opcode == 15 || ext_opcode == 29 { "-" } else { "+" },
frb
));
if ext_opcode == 29 {
code.push_str(&self.indent());
code.push_str("let result = -result;\n");
}
} else {
anyhow::bail!("Multiply-add/subtract requires 4 operands");
}
} else {
code.push_str(&self.indent());
code.push_str(&format!(
"let result = ctx.get_fpr({}) {} ctx.get_fpr({});\n",
fra, op, frb
));
}
code.push_str(&self.indent());
code.push_str(&format!("ctx.set_fpr({}, result);\n", frt));
}
2 => {
let frt = match &inst.instruction.operands[0] {
Operand::FpRegister(r) => *r,
_ => anyhow::bail!("First operand must be FP register"),
};
let ra = match &inst.instruction.operands[1] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Second operand must be register"),
};
code.push_str(&self.indent());
code.push_str(&format!(
"let addr = ctx.get_register({}) as u32;\n",
ra
));
code.push_str(&self.indent());
code.push_str("let value = f64::from_bits(memory.read_u64(addr).unwrap_or(0));\n");
code.push_str(&self.indent());
code.push_str(&format!("ctx.set_fpr({}, value);\n", frt));
}
_ => {
code.push_str(&self.indent());
code.push_str("// Complex floating point instruction\n");
}
}
Ok(code)
}
fn generate_condition_register(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.len() == 1 {
let reg = match &inst.instruction.operands[0] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Operand must be register"),
};
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.set_register({}, ctx.cr); // Move from/to condition register\n",
reg
));
} else if inst.instruction.operands.len() == 3 {
let bt = match &inst.instruction.operands[0] {
Operand::Condition(c) => *c,
_ => anyhow::bail!("First operand must be condition"),
};
let ba = match &inst.instruction.operands[1] {
Operand::Condition(c) => *c,
_ => anyhow::bail!("Second operand must be condition"),
};
let bb = match &inst.instruction.operands[2] {
Operand::Condition(c) => *c,
_ => anyhow::bail!("Third operand must be condition"),
};
code.push_str(&self.indent());
code.push_str(&format!(
"let cr_a = ctx.get_cr_field({});\n",
ba / 4
));
code.push_str(&self.indent());
code.push_str(&format!(
"let cr_b = ctx.get_cr_field({});\n",
bb / 4
));
let ext_opcode = (inst.raw >> 1) & 0x3FF;
let cr_op = match ext_opcode {
257 => "&", 449 => "|", 193 => "^", 225 => "&", 33 => "|", 289 => "^", 129 => "&", 417 => "|", _ => "&", };
code.push_str(&self.indent());
if ext_opcode == 225 || ext_opcode == 33 || ext_opcode == 289 {
code.push_str(&format!(
"let cr_result = !(ctx.get_cr_field({}) {} ctx.get_cr_field({}));\n",
ba / 4, cr_op, bb / 4
));
} else if ext_opcode == 129 {
code.push_str(&format!(
"let cr_result = ctx.get_cr_field({}) & !ctx.get_cr_field({});\n",
ba / 4, bb / 4
));
} else if ext_opcode == 417 {
code.push_str(&format!(
"let cr_result = ctx.get_cr_field({}) | !ctx.get_cr_field({});\n",
ba / 4, bb / 4
));
} else {
code.push_str(&format!(
"let cr_result = ctx.get_cr_field({}) {} ctx.get_cr_field({});\n",
ba / 4, cr_op, bb / 4
));
}
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.set_cr_field({}, cr_result);\n",
bt / 4
));
}
Ok(code)
}
fn generate_shift(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.len() < 3 {
anyhow::bail!("Shift instruction requires at least 3 operands");
}
let rs = match &inst.instruction.operands[0] {
Operand::Register(r) => *r,
_ => anyhow::bail!("First operand must be register"),
};
let ra = match &inst.instruction.operands[1] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Second operand must be register"),
};
let sh = match &inst.instruction.operands[2] {
Operand::ShiftAmount(s) => *s,
Operand::Register(r) => {
code.push_str(&self.indent());
code.push_str(&format!(
"let sh_amount = ctx.get_register({}) & 0x1F;\n",
r
));
0 }
_ => anyhow::bail!("Third operand must be shift amount or register"),
};
code.push_str(&self.indent());
if sh > 0 {
code.push_str(&format!(
"ctx.set_register({}, ctx.get_register({}) << {});\n",
ra, rs, sh
));
} else {
code.push_str(&format!(
"ctx.set_register({}, ctx.get_register({}) >> sh_amount);\n",
ra, rs
));
}
Ok(code)
}
fn generate_rotate(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if inst.instruction.operands.len() < 4 {
anyhow::bail!("Rotate instruction requires 4 operands");
}
let rs = match &inst.instruction.operands[0] {
Operand::Register(r) => *r,
_ => anyhow::bail!("First operand must be register"),
};
let ra = match &inst.instruction.operands[1] {
Operand::Register(r) => *r,
_ => anyhow::bail!("Second operand must be register"),
};
let sh = match &inst.instruction.operands[2] {
Operand::ShiftAmount(s) => *s,
_ => anyhow::bail!("Third operand must be shift amount"),
};
let mask = match &inst.instruction.operands[3] {
Operand::Mask(m) => *m,
_ => anyhow::bail!("Fourth operand must be mask"),
};
code.push_str(&self.indent());
code.push_str(&format!(
"let rotated = ctx.get_register({}).rotate_left({} as u32);\n",
rs, sh
));
code.push_str(&self.indent());
code.push_str(&format!(
"let masked = rotated & 0x{:08X}u32;\n",
mask
));
code.push_str(&self.indent());
code.push_str(&format!(
"ctx.set_register({}, masked);\n",
ra
));
Ok(code)
}
fn generate_system(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
if !inst.instruction.operands.is_empty() {
if let Operand::SpecialRegister(spr) = &inst.instruction.operands[0] {
code.push_str(&self.indent());
code.push_str(&format!(
"// System register operation: SPR {}\n",
spr
));
if inst.instruction.operands.len() > 1 {
if let Operand::Register(rt) = &inst.instruction.operands[1] {
code.push_str(&self.indent());
code.push_str(&format!(
"// Move from/to SPR {} to/from r{}\n",
spr, rt
));
}
}
} else {
code.push_str(&self.indent());
code.push_str("// Cache control or memory synchronization\n");
}
} else {
code.push_str(&self.indent());
code.push_str(&format!("// System instruction: opcode 0x{:02X}\n", inst.instruction.opcode));
code.push_str(&self.indent());
code.push_str("// System instructions typically require special handling\n");
}
Ok(code)
}
fn generate_generic(&mut self, inst: &DecodedInstruction) -> Result<String> {
let mut code = String::new();
code.push_str(&self.indent());
code.push_str(&format!("// Instruction type: {:?}, opcode: 0x{:02X}\n",
inst.instruction.instruction_type, inst.instruction.opcode));
code.push_str(&self.indent());
code.push_str(&format!("// Raw: 0x{:08X}\n", inst.raw));
code.push_str(&self.indent());
code.push_str("// TODO: Implement proper handling for this instruction\n");
if !inst.instruction.operands.is_empty() {
if let Operand::Register(rt) = &inst.instruction.operands[0] {
code.push_str(&self.indent());
code.push_str(&format!(
"// First operand is register r{}\n",
rt
));
}
}
Ok(code)
}
fn type_to_rust(&self, ty: &crate::recompiler::analysis::TypeInfo) -> String {
match ty {
crate::recompiler::analysis::TypeInfo::Void => "()".to_string(),
crate::recompiler::analysis::TypeInfo::Integer { signed, size } => {
match (*signed, *size) {
(true, 8) => "i8".to_string(),
(false, 8) => "u8".to_string(),
(true, 16) => "i16".to_string(),
(false, 16) => "u16".to_string(),
(true, 32) => "i32".to_string(),
(false, 32) => "u32".to_string(),
(true, 64) => "i64".to_string(),
(false, 64) => "u64".to_string(),
_ => "u32".to_string(),
}
}
crate::recompiler::analysis::TypeInfo::Pointer { pointee } => {
format!("*mut {}", self.type_to_rust(pointee))
}
_ => "u32".to_string(),
}
}
pub fn sanitize_identifier(&self, name: &str) -> String {
name.replace(' ', "_")
.replace('-', "_")
.replace('.', "_")
.chars()
.filter(|c| c.is_alphanumeric() || *c == '_')
.collect()
}
fn indent(&self) -> String {
" ".repeat(self.indent_level)
}
}
impl Default for CodeGenerator {
fn default() -> Self {
Self::new()
}
}