lib-tisc/src/vm.rs

170 lines
5.9 KiB
Rust
Raw Normal View History

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
}
}