DADD and DADDI instructions

This commit is contained in:
2022-01-05 11:30:50 -05:00
parent 02c4334bfa
commit 4c4df9b78d

View File

@@ -1,5 +1,19 @@
use crate::registers::{CPURegisters};
pub fn params_rd_rs_rt(opcode: u32) -> (usize, usize, usize) {
let rd = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let rt = (opcode >> 16) & 0b11111;
(rd as usize, rs as usize, rt as usize)
}
pub fn params_rt_rs_immediate(opcode: u32) -> (usize, usize, i16) {
let rt = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let immediate = ((opcode & 0xFFFF) as u16) as i16;
(rt as usize, rs as usize, immediate)
}
pub struct CPU {
registers: CPURegisters,
}
@@ -16,71 +30,95 @@ impl CPU {
let bytes = opcode.to_be_bytes();
let inst = bytes[0] >> 2;
match inst {
0b000000 => {
0b0000_00 => {
match opcode & 0b111_1111_1111 {
// ADD
0b000_0010_0000 => {
let rd = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let rt = (opcode >> 16) & 0b11111;
let res = self.add(rd as usize, rs as usize, rt as usize);
let (rd, rs, rt) = params_rd_rs_rt(opcode);
let res = self.add(rd, rs, rt);
if let Err(_) = res {
todo!("Throw exception for add overflow ADD");
}
},
// DADD
0b000_0010_1100 => {
let (rd, rs, rt) = params_rd_rs_rt(opcode);
let res = self.dadd(rd, rs, rt);
if let Err(_) = res {
todo!("Throw exception for add overflow DADD");
}
},
// DADDU
0b000_0010_1101 => {
let (rd, rs, rt) = params_rd_rs_rt(opcode);
let _ = self.dadd(rd, rs, rt);
},
// ADDU
0b000_0010_0001 => {
let rd = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let rt = (opcode >> 16) & 0b11111;
let _ = self.add(rd as usize, rs as usize, rt as usize);
},
// AND
0b000_0010_0100 => {
let rd = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let rt = (opcode >> 16) & 0b11111;
self.and(rd as usize, rs as usize, rt as usize);
let (rd, rs, rt) = params_rd_rs_rt(opcode);
let _ = self.add(rd, rs, rt);
},
// SUB
0b000_0010_0010 => {
let rd = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let rt = (opcode >> 16) & 0b11111;
let res = self.sub(rd as usize, rs as usize, rt as usize);
let (rd, rs, rt) = params_rd_rs_rt(opcode);
let res = self.sub(rd, rs, rt);
if let Err(_) = res {
todo!("Throw exception for sub overflow SUB");
}
},
// SUBU
0b000_0010_0011 => {
let rd = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let rt = (opcode >> 16) & 0b11111;
let _ = self.sub(rd as usize, rs as usize, rt as usize);
let (rd, rs, rt) = params_rd_rs_rt(opcode);
let _ = self.sub(rd, rs, rt);
},
// AND
0b000_0010_0100 => {
let (rd, rs, rt) = params_rd_rs_rt(opcode);
self.and(rd, rs, rt);
},
// OR
0b000_0010_0101 => {
let (rd, rs, rt) = params_rd_rs_rt(opcode);
self.or(rd, rs, rt);
},
// NOR
0b000_0010_0111 => {
let (rd, rs, rt) = params_rd_rs_rt(opcode);
self.nor(rd, rs, rt);
},
_ => unimplemented!(),
};
},
// DADDI | DADDIU
0b0110_00 | 0b0110_01 => {
let (rt, rs, immediate) = params_rt_rs_immediate(opcode);
let res = self.daddi(rt, rs, immediate);
if inst == 0b0110_00 {
if let Err(_) = res {
todo!("Throw exception for add overflow DADDI");
}
}
},
// ADDI | ADDIU
0b001000 | 0b001001 => {
let rt = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let immediate = (opcode & 0xFFFF) as i16;
let res = self.addi(rt as usize, rs as usize, immediate);
if inst == 0b001000 {
0b0010_00 | 0b0010_01 => {
let (rt, rs, immediate) = params_rt_rs_immediate(opcode);
let res = self.addi(rt, rs, immediate);
if inst == 0b0010_00 {
if let Err(_) = res {
todo!("Throw exception for add overflow ADDI");
}
}
},
// ANDI
0b001100 => {
let rt = (opcode >> 11) & 0b11111;
let rs = (opcode >> 21) & 0b11111;
let immediate = ((opcode & 0xFFFF) as u16) as i16;
self.andi(rt as usize, rs as usize, immediate);
},
// ANDI
0b0011_00 => {
let (rt, rs, immediate) = params_rt_rs_immediate(opcode);
self.andi(rt, rs, immediate);
},
// ORI
0b0011_01 => {
let (rt, rs, immediate) = params_rt_rs_immediate(opcode);
self.ori(rt, rs, immediate);
},
_ => unimplemented!(),
}
}
@@ -109,6 +147,30 @@ impl CPU {
}
}
pub fn dadd(&mut self, rd: usize, rs: usize, rt: usize) -> Result<i64, i64> {
let s = self.registers.get_by_number(rs);
let t = self.registers.get_by_number(rt);
let result = s.wrapping_add(t);
let will_overflow = s.checked_add(t);
self.registers.set_by_number(rd, result);
match will_overflow {
Some(_) => Ok(result),
None => Err(result),
}
}
pub fn daddi(&mut self, rt: usize, rs: usize, immediate: i16) -> Result<i64, i64> {
let s = self.registers.get_by_number(rs);
let immediate = immediate as i64;
let result = s.wrapping_add(immediate);
let will_overflow = s.checked_add(immediate);
self.registers.set_by_number(rt, result);
match will_overflow {
Some(_) => Ok(result),
None => Err(result),
}
}
pub fn sub(&mut self, rd: usize, rs: usize, rt: usize) -> Result<i64, i64> {
let s = self.registers.get_by_number(rs) as i32;
let t = self.registers.get_by_number(rt) as i32;
@@ -122,9 +184,7 @@ impl CPU {
}
pub fn and(&mut self, rd: usize, rs: usize, rt: usize) {
let s = self.registers.get_by_number(rs);
let t = self.registers.get_by_number(rt);
let result = s & t;
let result = self.registers.get_by_number(rs) & self.registers.get_by_number(rt);
self.registers.set_by_number(rd, result);
}
@@ -134,6 +194,35 @@ impl CPU {
let result = s & immediate;
self.registers.set_by_number(rt, result);
}
pub fn or(&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);
}
pub fn ori(&mut self, rt: usize, rs: usize, immediate: i16) {
let s = self.registers.get_by_number(rs);
let immediate = immediate as i64;
let result = s | immediate;
self.registers.set_by_number(rt, result);
}
pub fn xor(&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);
}
pub fn xori(&mut self, rt: usize, rs: usize, immediate: i16) {
let s = self.registers.get_by_number(rs);
let immediate = immediate as i64;
let result = s ^ immediate;
self.registers.set_by_number(rt, result);
}
pub fn nor(&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);
}
}
#[cfg(test)]
@@ -182,6 +271,48 @@ mod cpu_instructions_tests {
assert_eq!(cpu.registers.get_by_number(reg_dest) as i32, i32::MIN);
}
#[test]
fn test_dadd() {
let mut cpu = CPU::new();
let reg_dest = 10;
let reg_s = 15;
let reg_t = 20;
cpu.registers.set_by_number(reg_s, 80);
cpu.registers.set_by_number(reg_t, 80);
let _ = cpu.dadd(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), 160);
cpu.registers.set_by_number(reg_s, 40);
cpu.registers.set_by_number(reg_t, -80);
let _ = cpu.dadd(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), -40);
cpu.registers.set_by_number(reg_s, i64::MAX);
cpu.registers.set_by_number(reg_t, 1);
let res = cpu.dadd(reg_dest, reg_s, reg_t);
assert!(res.is_err());
assert_eq!(cpu.registers.get_by_number(reg_dest), i64::MIN);
}
#[test]
fn test_daddi() {
let mut cpu = CPU::new();
let reg_dest = 10;
let reg_s = 15;
cpu.registers.set_by_number(reg_s, 80);
let _ = cpu.daddi(reg_dest, reg_s, 80);
assert_eq!(cpu.registers.get_by_number(reg_dest), 160);
cpu.registers.set_by_number(reg_s, 80);
let _ = cpu.daddi(reg_dest, reg_s, -40);
assert_eq!(cpu.registers.get_by_number(reg_dest), 40);
cpu.registers.set_by_number(reg_s, i64::MAX);
let res = cpu.daddi(reg_dest, reg_s, 1);
assert!(res.is_err());
assert_eq!(cpu.registers.get_by_number(reg_dest), i64::MIN);
}
#[test]
fn test_sub() {
let mut cpu = CPU::new();
@@ -235,4 +366,83 @@ mod cpu_instructions_tests {
cpu.andi(reg_dest, reg_s, 321);
assert_eq!(cpu.registers.get_by_number(reg_dest), 65);
}
#[test]
fn test_or() {
let mut cpu = CPU::new();
let reg_dest = 10;
let reg_s = 15;
let reg_t = 20;
cpu.registers.set_by_number(reg_s, 123);
cpu.registers.set_by_number(reg_t, 123);
cpu.or(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), 123);
cpu.registers.set_by_number(reg_s, 123);
cpu.registers.set_by_number(reg_t, 321);
cpu.or(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), 379);
}
#[test]
fn test_ori() {
let mut cpu = CPU::new();
let reg_dest = 10;
let reg_s = 15;
cpu.registers.set_by_number(reg_s, 80);
cpu.ori(reg_dest, reg_s, 80);
assert_eq!(cpu.registers.get_by_number(reg_dest), 80);
cpu.registers.set_by_number(reg_s, 123);
cpu.ori(reg_dest, reg_s, 321);
assert_eq!(cpu.registers.get_by_number(reg_dest), 379);
}
#[test]
fn test_xor() {
let mut cpu = CPU::new();
let reg_dest = 10;
let reg_s = 15;
let reg_t = 20;
cpu.registers.set_by_number(reg_s, 123);
cpu.registers.set_by_number(reg_t, 123);
cpu.xor(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), 0);
cpu.registers.set_by_number(reg_s, 123);
cpu.registers.set_by_number(reg_t, 321);
cpu.xor(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), 314);
}
#[test]
fn test_xori() {
let mut cpu = CPU::new();
let reg_dest = 10;
let reg_s = 15;
cpu.registers.set_by_number(reg_s, 80);
cpu.xori(reg_dest, reg_s, 80);
assert_eq!(cpu.registers.get_by_number(reg_dest), 0);
cpu.registers.set_by_number(reg_s, 123);
cpu.xori(reg_dest, reg_s, 321);
assert_eq!(cpu.registers.get_by_number(reg_dest), 314);
}
#[test]
fn test_nor() {
let mut cpu = CPU::new();
let reg_dest = 10;
let reg_s = 15;
let reg_t = 20;
cpu.registers.set_by_number(reg_s, 123);
cpu.registers.set_by_number(reg_t, 123);
cpu.nor(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), -124);
cpu.registers.set_by_number(reg_s, 123);
cpu.registers.set_by_number(reg_t, 321);
cpu.nor(reg_dest, reg_s, reg_t);
assert_eq!(cpu.registers.get_by_number(reg_dest), -380);
}
}