Dekejit/src/cpu/mod.rs
2023-05-02 14:13:49 +02:00

189 lines
5.4 KiB
Rust

mod decoder;
mod ram;
mod registers;
mod sysenv;
mod tests;
pub use sysenv::*;
pub use registers::*;
pub use decoder::OP;
use ram::Ram;
#[derive(Debug)]
pub enum ExecErr {
InvalidRegister,
InvalidMemoryAddr,
InvalidSyscall,
InvalidPC,
SyscallError(String),
}
use ExecErr::*;
use crate::{interpret_as_signed, interpret_as_unsigned};
use self::decoder::decode;
/// Simple synonim for Result<T, ExecErr>.
type CPUResult<T> = Result<T, ExecErr>;
#[derive(Debug)]
/// The state of the interpreter.
pub struct CPU<'a, T> {
pub regs: Registers,
pub ram: Ram,
pub env: &'a mut T,
// should execution be halted? not sure if to include this or nah
halt: bool,
}
impl<'a, T> CPU<'a, T>
where
T: Sys,
{
pub fn execute_op(&mut self, op: OP) -> CPUResult<()> {
match op {
OP::NOP => {
self.regs.pc += 1;
}
OP::ADD(d, r1, r2) => {
let v1 = self.regs.get(r1).ok_or(InvalidRegister)?;
let v2 = self.regs.get(r2).ok_or(InvalidRegister)?;
self.regs.write(d, v1 + v2).ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::SUB(d, r1, r2) => {
let v1 = self.regs.get(r1).ok_or(InvalidRegister)?;
let v2 = self.regs.get(r2).ok_or(InvalidRegister)?;
self.regs.write(d, v1 - v2).ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::AND(d, r1, r2) => {
let v1 = self.regs.get(r1).ok_or(InvalidRegister)?;
let v2 = self.regs.get(r2).ok_or(InvalidRegister)?;
self.regs.write(d, v1 & v2).ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::XOR(d, r1, r2) => {
let v1 = self.regs.get(r1).ok_or(InvalidRegister)?;
let v2 = self.regs.get(r2).ok_or(InvalidRegister)?;
self.regs.write(d, v1 ^ v2).ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::SLL(d, r1, r2) => {
let v1 = self.regs.get(r1).ok_or(InvalidRegister)?;
let v2 = self.regs.get(r2).ok_or(InvalidRegister)?;
self.regs.write(d, v1 << v2).ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::SLI(d, c) => {
let v1 = self.regs.get(d).ok_or(InvalidRegister)?;
self.regs.write(d, v1 << c).ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::ADDI(d, c) => {
let v1 = self.regs.get(d).ok_or(InvalidRegister)?;
self.regs
.write(
d,
interpret_as_unsigned(interpret_as_signed(v1) + (c as i16)),
)
.ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::BEQ(d, x0, x1) => {
if x0 == x1 {
let v = self.regs.get(d).ok_or(InvalidRegister)?;
self.regs.pc = v;
}
}
OP::BGT(d, x0, x1) => {
if x0 > x1 {
let v = self.regs.get(d).ok_or(InvalidRegister)?;
self.regs.pc = v;
}
}
OP::JAL(s0, s1, c) => {
self.regs
.write(s0, self.regs.pc + 1)
.ok_or(InvalidRegister)?;
let v = self.regs.get(s1).ok_or(InvalidRegister)?;
self.regs.pc = (v as i16 + (c as i16)) as Word;
}
OP::LOAD(d, s1, s2) => {
let start = self.regs.get(s1).ok_or(InvalidRegister)?;
let offset = self.regs.get(s2).ok_or(InvalidRegister)?;
let v = self.ram.get(start + offset).ok_or(InvalidMemoryAddr)?;
self.regs.write(d, v).ok_or(InvalidRegister)?;
self.regs.pc += 1;
}
OP::STORE(d, s1, s2) => {
let start = self.regs.get(s1).ok_or(InvalidRegister)?;
let offset = self.regs.get(s2).ok_or(InvalidRegister)?;
let v = self.regs.get(d).ok_or(InvalidRegister)?;
self.ram.write(start + offset, v).ok_or(InvalidMemoryAddr)?;
self.regs.pc += 1;
}
OP::CALL(r, c) => {
T::call(self, r.into(), c as u16)?;
self.regs.pc += 1;
}
OP::HALT => {
self.halt = true;
}
}
return Ok(());
}
fn fetch(&self) -> CPUResult<OP> {
let binop = self.ram.get(self.regs.pc).ok_or(ExecErr::InvalidPC)?;
println!("binop: {:#018b}", binop);
Ok(decode(binop))
}
fn step(&mut self) -> CPUResult<()> {
let op = self.fetch()?;
println!("fetched op: {:?}, pc: {} ", op, self.regs.pc);
self.execute_op(op)
}
pub fn run_code_raw(&mut self, bin_code: &[Word]) -> CPUResult<()> {
self.halt = false;
// put the code in memory:
self.ram.write_array(bin_code, 0);
while !self.halt {
self.step()?;
}
Ok(())
}
pub fn new(env: &'a mut T) -> Self {
CPU {
regs: Registers::default(),
ram: Ram::default(),
env,
halt: false,
}
}
}