Skip to content

Commit

Permalink
Merge pull request valida-xyz#148 from valida-xyz/ali/pretty_print
Browse files Browse the repository at this point in the history
make interactive debugger to pretty print instructions
  • Loading branch information
morganthomas authored Apr 10, 2024
2 parents 37e513a + 2d69813 commit 704a594
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 46 deletions.
48 changes: 42 additions & 6 deletions basic/src/bin/valida.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ impl Context<'_> {
let pc = self.machine_.cpu().pc;
let fp = self.machine_.cpu().fp;

let instruction = self.machine_.program().program_rom.get_instruction(pc);
println!("{:4} : {:?}", pc, instruction.to_string());

// check if fp is changed
if fp != self.recorded_current_fp_ {
self.last_fp_size_ = self.recorded_current_fp_ - fp;
Expand Down Expand Up @@ -176,20 +179,27 @@ fn last_frame(_: ArgMatches, context: &mut Context) -> Result<Option<String>> {
Ok(Some(frame))
}

fn list_instrs(_: ArgMatches, context: &mut Context) -> Result<Option<String>> {
fn list_instrs(args: ArgMatches, context: &mut Context) -> Result<Option<String>> {
let pc = context.machine_.cpu().pc;

let program_rom = &context.machine_.program().program_rom;
let total_size = program_rom.0.len();

let print_size_arg = args.get_one::<String>("size");

let print_size = match print_size_arg {
Some(size) => size.parse::<u32>().unwrap(),
None => 10,
};

let mut formatted = String::new();
for i in 0..5 {
for i in 0..print_size {
let cur_pc = pc + i;
if cur_pc >= total_size as u32 {
break;
}
let instruction = program_rom.get_instruction(cur_pc);
formatted.push_str(format!("{:?} : {:?}\n", cur_pc, instruction).as_str());
formatted.push_str(format!("{:4} : {:?}\n", cur_pc, instruction.to_string()).as_str());
}
Ok(Some(formatted))
}
Expand All @@ -204,8 +214,26 @@ fn set_bp(args: ArgMatches, context: &mut Context) -> Result<Option<String>> {
let message = format!("Breakpoint set at pc: {}", pc);
Ok(Some(message))
}
fn show_memory(args: ArgMatches, context: &mut Context) -> Result<Option<String>> {
let addr = args
.get_one::<String>("addr")
.unwrap()
.parse::<u32>()
.unwrap();

// show memory at address, by default show 20 cells
let mut memory = String::new();
for i in 0..8 {
let read_addr = addr + i * 4;
let string_val = context.machine_.mem().examine(read_addr);
let memory_str = format!("0x{:<8x} : {}\n", read_addr, string_val);
memory += &memory_str;
}

Ok(Some(memory))
}

fn run_until(args: ArgMatches, context: &mut Context) -> Result<Option<String>> {
fn run_until(_: ArgMatches, context: &mut Context) -> Result<Option<String>> {
let mut message = String::new();
loop {
let (stop, pc) = context.step();
Expand All @@ -222,7 +250,7 @@ fn run_until(args: ArgMatches, context: &mut Context) -> Result<Option<String>>
Ok(Some(message))
}

fn step(args: ArgMatches, context: &mut Context) -> Result<Option<String>> {
fn step(_: ArgMatches, context: &mut Context) -> Result<Option<String>> {
let (stop, _) = context.step();
if stop {
context.stopped_ = true;
Expand Down Expand Up @@ -267,9 +295,17 @@ fn repl_run(args: &Args) {
run_until,
)
.with_command(
Command::new("l").about("list instruction at current PC"),
Command::new("l")
.about("list instruction at current PC")
.arg(Arg::new("size").required(false)),
list_instrs,
)
.with_command(
Command::new("m")
.arg(Arg::new("addr").required(true))
.about("show memory at address"),
show_memory,
)
.with_command(
Command::new("reset").about("reset machine state!"),
init_context,
Expand Down
1 change: 0 additions & 1 deletion derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ fn step_method(machine: &syn::DeriveInput, instructions: &[&Field], val: &Ident)
let opcode = instruction.opcode;
let ops = instruction.operands;

std::println!("step: pc = {:?}, instruction = {:?}", pc, instruction);
match opcode {
#opcode_arms
_ => panic!("Unrecognized opcode: {}", opcode),
Expand Down
2 changes: 2 additions & 0 deletions machine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ itertools = "0.12.0"
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] }
tracing = "0.1.37"

valida-opcodes = { path = "../opcodes" }

p3-air = { workspace = true }
p3-baby-bear = { workspace = true }
p3-commit = { workspace = true }
Expand Down
93 changes: 85 additions & 8 deletions machine/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ use crate::{AdviceProvider, Machine, Word, INSTRUCTION_ELEMENTS, OPERAND_ELEMENT
use byteorder::{ByteOrder, LittleEndian};
use p3_field::Field;

/*
use derive_more::Display;
#[derive(Display)]
enum Opcode {
// TODO
}
*/
use valida_opcodes::{Opcode, IMM32};

pub trait Instruction<M: Machine<F>, F: Field> {
const OPCODE: u32;
Expand All @@ -31,13 +24,97 @@ pub struct InstructionWord<F> {
pub operands: Operands<F>,
}

impl ToString for InstructionWord<i32> {
fn to_string(&self) -> String {
let opcode = match Opcode::try_from(self.opcode) {
Ok(opcode_name) => {
format!("{:?}", opcode_name)
}
Err(_) => {
format!("UNKNOWN_OP:{}", self.opcode.to_string())
}
};
format!("{} {}", opcode, self.print_operands())
}
}

impl InstructionWord<i32> {
pub fn flatten<F: Field>(&self) -> [F; INSTRUCTION_ELEMENTS] {
let mut result = [F::default(); INSTRUCTION_ELEMENTS];
result[0] = F::from_canonical_u32(self.opcode);
result[1..].copy_from_slice(&Operands::<F>::from_i32_slice(&self.operands.0).0);
result
}

pub fn print_imm32(&self) -> String {
assert!(self.opcode == IMM32, "Instruction is not immediate");

//extract the immediate value
let imm0 = self.operands.0[1];
let imm1 = self.operands.0[2];
let imm2 = self.operands.0[3];
let imm3 = self.operands.0[4];
format!(
"{}(fp), {}",
self.operands.0[0],
imm0 << 24 | imm1 << 16 | imm2 << 8 | imm3
)
}

pub fn print_first_operand(&self) -> String {
format!("{}(fp)", self.operands.0[1])
}

pub fn print_second_operand(&self) -> String {
let second_opnd_is_imm = self.operands.0[4] != 0;
if second_opnd_is_imm {
format!("{}", self.operands.0[2])
} else {
format!("{}(fp)", self.operands.0[2])
}
}

pub fn print_address(&self, index: usize) -> String {
format!("{}", self.operands.0[index] / 24)
}

pub fn print_operands(&self) -> String {
match self.opcode {
valida_opcodes::IMM32 => self.print_imm32(),
valida_opcodes::JAL => format!(
"{}(fp), PC: {}, {}",
self.operands.0[0],
self.print_address(1),
self.operands.0[2]
),
valida_opcodes::JALV => format!(
"{}(fp), {}(fp), {}(fp)",
self.operands.0[0], self.operands.0[1], self.operands.0[2]
),
valida_opcodes::LOADFP => format!("{}(fp), {}", self.operands.0[0], self.operands.0[1]),
valida_opcodes::BEQ | valida_opcodes::BNE => format!(
"{}, {}, {}",
self.print_address(0),
self.print_first_operand(),
self.print_second_operand()
),
valida_opcodes::STOP => "".to_string(),
valida_opcodes::LOAD32 => {
format!("{}(fp), {}(fp)", self.operands.0[0], self.operands.0[2])
}
valida_opcodes::STORE32 => {
format!("{}(fp), {}(fp)", self.operands.0[1], self.operands.0[2])
}
_ => {
format!(
"{}(fp), {}, {}",
self.operands.0[0],
self.print_first_operand(),
self.print_second_operand()
)
}
}
}
}

#[derive(Copy, Clone, Default, Debug)]
Expand Down
4 changes: 4 additions & 0 deletions opcodes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ name = "valida-opcodes"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
num_enum = "0.5"

108 changes: 77 additions & 31 deletions opcodes/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,88 @@
use num_enum::TryFromPrimitive;

pub const BYTES_PER_INSTR: u32 = 24; // 4 bytes per word * 6 words per instruction

#[repr(u32)]
#[derive(Debug, TryFromPrimitive)]
pub enum Opcode {
LOAD32 = 1,
STORE32 = 2,
JAL = 3,
JALV = 4,
BEQ = 5,
BNE = 6,
IMM32 = 7,
STOP = 8,
READ_ADVICE = 9,
LOADFP = 10,
ADD32 = 100,
SUB32 = 101,
MUL32 = 102,
DIV32 = 103,
SDIV32 = 110,
LT32 = 104,
SHL32 = 105,
SHR32 = 106,
AND32 = 107,
OR32 = 108,
XOR32 = 109,
NE32 = 111,
MULHU32 = 112,
SRA32 = 113,
MULHS32 = 114,
LTE32 = 115,
EQ32 = 116,
ADD = 200,
SUB = 201,
MUL = 202,
WRITE = 300,
}

macro_rules! declare_opcode {
($opcode : ident) => {
pub const $opcode: u32 = Opcode::$opcode as u32;
};
}

// TODO: should combine enum together

/// CORE
pub const LOAD32: u32 = 1;
pub const STORE32: u32 = 2;
pub const JAL: u32 = 3;
pub const JALV: u32 = 4;
pub const BEQ: u32 = 5;
pub const BNE: u32 = 6;
pub const IMM32: u32 = 7;
pub const STOP: u32 = 8;
pub const LOADFP: u32 = 10;
declare_opcode!(LOAD32);
declare_opcode!(STORE32);
declare_opcode!(JAL);
declare_opcode!(JALV);
declare_opcode!(BEQ);
declare_opcode!(BNE);
declare_opcode!(IMM32);
declare_opcode!(STOP);
declare_opcode!(LOADFP);

/// NONDETERMINISTIC
pub const READ_ADVICE: u32 = 9;
declare_opcode!(READ_ADVICE);

/// U32 ALU
pub const ADD32: u32 = 100;
pub const SUB32: u32 = 101;
pub const MUL32: u32 = 102;
pub const DIV32: u32 = 103;
pub const SDIV32: u32 = 110; // TODO: Should we redo the numbers? Need to update compiler?
pub const LT32: u32 = 104;
pub const SHL32: u32 = 105;
pub const SHR32: u32 = 106;
pub const AND32: u32 = 107;
pub const OR32: u32 = 108;
pub const XOR32: u32 = 109;
pub const NE32: u32 = 111;
pub const MULHU32: u32 = 112;
pub const SRA32: u32 = 113;
pub const MULHS32: u32 = 114;
pub const LTE32: u32 = 115;
pub const EQ32: u32 = 116;
declare_opcode!(ADD32);
declare_opcode!(SUB32);
declare_opcode!(MUL32);
declare_opcode!(DIV32);
declare_opcode!(SDIV32);
declare_opcode!(LT32);
declare_opcode!(SHL32);
declare_opcode!(SHR32);
declare_opcode!(AND32);
declare_opcode!(OR32);
declare_opcode!(XOR32);
declare_opcode!(NE32);
declare_opcode!(MULHU32);
declare_opcode!(SRA32);
declare_opcode!(MULHS32);
declare_opcode!(LTE32);
declare_opcode!(EQ32);

/// NATIVE FIELD
pub const ADD: u32 = 200;
pub const SUB: u32 = 201;
pub const MUL: u32 = 202;
declare_opcode!(ADD);
declare_opcode!(SUB);
declare_opcode!(MUL);

/// OUTPUT
pub const WRITE: u32 = 300;
declare_opcode!(WRITE);

0 comments on commit 704a594

Please sign in to comment.