Skip to content

Commit

Permalink
feat: Add branch instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
howjmay committed Feb 20, 2024
1 parent a4ba1c4 commit a0792bf
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 24 deletions.
43 changes: 37 additions & 6 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,43 @@ pub fn exec_jalr(cpu: &mut CPU, instr: u32) {
// ignore the last 1 bit with 0xfffffffe
cpu.pc = (cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32 & 0xfffffffe;
}
pub fn exec_beq(cpu: &mut CPU, instr: u32) {}
pub fn exec_bne(cpu: &mut CPU, instr: u32) {}
pub fn exec_blt(cpu: &mut CPU, instr: u32) {}
pub fn exec_bge(cpu: &mut CPU, instr: u32) {}
pub fn exec_bltu(cpu: &mut CPU, instr: u32) {}
pub fn exec_bgeu(cpu: &mut CPU, instr: u32) {}
pub fn exec_beq(cpu: &mut CPU, instr: u32) {
let imm = imm_b(instr) as i32;
if cpu.xregs.regs[rs1(instr) as usize] == cpu.xregs.regs[rs2(instr) as usize] {
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
}
}
pub fn exec_bne(cpu: &mut CPU, instr: u32) {
let imm = imm_b(instr) as i32;
if cpu.xregs.regs[rs1(instr) as usize] != cpu.xregs.regs[rs2(instr) as usize] {
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
}
}
pub fn exec_blt(cpu: &mut CPU, instr: u32) {
let imm = imm_b(instr) as i32;
if (cpu.xregs.regs[rs1(instr) as usize] as i32) < (cpu.xregs.regs[rs2(instr) as usize] as i32) {
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
}
}
pub fn exec_bge(cpu: &mut CPU, instr: u32) {
let imm = imm_b(instr) as i32;
if (cpu.xregs.regs[rs1(instr) as usize] as i32) >= (cpu.xregs.regs[rs2(instr) as usize] as i32)
{
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
}
}
pub fn exec_bltu(cpu: &mut CPU, instr: u32) {
let imm = imm_b(instr) as i32;
if cpu.xregs.regs[rs1(instr) as usize] < cpu.xregs.regs[rs2(instr) as usize] {
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
}
}
pub fn exec_bgeu(cpu: &mut CPU, instr: u32) {
let imm = imm_b(instr) as i32;
if cpu.xregs.regs[rs1(instr) as usize] >= rs2(instr) {
cpu.pc = cpu.pc.wrapping_add(imm as u32).wrapping_sub(4);
}
}
pub fn exec_lb(cpu: &mut CPU, instr: u32) {}
pub fn exec_lh(cpu: &mut CPU, instr: u32) {}
pub fn exec_lw(cpu: &mut CPU, instr: u32) {}
Expand Down
142 changes: 134 additions & 8 deletions tests/cpu_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,143 @@ mod tests {
assert_eq!(cpu_test.pc, (3 + 12) & 0xfffffffe);
}
#[test]
fn test_exec_beq() {}
fn test_exec_beq() {
// TODO add test case for imm is a negative number
let mut cpu_test = cpu::CPU::new();

cpu_test.pc = 500;
let ori_pc = cpu_test.pc;
// set x7=3
helper::set_register_val(&mut cpu_test, 7, 3);
// set x8=3
helper::set_register_val(&mut cpu_test, 8, 3);
// beq x8, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 8, BEQ as u8);
cpu::exec_beq(&mut cpu_test, instr);
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);

// set x9=4
helper::set_register_val(&mut cpu_test, 9, 4);
// beq x9, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 9, BEQ as u8);
cpu::exec_beq(&mut cpu_test, instr);
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);
}
#[test]
fn test_exec_bne() {}
fn test_exec_bne() {
// TODO add test case for imm is a negative number
let mut cpu_test = cpu::CPU::new();

cpu_test.pc = 500;
let ori_pc = cpu_test.pc;
// set x7=3
helper::set_register_val(&mut cpu_test, 7, 3);
// set x8=3
helper::set_register_val(&mut cpu_test, 8, 3);
// bne x8, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 8, BNE as u8);
cpu::exec_bne(&mut cpu_test, instr);
assert_eq!(cpu_test.pc, ori_pc);

// set x9=4
helper::set_register_val(&mut cpu_test, 9, 4);
// bne x9, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 9, BNE as u8);
cpu::exec_bne(&mut cpu_test, instr);
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);
}
#[test]
fn test_exec_blt() {}
fn test_exec_blt() {
// TODO add test case for imm is a negative number
let mut cpu_test = cpu::CPU::new();

cpu_test.pc = 500;
let ori_pc = cpu_test.pc;
// set x7=3
helper::set_register_val(&mut cpu_test, 7, 2);
// set x8=3
helper::set_register_val(&mut cpu_test, 8, 3);
// blt x8, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 8, BLT as u8);
cpu::exec_blt(&mut cpu_test, instr);
assert_eq!(cpu_test.pc, ori_pc);

// set x9=4
helper::set_register_val(&mut cpu_test, 9, 1);
// blt x9, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 9, BLT as u8);
cpu::exec_blt(&mut cpu_test, instr);
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);
}
#[test]
fn test_exec_bge() {}
fn test_exec_bge() {
// TODO add test case for imm is a negative number
let mut cpu_test = cpu::CPU::new();

cpu_test.pc = 500;
let ori_pc = cpu_test.pc;
// set x7=3
helper::set_register_val(&mut cpu_test, 7, 4);
// set x8=3
helper::set_register_val(&mut cpu_test, 8, 3);
// bge x8, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 8, BGE as u8);
cpu::exec_bge(&mut cpu_test, instr);
assert_eq!(cpu_test.pc, ori_pc);

// set x9=4
helper::set_register_val(&mut cpu_test, 9, 5);
// bge x9, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 9, BGE as u8);
cpu::exec_bge(&mut cpu_test, instr);
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);
}
#[test]
fn test_exec_bltu() {}
fn test_exec_bltu() {
// TODO add test case for imm is a negative number
let mut cpu_test = cpu::CPU::new();

cpu_test.pc = 500;
let ori_pc = cpu_test.pc;
// set x7=3
helper::set_register_val(&mut cpu_test, 7, -2);
// set x8=3
helper::set_register_val(&mut cpu_test, 8, -1);
// bltu x8, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 8, BLTU as u8);
cpu::exec_bltu(&mut cpu_test, instr);
assert_eq!(cpu_test.pc, ori_pc);

// set x9=4
helper::set_register_val(&mut cpu_test, 9, 3);
// bltu x9, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 9, BLTU as u8);
cpu::exec_bltu(&mut cpu_test, instr);
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);
}
#[test]
fn test_exec_bgeu() {}
fn test_exec_bgeu() {
// TODO add test case for imm is a negative number
let mut cpu_test = cpu::CPU::new();

cpu_test.pc = 500;
let ori_pc = cpu_test.pc;
// set x7=3
helper::set_register_val(&mut cpu_test, 7, -1);
// set x8=3
helper::set_register_val(&mut cpu_test, 8, 3);
// bgeu x8, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 8, BGEU as u8);
cpu::exec_bgeu(&mut cpu_test, instr);
assert_eq!(cpu_test.pc, ori_pc);

// set x9=4
helper::set_register_val(&mut cpu_test, 9, -2);
// bgeu x9, x7, 12
let instr: u32 = helper::set_b_type_instruction(12, 7, 9, BGEU as u8);
cpu::exec_bgeu(&mut cpu_test, instr);
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);
}
#[test]
fn test_exec_lb() {}
#[test]
Expand Down Expand Up @@ -214,7 +340,7 @@ mod tests {
// set x6=4
helper::set_register_val(&mut cpu_test, 6, 4);
// add x31, x5, x6
let instr: u32 = helper::set_r_type_instruction(ADD as u8, 5, 6, 31);
let instr: u32 = helper::set_r_type_instruction(5, 6, ADD as u8, 31);
cpu::exec_add(&mut cpu_test, instr);
assert_eq!(cpu_test.xregs.regs[31], 2);
}
Expand All @@ -227,7 +353,7 @@ mod tests {
// set x6=4
helper::set_register_val(&mut cpu_test, 6, 4);
// sub x31, x5, x6
let instr: u32 = helper::set_r_type_instruction(SUB as u8, 6, 5, 31);
let instr: u32 = helper::set_r_type_instruction(6, 5, SUB as u8, 31);
cpu::exec_sub(&mut cpu_test, instr);
assert_eq!(cpu_test.xregs.regs[31], 0xfffffffa); // 0xfffffffa is -6
}
Expand Down
36 changes: 26 additions & 10 deletions tests/helper.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
use emurv::{
cpu,
opcode::{I_TYPE, R_TYPE},
opcode::{B_TYPE, I_TYPE, R_TYPE},
};

