1use std::{fmt, fmt::Display};
2
3use itertools::Itertools;
4use openvm_stark_backend::p3_field::Field;
5use serde::{Deserialize, Serialize};
6
7use crate::instruction::{DebugInfo, Instruction};
8
9pub const PC_BITS: usize = 30;
10pub const DEFAULT_PC_STEP: u32 = 4;
13pub const DEFAULT_MAX_NUM_PUBLIC_VALUES: usize = 32;
14pub const MAX_ALLOWED_PC: u32 = (1 << PC_BITS) - 1;
15
16#[derive(Clone, Debug, Default, Serialize, Deserialize)]
17pub struct Program<F> {
18 pub instructions_and_debug_infos: Vec<Option<(Instruction<F>, Option<DebugInfo>)>>,
22 pub step: u32,
23 pub pc_base: u32,
24 pub max_num_public_values: usize,
28}
29
30impl<F: Field> Program<F> {
31 pub fn new_empty(step: u32, pc_base: u32, max_num_public_values: usize) -> Self {
32 Self {
33 instructions_and_debug_infos: vec![],
34 step,
35 pc_base,
36 max_num_public_values,
37 }
38 }
39
40 pub fn new_without_debug_infos(
41 instructions: &[Instruction<F>],
42 step: u32,
43 pc_base: u32,
44 max_num_public_values: usize,
45 ) -> Self {
46 Self {
47 instructions_and_debug_infos: instructions
48 .iter()
49 .map(|instruction| Some((instruction.clone(), None)))
50 .collect(),
51 step,
52 pc_base,
53 max_num_public_values,
54 }
55 }
56
57 pub fn new_without_debug_infos_with_option(
58 instructions: &[Option<Instruction<F>>],
59 step: u32,
60 pc_base: u32,
61 max_num_public_values: usize,
62 ) -> Self {
63 Self {
64 instructions_and_debug_infos: instructions
65 .iter()
66 .map(|instruction| instruction.clone().map(|instruction| (instruction, None)))
67 .collect(),
68 step,
69 pc_base,
70 max_num_public_values,
71 }
72 }
73
74 pub fn from_instructions_and_debug_infos(
77 instructions: &[Instruction<F>],
78 debug_infos: &[Option<DebugInfo>],
79 ) -> Self {
80 Self {
81 instructions_and_debug_infos: instructions
82 .iter()
83 .zip_eq(debug_infos.iter())
84 .map(|(instruction, debug_info)| Some((instruction.clone(), debug_info.clone())))
85 .collect(),
86 step: DEFAULT_PC_STEP,
87 pc_base: 0,
88 max_num_public_values: DEFAULT_MAX_NUM_PUBLIC_VALUES,
89 }
90 }
91
92 pub fn strip_debug_infos(self) -> Self {
93 Self {
94 instructions_and_debug_infos: self
95 .instructions_and_debug_infos
96 .into_iter()
97 .map(|opt| opt.map(|(ins, _)| (ins, None)))
98 .collect(),
99 ..self
100 }
101 }
102
103 pub fn from_instructions(instructions: &[Instruction<F>]) -> Self {
104 Self::new_without_debug_infos(
105 instructions,
106 DEFAULT_PC_STEP,
107 0,
108 DEFAULT_MAX_NUM_PUBLIC_VALUES,
109 )
110 }
111
112 pub fn len(&self) -> usize {
113 self.instructions_and_debug_infos.len()
114 }
115
116 pub fn is_empty(&self) -> bool {
117 self.instructions_and_debug_infos.is_empty()
118 }
119
120 pub fn defined_instructions(&self) -> Vec<Instruction<F>> {
121 self.instructions_and_debug_infos
122 .iter()
123 .flatten()
124 .map(|(instruction, _)| instruction.clone())
125 .collect()
126 }
127
128 pub fn num_defined_instructions(&self) -> usize {
130 self.defined_instructions().len()
131 }
132
133 pub fn debug_infos(&self) -> Vec<Option<DebugInfo>> {
134 self.instructions_and_debug_infos
135 .iter()
136 .flatten()
137 .map(|(_, debug_info)| debug_info.clone())
138 .collect()
139 }
140
141 pub fn enumerate_by_pc(&self) -> Vec<(u32, Instruction<F>, Option<DebugInfo>)> {
142 self.instructions_and_debug_infos
143 .iter()
144 .enumerate()
145 .flat_map(|(index, option)| {
146 option.clone().map(|(instruction, debug_info)| {
147 (
148 self.pc_base + (self.step * (index as u32)),
149 instruction,
150 debug_info,
151 )
152 })
153 })
154 .collect()
155 }
156
157 pub fn get_instruction_and_debug_info(
159 &self,
160 index: usize,
161 ) -> Option<&(Instruction<F>, Option<DebugInfo>)> {
162 self.instructions_and_debug_infos
163 .get(index)
164 .and_then(|x| x.as_ref())
165 }
166
167 pub fn push_instruction_and_debug_info(
168 &mut self,
169 instruction: Instruction<F>,
170 debug_info: Option<DebugInfo>,
171 ) {
172 self.instructions_and_debug_infos
173 .push(Some((instruction, debug_info)));
174 }
175
176 pub fn push_instruction(&mut self, instruction: Instruction<F>) {
177 self.push_instruction_and_debug_info(instruction, None);
178 }
179
180 pub fn append(&mut self, other: Program<F>) {
181 self.instructions_and_debug_infos
182 .extend(other.instructions_and_debug_infos);
183 }
184}
185impl<F: Field> Display for Program<F> {
186 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
187 for instruction in self.defined_instructions().iter() {
188 let Instruction {
189 opcode,
190 a,
191 b,
192 c,
193 d,
194 e,
195 f,
196 g,
197 } = instruction;
198 writeln!(
199 formatter,
200 "{:?} {} {} {} {} {} {} {}",
201 opcode, a, b, c, d, e, f, g,
202 )?;
203 }
204 Ok(())
205 }
206}
207
208pub fn display_program_with_pc<F: Field>(program: &Program<F>) {
209 for (pc, instruction) in program.defined_instructions().iter().enumerate() {
210 let Instruction {
211 opcode,
212 a,
213 b,
214 c,
215 d,
216 e,
217 f,
218 g,
219 } = instruction;
220 println!(
221 "{} | {:?} {} {} {} {} {} {} {}",
222 pc, opcode, a, b, c, d, e, f, g
223 );
224 }
225}