use sp1_jit::debug::State;
use crate::{Program, Register, SyscallCode, HALT_PC};
#[allow(unused)]
pub fn render_current_instruction(program: &Program, state: &State) -> String {
if state.pc == HALT_PC {
return "<HALTED>".to_string();
}
let Some(instruction) = program.fetch(state.pc) else {
return format!("<INVALID_PC=0x{:016x}>", state.pc);
};
let a = instruction.op_a;
let b = if instruction.imm_b {
format!("0x{:016x} (imm) ", instruction.op_b as i32)
} else {
let index = instruction.op_b as usize;
let value = state.registers[index];
format!("0x{value:016x} (%x{index:02})",)
};
let c = if instruction.imm_c {
format!("0x{:016x} (imm) ", instruction.op_c as i32)
} else {
let index = instruction.op_c as usize;
let value = state.registers[index];
format!("0x{value:016x} (%x{index:02})",)
};
let rd = if instruction.is_ecall_instruction() {
let syscall_name =
SyscallCode::from_u32(state.registers[Register::X5 as usize] as u32).to_string();
syscall_name[..syscall_name.len().min(12)].to_string()
} else {
format!("%x{a:02}")
};
let pc = state.pc;
let opcode = instruction.opcode.mnemonic();
let clk = state.clk;
format!("{clk:>12} {pc:x} {opcode:>10} {rd:>12} {b} {c}")
}
#[allow(unused)]
pub fn compare_states(program: &Program, got: &State, expected: &State) -> (bool, String) {
use std::fmt::Write;
let mut is_equal = true;
let mut report = String::new();
writeln!(report, " REGISTER GOT EXPECTED").unwrap();
for i in 0..32 {
let got = got.registers[i];
let expected = expected.registers[i];
if got == expected {
writeln!(report, " {i:>2}: ✅ 0x{got:016x} == 0x{expected:016x}").unwrap();
} else {
writeln!(report, " {i:>2}: ❌ 0x{got:016x} != 0x{expected:016x}").unwrap();
is_equal = false;
}
}
if got.pc == expected.pc {
writeln!(report, " PC: ✅ 0x{:016x} == 0x{:016x}", got.pc, expected.pc).unwrap();
} else {
writeln!(
report,
" PC: ❌ 0x{:016x} != 0x{:016x} (diff = {})",
got.pc,
expected.pc,
got.pc as i64 - expected.pc as i64
)
.unwrap();
is_equal = false;
}
if got.clk == expected.clk {
writeln!(report, " CLK: ✅ 0x{:016x} == 0x{:016x}", got.clk, expected.clk).unwrap();
} else {
writeln!(
report,
" CLK: ❌ 0x{:016x} != 0x{:016x} (diff = {})",
got.clk,
expected.clk,
got.clk as i64 - expected.clk as i64
)
.unwrap();
is_equal = false;
}
if got.global_clk == expected.global_clk {
writeln!(
report,
"GLOBAL_CLK: ✅ 0x{:016x} == 0x{:016x}",
got.global_clk, expected.global_clk
)
.unwrap();
} else {
writeln!(
report,
"GLOBAL_CLK: ❌ 0x{:016x} != 0x{:016x} (diff = {})",
got.global_clk,
expected.global_clk,
got.global_clk as i64 - expected.global_clk as i64
)
.unwrap();
is_equal = false;
}
writeln!(report).unwrap();
let got_instruction = render_current_instruction(program, got);
let expected_instruction = render_current_instruction(program, expected);
if got_instruction == expected_instruction {
writeln!(report, "✅ CURRENT INSTRUCTION MATCHES").unwrap();
writeln!(report, " GOT: {got_instruction}").unwrap();
writeln!(report, " EXPECTED: {expected_instruction}").unwrap();
} else {
writeln!(report, "❌ CURRENT INSTRUCTION DOES NOT MATCH").unwrap();
writeln!(report, " GOT: {got_instruction}").unwrap();
writeln!(report, " EXPECTED: {expected_instruction}").unwrap();
is_equal = false;
}
(is_equal, report)
}