291 lines
11 KiB
Rust
291 lines
11 KiB
Rust
pub type VM_Word = i64;
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
#[repr(u64)]
|
|
pub enum VM_Instruction {
|
|
Nop, Jmp, Call, Branch, Ret,
|
|
Lit, Pick, Roll, Dup, Drop, Swap, Rot,
|
|
Fetch, Store,
|
|
Accept, Emit,
|
|
IntAdd, IntSub, IntMul, IntDiv, IntRem,
|
|
FltAdd, FltSub, FltMul, FltDiv, FltRem,
|
|
BitNeg, BitAnd, BitOr, BitXor,
|
|
BitShl, BitShr,
|
|
}
|
|
|
|
impl VM_Instruction {
|
|
pub fn param_length(&self) -> usize {
|
|
match self {
|
|
VM_Instruction::Jmp |
|
|
VM_Instruction::Call |
|
|
VM_Instruction::Branch |
|
|
VM_Instruction::Lit => {
|
|
1
|
|
},
|
|
_ => 0
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct VM {
|
|
pub data_stack: Vec< VM_Word >,
|
|
pub call_stack: Vec< VM_Word >,
|
|
|
|
pub inst_ptr: VM_Word,
|
|
pub memory: Vec< VM_Word >,
|
|
}
|
|
|
|
impl VM {
|
|
pub fn new(memsize: usize) -> Self {
|
|
VM {
|
|
data_stack: Vec::new(),
|
|
call_stack: Vec::new(),
|
|
|
|
inst_ptr: 0,
|
|
memory: vec![0; memsize]
|
|
}
|
|
}
|
|
|
|
pub fn load(&mut self, bytecode: Vec< VM_Word >) {
|
|
let mut addr = 0;
|
|
for w in bytecode {
|
|
self.memory[addr] = w;
|
|
addr += 1;
|
|
}
|
|
}
|
|
|
|
pub fn execute(&mut self, entry: VM_Word) {
|
|
self.inst_ptr = entry;
|
|
while self.execute_step() {}
|
|
}
|
|
|
|
pub fn execute_step(&mut self) -> bool {
|
|
// fetch instruction from memory
|
|
let inst = unsafe { std::mem::transmute(self.memory[ self.inst_ptr as usize ]) };
|
|
self.inst_ptr += 1;
|
|
|
|
// decode instruction & load immediate if neccesary
|
|
let mut imm : VM_Word = 0;
|
|
match inst {
|
|
VM_Instruction::Jmp |
|
|
VM_Instruction::Call |
|
|
VM_Instruction::Branch |
|
|
VM_Instruction::Lit => {
|
|
imm = self.memory[ self.inst_ptr as usize ];
|
|
self.inst_ptr += 1;
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
// execute instruction
|
|
self.execute_instruction( inst, imm )
|
|
}
|
|
|
|
pub fn execute_instruction(&mut self, inst: VM_Instruction, imm: VM_Word) -> bool {
|
|
// eprintln!("execute {:?}, {}", inst, imm);
|
|
match inst {
|
|
VM_Instruction::Nop => {}
|
|
VM_Instruction::Lit => {
|
|
self.data_stack.push( imm );
|
|
}
|
|
VM_Instruction::Jmp => {
|
|
self.inst_ptr += imm;
|
|
}
|
|
VM_Instruction::Call => {
|
|
self.call_stack.push( self.inst_ptr );
|
|
self.inst_ptr = imm;
|
|
}
|
|
VM_Instruction::Branch => {
|
|
if self.data_stack.pop().expect("branch expects val") == 0 {
|
|
//self.call_stack.push( self.inst_ptr );
|
|
self.inst_ptr += imm;
|
|
}
|
|
}
|
|
VM_Instruction::Ret => {
|
|
if let Some(target) = self.call_stack.pop() {
|
|
self.inst_ptr = target;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
VM_Instruction::Fetch => {
|
|
let addr = self.data_stack.pop().expect("fetch requries addr");
|
|
let val = self.memory[ addr as usize ];
|
|
self.data_stack.push(val);
|
|
}
|
|
VM_Instruction::Store => {
|
|
let addr = self.data_stack.pop().expect("store requires addr");
|
|
let val = self.data_stack.pop().expect("store requires val");
|
|
self.memory[ addr as usize ] = val;
|
|
}
|
|
VM_Instruction::Accept => {
|
|
// todo: read word from stdin
|
|
self.data_stack.push(0);
|
|
}
|
|
VM_Instruction::Emit => {
|
|
let val = char::from(self.data_stack.pop().expect("emit expects value") as u8);
|
|
print!("{}", val);
|
|
}
|
|
VM_Instruction::Pick => {
|
|
let n = self.data_stack.pop().expect("pick requires index") as usize;
|
|
self.data_stack.push( *self.data_stack.get( self.data_stack.len() - n ).expect("pick invalid index") );
|
|
}
|
|
VM_Instruction::Roll => {
|
|
let n = self.data_stack.pop().expect("pick requires index") as usize;
|
|
let l = self.data_stack.len();
|
|
if n <= l {
|
|
if n > 1 {
|
|
let val = self.data_stack.remove( l-n );
|
|
self.data_stack.push( val );
|
|
}
|
|
} else {
|
|
eprintln!("stack = {:?}", self.data_stack);
|
|
eprintln!("roll invalid index");
|
|
}
|
|
}
|
|
VM_Instruction::Dup => {
|
|
self.data_stack.push( *self.data_stack.last().expect("dup expect val") );
|
|
}
|
|
VM_Instruction::Drop => {
|
|
self.data_stack.pop().expect("drop expects value");
|
|
}
|
|
VM_Instruction::Swap => {
|
|
let a = self.data_stack.pop().expect("swap expects value");
|
|
let b = self.data_stack.pop().expect("swap expects value");
|
|
self.data_stack.push(a);
|
|
self.data_stack.push(b);
|
|
}
|
|
VM_Instruction::Rot => {
|
|
let a = self.data_stack.pop().expect("rot expects value");
|
|
let b = self.data_stack.pop().expect("rot expects value");
|
|
let c = self.data_stack.pop().expect("rot expects value");
|
|
self.data_stack.push(a);
|
|
self.data_stack.push(c);
|
|
self.data_stack.push(b);
|
|
}
|
|
VM_Instruction::IntAdd => {
|
|
let a = self.data_stack.pop().expect("add expects value");
|
|
let b = self.data_stack.pop().expect("add expects value");
|
|
self.data_stack.push( a + b );
|
|
}
|
|
VM_Instruction::IntSub => {
|
|
let a = self.data_stack.pop().expect("add expects value");
|
|
let b = self.data_stack.pop().expect("add expects value");
|
|
self.data_stack.push( a - b );
|
|
}
|
|
VM_Instruction::IntMul => {
|
|
let a = self.data_stack.pop().expect("add expects value");
|
|
let b = self.data_stack.pop().expect("add expects value");
|
|
self.data_stack.push( a * b );
|
|
}
|
|
VM_Instruction::IntDiv => {
|
|
let a = self.data_stack.pop().expect("add expects value");
|
|
let b = self.data_stack.pop().expect("add expects value");
|
|
self.data_stack.push( a / b );
|
|
}
|
|
VM_Instruction::IntRem => {
|
|
let a = self.data_stack.pop().expect("add expects value");
|
|
let b = self.data_stack.pop().expect("add expects value");
|
|
self.data_stack.push( a % b );
|
|
}
|
|
VM_Instruction::FltAdd => {
|
|
let a = self.data_stack.pop().expect("addf expects value");
|
|
let af : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let b = self.data_stack.pop().expect("addf expects value");
|
|
let bf : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let cf = af + bf;
|
|
let c : i64 = unsafe{ std::mem::transmute(cf) };
|
|
|
|
self.data_stack.push(c);
|
|
}
|
|
VM_Instruction::FltSub => {
|
|
let a = self.data_stack.pop().expect("addf expects value");
|
|
let af : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let b = self.data_stack.pop().expect("addf expects value");
|
|
let bf : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let cf = af - bf;
|
|
let c : i64 = unsafe{ std::mem::transmute(cf) };
|
|
|
|
self.data_stack.push(c);
|
|
}
|
|
VM_Instruction::FltMul => {
|
|
let a = self.data_stack.pop().expect("addf expects value");
|
|
let af : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let b = self.data_stack.pop().expect("addf expects value");
|
|
let bf : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let cf = af * bf;
|
|
let c : i64 = unsafe{ std::mem::transmute(cf) };
|
|
|
|
self.data_stack.push(c);
|
|
}
|
|
VM_Instruction::FltDiv => {
|
|
let a = self.data_stack.pop().expect("addf expects value");
|
|
let af : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let b = self.data_stack.pop().expect("addf expects value");
|
|
let bf : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let cf = af / bf;
|
|
let c : i64 = unsafe{ std::mem::transmute(cf) };
|
|
|
|
self.data_stack.push(c);
|
|
}
|
|
VM_Instruction::FltRem => {
|
|
let a = self.data_stack.pop().expect("addf expects value");
|
|
let af : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let b = self.data_stack.pop().expect("addf expects value");
|
|
let bf : f64 = unsafe{ std::mem::transmute(a) };
|
|
|
|
let cf = af % bf;
|
|
let c : i64 = unsafe{ std::mem::transmute(cf) };
|
|
|
|
self.data_stack.push(c);
|
|
}
|
|
|
|
VM_Instruction::BitNeg => {
|
|
let a = self.data_stack.pop().expect("bitwise not expects value");
|
|
self.data_stack.push( !a );
|
|
}
|
|
VM_Instruction::BitAnd => {
|
|
let a = self.data_stack.pop().expect("bitwise and expects value");
|
|
let b = self.data_stack.pop().expect("bitwise and expects value");
|
|
self.data_stack.push( a & b );
|
|
}
|
|
VM_Instruction::BitOr => {
|
|
let a = self.data_stack.pop().expect("bitwise and expects value");
|
|
let b = self.data_stack.pop().expect("bitwise and expects value");
|
|
self.data_stack.push( a | b );
|
|
}
|
|
VM_Instruction::BitXor => {
|
|
let a = self.data_stack.pop().expect("bitwise and expects value");
|
|
let b = self.data_stack.pop().expect("bitwise and expects value");
|
|
self.data_stack.push( a ^ b );
|
|
}
|
|
VM_Instruction::BitAnd => {
|
|
let a = self.data_stack.pop().expect("bitwise and expects value");
|
|
let b = self.data_stack.pop().expect("bitwise and expects value");
|
|
self.data_stack.push( a & b );
|
|
}
|
|
VM_Instruction::BitShl => {
|
|
let x = self.data_stack.pop().expect("bitwise and expects value");
|
|
let n = self.data_stack.pop().expect("bitwise and expects value");
|
|
self.data_stack.push( x << n );
|
|
}
|
|
VM_Instruction::BitShr => {
|
|
let x = self.data_stack.pop().expect("bitwise and expects value");
|
|
let n = self.data_stack.pop().expect("bitwise and expects value");
|
|
self.data_stack.push( x >> n );
|
|
}
|
|
}
|
|
|
|
true
|
|
}
|
|
}
|
|
|