diff --git a/backend/src/core/cpu.rs b/backend/src/core/cpu.rs index 9370a0f..7d12b4e 100644 --- a/backend/src/core/cpu.rs +++ b/backend/src/core/cpu.rs @@ -1,4 +1,7 @@ -use crate::core::{instruction::Instruction, mem::Memory, registers::Registers}; +use crate::{ + core::{instruction::Instruction, mem::Memory, registers::Registers}, + utils::error::Error, +}; pub enum CpuType { Interpreter, @@ -16,11 +19,11 @@ pub trait Cpu { fn fetch_then_advance(&mut self, _: &Memory) -> Option { None } - fn execute(&mut self, mem: &Memory) -> Result; + fn step(&mut self, mem: &Memory) -> Result; fn advance(&mut self) -> bool { false } - fn decode(&mut self, instr: Instruction) -> Result<(), String>; + fn decode_execute(&mut self, instr: Instruction) -> Result<(), Error>; 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 index c4c1dd2..dea63d6 100644 --- a/backend/src/core/instruction.rs +++ b/backend/src/core/instruction.rs @@ -1,7 +1,8 @@ use proc_bitfield::bitfield; bitfield! { - pub struct Instruction(pub u32): Debug, FromStorage, IntoStorage, DerefStorage { + #[derive(Clone, Copy, Debug)] + pub struct Instruction(pub u32): FromStorage, IntoStorage, DerefStorage { pub special: u8 @ 0..6, pub regimm: u8 @ 16..21, pub rt: u8 @ 16..21, @@ -17,7 +18,7 @@ bitfield! { } } -enum BranchType { +pub enum BranchType { Pure, Likely, Link, @@ -25,7 +26,7 @@ enum BranchType { } impl Instruction { - fn get_branch(self) -> Option { + pub fn get_branch(self) -> Option { match self.opcode() { Instruction::BEQ | Instruction::BNE | Instruction::BLEZ | Instruction::BGTZ => { Some(BranchType::Pure) @@ -55,129 +56,129 @@ impl Instruction { } } - 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; + pub const SPECIAL: u8 = 0b000000; + pub const REGIMM: u8 = 0b000001; + pub const J: u8 = 0b000010; + pub const JAL: u8 = 0b000011; + pub const BEQ: u8 = 0b000100; + pub const BNE: u8 = 0b000101; + pub const BLEZ: u8 = 0b000110; + pub const BGTZ: u8 = 0b000111; + pub const ADDI: u8 = 0b001000; + pub const ADDIU: u8 = 0b001001; + pub const SLTI: u8 = 0b001010; + pub const SLTIU: u8 = 0b001011; + pub const ANDI: u8 = 0b001100; + pub const ORI: u8 = 0b001101; + pub const XORI: u8 = 0b001110; + pub const LUI: u8 = 0b001111; + pub const COP0: u8 = 0b010000; + pub const COP1: u8 = 0b010001; + pub const COP2: u8 = 0b010010; + pub const BEQL: u8 = 0b010100; + pub const BNEL: u8 = 0b010101; + pub const BLEZL: u8 = 0b010110; + pub const BGTZL: u8 = 0b010111; + pub const DADDI: u8 = 0b011000; + pub const DADDIU: u8 = 0b011001; + pub const LDL: u8 = 0b011010; + pub const LDR: u8 = 0b011011; + pub const LB: u8 = 0b100000; + pub const LH: u8 = 0b100001; + pub const LWL: u8 = 0b100010; + pub const LW: u8 = 0b100011; + pub const LBU: u8 = 0b100100; + pub const LHU: u8 = 0b100101; + pub const LWR: u8 = 0b100110; + pub const LWU: u8 = 0b100111; + pub const SB: u8 = 0b101000; + pub const SH: u8 = 0b101001; + pub const SWL: u8 = 0b101010; + pub const SW: u8 = 0b101011; + pub const SDL: u8 = 0b101100; + pub const SDR: u8 = 0b101101; + pub const SWR: u8 = 0b101110; + pub const CACHE: u8 = 0b101111; + pub const LL: u8 = 0b110000; + pub const LWC1: u8 = 0b110001; + pub const LWC2: u8 = 0b110010; + pub const LLD: u8 = 0b110100; + pub const LDC1: u8 = 0b110101; + pub const LDC2: u8 = 0b110110; + pub const LD: u8 = 0b110111; + pub const SC: u8 = 0b111000; + pub const SWC1: u8 = 0b111001; + pub const SWC2: u8 = 0b111010; + pub const SCD: u8 = 0b111100; + pub const SDC1: u8 = 0b111101; + pub const SDC2: u8 = 0b111110; + pub 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; + pub const SLL: u8 = 0b000000; + pub const SRL: u8 = 0b000010; + pub const SRA: u8 = 0b000011; + pub const SLLV: u8 = 0b000100; + pub const SRLV: u8 = 0b000110; + pub const SRAV: u8 = 0b000111; + pub const JR: u8 = 0b001000; + pub const JALR: u8 = 0b001001; + pub const SYSCALL: u8 = 0b001100; + pub const BREAK: u8 = 0b001101; + pub const SYNC: u8 = 0b001111; + pub const MFHI: u8 = 0b010000; + pub const MTHI: u8 = 0b010001; + pub const MFLO: u8 = 0b010010; + pub const MTLO: u8 = 0b010011; + pub const DSLLV: u8 = 0b010100; + pub const DSRLV: u8 = 0b010110; + pub const DSRAV: u8 = 0b010111; + pub const MULT: u8 = 0b011000; + pub const MULTU: u8 = 0b011001; + pub const DIV: u8 = 0b011010; + pub const DIVU: u8 = 0b011011; + pub const DMULT: u8 = 0b011100; + pub const DMULTU: u8 = 0b011101; + pub const DDIV: u8 = 0b011110; + pub const DDIVU: u8 = 0b011111; + pub const ADD: u8 = 0b100000; + pub const ADDU: u8 = 0b100001; + pub const SUB: u8 = 0b100010; + pub const SUBU: u8 = 0b100011; + pub const AND: u8 = 0b100100; + pub const OR: u8 = 0b100101; + pub const XOR: u8 = 0b100110; + pub const NOR: u8 = 0b100111; + pub const SLT: u8 = 0b101010; + pub const SLTU: u8 = 0b101011; + pub const DADD: u8 = 0b101100; + pub const DADDU: u8 = 0b101101; + pub const DSUB: u8 = 0b101110; + pub const DSUBU: u8 = 0b101111; + pub const TGE: u8 = 0b110000; + pub const TGEU: u8 = 0b110001; + pub const TLT: u8 = 0b110010; + pub const TLTU: u8 = 0b110011; + pub const TEQ: u8 = 0b110100; + pub const TNE: u8 = 0b110110; + pub const DSLL: u8 = 0b111000; + pub const DSRL: u8 = 0b111010; + pub const DSRA: u8 = 0b111011; + pub const DSLL32: u8 = 0b111100; + pub const DSRL32: u8 = 0b111110; + pub 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; + pub const BLTZ: u8 = 0b00000; + pub const BGEZ: u8 = 0b00001; + pub const BLTZL: u8 = 0b00010; + pub const BGEZL: u8 = 0b00011; + pub const TGEI: u8 = 0b01000; + pub const TGEIU: u8 = 0b01001; + pub const TLTI: u8 = 0b01010; + pub const TLTIU: u8 = 0b01011; + pub const TEQI: u8 = 0b01100; + pub const TNEI: u8 = 0b01110; + pub const BLTZAL: u8 = 0b10000; + pub const BGEZAL: u8 = 0b10001; + pub const BLTZALL: u8 = 0b10010; + pub const BGEZALL: u8 = 0b10011; } diff --git a/backend/src/core/interpreter.rs b/backend/src/core/interpreter.rs index af9aab8..a8d0608 100644 --- a/backend/src/core/interpreter.rs +++ b/backend/src/core/interpreter.rs @@ -5,7 +5,10 @@ use crate::{ mem::Memory, registers::Registers, }, - utils::access::is_address_error, + utils::{ + access::is_address_error, + error::{Error, Severity, Type::UnhandledInstruction}, + }, }; pub struct Interpreter { @@ -59,16 +62,21 @@ impl Cpu for Interpreter { Some(instr) } - fn execute(&mut self, mem: &Memory) -> Result { + fn step(&mut self, mem: &Memory) -> Result { if let Some(instr) = self.fetch_then_advance(mem) { - self.decode(instr)?; + self.decode_execute(instr)?; } Ok(1) } - fn decode(&mut self, instr: Instruction) -> Result<(), String> { - todo!("decode") + fn decode_execute(&mut self, instr: Instruction) -> Result<(), Error> { + match instr.opcode() { + _ => Err(Error { + severity: Severity::Error, + err_type: UnhandledInstruction(instr), + }), + } } fn reset(&mut self) { diff --git a/backend/src/utils/error.rs b/backend/src/utils/error.rs new file mode 100644 index 0000000..5fa588f --- /dev/null +++ b/backend/src/utils/error.rs @@ -0,0 +1,98 @@ +use crate::core::instruction::Instruction; +use std::fmt; + +#[derive(Debug, Clone, Copy)] +pub enum Severity { + Warning, + Error, + Fatal, +} + +impl fmt::Display for Severity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let sev = match self { + Self::Warning => "Warning", + Self::Error => "Error", + Self::Fatal => "Fatal", + }; + write!(f, "{sev}") + } +} + +#[derive(Debug, Clone, Copy)] +pub enum AccessType { + U8(Option), + U16(Option), + U32(Option), + U64(Option), +} + +impl fmt::Display for AccessType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + &Self::U8(val) => { + if let Some(val) = val { + write!(f, "write8 with value {val:02X}") + } else { + write!(f, "read8") + } + } + &Self::U16(val) => { + if let Some(val) = val { + write!(f, "write16 with value {val:04X}") + } else { + write!(f, "read16") + } + } + &Self::U32(val) => { + if let Some(val) = val { + write!(f, "write32 with value {val:08X}") + } else { + write!(f, "read32") + } + } + &Self::U64(val) => { + if let Some(val) = val { + write!(f, "write64 with value {val:08X}") + } else { + write!(f, "read64") + } + } + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Type { + UnhandledInstruction(Instruction), + UnhandledMemoryAccess(u32, AccessType), +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let err_type = match self { + Type::UnhandledInstruction(instr) => { + format!("Unhandled instruction: {:02X}", instr.opcode()) + } + Type::UnhandledMemoryAccess(addr, access) => { + format!("Unhandled addr @ {addr:08X} for {access}") + } + }; + + write!(f, "{err_type}") + } +} + +type Result = std::result::Result; + +#[derive(Debug, Clone, Copy)] +pub struct Error { + pub severity: Severity, + pub err_type: Type, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[{}]: {}", self.severity, self.err_type) + } +} diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs index 207872c..92fe523 100644 --- a/backend/src/utils/mod.rs +++ b/backend/src/utils/mod.rs @@ -1 +1,2 @@ -pub mod access; \ No newline at end of file +pub mod access; +pub mod error;