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. type CPUResult = Result; #[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 { 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, } } }