2024-05-04 18:11:13 +02:00
|
|
|
pub type VM_Word = i64;
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
#[repr(u64)]
|
|
|
|
pub enum VM_Instruction {
|
|
|
|
Nop, Jmp, Call, Branch, Ret,
|
2024-05-05 18:16:07 +02:00
|
|
|
Lit, Pick, Roll, Dup, Drop, Swap, Rot,
|
2024-05-04 18:11:13 +02:00
|
|
|
Fetch, Store,
|
|
|
|
Accept, Emit,
|
|
|
|
Add, //Sub, Mul, Div, Rem,
|
|
|
|
Addf,//Subf, Mulf, Divf
|
|
|
|
BitwiseNot,
|
|
|
|
}
|
|
|
|
|
|
|
|
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 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);
|
|
|
|
}
|
2024-05-05 18:16:07 +02:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
2024-05-04 18:11:13 +02:00
|
|
|
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);
|
2024-05-05 18:16:07 +02:00
|
|
|
}
|
2024-05-04 18:11:13 +02:00
|
|
|
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::Add => {
|
|
|
|
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::Addf => {
|
|
|
|
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::BitwiseNot => {
|
|
|
|
let a = self.data_stack.pop().expect("bitwise not expects value");
|
|
|
|
self.data_stack.push( !a );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|