mirror of
https://github.com/FranLMSP/rultra64.git
synced 2026-01-01 07:51:34 -05:00
DIV and DDIV instructions
This commit is contained in:
70
src/cpu.rs
70
src/cpu.rs
@@ -14,6 +14,12 @@ pub fn params_rt_rs_immediate(opcode: u32) -> (usize, usize, i16) {
|
||||
(rt as usize, rs as usize, immediate)
|
||||
}
|
||||
|
||||
pub fn params_rs_rt(opcode: u32) -> (usize, usize) {
|
||||
let rs = (opcode >> 21) & 0b11111;
|
||||
let rt = (opcode >> 11) & 0b11111;
|
||||
(rt as usize, rs as usize)
|
||||
}
|
||||
|
||||
pub struct CPU {
|
||||
registers: CPURegisters,
|
||||
}
|
||||
@@ -84,6 +90,16 @@ impl CPU {
|
||||
let (rd, rs, rt) = params_rd_rs_rt(opcode);
|
||||
let _ = self.dsub(rd, rs, rt);
|
||||
},
|
||||
// DIV | DIVU
|
||||
0b000_0001_1010 | 0b000_0001_1011 => {
|
||||
let (rs, rt) = params_rs_rt(opcode);
|
||||
self.div(rs, rt);
|
||||
},
|
||||
// DDIV | DDIVU
|
||||
0b000_0001_1110 | 0b000_0001_1111 => {
|
||||
let (rs, rt) = params_rs_rt(opcode);
|
||||
self.ddiv(rs, rt);
|
||||
},
|
||||
// AND
|
||||
0b000_0010_0100 => {
|
||||
let (rd, rs, rt) = params_rd_rs_rt(opcode);
|
||||
@@ -208,6 +224,24 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn div(&mut self, rs: usize, rt: usize) {
|
||||
let s = self.registers.get_by_number(rs) as i32;
|
||||
let t = self.registers.get_by_number(rt) as i32;
|
||||
let quotient = s.wrapping_div(t);
|
||||
let remainder = s.wrapping_rem_euclid(t);
|
||||
self.registers.set_lo(quotient as i64);
|
||||
self.registers.set_hi(remainder as i64);
|
||||
}
|
||||
|
||||
pub fn ddiv(&mut self, rs: usize, rt: usize) {
|
||||
let s = self.registers.get_by_number(rs);
|
||||
let t = self.registers.get_by_number(rt);
|
||||
let quotient = s.wrapping_div(t);
|
||||
let remainder = s.wrapping_rem_euclid(t);
|
||||
self.registers.set_lo(quotient);
|
||||
self.registers.set_hi(remainder);
|
||||
}
|
||||
|
||||
pub fn and(&mut self, rd: usize, rs: usize, rt: usize) {
|
||||
let result = self.registers.get_by_number(rs) & self.registers.get_by_number(rt);
|
||||
self.registers.set_by_number(rd, result);
|
||||
@@ -384,6 +418,42 @@ mod cpu_instructions_tests {
|
||||
assert_eq!(cpu.registers.get_by_number(reg_dest), i64::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div() {
|
||||
let mut cpu = CPU::new();
|
||||
let reg_s = 15;
|
||||
let reg_t = 20;
|
||||
cpu.registers.set_by_number(reg_s, 80);
|
||||
cpu.registers.set_by_number(reg_t, 80);
|
||||
cpu.div(reg_s, reg_t);
|
||||
assert_eq!(cpu.registers.get_lo(), 1);
|
||||
assert_eq!(cpu.registers.get_hi(), 0);
|
||||
|
||||
cpu.registers.set_by_number(reg_s, 3);
|
||||
cpu.registers.set_by_number(reg_t, 2);
|
||||
cpu.div(reg_s, reg_t);
|
||||
assert_eq!(cpu.registers.get_lo(), 1);
|
||||
assert_eq!(cpu.registers.get_hi(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ddiv() {
|
||||
let mut cpu = CPU::new();
|
||||
let reg_s = 15;
|
||||
let reg_t = 20;
|
||||
cpu.registers.set_by_number(reg_s, 80);
|
||||
cpu.registers.set_by_number(reg_t, 80);
|
||||
cpu.ddiv(reg_s, reg_t);
|
||||
assert_eq!(cpu.registers.get_lo(), 1);
|
||||
assert_eq!(cpu.registers.get_hi(), 0);
|
||||
|
||||
cpu.registers.set_by_number(reg_s, 3);
|
||||
cpu.registers.set_by_number(reg_t, 2);
|
||||
cpu.ddiv(reg_s, reg_t);
|
||||
assert_eq!(cpu.registers.get_lo(), 1);
|
||||
assert_eq!(cpu.registers.get_hi(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_and() {
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
@@ -18,14 +18,18 @@ impl<T: PartialOrd + Copy> Register<T> for Generic<T> {
|
||||
}
|
||||
|
||||
pub const CPU_REGISTER_NAMES: [&'static str; 32] = [
|
||||
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2",
|
||||
"t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5",
|
||||
"s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
|
||||
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
|
||||
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
|
||||
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
|
||||
];
|
||||
|
||||
pub struct CPURegisters {
|
||||
registers: [Box<dyn Register<i64>>; 32],
|
||||
program_counter: Generic<i64>,
|
||||
hi: Generic<i64>,
|
||||
lo: Generic<i64>,
|
||||
load_link: bool,
|
||||
}
|
||||
|
||||
impl CPURegisters {
|
||||
@@ -66,6 +70,9 @@ impl CPURegisters {
|
||||
Box::new(Generic(0_i64)),
|
||||
],
|
||||
program_counter: Generic(0xBFC00000),
|
||||
hi: Generic(0_i64),
|
||||
lo: Generic(0_i64),
|
||||
load_link: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +111,22 @@ impl CPURegisters {
|
||||
pub fn increment_program_counter(&mut self, val: i64) {
|
||||
self.program_counter.set(self.program_counter.get().wrapping_add(val));
|
||||
}
|
||||
|
||||
pub fn set_hi(&mut self, val: i64) {
|
||||
self.hi.set(val);
|
||||
}
|
||||
|
||||
pub fn set_lo(&mut self, val: i64) {
|
||||
self.lo.set(val);
|
||||
}
|
||||
|
||||
pub fn get_hi(&self) -> i64 {
|
||||
self.hi.get()
|
||||
}
|
||||
|
||||
pub fn get_lo(&self) -> i64 {
|
||||
self.lo.get()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user