/// Represents a single instruction in the Prometeu Virtual Machine. /// /// Each OpCode is encoded as a 16-bit unsigned integer (u16) in the bytecode. /// The PVM is a stack-based machine, meaning most instructions take their /// operands from the top of the stack and push their results back onto it. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u16)] pub enum OpCode { // --- 6.1 Execution Control --- /// No operation. Does nothing for 1 cycle. Nop = 0x00, /// Stops the Virtual Machine execution immediately. Halt = 0x01, /// Unconditional jump to a specific PC (Program Counter) address. /// Operand: addr (u32) Jmp = 0x02, /// Jumps to `addr` if the value at the top of the stack is `false`. /// Operand: addr (u32) /// Stack: [bool] -> [] JmpIfFalse = 0x03, /// Jumps to `addr` if the value at the top of the stack is `true`. /// Operand: addr (u32) /// Stack: [bool] -> [] JmpIfTrue = 0x04, /// Triggers a software breakpoint. Used for debugging. Trap = 0x05, // --- 6.2 Stack Manipulation --- /// Loads a constant from the Constant Pool into the stack. /// Operand: index (u32) /// Stack: [] -> [value] PushConst = 0x10, /// Removes the top value from the stack. /// Stack: [val] -> [] Pop = 0x11, /// Duplicates the top value of the stack. /// Stack: [val] -> [val, val] Dup = 0x12, /// Swaps the two top values of the stack. /// Stack: [a, b] -> [b, a] Swap = 0x13, /// Pushes a 64-bit integer literal onto the stack. /// Operand: value (i64) PushI64 = 0x14, /// Pushes a 64-bit float literal onto the stack. /// Operand: value (f64) PushF64 = 0x15, /// Pushes a boolean literal onto the stack (0=false, 1=true). /// Operand: value (u8) PushBool = 0x16, /// Pushes a 32-bit integer literal onto the stack. /// Operand: value (i32) PushI32 = 0x17, /// Removes `n` values from the stack. /// Operand: n (u32) PopN = 0x18, // --- 6.3 Arithmetic --- /// Adds the two top values (a + b). /// Stack: [a, b] -> [result] Add = 0x20, /// Subtracts the top value from the second one (a - b). /// Stack: [a, b] -> [result] Sub = 0x21, /// Multiplies the two top values (a * b). /// Stack: [a, b] -> [result] Mul = 0x22, /// Divides the second top value by the top one (a / b). /// Stack: [a, b] -> [result] Div = 0x23, /// Remainder of the division of the second top value by the top one (a % b). /// Stack: [a, b] -> [result] Mod = 0x24, // --- 6.4 Comparison and Logic --- /// Checks if a equals b. /// Stack: [a, b] -> [bool] Eq = 0x30, /// Checks if a is not equal to b. /// Stack: [a, b] -> [bool] Neq = 0x31, /// Checks if a is less than b. /// Stack: [a, b] -> [bool] Lt = 0x32, /// Checks if a is greater than b. /// Stack: [a, b] -> [bool] Gt = 0x33, /// Logical AND. /// Stack: [bool, bool] -> [bool] And = 0x34, /// Logical OR. /// Stack: [bool, bool] -> [bool] Or = 0x35, /// Logical NOT. /// Stack: [bool] -> [bool] Not = 0x36, /// Bitwise AND. /// Stack: [int, int] -> [int] BitAnd = 0x37, /// Bitwise OR. /// Stack: [int, int] -> [int] BitOr = 0x38, /// Bitwise XOR. /// Stack: [int, int] -> [int] BitXor = 0x39, /// Bitwise Shift Left. /// Stack: [int, count] -> [int] Shl = 0x3A, /// Bitwise Shift Right. /// Stack: [int, count] -> [int] Shr = 0x3B, /// Checks if a is less than or equal to b. /// Stack: [a, b] -> [bool] Lte = 0x3C, /// Checks if a is greater than or equal to b. /// Stack: [a, b] -> [bool] Gte = 0x3D, /// Negates a number (-a). /// Stack: [num] -> [num] Neg = 0x3E, // --- 6.5 Variables --- /// Loads a value from a global variable slot. /// Operand: slot_index (u32) /// Stack: [] -> [value] GetGlobal = 0x40, /// Stores the top value into a global variable slot. /// Operand: slot_index (u32) /// Stack: [value] -> [] SetGlobal = 0x41, /// Loads a value from a local variable slot in the current frame. /// Operand: slot_index (u32) /// Stack: [] -> [value] GetLocal = 0x42, /// Stores the top value into a local variable slot in the current frame. /// Operand: slot_index (u32) /// Stack: [value] -> [] SetLocal = 0x43, // --- 6.6 Functions --- /// Calls a function by its index in the function table. /// Operand: func_id (u32) /// Stack: [arg0, arg1, ...] -> [return_slots...] Call = 0x50, /// Returns from the current function. /// Stack: [return_val] -> [return_val] Ret = 0x51, /// Creates a closure capturing values from the operand stack (Model B). /// Operands: fn_id (u32), capture_count (u32) /// Stack before: [..., captured_N, ..., captured_1] /// Pops capture_count values (top-first), preserves order as [captured_1..captured_N] /// and stores them inside the closure environment. Pushes a HeapRef to the closure. MakeClosure = 0x52, /// Calls a closure value with hidden arg0 semantics (Model B). /// Operand: arg_count (u32) — number of user-supplied args (excludes hidden arg0) /// Stack before: [..., argN, ..., arg1, closure_ref] /// Behavior: /// - Pops `closure_ref` and validates it is a Closure. /// - Pops `arg_count` user args. /// - Fetches `fn_id` from the closure and creates a new call frame. /// - Injects hidden arg0 = closure_ref, followed by user args as arg1..argN. CallClosure = 0x53, // --- 7.x Concurrency / Coroutines --- /// Spawns a new coroutine to run a function with arguments. /// Operands: fn_id (u32), arg_count (u32) /// Semantics: /// - Pops `arg_count` arguments from the current operand stack (top-first), /// preserving user order as arg1..argN for the callee. /// - Allocates a new Coroutine object with its own stack and a single entry frame /// pointing at `fn_id`. /// - Enqueues the coroutine into the scheduler ready queue. /// - Does NOT switch execution immediately; current coroutine continues. Spawn = 0x54, /// Cooperatively yields the current coroutine. Execution continues /// until the next VM safepoint (FRAME_SYNC), where the scheduler /// may switch to another ready coroutine. Yield = 0x55, /// Suspends the current coroutine for a number of logical ticks. /// Operand: duration_ticks (u32) /// Semantics: /// - Set the coroutine wake tick to `current_tick + duration_ticks`. /// - End the current logical frame (as if reaching FRAME_SYNC). /// - The coroutine will resume execution on or after the wake tick. Sleep = 0x56, // --- 6.8 Peripherals and System --- /// Pre-load host binding call by `SYSC` table index. /// Operand: sysc_index (u32) /// This opcode is valid only in PBX artifact form and must be patched by the loader /// into a final numeric `SYSCALL ` before verification or execution. Hostcall = 0x71, /// Invokes a final numeric system function (Firmware/OS). /// Raw `SYSCALL` is valid only after loader patching and is rejected in PBX pre-load artifacts. /// Operand: syscall_id (u32) /// Stack: [args...] -> [results...] (depends on syscall) Syscall = 0x70, /// Invokes a VM-owned intrinsic by final numeric id. /// Operand: intrinsic_id (u32) /// Stack: [args...] -> [results...] (depends on intrinsic metadata) Intrinsic = 0x72, /// Synchronizes the VM with the hardware frame (usually 60Hz). /// Execution pauses until the next VSync. FrameSync = 0x80, } impl TryFrom for OpCode { type Error = String; fn try_from(value: u16) -> Result { match value { 0x00 => Ok(OpCode::Nop), 0x01 => Ok(OpCode::Halt), 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), 0x13 => Ok(OpCode::Swap), 0x14 => Ok(OpCode::PushI64), 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), 0x23 => Ok(OpCode::Div), 0x24 => Ok(OpCode::Mod), 0x30 => Ok(OpCode::Eq), 0x31 => Ok(OpCode::Neq), 0x32 => Ok(OpCode::Lt), 0x33 => Ok(OpCode::Gt), 0x34 => Ok(OpCode::And), 0x35 => Ok(OpCode::Or), 0x36 => Ok(OpCode::Not), 0x37 => Ok(OpCode::BitAnd), 0x38 => Ok(OpCode::BitOr), 0x39 => Ok(OpCode::BitXor), 0x3A => Ok(OpCode::Shl), 0x3B => Ok(OpCode::Shr), 0x3C => Ok(OpCode::Lte), 0x3D => Ok(OpCode::Gte), 0x3E => Ok(OpCode::Neg), 0x40 => Ok(OpCode::GetGlobal), 0x41 => Ok(OpCode::SetGlobal), 0x42 => Ok(OpCode::GetLocal), 0x43 => Ok(OpCode::SetLocal), 0x50 => Ok(OpCode::Call), 0x51 => Ok(OpCode::Ret), 0x52 => Ok(OpCode::MakeClosure), 0x53 => Ok(OpCode::CallClosure), 0x54 => Ok(OpCode::Spawn), 0x55 => Ok(OpCode::Yield), 0x56 => Ok(OpCode::Sleep), 0x70 => Ok(OpCode::Syscall), 0x71 => Ok(OpCode::Hostcall), 0x72 => Ok(OpCode::Intrinsic), 0x80 => Ok(OpCode::FrameSync), _ => Err(format!("Invalid OpCode: 0x{:04X}", value)), } } } impl OpCode { /// Returns the cost of the instruction in VM cycles. /// This is used for performance monitoring and resource limiting (Certification). pub fn cycles(&self) -> u64 { match self { OpCode::Nop => 1, OpCode::Halt => 1, 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, OpCode::PushF64 => 2, OpCode::PushBool => 2, OpCode::PushI32 => 2, OpCode::Add => 2, OpCode::Sub => 2, OpCode::Mul => 4, OpCode::Div => 6, OpCode::Mod => 6, OpCode::Eq => 2, OpCode::Neq => 2, OpCode::Lt => 2, OpCode::Gt => 2, OpCode::And => 2, OpCode::Or => 2, OpCode::Not => 1, OpCode::BitAnd => 2, OpCode::BitOr => 2, OpCode::BitXor => 2, OpCode::Shl => 2, OpCode::Shr => 2, OpCode::Lte => 2, OpCode::Gte => 2, OpCode::Neg => 1, OpCode::GetGlobal => 3, OpCode::SetGlobal => 3, OpCode::GetLocal => 2, OpCode::SetLocal => 2, OpCode::Call => 5, OpCode::Ret => 4, OpCode::MakeClosure => 8, OpCode::CallClosure => 6, OpCode::Spawn => 6, OpCode::Yield => 1, OpCode::Sleep => 1, OpCode::Syscall => 1, OpCode::Hostcall => 1, OpCode::Intrinsic => 1, OpCode::FrameSync => 1, } } }