57 lines
2.1 KiB
Rust
57 lines
2.1 KiB
Rust
use prometeu_bytecode::isa::core::{CoreOpCode, CoreOpCodeSpecExt};
|
|
use prometeu_hal::{HostContext, HostReturn, NativeInterface, SyscallId};
|
|
use prometeu_vm::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
|
|
use prometeu_bytecode::Value;
|
|
|
|
fn emit(op: CoreOpCode, imm: Option<&[u8]>, out: &mut Vec<u8>) {
|
|
out.extend_from_slice(&(op as u16).to_le_bytes());
|
|
let need = op.spec().imm_bytes as usize;
|
|
match (need, imm) {
|
|
(0, None) => {}
|
|
(n, Some(bytes)) if bytes.len() == n => out.extend_from_slice(bytes),
|
|
(n, Some(bytes)) => panic!("imm size mismatch for {:?}: need {}, got {}", op, n, bytes.len()),
|
|
(n, None) => panic!("missing imm for {:?}: need {} bytes", op, n),
|
|
}
|
|
}
|
|
|
|
struct NoopNative;
|
|
impl NativeInterface for NoopNative {
|
|
fn syscall(
|
|
&mut self,
|
|
_id: SyscallId,
|
|
_args: &[Value],
|
|
_ret: &mut HostReturn,
|
|
_ctx: &mut HostContext,
|
|
) -> Result<(), prometeu_hal::vm_fault::VmFault> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn vm_executes_valid_program_in_slices() {
|
|
// Program: PUSH_I32 2; PUSH_I32 3; ADD; FRAME_SYNC; HALT
|
|
let mut rom = Vec::new();
|
|
emit(CoreOpCode::PushI32, Some(&2i32.to_le_bytes()), &mut rom);
|
|
emit(CoreOpCode::PushI32, Some(&3i32.to_le_bytes()), &mut rom);
|
|
emit(CoreOpCode::Add, None, &mut rom);
|
|
emit(CoreOpCode::FrameSync, None, &mut rom);
|
|
emit(CoreOpCode::Halt, None, &mut rom);
|
|
|
|
// Construct VM directly; assume input is already verified.
|
|
let mut vm = VirtualMachine::new(rom, vec![]);
|
|
vm.prepare_call("0");
|
|
|
|
let mut native = NoopNative;
|
|
let mut ctx = HostContext::new(None);
|
|
|
|
// First slice should stop at FRAME_SYNC deterministically.
|
|
let report: BudgetReport = vm.run_budget(100, &mut native, &mut ctx).expect("run ok");
|
|
assert_eq!(report.reason, LogicalFrameEndingReason::FrameSync);
|
|
assert!(!vm.is_halted());
|
|
|
|
// Second slice proceeds to HALT.
|
|
let report2: BudgetReport = vm.run_budget(100, &mut native, &mut ctx).expect("run ok");
|
|
assert_eq!(report2.reason, LogicalFrameEndingReason::Halted);
|
|
assert!(vm.is_halted());
|
|
}
|