From 481deacc6528e876e45e13c0ed58a006a7354ef6 Mon Sep 17 00:00:00 2001 From: Nilton Constantino Date: Tue, 20 Jan 2026 09:51:31 +0000 Subject: [PATCH] add trap and dropN --- .../src/virtual_machine/opcode.rs | 8 +++ .../src/virtual_machine/virtual_machine.rs | 60 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/crates/prometeu-core/src/virtual_machine/opcode.rs b/crates/prometeu-core/src/virtual_machine/opcode.rs index f71168a1..11b4fb9b 100644 --- a/crates/prometeu-core/src/virtual_machine/opcode.rs +++ b/crates/prometeu-core/src/virtual_machine/opcode.rs @@ -8,6 +8,7 @@ pub enum OpCode { Jmp = 0x02, JmpIfFalse = 0x03, JmpIfTrue = 0x04, + Trap = 0x05, // 6.2 Stack PushConst = 0x10, @@ -18,6 +19,7 @@ pub enum OpCode { PushF64 = 0x15, PushBool = 0x16, PushI32 = 0x17, + PopN = 0x18, // 6.3 Arithmetic Add = 0x20, @@ -74,6 +76,7 @@ impl TryFrom for OpCode { 0x02 => Ok(OpCode::Jmp), 0x03 => Ok(OpCode::JmpIfFalse), 0x04 => Ok(OpCode::JmpIfTrue), + 0x05 => Ok(OpCode::Trap), 0x10 => Ok(OpCode::PushConst), 0x11 => Ok(OpCode::Pop), 0x12 => Ok(OpCode::Dup), @@ -82,6 +85,7 @@ impl TryFrom for OpCode { 0x15 => Ok(OpCode::PushF64), 0x16 => Ok(OpCode::PushBool), 0x17 => Ok(OpCode::PushI32), + 0x18 => Ok(OpCode::PopN), 0x20 => Ok(OpCode::Add), 0x21 => Ok(OpCode::Sub), 0x22 => Ok(OpCode::Mul), @@ -127,8 +131,10 @@ impl OpCode { OpCode::Jmp => 2, OpCode::JmpIfFalse => 3, OpCode::JmpIfTrue => 3, + OpCode::Trap => 1, OpCode::PushConst => 2, OpCode::Pop => 1, + OpCode::PopN => 2, OpCode::Dup => 1, OpCode::Swap => 1, OpCode::PushI64 => 2, @@ -178,7 +184,9 @@ mod tests { #[test] fn test_opcode_decoding() { assert_eq!(OpCode::try_from(0x00).unwrap(), OpCode::Nop); + assert_eq!(OpCode::try_from(0x05).unwrap(), OpCode::Trap); assert_eq!(OpCode::try_from(0x10).unwrap(), OpCode::PushConst); + assert_eq!(OpCode::try_from(0x18).unwrap(), OpCode::PopN); assert_eq!(OpCode::try_from(0x20).unwrap(), OpCode::Add); assert_eq!(OpCode::try_from(0x70).unwrap(), OpCode::Syscall); assert_eq!(OpCode::try_from(0x80).unwrap(), OpCode::FrameSync); diff --git a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs index a6e69de3..4d336434 100644 --- a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs +++ b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs @@ -243,6 +243,14 @@ impl VirtualMachine { 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) self.step(native, hw)?; steps_executed += 1; @@ -323,6 +331,10 @@ impl VirtualMachine { self.pc = addr; } } + OpCode::Trap => { + // Handled in run_budget for interruption, + // but we need to advance PC if executed via step() directly. + } OpCode::PushConst => { let idx = self.read_u32()? as usize; let val = self.program.constant_pool.get(idx).cloned().ok_or("Invalid constant index")?; @@ -347,6 +359,12 @@ impl VirtualMachine { OpCode::Pop => { self.pop()?; } + OpCode::PopN => { + let n = self.read_u16()?; + for _ in 0..n { + self.pop()?; + } + } OpCode::Dup => { let val = self.peek()?.clone(); self.push(val); @@ -1180,4 +1198,46 @@ mod tests { vm.step(&mut native, &mut hw).unwrap(); // PushI32 assert_eq!(vm.pop().unwrap(), Value::Int32(100)); } + + #[test] + fn test_trap_opcode() { + let mut native = MockNative; + let mut hw = MockHardware; + + let mut rom = Vec::new(); + rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); + rom.extend_from_slice(&42i32.to_le_bytes()); + rom.extend_from_slice(&(OpCode::Trap as u16).to_le_bytes()); + rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); + + let mut vm = VirtualMachine::new(rom, vec![]); + let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + + assert_eq!(report.reason, LogicalFrameEndingReason::Breakpoint); + assert_eq!(vm.pc, 8); // PushI32 (6 bytes) + Trap (2 bytes) + assert_eq!(vm.peek().unwrap(), &Value::Int32(42)); + } + + #[test] + fn test_pop_n_opcode() { + let mut native = MockNative; + let mut hw = MockHardware; + + let mut rom = Vec::new(); + rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); + rom.extend_from_slice(&1i32.to_le_bytes()); + rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); + rom.extend_from_slice(&2i32.to_le_bytes()); + rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); + rom.extend_from_slice(&3i32.to_le_bytes()); + rom.extend_from_slice(&(OpCode::PopN as u16).to_le_bytes()); + rom.extend_from_slice(&2u16.to_le_bytes()); + rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); + + let mut vm = VirtualMachine::new(rom, vec![]); + vm.run_budget(100, &mut native, &mut hw).unwrap(); + + assert_eq!(vm.pop().unwrap(), Value::Int32(1)); + assert!(vm.pop().is_err()); // Stack should be empty + } }