even more instructions

This commit is contained in:
2026-08-19 15:52:22 +02:00
parent 22752d1f2b
commit dd38da6dea
6 changed files with 192 additions and 33 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ pub trait Cpu {
fn fetch_then_advance(&mut self, _: &Memory) -> Option<Instruction> { fn fetch_then_advance(&mut self, _: &Memory) -> Option<Instruction> {
None None
} }
fn step(&mut self, mem: &Memory) -> Result<u32, Error>; fn step(&mut self, mem: &Memory) -> Result<u32, Error<'_>>;
fn advance(&mut self) -> bool { fn advance(&mut self) -> bool {
false false
} }
+1 -1
View File
@@ -65,7 +65,7 @@ impl Cpu for Interpreter {
Some(instr) Some(instr)
} }
fn step(&mut self, mem: &Memory) -> Result<u32, Error> { fn step(&mut self, mem: &Memory) -> Result<u32, Error<'_>> {
if let Some(instr) = self.fetch_then_advance(mem) { if let Some(instr) = self.fetch_then_advance(mem) {
self.decode_execute(instr)?; self.decode_execute(instr)?;
} }
+5 -11
View File
@@ -6,30 +6,24 @@ use utils::{
use crate::core::interpreter::Interpreter; use crate::core::interpreter::Interpreter;
impl 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() { match instr.special() {
Instruction::SLL => { Instruction::SLL => Ok(self.sll(instr)),
if instr.0 == 0 {
Ok(()) // nop
} else {
Ok(self.sll(instr))
}
}
Instruction::ADD => Ok(self.add(instr)), Instruction::ADD => Ok(self.add(instr)),
Instruction::ADDU => Ok(self.addu(instr)), Instruction::ADDU => Ok(self.addu(instr)),
_ => Err(Error { _ => Err(Error {
severity: Severity::Fatal, 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() { match instr.opcode() {
Instruction::SPECIAL => self.decode_special(instr), Instruction::SPECIAL => self.decode_special(instr),
_ => Err(Error { _ => Err(Error {
severity: Severity::Error, severity: Severity::Error,
err_type: UnhandledInstruction(instr), err_type: UnhandledInstruction("CPU::Opcode", instr),
}), }),
} }
} }
+175 -7
View File
@@ -10,8 +10,8 @@ use crate::core::interpreter::Interpreter;
impl Interpreter { impl Interpreter {
pub fn add(&mut self, instr: Instruction) { pub fn add(&mut self, instr: Instruction) {
let rs = self.regs.read::<i64>(instr.rs()) as u32; let rs = self.regs.read(instr.rs()) as u32;
let rt = self.regs.read::<i64>(instr.rt()) as u32; let rt = self.regs.read(instr.rt()) as u32;
let (rd, overflow) = rs.overflowing_add(rt); let (rd, overflow) = rs.overflowing_add(rt);
if overflow { if overflow {
todo!("add overflow!") todo!("add overflow!")
@@ -21,14 +21,182 @@ impl Interpreter {
} }
pub fn addu(&mut self, instr: Instruction) { pub fn addu(&mut self, instr: Instruction) {
let rs = self.regs.read::<i64>(instr.rs()) as i32; let rs = self.regs.read(instr.rs()) as i32;
let rt = self.regs.read::<i64>(instr.rt()) as i32; let rt = self.regs.read(instr.rt()) as i32;
let rd = rs + rt; self.regs.write(instr.rd(), rs + rt);
self.regs.write(instr.rd(), rd); }
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) { pub fn sll(&mut self, instr: Instruction) {
let rd = self.regs.read::<i64>(instr.rt()) << instr.sa(); if instr.0 == 0 {
return;
}
let rd = self.regs.read(instr.rt()) << instr.sa();
self.regs.write(instr.rd(), rd); self.regs.write(instr.rd(), rd);
} }
} }
+2 -5
View File
@@ -30,11 +30,8 @@ impl Registers {
self.next_pc = self.curr_pc + 4; self.next_pc = self.curr_pc + 4;
} }
pub fn read<T>(&self, idx: usize) -> T pub fn read(&self, idx: usize) -> i64 {
where self.gpr[idx]
T: From<i64>,
{
self.gpr[idx].into()
} }
pub fn write<T>(&mut self, idx: usize, value: T) pub fn write<T>(&mut self, idx: usize, value: T)
+8 -8
View File
@@ -63,16 +63,16 @@ impl fmt::Display for AccessType {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Type { pub enum Type<'a> {
UnhandledInstruction(Instruction), UnhandledInstruction(&'a str, Instruction),
UnhandledMemoryAccess(u32, AccessType), UnhandledMemoryAccess(u32, AccessType),
} }
impl fmt::Display for Type { impl<'a> fmt::Display for Type<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let err_type = match self { let err_type = match self {
Type::UnhandledInstruction(instr) => { Type::UnhandledInstruction(which_type, instr) => {
format!("Unhandled instruction: {:02X}", instr.opcode()) format!("Unhandled instruction: {which_type} {:02X}", instr.opcode())
} }
Type::UnhandledMemoryAccess(addr, access) => { Type::UnhandledMemoryAccess(addr, access) => {
format!("Unhandled addr @ {addr:08X} for {access}") format!("Unhandled addr @ {addr:08X} for {access}")
@@ -84,12 +84,12 @@ impl fmt::Display for Type {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Error { pub struct Error<'a> {
pub severity: Severity, 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 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]: {}", self.severity, self.err_type) write!(f, "[{}]: {}", self.severity, self.err_type)
} }