DIV and DDIV instructions

This commit is contained in:
2022-01-05 14:12:10 -05:00
parent 78c0438c7d
commit 4f49d768e1
2 changed files with 96 additions and 3 deletions

View File

@@ -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();

View File

@@ -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)]