use crate::hardware::HardwareBridge; use crate::prometeu_os::NativeInterface; use crate::vm::call_frame::CallFrame; use crate::vm::opcode::OpCode; use crate::vm::value::Value; use crate::vm::Program; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LogicalFrameEndingReason { FrameSync, BudgetExhausted, Halted, EndOfRom, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BudgetReport { pub cycles_used: u64, pub reason: LogicalFrameEndingReason, } pub struct VirtualMachine { pub pc: usize, pub operand_stack: Vec, pub call_stack: Vec, pub globals: Vec, pub program: Program, pub heap: Vec, // Simplificado para demo, futuramente RAM/Heap real pub cycles: u64, pub halted: bool, } impl VirtualMachine { pub fn new(rom: Vec, constant_pool: Vec) -> Self { Self { pc: 0, operand_stack: Vec::new(), call_stack: Vec::new(), globals: Vec::new(), program: Program::new(rom, constant_pool), heap: Vec::new(), cycles: 0, halted: false, } } } impl Default for VirtualMachine { fn default() -> Self { Self::new(vec![], vec![]) } } impl VirtualMachine { pub fn run_budget( &mut self, budget: u64, native: &mut dyn NativeInterface, hw: &mut dyn HardwareBridge, ) -> Result { let start_cycles = self.cycles; let mut ending_reason: Option = None; while (self.cycles - start_cycles) < budget && !self.halted && self.pc < self.program.rom.len() { let pc_before = self.pc; let cycles_before = self.cycles; // Fast-path: FRAME_SYNC encerra o frame lógico let opcode_val = self.peek_u16()?; let opcode = OpCode::try_from(opcode_val)?; if opcode == OpCode::FrameSync { self.pc += 2; self.cycles += OpCode::FrameSync.cycles(); ending_reason = Some(LogicalFrameEndingReason::FrameSync); break; } self.step(native, hw)?; // garante progresso real if self.pc == pc_before && self.cycles == cycles_before && !self.halted { return Err(format!("VM stuck at PC 0x{:08X}", self.pc)); } } if ending_reason.is_none() { if self.halted { ending_reason = Some(LogicalFrameEndingReason::Halted); } else if self.pc >= self.program.rom.len() { ending_reason = Some(LogicalFrameEndingReason::EndOfRom); } else { ending_reason = Some(LogicalFrameEndingReason::BudgetExhausted); } } Ok(BudgetReport { cycles_used: self.cycles - start_cycles, reason: ending_reason.unwrap(), }) } fn peek_u16(&self) -> Result { if self.pc + 2 > self.program.rom.len() { return Err("Unexpected end of ROM".into()); } let bytes = [ self.program.rom[self.pc], self.program.rom[self.pc + 1], ]; Ok(u16::from_le_bytes(bytes)) } pub fn step(&mut self, native: &mut dyn NativeInterface, hw: &mut dyn HardwareBridge) -> Result<(), String> { if self.halted || self.pc >= self.program.rom.len() { return Ok(()); } let opcode_val = self.read_u16()?; let opcode = OpCode::try_from(opcode_val)?; match opcode { OpCode::Nop => {} OpCode::Halt => { self.halted = true; } OpCode::Jmp => { let addr = self.read_u32()? as usize; self.pc = addr; } OpCode::JmpIfFalse => { let addr = self.read_u32()? as usize; let val = self.pop()?; if let Value::Boolean(false) = val { self.pc = addr; } } OpCode::PushConst => { let idx = self.read_u32()? as usize; let val = self.program.constant_pool.get(idx).cloned().ok_or("Invalid constant index")?; self.push(val); } OpCode::Pop => { self.pop()?; } OpCode::Dup => { let val = self.peek()?.clone(); self.push(val); } OpCode::Swap => { let a = self.pop()?; let b = self.pop()?; self.push(a); self.push(b); } OpCode::Add => self.binary_op(|a, b| match (a, b) { (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a.wrapping_add(b))), (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a + b)), (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(a as f64 + b)), (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a + b as f64)), _ => Err("Invalid types for ADD".into()), })?, OpCode::Sub => self.binary_op(|a, b| match (a, b) { (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a.wrapping_sub(b))), (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a - b)), (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(a as f64 - b)), (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a - b as f64)), _ => Err("Invalid types for SUB".into()), })?, OpCode::Mul => self.binary_op(|a, b| match (a, b) { (Value::Integer(a), Value::Integer(b)) => Ok(Value::Integer(a.wrapping_mul(b))), (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a * b)), (Value::Integer(a), Value::Float(b)) => Ok(Value::Float(a as f64 * b)), (Value::Float(a), Value::Integer(b)) => Ok(Value::Float(a * b as f64)), _ => Err("Invalid types for MUL".into()), })?, OpCode::Div => self.binary_op(|a, b| match (a, b) { (Value::Integer(a), Value::Integer(b)) => { if b == 0 { return Err("Division by zero".into()); } Ok(Value::Integer(a / b)) } (Value::Float(a), Value::Float(b)) => { if b == 0.0 { return Err("Division by zero".into()); } Ok(Value::Float(a / b)) } (Value::Integer(a), Value::Float(b)) => { if b == 0.0 { return Err("Division by zero".into()); } Ok(Value::Float(a as f64 / b)) } (Value::Float(a), Value::Integer(b)) => { if b == 0 { return Err("Division by zero".into()); } Ok(Value::Float(a / b as f64)) } _ => Err("Invalid types for DIV".into()), })?, OpCode::Eq => self.binary_op(|a, b| Ok(Value::Boolean(a == b)))?, OpCode::Neq => self.binary_op(|a, b| Ok(Value::Boolean(a != b)))?, OpCode::Lt => self.binary_op(|a, b| { match (a, b) { (Value::Integer(a), Value::Integer(b)) => Ok(Value::Boolean(a < b)), (Value::Float(a), Value::Float(b)) => Ok(Value::Boolean(a < b)), (Value::Integer(a), Value::Float(b)) => Ok(Value::Boolean((a as f64) < b)), (Value::Float(a), Value::Integer(b)) => Ok(Value::Boolean(a < (b as f64))), _ => Err("Invalid types for LT".into()), } })?, OpCode::Gt => self.binary_op(|a, b| { match (a, b) { (Value::Integer(a), Value::Integer(b)) => Ok(Value::Boolean(a > b)), (Value::Float(a), Value::Float(b)) => Ok(Value::Boolean(a > b)), (Value::Integer(a), Value::Float(b)) => Ok(Value::Boolean((a as f64) > b)), (Value::Float(a), Value::Integer(b)) => Ok(Value::Boolean(a > (b as f64))), _ => Err("Invalid types for GT".into()), } })?, OpCode::And => self.binary_op(|a, b| match (a, b) { (Value::Boolean(a), Value::Boolean(b)) => Ok(Value::Boolean(a && b)), _ => Err("Invalid types for AND".into()), })?, OpCode::Or => self.binary_op(|a, b| match (a, b) { (Value::Boolean(a), Value::Boolean(b)) => Ok(Value::Boolean(a || b)), _ => Err("Invalid types for OR".into()), })?, OpCode::Not => { let val = self.pop()?; if let Value::Boolean(b) = val { self.push(Value::Boolean(!b)); } else { return Err("Invalid type for NOT".into()); } } OpCode::GetGlobal => { let idx = self.read_u32()? as usize; let val = self.globals.get(idx).cloned().ok_or("Invalid global index")?; self.push(val); } OpCode::SetGlobal => { let idx = self.read_u32()? as usize; let val = self.pop()?; if idx >= self.globals.len() { self.globals.resize(idx + 1, Value::Null); } self.globals[idx] = val; } OpCode::GetLocal => { let idx = self.read_u32()? as usize; let frame = self.call_stack.last().ok_or("No active call frame")?; let val = self.operand_stack.get(frame.stack_base + idx).cloned().ok_or("Invalid local index")?; self.push(val); } OpCode::SetLocal => { let idx = self.read_u32()? as usize; let val = self.pop()?; let frame = self.call_stack.last().ok_or("No active call frame")?; let stack_idx = frame.stack_base + idx; if stack_idx >= self.operand_stack.len() { return Err("Local index out of bounds".into()); } self.operand_stack[stack_idx] = val; } OpCode::Call => { let addr = self.read_u32()? as usize; let args_count = self.read_u32()? as usize; let stack_base = self.operand_stack.len() - args_count; self.call_stack.push(CallFrame { return_address: self.pc, stack_base, locals_count: args_count, }); self.pc = addr; } OpCode::Ret => { let frame = self.call_stack.pop().ok_or("Call stack underflow")?; let return_val = self.pop()?; self.operand_stack.truncate(frame.stack_base); self.push(return_val); self.pc = frame.return_address; } OpCode::PushScope => { let locals_count = self.read_u32()? as usize; let stack_base = self.operand_stack.len(); for _ in 0..locals_count { self.push(Value::Null); } self.call_stack.push(CallFrame { return_address: 0, stack_base, locals_count, }); } OpCode::PopScope => { let frame = self.call_stack.pop().ok_or("Call stack underflow")?; self.operand_stack.truncate(frame.stack_base); } OpCode::Alloc => { let size = self.read_u32()? as usize; let ref_idx = self.heap.len(); for _ in 0..size { self.heap.push(Value::Null); } self.push(Value::Ref(ref_idx)); } OpCode::LoadRef => { let offset = self.read_u32()? as usize; let ref_val = self.pop()?; if let Value::Ref(base) = ref_val { let val = self.heap.get(base + offset).cloned().ok_or("Invalid heap access")?; self.push(val); } else { return Err("Expected reference for LOAD_REF".into()); } } OpCode::StoreRef => { let offset = self.read_u32()? as usize; let val = self.pop()?; let ref_val = self.pop()?; if let Value::Ref(base) = ref_val { if base + offset >= self.heap.len() { return Err("Invalid heap access".into()); } self.heap[base + offset] = val; } else { return Err("Expected reference for STORE_REF".into()); } } OpCode::Syscall => { let id = self.read_u32()?; let native_cycles = native.syscall(id, self, hw).map_err(|e| format!("syscall 0x{:08X} failed: {}", id, e))?; self.cycles += native_cycles; } OpCode::FrameSync => { return Ok(()); } } self.cycles += opcode.cycles(); Ok(()) } fn read_u32(&mut self) -> Result { if self.pc + 4 > self.program.rom.len() { return Err("Unexpected end of ROM".into()); } let bytes = [ self.program.rom[self.pc], self.program.rom[self.pc + 1], self.program.rom[self.pc + 2], self.program.rom[self.pc + 3], ]; self.pc += 4; Ok(u32::from_le_bytes(bytes)) } fn read_u16(&mut self) -> Result { if self.pc + 2 > self.program.rom.len() { return Err("Unexpected end of ROM".into()); } let bytes = [ self.program.rom[self.pc], self.program.rom[self.pc + 1], ]; self.pc += 2; Ok(u16::from_le_bytes(bytes)) } pub fn push(&mut self, val: Value) { self.operand_stack.push(val); } pub fn pop(&mut self) -> Result { self.operand_stack.pop().ok_or("Stack underflow".into()) } pub fn pop_number(&mut self) -> Result { let val = self.pop()?; val.as_float().ok_or_else(|| "Expected number".into()) } pub fn pop_integer(&mut self) -> Result { let val = self.pop()?; val.as_integer().ok_or_else(|| "Expected integer".into()) } pub fn peek(&self) -> Result<&Value, String> { self.operand_stack.last().ok_or("Stack underflow".into()) } fn binary_op(&mut self, f: F) -> Result<(), String> where F: FnOnce(Value, Value) -> Result, { let b = self.pop()?; let a = self.pop()?; let res = f(a, b)?; self.push(res); Ok(()) } }