mod exec;
use crate::error::{self, Result};
use crate::isa::{An, Long};
use crate::vm::{Mem, Regs};
use crate::signal::Signal;
use std::fs::File;
use std::io::Read;
use std::os::unix::fs::MetadataExt;
use std::path::Path;
#[derive(Debug, Default)]
pub struct Vm {
regs: Regs,
mem: Mem,
}
impl Vm {
#[inline]
#[must_use]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn read_image<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
let path = path.as_ref();
eprintln!("reading executable image at \"{}\"", path.display());
let mut file = File::open_buffered(path)?;
if file.get_ref().metadata()?.size() > Mem::IMG_SIZE as u64 {
let e = error::Builder::new()
.message("executable file may not be larger than `8388608` bytes")
.build();
return Err(e);
}
let slot = self.mem.raw_mut()
.get_mut(..Mem::IMG_SIZE)
.unwrap_or_default();
let image_size = file.read(slot)?;
eprintln!("successfully read `{image_size}` byte(s) of executable");
Ok(())
}
#[inline]
pub fn boot(&mut self) {
const SP_ADDR: Long = Long::from_u32(0);
const PC_ADDR: Long = Long::from_u32(4);
let mem = self.mem();
let sp = mem.load_long(SP_ADDR).unwrap();
let pc = mem.load_long(PC_ADDR).unwrap();
let regs = self.regs_mut();
*regs.an_mut(An::Sp) = sp;
*regs.pc_mut() = pc;
}
#[inline]
pub fn render_signal(&mut self, _buf: &mut Signal) {
self.boot();
loop {
let exception = self.exec();
eprintln!("got exception #{}: \"{}\"", exception.as_u8(), exception.as_str());
}
}
#[inline(always)]
#[must_use]
pub fn regs(&self) -> &Regs {
&self.regs
}
#[inline(always)]
#[must_use]
pub fn regs_mut(&mut self) -> &mut Regs {
&mut self.regs
}
#[inline(always)]
#[must_use]
pub fn mem(&self) -> &Mem {
&self.mem
}
#[inline(always)]
#[must_use]
pub fn mem_mut(&mut self) -> &mut Mem {
&mut self.mem
}
}