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}