diff --git a/crates/console/prometeu-vm/src/virtual_machine.rs b/crates/console/prometeu-vm/src/virtual_machine.rs index e50b7656..f3a99cab 100644 --- a/crates/console/prometeu-vm/src/virtual_machine.rs +++ b/crates/console/prometeu-vm/src/virtual_machine.rs @@ -257,10 +257,7 @@ impl VirtualMachine { let mut steps_executed = 0; let mut ending_reason: Option = None; - while (self.cycles - start_cycles) < budget - && !self.halted - && self.pc < self.program.rom.len() - { + while (self.cycles - start_cycles) < budget && !self.halted && self.pc < self.program.rom.len() { // Debugger support: stop before executing an instruction if there's a breakpoint. // Note: we skip the check for the very first step of a slice to avoid // getting stuck on the same breakpoint repeatedly. @@ -272,27 +269,6 @@ impl VirtualMachine { let pc_before = self.pc; let cycles_before = self.cycles; - // Fast-path for FRAME_SYNC: - // This instruction is special because it marks the end of a logical game frame. - // We peak ahead to handle it efficiently. - let opcode_val = self.peek_u16()?; - let opcode = OpCode::try_from(opcode_val)?; - if opcode == OpCode::FrameSync { - self.pc += 2; // Advance PC past the opcode - self.cycles += OpCode::FrameSync.cycles(); - steps_executed += 1; - ending_reason = Some(LogicalFrameEndingReason::FrameSync); - break; - } - - if opcode == OpCode::Trap { - self.pc += 2; // Advance PC past the opcode - self.cycles += OpCode::Trap.cycles(); - steps_executed += 1; - ending_reason = Some(LogicalFrameEndingReason::Breakpoint); - break; - } - // Execute a single step (Fetch-Decode-Execute) if let Err(reason) = self.step(native, ctx) { ending_reason = Some(reason); @@ -433,7 +409,9 @@ impl VirtualMachine { } } OpCode::Trap => { - // Handled in run_budget for interruption + // Manual breakpoint instruction: consume cycles and signal a breakpoint + self.cycles += OpCode::Trap.cycles(); + return Err(LogicalFrameEndingReason::Breakpoint); } OpCode::PushConst => { let idx = instr @@ -994,7 +972,9 @@ impl VirtualMachine { } } OpCode::FrameSync => { - return Ok(()); + // Marks the logical end of a frame: consume cycles and signal to the driver + self.cycles += OpCode::FrameSync.cycles(); + return Err(LogicalFrameEndingReason::FrameSync); } } diff --git a/files/TODOs.md b/files/TODOs.md index 8743cfba..d1e05a7b 100644 --- a/files/TODOs.md +++ b/files/TODOs.md @@ -1,54 +1,3 @@ -# PR-2.2 — Simplify VM Execution Loop (Pure Stack Machine) - -### Briefing - -The VM should operate as a simple stack-based interpreter with a clear fetch–decode–execute loop, without hidden side channels or legacy behaviors. - -### Target - -* Normalize the VM main loop to a clean stack-machine structure. -* Remove any legacy control paths tied to HIP/RC behavior. - -### Work items - -* Refactor the main interpreter loop to: - - * Fetch instruction at PC. - * Decode opcode. - * Execute operation on stack/frames. -* Remove any conditional logic that depends on HIP/RC state. -* Ensure PC advancement is canonical and centralized. - -### Acceptance checklist - -* [ ] VM loop is structurally simple and readable. -* [ ] No HIP/RC conditionals remain. -* [ ] VM compiles and runs basic programs. -* [ ] `cargo test` passes. - -### Tests - -* Existing tests only. - -### Junie instructions - -**You MAY:** - -* Refactor the interpreter loop for clarity. -* Remove legacy conditionals. - -**You MUST NOT:** - -* Change opcode semantics. -* Introduce GC, closures, or coroutines here. -* Redesign the instruction set. - -**If unclear:** - -* Ask before modifying control flow assumptions. - ---- - # PR-2.3 — Normalize Value Model (Stack vs Heap References) ### Briefing