diff --git a/core/src/alu/add/mod.rs b/core/src/alu/add/mod.rs index 69c9fd8eaa..eddb2cb4f6 100644 --- a/core/src/alu/add/mod.rs +++ b/core/src/alu/add/mod.rs @@ -14,8 +14,6 @@ use crate::lookup::Interaction; use crate::utils::{pad_to_power_of_two, Chip}; use crate::Runtime; -use super::AluEvent; - pub const NUM_ADD_COLS: usize = size_of::>(); /// The column layout for the chip. @@ -35,15 +33,19 @@ pub struct AddCols { } /// A chip that implements addition for the opcodes ADD and ADDI. -pub struct AddChip { - events: Vec, +pub struct AddChip; + +impl AddChip { + pub fn new() -> Self { + Self {} + } } impl Chip for AddChip { - fn generate_trace(&self, _: &mut Runtime) -> RowMajorMatrix { + fn generate_trace(&self, runtime: &mut Runtime) -> RowMajorMatrix { // Generate the trace rows for each event. - let rows = self - .events + let rows = runtime + .add_events .par_iter() .map(|event| { let mut row = [F::zero(); NUM_ADD_COLS]; @@ -165,14 +167,8 @@ mod tests { fn generate_trace() { let program = vec![]; let mut runtime = Runtime::new(program); - let events = vec![AluEvent { - clk: 0, - opcode: Opcode::ADD, - a: 14, - b: 8, - c: 6, - }]; - let chip = AddChip { events }; + runtime.add_events = vec![AluEvent::new(0, Opcode::ADD, 14, 8, 6)]; + let chip = AddChip::new(); let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); println!("{:?}", trace.values) } @@ -221,15 +217,8 @@ mod tests { let program = vec![]; let mut runtime = Runtime::new(program); - let events = vec![AluEvent { - clk: 0, - opcode: Opcode::ADD, - a: 14, - b: 8, - c: 6, - }] - .repeat(1000); - let chip = AddChip { events }; + runtime.add_events = vec![AluEvent::new(0, Opcode::ADD, 14, 8, 6)].repeat(1000); + let chip = AddChip::new(); let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); let proof = prove::(&config, &chip, &mut challenger, trace); diff --git a/core/src/alu/bitwise/mod.rs b/core/src/alu/bitwise/mod.rs index de910de94c..bcb2707018 100644 --- a/core/src/alu/bitwise/mod.rs +++ b/core/src/alu/bitwise/mod.rs @@ -7,14 +7,14 @@ use p3_field::PrimeField; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; + use valida_derive::AlignedBorrow; use crate::air::Word; use crate::lookup::Interaction; use crate::runtime::Opcode; use crate::utils::{pad_to_power_of_two, Chip}; - -use super::AluEvent; +use crate::Runtime; pub const NUM_BITWISE_COLS: usize = size_of::>(); @@ -41,15 +41,19 @@ pub struct BitwiseCols { } /// A chip that implements bitwise operations for the opcodes XOR, XORI, OR, ORI, AND, and ANDI. -pub struct BitwiseChip { - events: Vec, +pub struct BitwiseChip; + +impl BitwiseChip { + pub fn new() -> Self { + Self {} + } } impl Chip for BitwiseChip { - fn generate_trace(&self, _: &mut crate::Runtime) -> RowMajorMatrix { + fn generate_trace(&self, runtime: &mut Runtime) -> RowMajorMatrix { // Generate the trace rows for each event. - let rows = self - .events + let rows = runtime + .bitwise_events .par_iter() .map(|event| { let mut row = [F::zero(); NUM_BITWISE_COLS]; @@ -195,14 +199,8 @@ mod tests { fn generate_trace() { let program = vec![]; let mut runtime = Runtime::new(program); - let events = vec![AluEvent { - clk: 0, - opcode: Opcode::ADD, - a: 14, - b: 8, - c: 6, - }]; - let chip = BitwiseChip { events }; + runtime.bitwise_events = vec![AluEvent::new(0, Opcode::XOR, 25, 10, 19)]; + let chip = BitwiseChip::new(); let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); println!("{:?}", trace.values) } @@ -251,31 +249,13 @@ mod tests { let program = vec![]; let mut runtime = Runtime::new(program); - let events = vec![ - AluEvent { - clk: 0, - opcode: Opcode::XOR, - a: 25, - b: 10, - c: 19, - }, - AluEvent { - clk: 0, - opcode: Opcode::OR, - a: 27, - b: 10, - c: 19, - }, - AluEvent { - clk: 0, - opcode: Opcode::AND, - a: 2, - b: 10, - c: 19, - }, + runtime.bitwise_events = vec![ + AluEvent::new(0, Opcode::XOR, 25, 10, 19), + AluEvent::new(0, Opcode::OR, 27, 10, 19), + AluEvent::new(0, Opcode::AND, 2, 10, 19), ] .repeat(1000); - let chip = BitwiseChip { events }; + let chip = BitwiseChip::new(); let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); let proof = prove::(&config, &chip, &mut challenger, trace); diff --git a/core/src/alu/mod.rs b/core/src/alu/mod.rs index 02b0d5b4d2..7bc7db48fe 100644 --- a/core/src/alu/mod.rs +++ b/core/src/alu/mod.rs @@ -1,11 +1,8 @@ -use p3_field::PrimeField; -use p3_matrix::dense::RowMajorMatrix; - -use crate::{lookup::Interaction, runtime::Opcode, Runtime}; -mod add; -mod bitwise; -mod shift; -mod sub; +use crate::runtime::Opcode; +pub mod add; +pub mod bitwise; +pub mod shift; +pub mod sub; #[derive(Debug, Clone, Copy)] pub struct AluEvent { @@ -15,3 +12,15 @@ pub struct AluEvent { pub b: u32, pub c: u32, } + +impl AluEvent { + pub fn new(clk: u32, opcode: Opcode, a: u32, b: u32, c: u32) -> Self { + Self { + clk, + opcode, + a, + b, + c, + } + } +} diff --git a/core/src/alu/sub/mod.rs b/core/src/alu/sub/mod.rs index 646a4a9348..6058fdca98 100644 --- a/core/src/alu/sub/mod.rs +++ b/core/src/alu/sub/mod.rs @@ -6,14 +6,15 @@ use p3_field::PrimeField; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; + use std::mem::transmute; use valida_derive::AlignedBorrow; use crate::air::Word; use crate::lookup::Interaction; -use crate::utils::{pad_to_power_of_two, Chip}; -use super::AluEvent; +use crate::utils::{pad_to_power_of_two, Chip}; +use crate::Runtime; pub const NUM_SUB_COLS: usize = size_of::>(); @@ -34,15 +35,19 @@ pub struct SubCols { } /// A chip that implements subtraction for the opcode SUB. -pub struct SubChip { - events: Vec, +pub struct SubChip; + +impl SubChip { + pub fn new() -> Self { + Self {} + } } impl Chip for SubChip { - fn generate_trace(&self, _: &mut crate::Runtime) -> RowMajorMatrix { + fn generate_trace(&self, runtime: &mut Runtime) -> RowMajorMatrix { // Generate the trace rows for each event. - let rows = self - .events + let rows = runtime + .sub_events .par_iter() .map(|event| { let mut row = [F::zero(); NUM_SUB_COLS]; @@ -169,14 +174,8 @@ mod tests { fn generate_trace() { let program = vec![]; let mut runtime = Runtime::new(program); - let events = vec![AluEvent { - clk: 0, - opcode: Opcode::ADD, - a: 2, - b: 8, - c: 6, - }]; - let chip = SubChip { events }; + runtime.sub_events = vec![AluEvent::new(0, Opcode::SUB, 14, 8, 6)]; + let chip = SubChip {}; let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); println!("{:?}", trace.values) } @@ -225,15 +224,8 @@ mod tests { let program = vec![]; let mut runtime = Runtime::new(program); - let events = vec![AluEvent { - clk: 0, - opcode: Opcode::SUB, - a: 2, - b: 8, - c: 6, - }] - .repeat(1000); - let chip = SubChip { events }; + runtime.sub_events = vec![AluEvent::new(0, Opcode::SUB, 14, 8, 6)].repeat(1000); + let chip = SubChip::new(); let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); let proof = prove::(&config, &chip, &mut challenger, trace); diff --git a/core/src/cpu/air.rs b/core/src/cpu/air.rs index 07e743d12e..a78026db35 100644 --- a/core/src/cpu/air.rs +++ b/core/src/cpu/air.rs @@ -1,14 +1,15 @@ -use crate::air::{reduce, AirConstraint, AirVariable, Bool, Word}; -use crate::lookup::{Interaction, IsRead}; +use crate::air::{reduce, AirConstraint, Word}; +use crate::runtime::{Instruction, Opcode}; use core::borrow::{Borrow, BorrowMut}; use core::mem::{size_of, transmute}; -use p3_air::{AirBuilder, BaseAir, VirtualPairCol}; -use p3_field::AbstractField; -use p3_field::{Field, PrimeField}; +use p3_air::AirBuilder; +use p3_field::{AbstractField, PrimeField}; use p3_matrix::MatrixRowSlices; use p3_util::indices_arr; use valida_derive::AlignedBorrow; +use super::CpuEvent; + #[derive(AlignedBorrow, Default)] #[repr(C)] pub struct OpcodeSelectors { @@ -45,6 +46,129 @@ pub struct OpcodeSelectors { pub reg_a_read: T, } +impl OpcodeSelectors { + pub fn populate(&mut self, instruction: Instruction) { + match instruction.opcode { + // Register instructions + Opcode::ADD + | Opcode::SUB + | Opcode::XOR + | Opcode::OR + | Opcode::AND + | Opcode::SLL + | Opcode::SRL + | Opcode::SRA + | Opcode::SLT + | Opcode::SLTU => { + // For register instructions, neither imm_b or imm_c should be turned on. + self.register_instruction = F::one(); + } + // Immediate instructions + Opcode::ADDI + | Opcode::XORI + | Opcode::ORI + | Opcode::ANDI + | Opcode::SLLI + | Opcode::SRLI + | Opcode::SRAI + | Opcode::SLTI + | Opcode::SLTIU => { + // For immediate instructions, imm_c should be turned on. + self.imm_c = F::one(); + self.immediate_instruction = F::one(); + } + // Load instructions + Opcode::LB | Opcode::LH | Opcode::LW | Opcode::LBU | Opcode::LHU => { + // For load instructions, imm_c should be turned on. + self.imm_c = F::one(); + self.load_instruction = F::one(); + match instruction.opcode { + Opcode::LB | Opcode::LBU => { + self.byte = F::one(); + } + Opcode::LH | Opcode::LHU => { + self.half = F::one(); + } + Opcode::LW => { + self.word = F::one(); + } + _ => {} + } + } + // Store instructions + Opcode::SB | Opcode::SH | Opcode::SW => { + // For store instructions, imm_c should be turned on. + self.imm_c = F::one(); + self.store_instruction = F::one(); + self.reg_a_read = F::one(); + match instruction.opcode { + Opcode::SB => { + self.byte = F::one(); + } + Opcode::SH => { + self.half = F::one(); + } + Opcode::SW => { + self.word = F::one(); + } + _ => {} + } + } + // Branch instructions + Opcode::BEQ | Opcode::BNE | Opcode::BLT | Opcode::BGE | Opcode::BLTU | Opcode::BGEU => { + self.imm_c = F::one(); + self.branch_instruction = F::one(); + self.reg_a_read = F::one(); + } + // Jump instructions + Opcode::JAL => { + self.JAL = F::one(); + self.imm_b = F::one(); + self.imm_c = F::one(); + self.jump_instruction = F::one(); + } + Opcode::JALR => { + self.JALR = F::one(); + self.imm_c = F::one(); + self.jump_instruction = F::one(); + } + // Upper immediate instructions + Opcode::LUI => { + // Note that we convert a LUI opcode to a SLL opcode with both imm_b and imm_c turned on. + // And the value of imm_c is 12. + self.imm_b = F::one(); + self.imm_c = F::one(); + // In order to process lookups for the SLL opcode table, we'll also turn on the "immediate_instruction". + self.immediate_instruction = F::one(); + } + Opcode::AUIPC => { + // Note that for an AUIPC opcode, we turn on both imm_b and imm_c. + self.imm_b = F::one(); + self.imm_c = F::one(); + self.AUIPC = F::one(); + // We constraint that imm_c = imm_b << 12 by looking up SLL(op_c_val, op_b_val, 12) with multiplicity AUIPC. + // Then we constraint op_a_val = op_c_val + pc by looking up ADD(op_a_val, op_c_val, pc) with multiplicity AUIPC. + } + // Multiply instructions + Opcode::MUL + | Opcode::MULH + | Opcode::MULSU + | Opcode::MULU + | Opcode::DIV + | Opcode::DIVU + | Opcode::REM + | Opcode::REMU => { + self.multiply_instruction = F::one(); + match instruction.opcode { + // TODO: set byte/half/word/unsigned based on which variant of multiply. + _ => {} + } + } + _ => panic!("Invalid opcode"), + } + } +} + #[derive(AlignedBorrow, Default)] #[repr(C)] pub struct InstructionCols { @@ -58,6 +182,27 @@ pub struct InstructionCols { pub op_c: T, } +impl InstructionCols { + pub fn populate(&mut self, instruction: Instruction) { + self.opcode = F::from_canonical_u32(instruction.opcode as u32); + match instruction.opcode { + Opcode::LUI => { + // For LUI, we convert it to a SLL instruction with imm_b and imm_c turned on. + self.opcode = F::from_canonical_u32(Opcode::SLL as u32); + assert_eq!(instruction.op_c as u32, 12); + } + Opcode::AUIPC => { + // For AUIPC, we set the 3rd operand to imm_b << 12. + assert_eq!(instruction.op_c as u32, instruction.op_b << 12); + } + _ => {} + } + self.op_a = F::from_canonical_u32(instruction.op_a as u32); + self.op_b = F::from_canonical_u32(instruction.op_b as u32); + self.op_c = F::from_canonical_u32(instruction.op_c as u32); + } +} + /// An AIR table for memory accesses. #[derive(AlignedBorrow, Default)] #[repr(C)] diff --git a/core/src/cpu/mod.rs b/core/src/cpu/mod.rs index 95c89572f5..0239a6a661 100644 --- a/core/src/cpu/mod.rs +++ b/core/src/cpu/mod.rs @@ -7,8 +7,7 @@ pub struct CpuEvent { pub clk: u32, pub pc: u32, pub instruction: Instruction, - pub operands: [u32; 3], - pub addr: Option, - pub memory_value: Option, - pub branch_condition: Option, + pub a: u32, + pub b: u32, + pub c: u32, } diff --git a/core/src/cpu/trace.rs b/core/src/cpu/trace.rs index 2275c5aa23..eab7dd6f5a 100644 --- a/core/src/cpu/trace.rs +++ b/core/src/cpu/trace.rs @@ -1,29 +1,33 @@ -use super::air::{CpuCols, InstructionCols, OpcodeSelectors, CPU_COL_MAP, NUM_CPU_COLS}; +use super::air::{CpuCols, CPU_COL_MAP, NUM_CPU_COLS}; use super::CpuEvent; use crate::lookup::{Interaction, IsRead}; -use core::mem::{size_of, transmute}; -use p3_air::{AirBuilder, BaseAir, VirtualPairCol}; +use crate::utils::Chip; +use core::mem::transmute; +use p3_air::VirtualPairCol; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; + +use crate::runtime::{Opcode, Runtime}; -use crate::air::Word; -use crate::runtime::chip::Chip; -use crate::runtime::{Instruction, Opcode, Runtime}; use p3_field::PrimeField; use p3_matrix::dense::RowMajorMatrix; -pub struct CpuChip { - pub _phantom: core::marker::PhantomData, +pub struct CpuChip; + +impl CpuChip { + pub fn new() -> Self { + Self {} + } } -impl Chip for CpuChip { +impl Chip for CpuChip { fn generate_trace(&self, runtime: &mut Runtime) -> RowMajorMatrix { - let mut rows = runtime + let rows = runtime .cpu_events - .iter() // TODO make this a par_iter - .enumerate() - .map(|(n, op)| self.event_to_row(*op)) + .par_iter() + .map(|op| self.event_to_row(*op)) .collect::>(); - let mut trace = + let trace = RowMajorMatrix::new(rows.into_iter().flatten().collect::>(), NUM_CPU_COLS); // TODO: pad to a power of 2. @@ -140,176 +144,55 @@ impl Chip for CpuChip { } } -impl CpuChip { - fn event_to_row(&self, event: CpuEvent) -> [F; NUM_CPU_COLS] { +impl CpuChip { + fn event_to_row(&self, event: CpuEvent) -> [F; NUM_CPU_COLS] { let mut row = [F::zero(); NUM_CPU_COLS]; let cols: &mut CpuCols = unsafe { transmute(&mut row) }; cols.clk = F::from_canonical_u32(event.clk); cols.pc = F::from_canonical_u32(event.pc); - self.populate_instruction(&mut cols.instruction, event.instruction); - self.populate_selectors(&mut cols.selectors, event.instruction.opcode); + cols.instruction.populate(event.instruction); + cols.selectors.populate(event.instruction); - cols.op_a_val = event.operands[0].into(); - cols.op_b_val = event.operands[1].into(); - cols.op_c_val = event.operands[2].into(); + cols.op_a_val = event.a.into(); + cols.op_b_val = event.b.into(); + cols.op_c_val = event.c.into(); self.populate_memory(cols, event); self.populate_branch(cols, event); row } - fn populate_instruction(&self, cols: &mut InstructionCols, instruction: Instruction) { - cols.opcode = F::from_canonical_u32(instruction.opcode as u32); - match instruction.opcode { - Opcode::LUI => { - // For LUI, we convert it to a SLL instruction with imm_b and imm_c turned on. - cols.opcode = F::from_canonical_u32(Opcode::SLL as u32); - assert_eq!(instruction.c as u32, 12); - } - Opcode::AUIPC => { - // For AUIPC, we set the 3rd operand to imm_b << 12. - assert_eq!(instruction.c as u32, instruction.b << 12); + fn populate_memory(&self, cols: &mut CpuCols, event: CpuEvent) { + match event.instruction.opcode { + Opcode::LB + | Opcode::LH + | Opcode::LW + | Opcode::LBU + | Opcode::LHU + | Opcode::SB + | Opcode::SH + | Opcode::SW => { + let memory_value = event.a; + let memory_addr = event.b.wrapping_add(event.c); + cols.mem_val = memory_value.into(); + cols.addr = memory_addr.into(); } _ => {} } - cols.op_a = F::from_canonical_u32(instruction.a as u32); - cols.op_b = F::from_canonical_u32(instruction.b as u32); - cols.op_c = F::from_canonical_u32(instruction.c as u32); - } - - fn populate_selectors(&self, cols: &mut OpcodeSelectors, opcode: Opcode) { - match opcode { - // Register instructions - Opcode::ADD - | Opcode::SUB - | Opcode::XOR - | Opcode::OR - | Opcode::AND - | Opcode::SLL - | Opcode::SRL - | Opcode::SRA - | Opcode::SLT - | Opcode::SLTU => { - // For register instructions, neither imm_b or imm_c should be turned on. - cols.register_instruction = F::one(); - } - // Immediate instructions - Opcode::ADDI - | Opcode::XORI - | Opcode::ORI - | Opcode::ANDI - | Opcode::SLLI - | Opcode::SRLI - | Opcode::SRAI - | Opcode::SLTI - | Opcode::SLTIU => { - // For immediate instructions, imm_c should be turned on. - cols.imm_c = F::one(); - cols.immediate_instruction = F::one(); - } - // Load instructions - Opcode::LB | Opcode::LH | Opcode::LW | Opcode::LBU | Opcode::LHU => { - // For load instructions, imm_c should be turned on. - cols.imm_c = F::one(); - cols.load_instruction = F::one(); - match opcode { - Opcode::LB | Opcode::LBU => { - cols.byte = F::one(); - } - Opcode::LH | Opcode::LHU => { - cols.half = F::one(); - } - Opcode::LW => { - cols.word = F::one(); - } - _ => {} - } - } - // Store instructions - Opcode::SB | Opcode::SH | Opcode::SW => { - // For store instructions, imm_c should be turned on. - cols.imm_c = F::one(); - cols.store_instruction = F::one(); - cols.reg_a_read = F::one(); - match opcode { - Opcode::SB => { - cols.byte = F::one(); - } - Opcode::SH => { - cols.half = F::one(); - } - Opcode::SW => { - cols.word = F::one(); - } - _ => {} - } - } - // Branch instructions - Opcode::BEQ | Opcode::BNE | Opcode::BLT | Opcode::BGE | Opcode::BLTU | Opcode::BGEU => { - cols.imm_c = F::one(); - cols.branch_instruction = F::one(); - cols.reg_a_read = F::one(); - } - // Jump instructions - Opcode::JAL => { - cols.JAL = F::one(); - cols.imm_b = F::one(); - cols.imm_c = F::one(); - cols.jump_instruction = F::one(); - } - Opcode::JALR => { - cols.JALR = F::one(); - cols.imm_c = F::one(); - cols.jump_instruction = F::one(); - } - // Upper immediate instructions - Opcode::LUI => { - // Note that we convert a LUI opcode to a SLL opcode with both imm_b and imm_c turned on. - // And the value of imm_c is 12. - cols.imm_b = F::one(); - cols.imm_c = F::one(); - // In order to process lookups for the SLL opcode table, we'll also turn on the "immediate_instruction". - cols.immediate_instruction = F::one(); - } - Opcode::AUIPC => { - // Note that for an AUIPC opcode, we turn on both imm_b and imm_c. - cols.imm_b = F::one(); - cols.imm_c = F::one(); - cols.AUIPC = F::one(); - // We constraint that imm_c = imm_b << 12 by looking up SLL(op_c_val, op_b_val, 12) with multiplicity AUIPC. - // Then we constraint op_a_val = op_c_val + pc by looking up ADD(op_a_val, op_c_val, pc) with multiplicity AUIPC. - } - // Multiply instructions - Opcode::MUL - | Opcode::MULH - | Opcode::MULSU - | Opcode::MULU - | Opcode::DIV - | Opcode::DIVU - | Opcode::REM - | Opcode::REMU => { - cols.multiply_instruction = F::one(); - match opcode { - // TODO: set byte/half/word/unsigned based on which variant of multiply. - _ => {} - } - } - _ => panic!("Invalid opcode"), - } } - fn populate_memory(&self, cols: &mut CpuCols, event: CpuEvent) { - if let Some(memory_value) = event.memory_value { - cols.mem_val = memory_value.into(); - } - if let Some(addr) = event.addr { - cols.addr = addr.into(); - } - } - - fn populate_branch(&self, cols: &mut CpuCols, event: CpuEvent) { - if let Some(branch_condition) = event.branch_condition { + fn populate_branch(&self, cols: &mut CpuCols, event: CpuEvent) { + let branch_condition = match event.instruction.opcode { + Opcode::BEQ => Some(event.a == event.b), + Opcode::BNE => Some(event.a != event.b), + Opcode::BLT => Some((event.a as i32) < (event.b as i32)), + Opcode::BGE => Some((event.a as i32) >= (event.b as i32)), + Opcode::BLTU => Some(event.a < event.b), + Opcode::BGEU => Some(event.a >= event.b), + _ => None, + }; + if let Some(branch_condition) = branch_condition { cols.branch_cond_val = (branch_condition as u32).into(); } } @@ -317,32 +200,29 @@ impl CpuChip { #[cfg(test)] mod tests { - use crate::runtime::Instruction; use p3_baby_bear::BabyBear; + use crate::runtime::Instruction; + use super::*; #[test] fn generate_trace() { let program = vec![]; let mut runtime = Runtime::new(program); - let events = vec![CpuEvent { + runtime.cpu_events = vec![CpuEvent { clk: 6, pc: 1, instruction: Instruction { opcode: Opcode::ADD, - a: 0, - b: 1, - c: 2, + op_a: 0, + op_b: 1, + op_c: 2, }, - operands: [1, 2, 3], - addr: None, - memory_value: None, - branch_condition: None, + a: 1, + b: 2, + c: 3, }]; - let chip = CpuChip:: { - _phantom: Default::default(), - }; - runtime.cpu_events = events; + let chip = CpuChip::new(); let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); println!("{:?}", trace.values) } diff --git a/core/src/lib.rs b/core/src/lib.rs index 745483adea..33ff893257 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -5,6 +5,7 @@ pub mod cpu; pub mod lookup; pub mod memory; pub mod precompiles; +pub mod program; pub mod utils; extern crate alloc; diff --git a/core/src/program/mod.rs b/core/src/program/mod.rs new file mode 100644 index 0000000000..cb067fc1ea --- /dev/null +++ b/core/src/program/mod.rs @@ -0,0 +1,116 @@ +use core::borrow::{Borrow, BorrowMut}; +use core::mem::{size_of, transmute}; +use p3_air::{Air, AirBuilder, BaseAir}; +use p3_field::PrimeField; +use p3_matrix::dense::RowMajorMatrix; +use rayon::iter::IntoParallelIterator; +use rayon::iter::{IndexedParallelIterator, ParallelIterator}; +use valida_derive::AlignedBorrow; + +use crate::cpu::air::{InstructionCols, OpcodeSelectors}; +use crate::lookup::Interaction; +use crate::utils::{pad_to_power_of_two, Chip}; +use crate::Runtime; + +pub const NUM_PROGRAM_COLS: usize = size_of::>(); + +/// The column layout for the chip. +#[derive(AlignedBorrow, Default)] +pub struct ProgramCols { + pub pc: T, + pub instruction: InstructionCols, + pub selectors: OpcodeSelectors, +} + +/// A chip that implements addition for the opcodes ADD and ADDI. +pub struct ProgramChip; + +impl ProgramChip { + pub fn new() -> Self { + Self {} + } +} + +impl Chip for ProgramChip { + fn generate_trace(&self, runtime: &mut Runtime) -> RowMajorMatrix { + // Generate the trace rows for each event. + let rows = runtime + .program + .clone() + .into_par_iter() + .enumerate() + .map(|(i, instruction)| { + let mut row = [F::zero(); NUM_PROGRAM_COLS]; + let cols: &mut ProgramCols = unsafe { transmute(&mut row) }; + cols.pc = F::from_canonical_usize(i); + cols.instruction.populate(instruction); + cols.selectors.populate(instruction); + row + }) + .collect::>(); + + // Convert the trace to a row major matrix. + let mut trace = RowMajorMatrix::new( + rows.into_iter().flatten().collect::>(), + NUM_PROGRAM_COLS, + ); + + // Pad the trace to a power of two. + pad_to_power_of_two::(&mut trace.values); + + trace + } + + fn sends(&self) -> Vec> { + vec![] + } + + fn receives(&self) -> Vec> { + vec![] + } +} + +impl BaseAir for ProgramChip { + fn width(&self) -> usize { + NUM_PROGRAM_COLS + } +} + +impl Air for ProgramChip +where + AB: AirBuilder, +{ + fn eval(&self, _: &mut AB) {} +} + +#[cfg(test)] +mod tests { + + use p3_baby_bear::BabyBear; + + use p3_matrix::dense::RowMajorMatrix; + + use crate::{ + program::ProgramChip, + runtime::{Instruction, Opcode}, + utils::Chip, + Runtime, + }; + + #[test] + fn generate_trace() { + // main: + // addi x29, x0, 5 + // addi x30, x0, 37 + // add x31, x30, x29 + let program = vec![ + Instruction::new(Opcode::ADDI, 29, 0, 5), + Instruction::new(Opcode::ADDI, 30, 0, 37), + Instruction::new(Opcode::ADD, 31, 30, 29), + ]; + let mut runtime = Runtime::new(program); + let chip = ProgramChip::new(); + let trace: RowMajorMatrix = chip.generate_trace(&mut runtime); + println!("{:?}", trace.values) + } +} diff --git a/core/src/runtime/chip.rs b/core/src/runtime/chip.rs deleted file mode 100644 index e2537eb0b7..0000000000 --- a/core/src/runtime/chip.rs +++ /dev/null @@ -1,10 +0,0 @@ -use super::Runtime; -use crate::lookup::Interaction; -use p3_field::PrimeField; -use p3_matrix::dense::RowMajorMatrix; - -pub trait Chip { - fn generate_trace(&self, runtime: &mut Runtime) -> RowMajorMatrix; - fn sends(&self) -> Vec>; - fn receives(&self) -> Vec>; -} diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs index 02a6046489..138ac2ed16 100644 --- a/core/src/runtime/mod.rs +++ b/core/src/runtime/mod.rs @@ -9,19 +9,22 @@ use std::{ collections::BTreeMap, fmt::{Display, Formatter}, - mem, }; +use p3_field::PrimeField; +use p3_matrix::dense::RowMajorMatrix; + use crate::{ - alu::AluEvent, - cpu::CpuEvent, + alu::{add::AddChip, bitwise::BitwiseChip, sub::SubChip, AluEvent}, + cpu::{trace::CpuChip, CpuEvent}, memory::{MemOp, MemoryEvent}, + program::ProgramChip, + utils::Chip, }; -pub mod chip; /// An opcode specifies which operation to execute. #[allow(dead_code)] -#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)] pub enum Opcode { /// Register instructions. ADD = 0, @@ -278,61 +281,66 @@ impl Display for Register { #[derive(Debug, Clone, Copy)] pub struct Instruction { pub opcode: Opcode, - pub a: u32, - pub b: u32, - pub c: u32, + pub op_a: u32, + pub op_b: u32, + pub op_c: u32, } impl Instruction { /// Create a new instruction. - pub fn new(opcode: Opcode, a: u32, b: u32, c: u32) -> Instruction { - Instruction { opcode, a, b, c } + pub fn new(opcode: Opcode, op_a: u32, op_b: u32, op_c: u32) -> Instruction { + Instruction { + opcode, + op_a, + op_b, + op_c, + } } /// Decode the instruction in the R-type format. pub fn r_type(&self) -> (Register, Register, Register) { ( - Register::from_u32(self.a), - Register::from_u32(self.b), - Register::from_u32(self.c), + Register::from_u32(self.op_a), + Register::from_u32(self.op_b), + Register::from_u32(self.op_c), ) } /// Decode the instruction in the I-type format. pub fn i_type(&self) -> (Register, Register, u32) { ( - Register::from_u32(self.a), - Register::from_u32(self.b), - self.c, + Register::from_u32(self.op_a), + Register::from_u32(self.op_b), + self.op_c, ) } /// Decode the instruction in the S-type format. pub fn s_type(&self) -> (Register, Register, u32) { ( - Register::from_u32(self.a), - Register::from_u32(self.b), - self.c, + Register::from_u32(self.op_a), + Register::from_u32(self.op_b), + self.op_c, ) } /// Decode the instruction in the B-type format. pub fn b_type(&self) -> (Register, Register, u32) { ( - Register::from_u32(self.a), - Register::from_u32(self.b), - self.c, + Register::from_u32(self.op_a), + Register::from_u32(self.op_b), + self.op_c, ) } /// Decode the instruction in the J-type format. pub fn j_type(&self) -> (Register, u32) { - (Register::from_u32(self.a), self.b) + (Register::from_u32(self.op_a), self.op_b) } /// Decode the instruction in the U-type format. pub fn u_type(&self) -> (Register, u32) { - (Register::from_u32(self.a), self.b) + (Register::from_u32(self.op_a), self.op_b) } } @@ -340,25 +348,31 @@ impl Instruction { #[derive(Debug)] pub struct Runtime { /// The clock keeps track of how many instructions have been executed. - clk: u32, + pub clk: u32, /// The program counter keeps track of the next instruction. - pc: u32, + pub pc: u32, /// The prgram used during execution. - program: Vec, + pub program: Vec, /// The memory which instructions operate over. - memory: BTreeMap, + pub memory: BTreeMap, - /// Cpu Event + /// A trace of the CPU events which get emitted during execution. pub cpu_events: Vec, /// A trace of the memory events which get emitted during execution. - memory_events: Vec, + pub memory_events: Vec, + + /// A trace of the ADD, and ADDI events. + pub add_events: Vec, - /// A trace of the ALU events which get emitted during execution. - alu_events: Vec, + /// A trace of the SUB events. + pub sub_events: Vec, + + /// A trace of the XOR, XORI, OR, ORI, AND, and ANDI events. + pub bitwise_events: Vec, } impl Runtime { @@ -371,7 +385,9 @@ impl Runtime { program, cpu_events: Vec::new(), memory_events: Vec::new(), - alu_events: Vec::new(), + add_events: Vec::new(), + sub_events: Vec::new(), + bitwise_events: Vec::new(), } } @@ -381,24 +397,14 @@ impl Runtime { Some(value) => *value, None => 0, }; - self.memory_events.push(MemoryEvent { - clk: self.clk, - addr, - op: MemOp::Read, - value, - }); + self.emit_memory(self.clk, addr, MemOp::Read, value); return value; } /// Write to memory. fn mw(&mut self, addr: u32, value: u32) { - self.memory_events.push(MemoryEvent { - clk: self.clk, - addr, - op: MemOp::Write, - value, - }); self.memory.insert(addr, value); + self.emit_memory(self.clk, addr, MemOp::Write, value); } /// Convert a register to a memory address. @@ -437,58 +443,55 @@ impl Runtime { return self.program[idx]; } - /// Emit an ALU event. - fn emit_alu(&mut self, opcode: Opcode, a: u32, b: u32, c: u32) { - self.alu_events.push(AluEvent { - clk: self.clk, - opcode, + /// Emit a CPU event. + fn emit_cpu(&mut self, clk: u32, pc: u32, instruction: Instruction, a: u32, b: u32, c: u32) { + self.cpu_events.push(CpuEvent { + clk: clk, + pc: pc, + instruction, a, b, c, }); } - fn emit_cpu(&mut self, clk: u32, pc: u32, instruction: Instruction, a: u32, b: u32, c: u32) { - let (addr, memory_value) = match instruction.opcode { - Opcode::LB | Opcode::LH | Opcode::LW | Opcode::LBU | Opcode::LHU => { - let addr = b.wrapping_add(c); - let memory_value = self.mr(addr); - (Some(addr), Some(memory_value)) + /// Emit a memory event. + fn emit_memory(&mut self, clk: u32, addr: u32, op: MemOp, value: u32) { + self.memory_events.push(MemoryEvent { + clk, + addr, + op, + value, + }); + } + + /// Emit an ALU event. + fn emit_alu(&mut self, clk: u32, opcode: Opcode, a: u32, b: u32, c: u32) { + let event = AluEvent { + clk, + opcode, + a, + b, + c, + }; + match opcode { + Opcode::ADD | Opcode::ADDI => { + self.add_events.push(event); } - Opcode::SB | Opcode::SH | Opcode::SW => { - let addr = b.wrapping_add(c); - let memory_value = self.mr(addr); - (Some(addr), Some(memory_value)) + Opcode::SUB => { + self.sub_events.push(event); } - _ => (None, None), - }; - let branch_condition = match instruction.opcode { - Opcode::BEQ => Some(a == b), - Opcode::BNE => Some(a != b), - Opcode::BLT => Some((a as i32) < (b as i32)), - Opcode::BGE => Some((a as i32) >= (b as i32)), - Opcode::BLTU => Some(a < b), - Opcode::BGEU => Some(a >= b), - _ => None, - }; - self.cpu_events.push(CpuEvent { - clk: self.clk, - pc: self.pc, - instruction, - operands: [a, b, c], - addr: addr, - memory_value, - branch_condition, - }); + Opcode::XOR | Opcode::XORI | Opcode::OR | Opcode::ORI | Opcode::AND | Opcode::ANDI => { + self.bitwise_events.push(event); + } + _ => {} + } } /// Execute the given instruction over the current state of the runtime. - fn execute(&mut self, instruction: Instruction) -> (u32, u32, u32) { - // Initialize these to dummy values - let mut a: u32 = u32::MAX; - let mut b: u32 = u32::MAX; - let mut c: u32 = u32::MAX; - + fn execute(&mut self, instruction: Instruction) { + let pc = self.pc; + let (mut a, mut b, mut c): (u32, u32, u32) = (u32::MAX, u32::MAX, u32::MAX); match instruction.opcode { // R-type instructions. Opcode::ADD => { @@ -496,70 +499,70 @@ impl Runtime { (b, c) = (self.rr(rs1), self.rr(rs2)); a = b.wrapping_add(c); self.rw(rd, a); - self.emit_alu(Opcode::ADD, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SUB => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = b.wrapping_sub(c); self.rw(rd, a); - self.emit_alu(Opcode::SUB, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::XOR => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = b ^ c; self.rw(rd, a); - self.emit_alu(Opcode::XOR, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::OR => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = b | c; self.rw(rd, a); - self.emit_alu(Opcode::OR, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::AND => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = b & c; self.rw(rd, a); - self.emit_alu(Opcode::AND, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SLL => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = b << c; self.rw(rd, a); - self.emit_alu(Opcode::SLL, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SRL => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = b >> c; self.rw(rd, a); - self.emit_alu(Opcode::SRL, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SRA => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = (b as i32 >> c) as u32; self.rw(rd, a); - self.emit_alu(Opcode::SRA, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SLT => { let (rd, rs1, rs2) = instruction.r_type(); (b, c) = (self.rr(rs1), self.rr(rs2)); a = if (b as i32) < (c as i32) { 1 } else { 0 }; self.rw(rd, a); - self.emit_alu(Opcode::SLT, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SLTU => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = if b < c { 1 } else { 0 }; self.rw(rd, a); - self.emit_alu(Opcode::SLTU, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } // I-type instructions. @@ -568,63 +571,63 @@ impl Runtime { (b, c) = (self.rr(rs1), imm); a = b.wrapping_add(c); self.rw(rd, a); - self.emit_alu(Opcode::ADDI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::XORI => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = b ^ c; self.rw(rd, a); - self.emit_alu(Opcode::XORI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::ORI => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = b | c; self.rw(rd, a); - self.emit_alu(Opcode::ORI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::ANDI => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = b & c; self.rw(rd, a); - self.emit_alu(Opcode::ANDI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SLLI => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = b << c; self.rw(rd, a); - self.emit_alu(Opcode::SLLI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SRLI => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = b >> c; self.rw(rd, a); - self.emit_alu(Opcode::SRLI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SRAI => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = (b as i32 >> c) as u32; self.rw(rd, a); - self.emit_alu(Opcode::SRAI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SLTI => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = if (b as i32) < (c as i32) { 1 } else { 0 }; self.rw(rd, a); - self.emit_alu(Opcode::SLTI, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } Opcode::SLTIU => { let (rd, rs1, imm) = instruction.i_type(); (b, c) = (self.rr(rs1), imm); a = if b < c { 1 } else { 0 }; self.rw(rd, a); - self.emit_alu(Opcode::SLTIU, a, b, c); + self.emit_alu(self.clk, instruction.opcode, a, b, c); } // Load instructions @@ -775,65 +778,56 @@ impl Runtime { let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = b.wrapping_mul(c); self.rw(rd, a); - self.emit_alu(Opcode::MUL, a, b, c); } Opcode::MULH => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = ((b as i64).wrapping_mul(c as i64) >> 32) as u32; self.rw(rd, a); - self.emit_alu(Opcode::MULH, a, b, c); } Opcode::MULSU => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = ((b as i64).wrapping_mul(c as i64) >> 32) as u32; self.rw(rd, a); - self.emit_alu(Opcode::MULSU, a, b, c); } Opcode::MULU => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = ((b as u64).wrapping_mul(c as u64) >> 32) as u32; self.rw(rd, a); - self.emit_alu(Opcode::MULU, a, b, c); } Opcode::DIV => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = (b as i32).wrapping_div(c as i32) as u32; self.rw(rd, a); - self.emit_alu(Opcode::DIV, a, b, c); } Opcode::DIVU => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = b.wrapping_div(c); self.rw(rd, a); - self.emit_alu(Opcode::DIVU, a, b, c); } Opcode::REM => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1) as i32, self.rr(rs2) as i32); let a = (b as i32).wrapping_rem(c as i32) as u32; self.rw(rd, a); - self.emit_alu(Opcode::REM, a, b as u32, c as u32); } Opcode::REMU => { let (rd, rs1, rs2) = instruction.r_type(); let (b, c) = (self.rr(rs1), self.rr(rs2)); let a = b.wrapping_rem(c); self.rw(rd, a); - self.emit_alu(Opcode::REMU, a, b, c); } } - if a == u32::MAX || b == u32::MAX || c == u32::MAX { - panic!("Invalid computation of a = {}, b = {}, c = {}", a, b, c); - } - (a, b, c) + + // Emit the CPU event for this cycle. + self.emit_cpu(self.clk, pc, instruction, a, b, c); } - /// Executes the code. + /// Execute the program. pub fn run(&mut self) { // Set %x2 to the size of memory when the CPU is initialized. self.rw(Register::X2, 1024 * 1024 * 8); @@ -842,13 +836,8 @@ impl Runtime { // Fetch the instruction at the current program counter. let instruction = self.fetch(); - let start_pc = self.pc; - // Execute the instruction. - let (a, b, c) = self.execute(instruction); - - // Emit a CPU event. - self.emit_cpu(self.clk, start_pc, instruction, a, b, c); + self.execute(instruction); // Increment the program counter by 4. self.pc = self.pc + 4; @@ -857,11 +846,42 @@ impl Runtime { self.clk += 1; } } + + /// Prove the program. + #[allow(unused)] + pub fn prove(&mut self) { + // Initialize chips. + let program = ProgramChip::new(); + let cpu = CpuChip::new(); + let add = AddChip::new(); + let sub = SubChip::new(); + let bitwise = BitwiseChip::new(); + + // Generate the trace for the program chip. + let program_trace: RowMajorMatrix = program.generate_trace(self); + + // Generate the trace for the CPU chip and also emit auxiliary events. + let cpu_trace: RowMajorMatrix = cpu.generate_trace(self); + + // Generate the trace of the add chip. + let add_trace: RowMajorMatrix = add.generate_trace(self); + + // Generate the trace of the sub chip. + let sub_trace: RowMajorMatrix = sub.generate_trace(self); + + // Generate the trace of the bitwise chip. + let bitwise_trace: RowMajorMatrix = bitwise.generate_trace(self); + + // Generate the proof. + // multiprove(vec![program, cpu, memory, alu]; + } } #[cfg(test)] #[allow(non_snake_case)] mod tests { + use p3_baby_bear::BabyBear; + use crate::{runtime::Register, Runtime}; use super::{Instruction, Opcode}; @@ -872,13 +892,14 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // add x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::ADD, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 42); } @@ -887,13 +908,14 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // sub x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::SUB, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 32); } @@ -902,13 +924,14 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // xor x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::XOR, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 32); } @@ -917,13 +940,14 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // or x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::OR, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 37); } @@ -932,13 +956,14 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // and x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::AND, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 5); } @@ -947,12 +972,12 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // sll x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::SLL, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 1184); } @@ -962,12 +987,12 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // srl x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::SRL, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 1); } @@ -977,12 +1002,12 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // sra x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::SRA, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 1); } @@ -992,12 +1017,12 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // slt x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::SLT, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 0); } @@ -1007,12 +1032,12 @@ mod tests { // addi x29, x0, 5 // addi x30, x0, 37 // sltu x31, x30, x29 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 0, 37), Instruction::new(Opcode::SLTU, 31, 30, 29), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 0); } @@ -1022,12 +1047,12 @@ mod tests { // addi x29, x0, 5 // addi x30, x29, 37 // addi x31, x30, 42 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ADDI, 30, 29, 37), Instruction::new(Opcode::ADDI, 31, 30, 42), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 84); } @@ -1037,13 +1062,14 @@ mod tests { // addi x29, x0, 5 // xori x30, x29, 37 // xori x31, x30, 42 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::XORI, 30, 29, 37), Instruction::new(Opcode::XORI, 31, 30, 42), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 10); } @@ -1052,13 +1078,14 @@ mod tests { // addi x29, x0, 5 // ori x30, x29, 37 // ori x31, x30, 42 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ORI, 30, 29, 37), Instruction::new(Opcode::ORI, 31, 30, 42), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 47); } @@ -1067,13 +1094,14 @@ mod tests { // addi x29, x0, 5 // andi x30, x29, 37 // andi x31, x30, 42 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::ANDI, 30, 29, 37), Instruction::new(Opcode::ANDI, 31, 30, 42), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); + runtime.prove::(); assert_eq!(runtime.registers()[Register::X31 as usize], 0); } @@ -1081,11 +1109,11 @@ mod tests { fn SLLI() { // addi x29, x0, 5 // slli x31, x29, 37 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 5), Instruction::new(Opcode::SLLI, 31, 29, 4), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 80); } @@ -1094,11 +1122,11 @@ mod tests { fn SRLI() { // addi x29, x0, 5 // srli x31, x29, 37 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 42), Instruction::new(Opcode::SRLI, 31, 29, 4), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 2); } @@ -1107,11 +1135,11 @@ mod tests { fn SRAI() { // addi x29, x0, 5 // srai x31, x29, 37 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 42), Instruction::new(Opcode::SRAI, 31, 29, 4), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 2); } @@ -1120,11 +1148,11 @@ mod tests { fn SLTI() { // addi x29, x0, 5 // slti x31, x29, 37 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 42), Instruction::new(Opcode::SLTI, 31, 29, 37), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 0); } @@ -1133,11 +1161,11 @@ mod tests { fn SLTIU() { // addi x29, x0, 5 // sltiu x31, x29, 37 - let code = vec![ + let program = vec![ Instruction::new(Opcode::ADDI, 29, 0, 42), Instruction::new(Opcode::SLTIU, 31, 29, 37), ]; - let mut runtime = Runtime::new(code); + let mut runtime = Runtime::new(program); runtime.run(); assert_eq!(runtime.registers()[Register::X31 as usize], 0); }