mirror of
https://github.com/FranLMSP/rultra64.git
synced 2026-01-01 07:51:34 -05:00
DADD and DADDI instructions
This commit is contained in:
290
src/cpu.rs
290
src/cpu.rs
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user