11use p3_field:: PrimeField64 ;
22
33use crate :: {
4- bytecode:: { instruction:: Instruction , operand:: MemOrFp } ,
4+ bytecode:: {
5+ instruction:: Instruction ,
6+ operand:: { MemOrConstant , MemOrFp , MemOrFpOrConstant } ,
7+ operation:: Operation ,
8+ } ,
59 context:: run_context:: RunContext ,
6- errors:: { memory:: MemoryError , vm:: VirtualMachineError } ,
7- memory:: manager:: MemoryManager ,
10+ errors:: { math :: MathError , memory:: MemoryError , vm:: VirtualMachineError } ,
11+ memory:: { manager:: MemoryManager , val :: MemoryValue } ,
812} ;
913
1014#[ derive( Debug , Default ) ]
@@ -43,7 +47,7 @@ impl VirtualMachine {
4347 // This will return an error if the memory location is uninitialized.
4448 let condition_val = self
4549 . run_context
46- . get_value_from_mem_or_constant ( condition, & self . memory_manager ) ?;
50+ . value_from_mem_or_constant ( condition, & self . memory_manager ) ?;
4751
4852 // A jump condition must be a field element.
4953 let is_zero = condition_val. to_f ( ) ?. is_zero ( ) ;
@@ -57,7 +61,7 @@ impl VirtualMachine {
5761 // First, resolve the `dest` operand to get the target address value.
5862 let dest_val = self
5963 . run_context
60- . get_value_from_mem_or_constant ( dest, & self . memory_manager ) ?;
64+ . value_from_mem_or_constant ( dest, & self . memory_manager ) ?;
6165
6266 // The resolved destination value must be a valid address.
6367 //
@@ -123,6 +127,171 @@ impl VirtualMachine {
123127
124128 Ok ( ( ) )
125129 }
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 (`res = arg_a op arg_b`), handling deduction and assertion.
187+ ///
188+ /// This function implements the core logic for `ADD` and `MUL` instructions. It follows
189+ /// a "constraint satisfaction" model:
190+ ///
191+ /// 1. **Deduction:** If exactly one of the three operands (`res`, `arg_a`, `arg_b`) is unknown
192+ /// (i.e., its memory cell is uninitialized), the function computes its value from the other
193+ /// two and writes it to memory.
194+ /// 2. **Assertion:** If all three operands are already known, the function computes `arg_a op arg_b`
195+ /// and asserts that it equals the value of `res`.
196+ fn execute_computation < F > (
197+ & mut self ,
198+ operation : & Operation ,
199+ arg_a : & MemOrConstant < F > ,
200+ arg_b : & MemOrFp ,
201+ res : & MemOrConstant < F > ,
202+ ) -> Result < ( ) , VirtualMachineError < F > >
203+ where
204+ F : PrimeField64 ,
205+ {
206+ let memory_manager = & self . memory_manager ;
207+ let run_ctx = & self . run_context ;
208+
209+ let val_a = run_ctx. value_from_mem_or_constant ( arg_a, memory_manager) ;
210+ let val_b = run_ctx. value_from_mem_or_fp ( arg_b, memory_manager) ;
211+ let val_res = run_ctx. value_from_mem_or_constant ( res, memory_manager) ;
212+
213+ match ( val_a, val_b, val_res) {
214+ // Case 1: a OP b = c — compute c
215+ ( Ok ( MemoryValue :: Int ( a) ) , Ok ( MemoryValue :: Int ( b) ) , Ok ( MemoryValue :: Address ( addr) ) ) => {
216+ let c = operation. compute ( a, b) ;
217+ self . memory_manager . memory . insert ( addr, c) ?;
218+ }
219+ // Case 2: a OP b = c — recover b
220+ ( Ok ( MemoryValue :: Int ( a) ) , Ok ( MemoryValue :: Address ( addr) ) , Ok ( MemoryValue :: Int ( c) ) ) => {
221+ let b = operation
222+ . inverse_compute ( c, a)
223+ . ok_or ( MathError :: DivisionByZero ) ?;
224+ self . memory_manager . memory . insert ( addr, b) ?;
225+ }
226+ // Case 3: a OP b = c — recover a
227+ ( Ok ( MemoryValue :: Address ( addr) ) , Ok ( MemoryValue :: Int ( b) ) , Ok ( MemoryValue :: Int ( c) ) ) => {
228+ let a = operation
229+ . inverse_compute ( c, b)
230+ . ok_or ( MathError :: DivisionByZero ) ?;
231+ self . memory_manager . memory . insert ( addr, a) ?;
232+ }
233+ // Case 4: a OP b = c — assert equality
234+ ( Ok ( MemoryValue :: Int ( a) ) , Ok ( MemoryValue :: Int ( b) ) , Ok ( MemoryValue :: Int ( c) ) ) => {
235+ let computed = operation. compute ( a, b) ;
236+ if computed != c {
237+ return Err ( VirtualMachineError :: AssertEqFailed {
238+ computed : computed. into ( ) ,
239+ expected : c. into ( ) ,
240+ } ) ;
241+ }
242+ }
243+ _ => return Err ( VirtualMachineError :: TooManyUnknownOperands ) ,
244+ }
245+
246+ Ok ( ( ) )
247+ }
248+
249+ /// Executes a double-dereference instruction (`res = m[m[fp + shift_0] + shift_1]`) and asserts the result.
250+ ///
251+ /// This function handles instructions that require reading a pointer from one memory
252+ /// location to access a value at another.
253+ ///
254+ /// # Errors
255+ /// This function will return an `Err` if:
256+ /// - Any memory access targets an uninitialized memory cell.
257+ /// - The first memory access at `m[fp + shift_0]` does not yield a valid `MemoryAddress`.
258+ /// - The final, dereferenced value does not match the expected value specified by `res`.
259+ fn execute_deref < F > (
260+ & self ,
261+ _shift_0 : usize ,
262+ _shift_1 : usize ,
263+ _res : & MemOrFpOrConstant < F > ,
264+ ) -> Result < ( ) , VirtualMachineError < F > >
265+ where
266+ F : PrimeField64 ,
267+ {
268+ // TODO: implement this instruction.
269+ Ok ( ( ) )
270+ }
271+
272+ fn execute_poseidon2_16 < F > ( & self , _shift : usize ) -> Result < ( ) , VirtualMachineError < F > >
273+ where
274+ F : PrimeField64 ,
275+ {
276+ // TODO: implement this instruction.
277+ Ok ( ( ) )
278+ }
279+
280+ fn execute_poseidon2_24 < F > ( & self , _shift : usize ) -> Result < ( ) , VirtualMachineError < F > >
281+ where
282+ F : PrimeField64 ,
283+ {
284+ // TODO: implement this instruction.
285+ Ok ( ( ) )
286+ }
287+
288+ fn execute_extension_mul < F > ( & self , _args : [ usize ; 3 ] ) -> Result < ( ) , VirtualMachineError < F > >
289+ where
290+ F : PrimeField64 ,
291+ {
292+ // TODO: implement this instruction.
293+ Ok ( ( ) )
294+ }
126295}
127296
128297#[ cfg( test) ]
0 commit comments