use crate::opcode::OpCode; use crate::readwrite::*; use std::io::{Cursor, Read}; /// Represents a disassembled instruction. #[derive(Debug, Clone)] pub struct Instr { /// The absolute address (PC) where this instruction starts in ROM. pub pc: u32, /// The decoded OpCode. pub opcode: OpCode, /// The list of operands extracted from the byte stream. pub operands: Vec, } /// Represents an operand decoded from the byte stream. #[derive(Debug, Clone)] pub enum DisasmOperand { U32(u32), I32(i32), I64(i64), F64(f64), Bool(bool), } /// Translates raw ROM bytes back into a human-readable list of instructions. /// /// This is the inverse of the assembly process. It reads the bytes sequentially, /// identifies the OpCode, and then reads the correct number of operand bytes /// based on the ISA rules. pub fn disasm(rom: &[u8]) -> Result, String> { let mut instructions = Vec::new(); let mut cursor = Cursor::new(rom); while (cursor.position() as usize) < rom.len() { let pc = cursor.position() as u32; let op_val = read_u16_le(&mut cursor).map_err(|e| e.to_string())?; let opcode = OpCode::try_from(op_val)?; let mut operands = Vec::new(); match opcode { OpCode::PushConst | OpCode::PushI32 | OpCode::PushBounded | OpCode::Jmp | OpCode::JmpIfFalse | OpCode::JmpIfTrue | OpCode::GetGlobal | OpCode::SetGlobal | OpCode::GetLocal | OpCode::SetLocal | OpCode::PopN | OpCode::Syscall | OpCode::GateLoad | OpCode::GateStore | OpCode::Call => { let v = read_u32_le(&mut cursor).map_err(|e| e.to_string())?; operands.push(DisasmOperand::U32(v)); } OpCode::PushI64 | OpCode::PushF64 => { let v = read_i64_le(&mut cursor).map_err(|e| e.to_string())?; operands.push(DisasmOperand::I64(v)); } OpCode::PushBool => { let mut b_buf = [0u8; 1]; cursor.read_exact(&mut b_buf).map_err(|e| e.to_string())?; operands.push(DisasmOperand::Bool(b_buf[0] != 0)); } OpCode::Alloc => { let v1 = read_u32_le(&mut cursor).map_err(|e| e.to_string())?; let v2 = read_u32_le(&mut cursor).map_err(|e| e.to_string())?; operands.push(DisasmOperand::U32(v1)); operands.push(DisasmOperand::U32(v2)); } _ => {} } instructions.push(Instr { pc, opcode, operands }); } Ok(instructions) }