openvm_circuit/system/program/
mod.rs
1use openvm_instructions::{
2 instruction::{DebugInfo, Instruction},
3 program::Program,
4};
5use openvm_stark_backend::{p3_field::PrimeField64, ChipUsageGetter};
6
7use crate::{arch::ExecutionError, system::program::trace::padding_instruction};
8
9#[cfg(test)]
10pub mod tests;
11
12mod air;
13mod bus;
14pub mod trace;
15
16pub use air::*;
17pub use bus::*;
18
19const EXIT_CODE_FAIL: usize = 1;
20
21#[derive(Debug)]
22pub struct ProgramChip<F> {
23 pub air: ProgramAir,
24 pub program: Program<F>,
25 pub true_program_length: usize,
26 pub execution_frequencies: Vec<usize>,
27}
28
29impl<F: PrimeField64> ProgramChip<F> {
30 pub fn new(bus: ProgramBus) -> Self {
31 Self {
32 execution_frequencies: vec![],
33 program: Program::default(),
34 true_program_length: 0,
35 air: ProgramAir { bus },
36 }
37 }
38
39 pub fn new_with_program(program: Program<F>, bus: ProgramBus) -> Self {
40 let mut ret = Self::new(bus);
41 ret.set_program(program);
42 ret
43 }
44
45 pub fn set_program(&mut self, mut program: Program<F>) {
46 let true_program_length = program.len();
47 let mut number_actual_instructions = program.num_defined_instructions();
48 while !number_actual_instructions.is_power_of_two() {
49 program.push_instruction(padding_instruction());
50 number_actual_instructions += 1;
51 }
52 self.true_program_length = true_program_length;
53 self.execution_frequencies = vec![0; program.len()];
54 self.program = program;
55 }
56
57 fn get_pc_index(&self, pc: u32) -> Result<usize, ExecutionError> {
58 let step = self.program.step;
59 let pc_base = self.program.pc_base;
60 let pc_index = ((pc - pc_base) / step) as usize;
61 if !(0..self.true_program_length).contains(&pc_index) {
62 return Err(ExecutionError::PcOutOfBounds {
63 pc,
64 step,
65 pc_base,
66 program_len: self.true_program_length,
67 });
68 }
69 Ok(pc_index)
70 }
71
72 pub fn get_instruction(
73 &mut self,
74 pc: u32,
75 ) -> Result<&(Instruction<F>, Option<DebugInfo>), ExecutionError> {
76 let pc_index = self.get_pc_index(pc)?;
77 self.execution_frequencies[pc_index] += 1;
78 self.program
79 .get_instruction_and_debug_info(pc_index)
80 .ok_or(ExecutionError::PcNotFound {
81 pc,
82 step: self.program.step,
83 pc_base: self.program.pc_base,
84 program_len: self.program.len(),
85 })
86 }
87}
88
89impl<F: PrimeField64> ChipUsageGetter for ProgramChip<F> {
90 fn air_name(&self) -> String {
91 "ProgramChip".to_string()
92 }
93
94 fn constant_trace_height(&self) -> Option<usize> {
95 Some(self.true_program_length.next_power_of_two())
96 }
97
98 fn current_trace_height(&self) -> usize {
99 self.true_program_length
100 }
101
102 fn trace_width(&self) -> usize {
103 1
104 }
105}