diff --git a/backend/src/core.rs b/backend/src/core.rs index e69de29..0c17cac 100644 --- a/backend/src/core.rs +++ b/backend/src/core.rs @@ -0,0 +1,12 @@ +pub mod cpu; +pub mod instruction; +pub mod interpreter; +pub mod mem; +pub mod registers; + +pub struct Core {} + +impl Core { + pub fn stop(&mut self) {} + pub fn reset(&mut self) {} +} diff --git a/backend/src/core/cpu.rs b/backend/src/core/cpu.rs new file mode 100644 index 0000000..9370a0f --- /dev/null +++ b/backend/src/core/cpu.rs @@ -0,0 +1,27 @@ +use crate::core::{instruction::Instruction, mem::Memory, registers::Registers}; + +pub enum CpuType { + Interpreter, + CachedInterpreter, + DynamicRecompiler, +} + +pub trait Cpu { + fn get_type() -> CpuType; + fn get_regs(&mut self) -> &mut Registers; + fn fetch(&self, _: &Memory, _: u64) -> Option { + None + } + + fn fetch_then_advance(&mut self, _: &Memory) -> Option { + None + } + fn execute(&mut self, mem: &Memory) -> Result; + fn advance(&mut self) -> bool { + false + } + fn decode(&mut self, instr: Instruction) -> Result<(), String>; + fn reset(&mut self); + fn should_service_interrupt(&self) -> bool; + fn update_compare_interrupt(&mut self); +} diff --git a/backend/src/core/instruction.rs b/backend/src/core/instruction.rs new file mode 100644 index 0000000..c4c1dd2 --- /dev/null +++ b/backend/src/core/instruction.rs @@ -0,0 +1,183 @@ +use proc_bitfield::bitfield; + +bitfield! { + pub struct Instruction(pub u32): Debug, FromStorage, IntoStorage, DerefStorage { + pub special: u8 @ 0..6, + pub regimm: u8 @ 16..21, + pub rt: u8 @ 16..21, + pub cop_rt: u8 @ 16..21, + pub rs: u8 @ 21..26, + pub cop_rs: u8 @ 21..26, + pub opcode: u8 @ 26..32, + pub imm: u16 @ 0..16, + pub target: u32 @ 0..26, + pub funct: u8 @ 0..6, + pub sa: u8 @ 6..11, + pub rd: u8 @ 11..16, + } +} + +enum BranchType { + Pure, + Likely, + Link, + LinkLikely, +} + +impl Instruction { + fn get_branch(self) -> Option { + match self.opcode() { + Instruction::BEQ | Instruction::BNE | Instruction::BLEZ | Instruction::BGTZ => { + Some(BranchType::Pure) + } + Instruction::BEQL | Instruction::BNEL | Instruction::BLEZL | Instruction::BGTZL => { + Some(BranchType::Likely) + } + Instruction::REGIMM => match self.regimm() { + Instruction::BLTZ | Instruction::BGEZ => Some(BranchType::Pure), + Instruction::BLTZAL | Instruction::BGEZAL => Some(BranchType::Link), + Instruction::BLTZL | Instruction::BGEZL => Some(BranchType::Likely), + Instruction::BLTZALL | Instruction::BGEZALL => Some(BranchType::LinkLikely), + _ => None, + }, + Instruction::COP1 => { + if self.cop_rs() == 8 { + match self.cop_rt() { + 0 | 1 => Some(BranchType::Pure), + 2 | 3 => Some(BranchType::Likely), + _ => None, + } + } else { + None + } + } + _ => None, + } + } + + const SPECIAL: u8 = 0b000000; + const REGIMM: u8 = 0b000001; + const J: u8 = 0b000010; + const JAL: u8 = 0b000011; + const BEQ: u8 = 0b000100; + const BNE: u8 = 0b000101; + const BLEZ: u8 = 0b000110; + const BGTZ: u8 = 0b000111; + const ADDI: u8 = 0b001000; + const ADDIU: u8 = 0b001001; + const SLTI: u8 = 0b001010; + const SLTIU: u8 = 0b001011; + const ANDI: u8 = 0b001100; + const ORI: u8 = 0b001101; + const XORI: u8 = 0b001110; + const LUI: u8 = 0b001111; + const COP0: u8 = 0b010000; + const COP1: u8 = 0b010001; + const COP2: u8 = 0b010010; + const BEQL: u8 = 0b010100; + const BNEL: u8 = 0b010101; + const BLEZL: u8 = 0b010110; + const BGTZL: u8 = 0b010111; + const DADDI: u8 = 0b011000; + const DADDIU: u8 = 0b011001; + const LDL: u8 = 0b011010; + const LDR: u8 = 0b011011; + const LB: u8 = 0b100000; + const LH: u8 = 0b100001; + const LWL: u8 = 0b100010; + const LW: u8 = 0b100011; + const LBU: u8 = 0b100100; + const LHU: u8 = 0b100101; + const LWR: u8 = 0b100110; + const LWU: u8 = 0b100111; + const SB: u8 = 0b101000; + const SH: u8 = 0b101001; + const SWL: u8 = 0b101010; + const SW: u8 = 0b101011; + const SDL: u8 = 0b101100; + const SDR: u8 = 0b101101; + const SWR: u8 = 0b101110; + const CACHE: u8 = 0b101111; + const LL: u8 = 0b110000; + const LWC1: u8 = 0b110001; + const LWC2: u8 = 0b110010; + const LLD: u8 = 0b110100; + const LDC1: u8 = 0b110101; + const LDC2: u8 = 0b110110; + const LD: u8 = 0b110111; + const SC: u8 = 0b111000; + const SWC1: u8 = 0b111001; + const SWC2: u8 = 0b111010; + const SCD: u8 = 0b111100; + const SDC1: u8 = 0b111101; + const SDC2: u8 = 0b111110; + const SD: u8 = 0b111111; + // special + const SLL: u8 = 0b000000; + const SRL: u8 = 0b000010; + const SRA: u8 = 0b000011; + const SLLV: u8 = 0b000100; + const SRLV: u8 = 0b000110; + const SRAV: u8 = 0b000111; + const JR: u8 = 0b001000; + const JALR: u8 = 0b001001; + const SYSCALL: u8 = 0b001100; + const BREAK: u8 = 0b001101; + const SYNC: u8 = 0b001111; + const MFHI: u8 = 0b010000; + const MTHI: u8 = 0b010001; + const MFLO: u8 = 0b010010; + const MTLO: u8 = 0b010011; + const DSLLV: u8 = 0b010100; + const DSRLV: u8 = 0b010110; + const DSRAV: u8 = 0b010111; + const MULT: u8 = 0b011000; + const MULTU: u8 = 0b011001; + const DIV: u8 = 0b011010; + const DIVU: u8 = 0b011011; + const DMULT: u8 = 0b011100; + const DMULTU: u8 = 0b011101; + const DDIV: u8 = 0b011110; + const DDIVU: u8 = 0b011111; + const ADD: u8 = 0b100000; + const ADDU: u8 = 0b100001; + const SUB: u8 = 0b100010; + const SUBU: u8 = 0b100011; + const AND: u8 = 0b100100; + const OR: u8 = 0b100101; + const XOR: u8 = 0b100110; + const NOR: u8 = 0b100111; + const SLT: u8 = 0b101010; + const SLTU: u8 = 0b101011; + const DADD: u8 = 0b101100; + const DADDU: u8 = 0b101101; + const DSUB: u8 = 0b101110; + const DSUBU: u8 = 0b101111; + const TGE: u8 = 0b110000; + const TGEU: u8 = 0b110001; + const TLT: u8 = 0b110010; + const TLTU: u8 = 0b110011; + const TEQ: u8 = 0b110100; + const TNE: u8 = 0b110110; + const DSLL: u8 = 0b111000; + const DSRL: u8 = 0b111010; + const DSRA: u8 = 0b111011; + const DSLL32: u8 = 0b111100; + const DSRL32: u8 = 0b111110; + const DSRA32: u8 = 0b111111; + // regimm + const BLTZ: u8 = 0b00000; + const BGEZ: u8 = 0b00001; + const BLTZL: u8 = 0b00010; + const BGEZL: u8 = 0b00011; + const TGEI: u8 = 0b01000; + const TGEIU: u8 = 0b01001; + const TLTI: u8 = 0b01010; + const TLTIU: u8 = 0b01011; + const TEQI: u8 = 0b01100; + const TNEI: u8 = 0b01110; + const BLTZAL: u8 = 0b10000; + const BGEZAL: u8 = 0b10001; + const BLTZALL: u8 = 0b10010; + const BGEZALL: u8 = 0b10011; +} diff --git a/backend/src/core/interpreter.rs b/backend/src/core/interpreter.rs new file mode 100644 index 0000000..af9aab8 --- /dev/null +++ b/backend/src/core/interpreter.rs @@ -0,0 +1,77 @@ +use crate::{ + core::{ + cpu::{Cpu, CpuType::*}, + instruction::Instruction, + mem::Memory, + registers::Registers, + }, + utils::access::is_address_error, +}; + +pub struct Interpreter { + regs: Registers, + delay_slot: bool, + prev_delay_slot: bool, +} + +impl Cpu for Interpreter { + fn get_type() -> super::cpu::CpuType { + Interpreter + } + + fn get_regs(&mut self) -> &mut Registers { + &mut self.regs + } + + fn should_service_interrupt(&self) -> bool { + false + } + + fn update_compare_interrupt(&mut self) { + todo!("update_compare_interrupt") + } + + fn fetch(&self, _mem: &Memory, _vaddr: u64) -> Option { + todo!("translate vaddr to paddr and if it fails, throw the exception and return None"); + // Some(mem.read(paddr).into()) + } + + fn fetch_then_advance(&mut self, mem: &Memory) -> Option { + self.update_compare_interrupt(); + + self.prev_delay_slot = self.delay_slot; + self.delay_slot = false; + + if is_address_error(&self.regs, 0b11, self.regs.curr_pc) { + todo!("is_address_error ? then throw exception and return None"); + } + + let instr = self.fetch(mem, self.regs.curr_pc as u64)?; + + if self.should_service_interrupt() { + todo!("should_service_interrupt ? then throw exception and return None"); + } + + self.regs.old_pc = self.regs.curr_pc; + self.regs.curr_pc = self.regs.next_pc; + self.regs.next_pc += 4; + + Some(instr) + } + + fn execute(&mut self, mem: &Memory) -> Result { + if let Some(instr) = self.fetch_then_advance(mem) { + self.decode(instr)?; + } + + Ok(1) + } + + fn decode(&mut self, instr: Instruction) -> Result<(), String> { + todo!("decode") + } + + fn reset(&mut self) { + todo!("reset") + } +} diff --git a/backend/src/core/mem.rs b/backend/src/core/mem.rs new file mode 100644 index 0000000..d8ca004 --- /dev/null +++ b/backend/src/core/mem.rs @@ -0,0 +1 @@ +pub struct Memory {} diff --git a/backend/src/core/registers.rs b/backend/src/core/registers.rs new file mode 100644 index 0000000..0771cda --- /dev/null +++ b/backend/src/core/registers.rs @@ -0,0 +1,51 @@ +pub struct Registers { + pub gpr: [i64; 32], + pub old_pc: i64, + pub curr_pc: i64, + pub next_pc: i64, + pub hi: i64, + pub lo: i64, + pub constant_regs: u64, +} + +impl Registers { + pub fn new() -> Self { + Self { + gpr: [0; 32], + old_pc: 0, + curr_pc: 0, + next_pc: 0, + hi: 0, + lo: 0, + constant_regs: 1, + } + } + + pub fn set_pc(&mut self, value: T) + where + i64: From, + { + self.old_pc = self.curr_pc; + self.curr_pc = value.into(); + self.next_pc = self.curr_pc + 4; + } + + pub fn read(&self, idx: usize) -> T + where + T: From, + { + self.gpr[idx].into() + } + + pub fn write(&mut self, idx: usize, value: T) + where + i64: From, + { + if idx == 0 { + return; + } + + self.constant_regs |= 1 << idx; + self.gpr[idx] = value.into(); + } +} diff --git a/backend/src/lib.rs b/backend/src/lib.rs index 8b13789..920371e 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -1 +1,5 @@ +#![allow(dead_code)] +pub mod core; +pub mod scheduler; +pub mod utils; diff --git a/backend/src/utils/access.rs b/backend/src/utils/access.rs new file mode 100644 index 0000000..1354f71 --- /dev/null +++ b/backend/src/utils/access.rs @@ -0,0 +1,6 @@ +use crate::core::registers::Registers; + +pub fn is_address_error(_regs: &Registers, mask: u8, vaddr: i64) -> bool { + vaddr & mask as i64 != 0 + // || (!regs.cop0.is64BitAddressing && s32(vaddr) != vaddr) +} diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs new file mode 100644 index 0000000..207872c --- /dev/null +++ b/backend/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod access; \ No newline at end of file