128 lines
4.5 KiB
Rust
128 lines
4.5 KiB
Rust
|
|
use crate::vm::{error::*, flags::Flags, inst::*, reg::*, vm::*};
|
||
|
|
|
||
|
|
impl Vm {
|
||
|
|
pub fn tick(&mut self) -> Result<()> {
|
||
|
|
let mut cursor = self.mem_cursor(self.ip() as usize);
|
||
|
|
let op = cursor.next_u16()?;
|
||
|
|
let next_ip;
|
||
|
|
|
||
|
|
macro_rules! math_inst {
|
||
|
|
($mapping:expr) => {{
|
||
|
|
let (r1, r2) = cursor.next_regs()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let value = ($mapping)(self.get_reg(r1), self.get_reg(r2));
|
||
|
|
self.set_reg(r1, value);
|
||
|
|
}}
|
||
|
|
}
|
||
|
|
match op {
|
||
|
|
ADD => math_inst!(|w1: u64, w2: u64| w1.wrapping_add(w2)),
|
||
|
|
MUL => math_inst!(|w1: u64, w2: u64| w1.wrapping_mul(w2)),
|
||
|
|
DIV => math_inst!(|w1: u64, w2: u64| w1.wrapping_div(w2)),
|
||
|
|
MOD => math_inst!(|w1: u64, w2: u64| w1 % w2),
|
||
|
|
INEG => { todo!() }
|
||
|
|
AND => math_inst!(|w1: u64, w2: u64| w1 & w2),
|
||
|
|
OR => math_inst!(|w1: u64, w2: u64| w1 | w2),
|
||
|
|
INV => {
|
||
|
|
let r1 = cursor.next_reg()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let value = self.get_reg(r1);
|
||
|
|
self.set_reg(r1, !value);
|
||
|
|
}
|
||
|
|
NOT => {
|
||
|
|
let r1 = cursor.next_reg()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let value = self.get_reg(r1);
|
||
|
|
self.set_reg(r1, (value == 0) as Word);
|
||
|
|
}
|
||
|
|
XOR => math_inst!(|w1: u64, w2: u64| w1 ^ w2),
|
||
|
|
SHL => math_inst!(|w1: u64, w2: u64| w1 << w2),
|
||
|
|
SHR => math_inst!(|w1: u64, w2: u64| w1 >> w2),
|
||
|
|
CMPEQ => {
|
||
|
|
let (r1, r2) = cursor.next_regs()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let cmp = self.get_reg(r1) == self.get_reg(r2);
|
||
|
|
if cmp {
|
||
|
|
self.insert_flags(Flags::COMPARE);
|
||
|
|
} else {
|
||
|
|
self.remove_flags(Flags::COMPARE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CMPLT => {
|
||
|
|
let (r1, r2) = cursor.next_regs()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let cmp = self.get_reg(r1) < self.get_reg(r2);
|
||
|
|
if cmp {
|
||
|
|
self.insert_flags(Flags::COMPARE);
|
||
|
|
} else {
|
||
|
|
self.remove_flags(Flags::COMPARE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
JMP => {
|
||
|
|
let r1 = cursor.next_reg()?;
|
||
|
|
next_ip = self.get_reg(r1);
|
||
|
|
}
|
||
|
|
JZ => {
|
||
|
|
let r1 = cursor.next_reg()?;
|
||
|
|
if !self.flags().contains(Flags::COMPARE) {
|
||
|
|
next_ip = self.get_reg(r1);
|
||
|
|
} else {
|
||
|
|
next_ip = cursor.position();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
JNZ => {
|
||
|
|
let r1 = cursor.next_reg()?;
|
||
|
|
if self.flags().contains(Flags::COMPARE) {
|
||
|
|
next_ip = self.get_reg(r1);
|
||
|
|
} else {
|
||
|
|
next_ip = cursor.position();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
LOAD => {
|
||
|
|
let (r1, r2) = cursor.next_regs()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let value = self.load(r2);
|
||
|
|
self.set_reg(r1, value);
|
||
|
|
}
|
||
|
|
REGCOPY => math_inst!(|_: u64, w2: u64| w2),
|
||
|
|
STOREIMM64 => {
|
||
|
|
let r1 = cursor.next_reg()?;
|
||
|
|
// skip
|
||
|
|
cursor.next_u32()?;
|
||
|
|
let imm = cursor.next_u64()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
self.set_reg(r1, imm);
|
||
|
|
}
|
||
|
|
STOREIMM32 => {
|
||
|
|
let r1 = cursor.next_reg()?;
|
||
|
|
let imm = cursor.next_u32()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
self.set_reg(r1, imm as u64);
|
||
|
|
}
|
||
|
|
MEMCOPY => {
|
||
|
|
let (r1, r2) = cursor.next_regs()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let value = self.load(r2);
|
||
|
|
self.store(r1, value);
|
||
|
|
}
|
||
|
|
STORE => {
|
||
|
|
let (r1, r2) = cursor.next_regs()?;
|
||
|
|
next_ip = cursor.position();
|
||
|
|
let value = self.get_reg(r1);
|
||
|
|
self.store(r2, value);
|
||
|
|
}
|
||
|
|
HALT => {
|
||
|
|
next_ip = cursor.position();
|
||
|
|
self.insert_flags(Flags::HALT);
|
||
|
|
}
|
||
|
|
NOP => {
|
||
|
|
next_ip = cursor.position();
|
||
|
|
}
|
||
|
|
_ => panic!("unknown instruction opcode: 0x{:04x}", op),
|
||
|
|
}
|
||
|
|
|
||
|
|
self.set_reg(IP, next_ip);
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
}
|