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