189 lines
5.4 KiB
Rust
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,
|
|
}
|
|
}
|
|
}
|