Files
rasp/src/vm/vm.rs

146 lines
4.0 KiB
Rust
Raw Normal View History

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<u8>,
pub(super) registers: Registers,
}
impl Vm {
pub fn new(mem: Vec<u8>, 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<u64> {
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<Word> {
self.check_read(addr, 8)?;
Ok(self.mem_cursor(addr as usize).next_u64().unwrap())
}
pub fn get_halfword(&self, addr: Addr) -> Result<HalfWord> {
self.check_read(addr, 4)?;
Ok(self.mem_cursor(addr as usize).next_u32().unwrap())
}
pub fn get_byte(&self, addr: Addr) -> Result<u8> {
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::<LE>(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::<LE>(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<Word> {
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<Word> {
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<Word> {
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(())
}
}
}