Add instruction visitor, which traverses memory and choosing instructions

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-02-10 13:22:54 -05:00
parent c982be553f
commit 6c352396fa
5 changed files with 287 additions and 128 deletions

View File

@@ -1,134 +1,190 @@
use crate::vm::{error::*, flags::Flags, inst::*, reg::*, vm::*};
use crate::vm::{error::*, flags::Flags, inst::*, reg::*, vm::*, visit::*, mem::MemCursor};
use std::io::stdin;
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_checked(r1)?, self.get_reg_checked(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_checked(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_checked(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),
}
println!("op: {:04x} {}", op, inst_name(op).unwrap());
println!("ip: {:05x}", self.ip());
println!("next_ip: {:05x}", next_ip);
let mut _line = String::new();
stdin().read_line(&mut _line).unwrap();
let next_ip = visit_inst(self)?;
self.set_reg(IP, next_ip);
Ok(())
}
fn next_ip(&self) -> Result<Addr> {
let ip = self.ip();
let op = self.get_inst_op(ip)?;
Ok(ip + (inst_len(op) as u64))
}
fn with_regs<F, B>(&mut self, r1: Reg, r2: Reg, mapping: F) -> B
where F: FnOnce(Word, Word) -> B
{
let w1 = self.get_reg(r1);
let w2 = self.get_reg(r2);
(mapping)(w1, w2)
}
}
impl InstAcceptor for Vm {
type Out = Addr;
fn cursor(&self) -> MemCursor {
self.mem_cursor(self.ip() as usize)
}
fn add(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_add(w2));
self.set_reg(r1, out);
self.next_ip()
}
fn mul(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_mul(w2));
self.set_reg(r1, out);
self.next_ip()
}
fn div(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
// TODO : check w2 == 0 and throw error/exception
let out = self.with_regs(r1, r2, |w1, w2| w1 / w2);
self.set_reg(r1, out);
self.next_ip()
}
fn mod_(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
// TODO : check w2 == 0 and throw error/exception
let out = self.with_regs(r1, r2, |w1, w2| w1 % w2);
self.set_reg(r1, out);
self.next_ip()
}
fn ineg(&mut self, r1: Reg) -> Result<Self::Out> {
let w1 = self.get_reg(r1);
self.set_reg(r1, (!w1).wrapping_add(1));
self.next_ip()
}
fn and(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 & w2);
self.set_reg(r1, out);
self.next_ip()
}
fn or(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 | w2);
self.set_reg(r1, out);
self.next_ip()
}
fn inv(&mut self, r1: Reg) -> Result<Self::Out> {
let w1 = self.get_reg(r1);
self.set_reg(r1, !w1);
self.next_ip()
}
fn not(&mut self, r1: Reg) -> Result<Self::Out> {
let w1 = self.get_reg(r1);
self.set_reg(r1, (w1 == 0) as Word);
self.next_ip()
}
fn xor(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 ^ w2);
self.set_reg(r1, out);
self.next_ip()
}
fn shl(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 << w2);
self.set_reg(r1, out);
self.next_ip()
}
fn shr(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 >> w2);
self.set_reg(r1, out);
self.next_ip()
}
fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let cmp = self.with_regs(r1, r2, |w1, w2| w1 == w2);
if cmp {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
self.next_ip()
}
fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let cmp = self.with_regs(r1, r2, |w1, w2| w1 < w2);
if cmp {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
self.next_ip()
}
fn jmp(&mut self, r1: Reg) -> Result<Self::Out> {
let addr = self.get_reg(r1);
Ok(addr)
}
fn jz(&mut self, r1: Reg) -> Result<Self::Out> {
if !self.flags().contains(Flags::COMPARE) {
Ok(self.get_reg(r1))
} else {
self.next_ip()
}
}
fn jnz(&mut self, r1: Reg) -> Result<Self::Out> {
if self.flags().contains(Flags::COMPARE) {
Ok(self.get_reg(r1))
} else {
self.next_ip()
}
}
fn load(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = Vm::load(self, r2)?;
self.set_reg_checked(r1, value)?;
self.next_ip()
}
fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = self.get_reg_checked(r2)?;
self.set_reg_checked(r1, value)?;
self.next_ip()
}
fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result<Self::Out> {
self.set_reg_checked(r1, w1)?;
self.next_ip()
}
fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result<Self::Out> {
self.set_reg_checked(r1, w1 as Word)?;
self.next_ip()
}
fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = Vm::load(self, r2)?;
self.store(r1, value)?;
self.next_ip()
}
fn store(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = self.get_reg_checked(r1)?;
self.store(r2, value)?;
self.next_ip()
}
fn halt(&mut self) -> Result<Self::Out> {
self.insert_flags(Flags::HALT);
self.next_ip()
}
fn nop(&mut self) -> Result<Self::Out> {
self.next_ip()
}
}