Nilton Constantino 127ec789bc
pr 13
2026-01-28 19:16:41 +00:00

293 lines
9.2 KiB
Rust

/// 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<u16> for OpCode {
type Error = String;
fn try_from(value: u16) -> Result<Self, Self::Error> {
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,
}
}
}