pub fn set_r_type_instruction(rs2: u8, rs1: u8, funct3: u8, rd: u8) -> u32 {
// |31-20|19-15|14-12|11-7|6-0|
return ((rs2 as u32 & 0x1f) << 20)
| ((rs1 as u32 & 0x1f) << 15)
| (funct3 as u32 & 0x3)
| ((rd as u32 & 0x1f) << 7)
| ((R_TYPE as u32) & 0x7f);
}

pub fn set_i_type_instruction(imm: i16, rs1: u8, funct3: u8, rd: u8) -> u32 {
// |31-20|19-15|14-12|11-7|6-0|
return ((imm as u32 & 0xfff) << 20)
Expand All @@ -12,8 +21,20 @@ pub fn set_i_type_instruction(imm: i16, rs1: u8, funct3: u8, rd: u8) -> u32 {
| ((I_TYPE as u32) & 0x7f);
}

pub fn set_u_type_instruction(imm: i32, rd: u8, opcode: u8) -> u32 {
return (imm as u32 & 0xfffff000) as u32 | ((rd as u32 & 0x1f) << 7) | ((opcode as u32) & 0x7f);
pub fn set_b_type_instruction(imm: i16, rs2: u8, rs1: u8, funct3: u8) -> u32 {
let imm12 = (imm & 0x800) as u32;
let imm11 = (imm & 0x1) as u32;
let imm10_5 = (imm & 0x3f0) as u32;
let imm4_1 = (imm & 0x1e) as u32;

return (imm12 << 19)
| (imm10_5 << 20)
| ((rs2 as u32 & 0x1f) << 20)
| ((rs1 as u32 & 0x1f) << 15)
| ((funct3 as u32 & 0x7) << 12)
| (imm4_1 << 7)
| (imm11 >> 4)
| ((B_TYPE as u32) & 0x7f);
}

pub fn set_j_type_instruction(imm: i32, rd: u8, opcode: u8) -> u32 {
Expand All @@ -26,13 +47,8 @@ pub fn set_j_type_instruction(imm: i32, rd: u8, opcode: u8) -> u32 {
return (instr_imm) as u32 | ((rd as u32 & 0x1f) << 7) | ((opcode as u32) & 0x7f);
}

pub fn set_r_type_instruction(funct7: u8, rs2: u8, rs1: u8, rd: u8) -> u32 {
// |31-20|19-15|14-12|11-7|6-0|
return ((funct7 as u32 & 0x7f) << 25)
| ((rs2 as u32 & 0x1f) << 20)
| ((rs1 as u32 & 0x1f) << 15)
| ((rd as u32 & 0x1f) << 7)
| ((R_TYPE as u32) & 0x7f);
pub fn set_u_type_instruction(imm: i32, rd: u8, opcode: u8) -> u32 {
return (imm as u32 & 0xfffff000) as u32 | ((rd as u32 & 0x1f) << 7) | ((opcode as u32) & 0x7f);
}

pub fn set_register_val(cpu: &mut cpu::CPU, rd: u8, val: i16) {
Expand Down

0 comments on commit a0792bf

Please sign in to comment.