From dd38da6dead1b6c71f51ad16e0ba953e984bc22b Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 19 Aug 2026 15:52:22 +0200 Subject: [PATCH] even more instructions --- backend/src/core/cpu.rs | 2 +- backend/src/core/interpreter.rs | 2 +- backend/src/core/interpreter/decode.rs | 16 +- backend/src/core/interpreter/instructions.rs | 182 ++++++++++++++++++- backend/src/core/registers.rs | 7 +- utils/src/error.rs | 16 +- 6 files changed, 192 insertions(+), 33 deletions(-) diff --git a/backend/src/core/cpu.rs b/backend/src/core/cpu.rs index f8021fe..aea7e29 100644 --- a/backend/src/core/cpu.rs +++ b/backend/src/core/cpu.rs @@ -18,7 +18,7 @@ pub trait Cpu { fn fetch_then_advance(&mut self, _: &Memory) -> Option { None } - fn step(&mut self, mem: &Memory) -> Result; + fn step(&mut self, mem: &Memory) -> Result>; fn advance(&mut self) -> bool { false } diff --git a/backend/src/core/interpreter.rs b/backend/src/core/interpreter.rs index 536cc31..9d0de6d 100644 --- a/backend/src/core/interpreter.rs +++ b/backend/src/core/interpreter.rs @@ -65,7 +65,7 @@ impl Cpu for Interpreter { Some(instr) } - fn step(&mut self, mem: &Memory) -> Result { + fn step(&mut self, mem: &Memory) -> Result> { if let Some(instr) = self.fetch_then_advance(mem) { self.decode_execute(instr)?; } diff --git a/backend/src/core/interpreter/decode.rs b/backend/src/core/interpreter/decode.rs index 88990d3..61ebf7d 100644 --- a/backend/src/core/interpreter/decode.rs +++ b/backend/src/core/interpreter/decode.rs @@ -6,30 +6,24 @@ use utils::{ use crate::core::interpreter::Interpreter; impl Interpreter { - pub fn decode_special(&mut self, instr: Instruction) -> Result<(), Error> { + pub fn decode_special(&mut self, instr: Instruction) -> Result<(), Error<'_>> { match instr.special() { - Instruction::SLL => { - if instr.0 == 0 { - Ok(()) // nop - } else { - Ok(self.sll(instr)) - } - } + Instruction::SLL => Ok(self.sll(instr)), Instruction::ADD => Ok(self.add(instr)), Instruction::ADDU => Ok(self.addu(instr)), _ => Err(Error { severity: Severity::Fatal, - err_type: UnhandledInstruction(instr), + err_type: UnhandledInstruction("CPU::SpecialFunction", instr), }), } } - pub fn decode_execute(&mut self, instr: Instruction) -> Result<(), Error> { + pub fn decode_execute(&mut self, instr: Instruction) -> Result<(), Error<'_>> { match instr.opcode() { Instruction::SPECIAL => self.decode_special(instr), _ => Err(Error { severity: Severity::Error, - err_type: UnhandledInstruction(instr), + err_type: UnhandledInstruction("CPU::Opcode", instr), }), } } diff --git a/backend/src/core/interpreter/instructions.rs b/backend/src/core/interpreter/instructions.rs index df4659e..d4f0a23 100644 --- a/backend/src/core/interpreter/instructions.rs +++ b/backend/src/core/interpreter/instructions.rs @@ -10,8 +10,8 @@ use crate::core::interpreter::Interpreter; impl Interpreter { pub fn add(&mut self, instr: Instruction) { - let rs = self.regs.read::(instr.rs()) as u32; - let rt = self.regs.read::(instr.rt()) as u32; + let rs = self.regs.read(instr.rs()) as u32; + let rt = self.regs.read(instr.rt()) as u32; let (rd, overflow) = rs.overflowing_add(rt); if overflow { todo!("add overflow!") @@ -21,14 +21,182 @@ impl Interpreter { } pub fn addu(&mut self, instr: Instruction) { - let rs = self.regs.read::(instr.rs()) as i32; - let rt = self.regs.read::(instr.rt()) as i32; - let rd = rs + rt; - self.regs.write(instr.rd(), rd); + let rs = self.regs.read(instr.rs()) as i32; + let rt = self.regs.read(instr.rt()) as i32; + self.regs.write(instr.rd(), rs + rt); + } + + pub fn addi(&mut self, instr: Instruction) { + let rs = self.regs.read(instr.rs()) as u32; + let imm = instr.imm() as i16 as i32 as u32; + let (rt, overflow) = rs.overflowing_add(imm); + if overflow { + todo!("addi overflow!") + } + + self.regs.write(instr.rt(), rt as i32); + } + + pub fn addiu(&mut self, instr: Instruction) { + let rs = self.regs.read(instr.rs()) as i32; + let imm = instr.imm() as i16 as i32; + self.regs.write(instr.rt(), rs + imm); + } + + pub fn dadd(&mut self, instr: Instruction) { + let rs = self.regs.read(instr.rs()) as u64; + let rt = self.regs.read(instr.rt()) as u64; + let (rd, overflow) = rs.overflowing_add(rt); + if overflow { + todo!("dadd overflow!") + } + + self.regs.write(instr.rd(), rd as i64); + } + + pub fn daddu(&mut self, instr: Instruction) { + let rs = self.regs.read(instr.rs()) as i64; + let rt = self.regs.read(instr.rt()) as i64; + self.regs.write(instr.rd(), rs + rt); + } + + pub fn daddi(&mut self, instr: Instruction) { + let rs = self.regs.read(instr.rs()) as u64; + let imm = instr.imm() as i16 as i64 as u64; + let (rt, overflow) = rs.overflowing_add(imm); + if overflow { + todo!("addi overflow!") + } + + self.regs.write(instr.rt(), rt as i64); + } + + pub fn daddiu(&mut self, instr: Instruction) { + let rs = self.regs.read(instr.rs()); + let imm = instr.imm() as i16 as i64; + self.regs.write(instr.rt(), rs + imm); + } + + fn div(&mut self, instr: Instruction) { + let dividend = self.regs.read(instr.rs()) as i32 as i64; + let divisor = self.regs.read(instr.rt()) as i32 as i64; + if divisor == 0 { + self.regs.lo = if dividend >= 0 { -1i64 } else { 1i64 }; + self.regs.hi = dividend + } else { + let quotient = (dividend / divisor) as i32; + let remainder = (dividend % divisor) as i32; + self.regs.lo = quotient as i64; + self.regs.hi = remainder as i64 + } + } + + fn divu(&mut self, instr: Instruction) { + let dividend = self.regs.read(instr.rs()) as u32; + let divisor = self.regs.read(instr.rt()) as u32; + if divisor == 0 { + self.regs.lo = -1; + self.regs.hi = dividend as i32 as i64 + } else { + let quotient = (dividend / divisor) as i32; + let remainder = (dividend % divisor) as i32; + self.regs.lo = quotient as i64; + self.regs.hi = remainder as i64 + } + } + + fn ddiv(&mut self, instr: Instruction) { + let dividend = self.regs.read(instr.rs()); + let divisor = self.regs.read(instr.rt()); + + match (dividend, divisor) { + (-9223372036854775808i64, -1i64) => { + self.regs.lo = dividend; + self.regs.hi = 0 + } + (_, 0) => { + self.regs.hi = dividend; + self.regs.lo = if dividend >= 0 { -1i64 } else { 1i64 }; + } + _ => { + let quotient = dividend / divisor; + let remainder = dividend % divisor; + self.regs.lo = quotient; + self.regs.hi = remainder + } + } + } + + fn ddivu(&mut self, instr: Instruction) { + let dividend = self.regs.read(instr.rs()) as u64; + let divisor = self.regs.read(instr.rt()) as u64; + if divisor == 0 { + self.regs.lo = -1; + self.regs.hi = dividend as i64 + } else { + let quotient = dividend / divisor; + let remainder = dividend % divisor; + self.regs.lo = quotient as i64; + self.regs.hi = remainder as i64 + } + } + + fn branch(&mut self, cond: bool, addr: i64) { + self.delay_slot = true; + self.regs.next_pc = if cond { addr } else { self.regs.next_pc } + } + + fn branch_likely(&mut self, cond: bool, addr: i64) { + if !cond { + self.regs.set_pc(self.regs.next_pc); + return; + } + + self.delay_slot = true; + self.regs.next_pc = addr; + } + + pub fn b(&mut self, instr: Instruction, cond: bool) { + let imm = instr.imm() as i16; + let offset = (imm as i64) << 2; + let address = self.regs.curr_pc + offset; + self.branch(cond, address); + } + + pub fn blink(&mut self, instr: Instruction, cond: bool) { + self.regs.write(31, self.regs.next_pc); + let imm = instr.imm() as i16; + let offset = (imm as i64) << 2; + let address = self.regs.curr_pc + offset; + self.branch(cond, address); + } + + pub fn bl(&mut self, instr: Instruction, cond: bool) { + let imm = instr.imm() as i16; + let offset = (imm as i64) << 2; + let address = self.regs.curr_pc + offset; + self.branch_likely(cond, address); + } + + pub fn bllink(&mut self, instr: Instruction, cond: bool) { + self.regs.write(31, self.regs.next_pc); + let imm = instr.imm() as i16; + let offset = (imm as i64) << 2; + let address = self.regs.curr_pc + offset; + self.branch_likely(cond, address); + } + + pub fn lui(&mut self, instr: Instruction) { + let imm = (instr.imm() as i16 as i64) << 16; + self.regs.write(instr.rt(), imm); } pub fn sll(&mut self, instr: Instruction) { - let rd = self.regs.read::(instr.rt()) << instr.sa(); + if instr.0 == 0 { + return; + } + + let rd = self.regs.read(instr.rt()) << instr.sa(); self.regs.write(instr.rd(), rd); } } diff --git a/backend/src/core/registers.rs b/backend/src/core/registers.rs index 0771cda..7f0bca9 100644 --- a/backend/src/core/registers.rs +++ b/backend/src/core/registers.rs @@ -30,11 +30,8 @@ impl Registers { self.next_pc = self.curr_pc + 4; } - pub fn read(&self, idx: usize) -> T - where - T: From, - { - self.gpr[idx].into() + pub fn read(&self, idx: usize) -> i64 { + self.gpr[idx] } pub fn write(&mut self, idx: usize, value: T) diff --git a/utils/src/error.rs b/utils/src/error.rs index c371506..082b23e 100644 --- a/utils/src/error.rs +++ b/utils/src/error.rs @@ -63,16 +63,16 @@ impl fmt::Display for AccessType { } #[derive(Debug, Clone, Copy)] -pub enum Type { - UnhandledInstruction(Instruction), +pub enum Type<'a> { + UnhandledInstruction(&'a str, Instruction), UnhandledMemoryAccess(u32, AccessType), } -impl fmt::Display for Type { +impl<'a> fmt::Display for Type<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let err_type = match self { - Type::UnhandledInstruction(instr) => { - format!("Unhandled instruction: {:02X}", instr.opcode()) + Type::UnhandledInstruction(which_type, instr) => { + format!("Unhandled instruction: {which_type} {:02X}", instr.opcode()) } Type::UnhandledMemoryAccess(addr, access) => { format!("Unhandled addr @ {addr:08X} for {access}") @@ -84,12 +84,12 @@ impl fmt::Display for Type { } #[derive(Debug, Clone, Copy)] -pub struct Error { +pub struct Error<'a> { pub severity: Severity, - pub err_type: Type, + pub err_type: Type<'a>, } -impl fmt::Display for Error { +impl<'a> fmt::Display for Error<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}]: {}", self.severity, self.err_type) }