2020-02-09 15:43:07 -05:00
|
|
|
use crate::vm::{error::*, flags::*, mem::*, obj::obj::*, reg::*};
|
2020-02-09 14:10:02 -05:00
|
|
|
use byteorder::{WriteBytesExt, LE};
|
2020-02-03 17:56:32 -05:00
|
|
|
use std::{io::Cursor, mem};
|
2020-01-25 19:17:39 -05:00
|
|
|
|
|
|
|
|
pub type Word = u64;
|
|
|
|
|
pub type HalfWord = u32;
|
|
|
|
|
pub type Registers = [Word; 64];
|
2020-02-03 17:56:32 -05:00
|
|
|
pub type Addr = u64;
|
2020-01-25 19:17:39 -05:00
|
|
|
|
|
|
|
|
pub struct Vm {
|
2020-02-03 17:56:32 -05:00
|
|
|
pub(super) mem: Vec<u8>,
|
|
|
|
|
pub(super) registers: Registers,
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Vm {
|
2020-02-09 15:43:07 -05:00
|
|
|
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(())
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-03 17:56:32 -05:00
|
|
|
pub fn mem_cursor(&self, at: usize) -> MemCursor {
|
2020-02-09 15:43:07 -05:00
|
|
|
let mut cursor = MemCursor::new(&self.mem);
|
|
|
|
|
cursor.set_position(at as u64);
|
|
|
|
|
cursor
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-03 17:56:32 -05:00
|
|
|
pub fn run(&mut self) -> Result<u64> {
|
|
|
|
|
while !self.is_halted() {
|
|
|
|
|
self.tick()?;
|
|
|
|
|
}
|
|
|
|
|
Ok(self.get_reg(STATUS))
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn resume(&mut self) {
|
|
|
|
|
self.remove_flags(Flags::HALT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_halted(&self) -> bool {
|
|
|
|
|
self.flags().contains(Flags::HALT)
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
pub fn get_word(&self, addr: Addr) -> Result<Word> {
|
|
|
|
|
self.check_read(addr, 8)?;
|
|
|
|
|
Ok(self.mem_cursor(addr as usize).next_u64().unwrap())
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
pub fn get_halfword(&self, addr: Addr) -> Result<HalfWord> {
|
|
|
|
|
self.check_read(addr, 4)?;
|
|
|
|
|
Ok(self.mem_cursor(addr as usize).next_u32().unwrap())
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
pub fn get_byte(&self, addr: Addr) -> Result<u8> {
|
|
|
|
|
self.check_addr(addr)?;
|
|
|
|
|
Ok(self.mem_cursor(addr as usize).next_u8().unwrap())
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
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())
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
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())
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
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())
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
pub fn load(&self, reg: Reg) -> Result<Word> {
|
|
|
|
|
self.get_word(self.get_reg_checked(reg)?)
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
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))
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_reg(&self, reg: Reg) -> Word {
|
|
|
|
|
self.registers[reg as usize]
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-09 14:10:02 -05:00
|
|
|
pub fn set_reg_checked(&mut self, reg: Reg, value: Word) -> Result<Word> {
|
|
|
|
|
self.check_reg(reg)?;
|
|
|
|
|
Ok(self.set_reg(reg, value))
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-25 19:17:39 -05:00
|
|
|
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 {
|
2020-01-27 18:41:33 -05:00
|
|
|
self.get_reg(IP)
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
2020-01-27 18:41:33 -05:00
|
|
|
unsafe { Flags::from_bits_unchecked(self.get_reg(FLAGS)) }
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
2020-02-03 17:56:32 -05:00
|
|
|
|
2020-01-25 19:17:39 -05:00
|
|
|
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) {
|
2020-01-27 18:41:33 -05:00
|
|
|
self.set_reg(FLAGS, flags.bits());
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|
2020-02-09 14:10:02 -05:00
|
|
|
|
|
|
|
|
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(())
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-25 19:17:39 -05:00
|
|
|
}
|