use crate::vm::{error::*, flags::*, mem::*, reg::*}; use byteorder::{WriteBytesExt, LE}; use std::{io::Cursor, mem}; pub type Word = u64; pub type HalfWord = u32; pub type Registers = [Word; 64]; pub type Addr = u64; pub struct Vm { pub(super) mem: Vec, pub(super) registers: Registers, } impl Vm { pub fn new(mem: Vec, registers: Registers) -> Self { Vm { mem, registers } } pub fn mem_cursor(&self, at: usize) -> MemCursor { MemCursor::new(&self.mem[at..]) } pub fn run(&mut self) -> Result { while !self.is_halted() { self.tick()?; } Ok(self.get_reg(STATUS)) } pub fn resume(&mut self) { self.remove_flags(Flags::HALT); } pub fn is_halted(&self) -> bool { self.flags().contains(Flags::HALT) } pub fn get_word(&self, addr: Addr) -> Result { self.check_read(addr, 8)?; Ok(self.mem_cursor(addr as usize).next_u64().unwrap()) } pub fn get_halfword(&self, addr: Addr) -> Result { self.check_read(addr, 4)?; Ok(self.mem_cursor(addr as usize).next_u32().unwrap()) } pub fn get_byte(&self, addr: Addr) -> Result { self.check_addr(addr)?; Ok(self.mem_cursor(addr as usize).next_u8().unwrap()) } pub fn set_word(&mut self, addr: Addr, value: Word) -> Result<()> { self.check_read(addr, 8)?; let mut cursor = Cursor::new(&mut self.mem[addr as usize..]); Ok(cursor.write_u64::(value).unwrap()) } pub fn set_halfword(&mut self, addr: Addr, value: HalfWord) -> Result<()> { self.check_read(addr, 4)?; let mut cursor = Cursor::new(&mut self.mem[addr as usize..]); Ok(cursor.write_u32::(value).unwrap()) } pub fn set_byte(&mut self, addr: Addr, value: u8) -> Result<()> { self.check_addr(addr)?; let mut cursor = Cursor::new(&mut self.mem[addr as usize..]); Ok(cursor.write_u8(value).unwrap()) } pub fn load(&self, reg: Reg) -> Result { self.get_word(self.get_reg_checked(reg)?) } pub fn store(&mut self, reg: Reg, value: Word) -> Result<()> { let addr = self.get_reg_checked(reg)?; self.set_word(addr, value) } pub fn get_reg_checked(&self, reg: Reg) -> Result { self.check_reg(reg)?; Ok(self.get_reg(reg)) } pub fn get_reg(&self, reg: Reg) -> Word { self.registers[reg as usize] } pub fn set_reg_checked(&mut self, reg: Reg, value: Word) -> Result { self.check_reg(reg)?; Ok(self.set_reg(reg, value)) } pub fn set_reg(&mut self, reg: Reg, value: Word) -> Word { mem::replace(&mut self.registers[reg as usize], value) } pub fn ip(&self) -> Word { self.get_reg(IP) } pub fn flags(&self) -> Flags { // this is safe because it's OK if there are random bits flipped - this shouldn't happen // anyway, but if it does, they're ignored unsafe { Flags::from_bits_unchecked(self.get_reg(FLAGS)) } } pub fn insert_flags(&mut self, flags: Flags) { let mut new_flags = self.flags(); new_flags.insert(flags); self.set_flags(new_flags); } pub fn remove_flags(&mut self, flags: Flags) { let mut new_flags = self.flags(); new_flags.remove(flags); self.set_flags(new_flags); } pub fn set_flags(&mut self, flags: Flags) { self.set_reg(FLAGS, flags.bits()); } fn check_addr(&self, addr: Addr) -> Result<()> { if addr >= (self.mem.len() as u64) { Err(VmError::MemOutOfBounds { addr }) } else { Ok(()) } } fn check_read(&self, addr: Addr, len: Word) -> Result<()> { self.check_addr(addr) .and_then(|_| self.check_addr(addr + len - 1)) } fn check_reg(&self, reg: Reg) -> Result<()> { if reg > LAST_REG { Err(VmError::IllegalReg { reg }) } else { Ok(()) } } }