/// 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, // --- 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 at a specific address. /// Operands: addr (u32), args_count (u32) /// Stack: [arg0, arg1, ...] -> [return_value] Call = 0x50, /// Returns from the current function. /// Stack: [return_val] -> [return_val] Ret = 0x51, /// Starts a new local scope (for blocks/loops). PushScope = 0x52, /// Ends the current local scope, discarding its local variables. PopScope = 0x53, // --- 6.7 Heap --- /// Allocates `size` slots on the heap. /// Stack: [size] -> [reference] Alloc = 0x60, /// Reads a value from the heap at `reference + offset`. /// Operand: offset (u32) /// Stack: [reference] -> [value] LoadRef = 0x61, /// Writes a value to the heap at `reference + offset`. /// Operand: offset (u32) /// Stack: [reference, value] -> [] StoreRef = 0x62, // --- 6.8 Peripherals and System --- /// Invokes a system function (Firmware/OS). /// Operand: syscall_id (u32) /// Stack: [args...] -> [results...] (depends on syscall) Syscall = 0x70, /// 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), 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::PushScope), 0x53 => Ok(OpCode::PopScope), 0x60 => Ok(OpCode::Alloc), 0x61 => Ok(OpCode::LoadRef), 0x62 => Ok(OpCode::StoreRef), 0x70 => Ok(OpCode::Syscall), 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::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::PushScope => 3, OpCode::PopScope => 3, OpCode::Alloc => 10, OpCode::LoadRef => 3, OpCode::StoreRef => 3, OpCode::Syscall => 1, OpCode::FrameSync => 1, } } }