forked from AbleOS/holey-bytes
96 lines
3 KiB
Rust
96 lines
3 KiB
Rust
|
mod value;
|
||
|
|
||
|
use {
|
||
|
crate::bytecode::{OpParam, ParamRI, ParamRR, ParamRRR},
|
||
|
core::ops,
|
||
|
static_assertions::assert_impl_one,
|
||
|
value::Value,
|
||
|
};
|
||
|
|
||
|
macro_rules! param {
|
||
|
($self:expr, $ty:ty) => {{
|
||
|
assert_impl_one!($ty: OpParam);
|
||
|
let data = $self.program.as_ptr()
|
||
|
.add($self.pc + 1)
|
||
|
.cast::<$ty>()
|
||
|
.read();
|
||
|
$self.pc += 1 + core::mem::size_of::<$ty>();
|
||
|
data
|
||
|
}};
|
||
|
}
|
||
|
|
||
|
macro_rules! binary_op {
|
||
|
($self:expr, $ty:ident, $handler:expr) => {{
|
||
|
let ParamRRR(tg, a0, a1) = param!($self, ParamRRR);
|
||
|
*$self.reg_mut(tg) = $handler(Value::$ty($self.reg(a0)), Value::$ty($self.reg(a1))).into();
|
||
|
}};
|
||
|
}
|
||
|
|
||
|
pub struct Vm<'a> {
|
||
|
pub registers: [Value; 60],
|
||
|
pc: usize,
|
||
|
program: &'a [u8],
|
||
|
}
|
||
|
|
||
|
impl<'a> Vm<'a> {
|
||
|
/// # Safety
|
||
|
/// Program code has to be validated
|
||
|
pub unsafe fn new_unchecked(program: &'a [u8]) -> Self {
|
||
|
Self {
|
||
|
registers: [Value::from(0); 60],
|
||
|
pc: 0,
|
||
|
program,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn run(&mut self) {
|
||
|
use crate::bytecode::opcode::*;
|
||
|
loop {
|
||
|
let Some(&opcode) = self.program.get(self.pc)
|
||
|
else { return };
|
||
|
|
||
|
unsafe {
|
||
|
match opcode {
|
||
|
NOP => param!(self, ()),
|
||
|
ADD => binary_op!(self, int, u64::wrapping_add),
|
||
|
SUB => binary_op!(self, int, u64::wrapping_sub),
|
||
|
MUL => binary_op!(self, int, u64::wrapping_mul),
|
||
|
DIV => binary_op!(self, int, u64::wrapping_div),
|
||
|
REM => binary_op!(self, int, u64::wrapping_rem),
|
||
|
AND => binary_op!(self, int, ops::BitAnd::bitand),
|
||
|
OR => binary_op!(self, int, ops::BitOr::bitor),
|
||
|
XOR => binary_op!(self, int, ops::BitXor::bitxor),
|
||
|
NOT => {
|
||
|
let param = param!(self, ParamRR);
|
||
|
*self.reg_mut(param.0) = (!self.reg(param.1).int()).into();
|
||
|
}
|
||
|
ADDF => binary_op!(self, float, ops::Add::add),
|
||
|
SUBF => binary_op!(self, float, ops::Sub::sub),
|
||
|
MULF => binary_op!(self, float, ops::Mul::mul),
|
||
|
DIVF => binary_op!(self, float, ops::Div::div),
|
||
|
LI => {
|
||
|
let param = param!(self, ParamRI);
|
||
|
*self.reg_mut(param.0) = param.1.into();
|
||
|
}
|
||
|
// TODO: LD, ST
|
||
|
JMP => {
|
||
|
self.pc =
|
||
|
self.program.as_ptr().add(self.pc + 1).cast::<u64>().read() as usize;
|
||
|
}
|
||
|
_ => core::hint::unreachable_unchecked(),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
unsafe fn reg(&self, n: u8) -> &Value {
|
||
|
self.registers.get_unchecked(n as usize)
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
unsafe fn reg_mut(&mut self, n: u8) -> &mut Value {
|
||
|
self.registers.get_unchecked_mut(n as usize)
|
||
|
}
|
||
|
}
|