use crate::vm::{error::*, flags::*, mem::*, obj::obj::*, 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() -> Self { Vm { mem: Default::default(), registers: [0; 64], } } /// Loads an object into this VM, clearing out all previous memory and resetting the registers. pub fn load_object(&mut self, object: Object, max_mem: usize) -> Result<()> { self.registers = [0; 64]; // determine memory spread let mem_size = object .sections .iter() .filter_map(|s| match s { Section::Data { end, .. } | Section::Code { end, .. } => Some(*end), Section::Meta { .. } => None, }) .max() .unwrap_or(0); if mem_size > (max_mem as u64) { todo!("raise max memory error"); } self.mem = vec![0; mem_size as usize]; let mut entry = 0; // write sections to memory for section in object.sections.into_iter() { match section { Section::Data { start, contents, .. } | Section::Code { start, contents, .. } => { let start = start as usize; for (value, dest) in contents.into_iter().zip(&mut self.mem[start..]) { *dest = value; } } Section::Meta { entries } => { if let Some(e) = entries.get("entry") { // set the entry point entry = *e; } } } } self.set_reg(IP, entry); Ok(()) } pub fn mem_cursor(&self, at: usize) -> MemCursor { let mut cursor = MemCursor::new(&self.mem); cursor.set_position(at as u64); cursor } 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(()) } } }