bQUARKz f9120e740b
dev/pbs (#8)
Co-authored-by: Nilton Constantino <nilton.constantino@visma.com>
Reviewed-on: #8
2026-03-24 13:40:22 +00:00

71 lines
2.5 KiB
Rust

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<DisasmOperand>,
}
/// 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<Vec<Instr>, 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)
}