|
1 | | -#![allow( |
2 | | - clippy::unnecessary_wraps, |
3 | | - clippy::missing_const_for_fn, |
4 | | - clippy::unused_self |
5 | | -)] |
6 | | - |
7 | 1 | use p3_field::PrimeField64; |
8 | 2 |
|
9 | 3 | use crate::{ |
10 | 4 | context::run_context::RunContext, |
11 | 5 | errors::{memory::MemoryError, vm::VirtualMachineError}, |
12 | | - memory::{address::MemoryAddress, manager::MemoryManager}, |
13 | | - types::instruction::{Instruction, MemOrConstant, MemOrFp, MemOrFpOrConstant, Operation}, |
| 6 | + memory::manager::MemoryManager, |
| 7 | + types::instruction::{Instruction, MemOrFp}, |
14 | 8 | }; |
15 | 9 |
|
16 | 10 | #[derive(Debug, Default)] |
@@ -127,173 +121,6 @@ impl VirtualMachine { |
127 | 121 |
|
128 | 122 | Ok(()) |
129 | 123 | } |
130 | | - |
131 | | - /// Executes a single instruction, forming one step of the VM's execution cycle. |
132 | | - /// |
133 | | - /// This function is the engine of the virtual machine. It orchestrates the two main phases |
134 | | - /// of a single step: execution and register update. |
135 | | - /// |
136 | | - /// 1. **Execution:** It first matches on the `instruction` variant to dispatch to the appropriate |
137 | | - /// helper method. These helpers are responsible for fetching operands, performing the instruction's core logic, and |
138 | | - /// verifying any required assertions (e.g., that a computed value matches an expected one). |
139 | | - /// |
140 | | - /// 2. **Register Update:** If the execution phase completes successfully, this function then |
141 | | - /// calls `update_registers` to advance the program counter (`pc`) and frame pointer (`fp`) |
142 | | - /// to prepare for the next instruction. |
143 | | - pub fn run_instruction<F>( |
144 | | - &mut self, |
145 | | - instruction: &Instruction<F>, |
146 | | - ) -> Result<(), VirtualMachineError<F>> |
147 | | - where |
148 | | - F: PrimeField64, |
149 | | - { |
150 | | - // Dispatch to the appropriate execution logic based on the instruction type. |
151 | | - match instruction { |
152 | | - // Handle arithmetic operations like ADD and MUL. |
153 | | - Instruction::Computation { |
154 | | - operation, |
155 | | - arg_a, |
156 | | - arg_b, |
157 | | - res, |
158 | | - } => self.execute_computation(operation, arg_a, arg_b, res)?, |
159 | | - |
160 | | - // Handle double-dereference memory operations. |
161 | | - Instruction::Deref { |
162 | | - shift_0, |
163 | | - shift_1, |
164 | | - res, |
165 | | - } => self.execute_deref(*shift_0, *shift_1, res)?, |
166 | | - |
167 | | - // The `JumpIfNotZero` instruction has no execution logic; its effects |
168 | | - // (changing pc and fp) are handled entirely within the register update phase. |
169 | | - Instruction::JumpIfNotZero { .. } => {} |
170 | | - |
171 | | - // Handle the Poseidon2 (16-element) precompile. |
172 | | - Instruction::Poseidon2_16 { shift } => self.execute_poseidon2_16(*shift)?, |
173 | | - |
174 | | - // Handle the Poseidon2 (24-element) precompile. |
175 | | - Instruction::Poseidon2_24 { shift } => self.execute_poseidon2_24(*shift)?, |
176 | | - |
177 | | - // Handle the extension field multiplication precompile. |
178 | | - Instruction::ExtensionMul { args } => self.execute_extension_mul(*args)?, |
179 | | - } |
180 | | - |
181 | | - // After the instruction's core logic has been successfully executed, |
182 | | - // update the pc and fp registers to prepare for the next cycle. |
183 | | - self.update_registers(instruction) |
184 | | - } |
185 | | - |
186 | | - /// Executes a computation instruction (ADD or MUL) and asserts the result. |
187 | | - fn execute_computation<F>( |
188 | | - &self, |
189 | | - operation: &Operation, |
190 | | - arg_a: &MemOrConstant<F>, |
191 | | - arg_b: &MemOrFp, |
192 | | - res: &MemOrConstant<F>, |
193 | | - ) -> Result<(), VirtualMachineError<F>> |
194 | | - where |
195 | | - F: PrimeField64, |
196 | | - { |
197 | | - // Resolve the values of the two input operands. |
198 | | - let val_a = self.run_context.get_value(arg_a, &self.memory_manager)?; |
199 | | - let val_b = self |
200 | | - .run_context |
201 | | - .get_value_from_mem_or_fp(arg_b, &self.memory_manager)?; |
202 | | - |
203 | | - // Perform the arithmetic operation. |
204 | | - let computed = match operation { |
205 | | - Operation::Add => (val_a + val_b)?, |
206 | | - Operation::Mul => (val_a * val_b)?, |
207 | | - }; |
208 | | - |
209 | | - // Resolve the expected result from the `res` operand in memory. |
210 | | - let expected = self.run_context.get_value(res, &self.memory_manager)?; |
211 | | - |
212 | | - // Assert that the computed result matches the value in memory. |
213 | | - if computed != expected { |
214 | | - // If they don't match, return the new, more descriptive error. |
215 | | - return Err(VirtualMachineError::AssertEqFailed { computed, expected }); |
216 | | - } |
217 | | - |
218 | | - Ok(()) |
219 | | - } |
220 | | - |
221 | | - /// Executes a double-dereference instruction (`res = m[m[fp + shift_0] + shift_1]`) and asserts the result. |
222 | | - /// |
223 | | - /// This function handles instructions that require reading a pointer from one memory |
224 | | - /// location to access a value at another. |
225 | | - /// |
226 | | - /// # Errors |
227 | | - /// This function will return an `Err` if: |
228 | | - /// - Any memory access targets an uninitialized memory cell. |
229 | | - /// - The first memory access at `m[fp + shift_0]` does not yield a valid `MemoryAddress`. |
230 | | - /// - The final, dereferenced value does not match the expected value specified by `res`. |
231 | | - fn execute_deref<F>( |
232 | | - &self, |
233 | | - shift_0: usize, |
234 | | - shift_1: usize, |
235 | | - res: &MemOrFpOrConstant<F>, |
236 | | - ) -> Result<(), VirtualMachineError<F>> |
237 | | - where |
238 | | - F: PrimeField64, |
239 | | - { |
240 | | - // Get the address of the cell that holds the pointer. |
241 | | - let pointer_addr = self.run_context.fp().add_usize(shift_0)?; |
242 | | - |
243 | | - // Get the value from that cell, which must be an address (our pointer). |
244 | | - let pointer_val = self |
245 | | - .memory_manager |
246 | | - .get(pointer_addr) |
247 | | - .ok_or(MemoryError::UninitializedMemory(pointer_addr))?; |
248 | | - let pointer = MemoryAddress::try_from(pointer_val)?; |
249 | | - |
250 | | - // Get the final address by adding the second shift to our pointer. |
251 | | - let final_addr = pointer.add_usize(shift_1)?; |
252 | | - |
253 | | - // Get the final value from the dereferenced address. |
254 | | - let final_val = self |
255 | | - .memory_manager |
256 | | - .get(final_addr) |
257 | | - .ok_or(MemoryError::UninitializedMemory(final_addr))?; |
258 | | - |
259 | | - // Resolve the expected result from the `res` operand. |
260 | | - let expected_res = self |
261 | | - .run_context |
262 | | - .get_value_from_mem_or_fp_or_constant(res, &self.memory_manager)?; |
263 | | - |
264 | | - // Assert that the dereferenced value matches the expected result. |
265 | | - if final_val != expected_res { |
266 | | - return Err(VirtualMachineError::AssertEqFailed { |
267 | | - computed: final_val, |
268 | | - expected: expected_res, |
269 | | - }); |
270 | | - } |
271 | | - Ok(()) |
272 | | - } |
273 | | - |
274 | | - fn execute_poseidon2_16<F>(&self, _shift: usize) -> Result<(), VirtualMachineError<F>> |
275 | | - where |
276 | | - F: PrimeField64, |
277 | | - { |
278 | | - // TODO: implement this instruction. |
279 | | - Ok(()) |
280 | | - } |
281 | | - |
282 | | - fn execute_poseidon2_24<F>(&self, _shift: usize) -> Result<(), VirtualMachineError<F>> |
283 | | - where |
284 | | - F: PrimeField64, |
285 | | - { |
286 | | - // TODO: implement this instruction. |
287 | | - Ok(()) |
288 | | - } |
289 | | - |
290 | | - fn execute_extension_mul<F>(&self, _args: [usize; 3]) -> Result<(), VirtualMachineError<F>> |
291 | | - where |
292 | | - F: PrimeField64, |
293 | | - { |
294 | | - // TODO: implement this instruction. |
295 | | - Ok(()) |
296 | | - } |
297 | 124 | } |
298 | 125 |
|
299 | 126 | #[cfg(test)] |
|
0 commit comments