Skip to content

Commit

Permalink
feat: Add LB, LH, LW
Browse files Browse the repository at this point in the history
  • Loading branch information
howjmay committed Feb 21, 2024
1 parent a0792bf commit be76276
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 62 deletions.
55 changes: 43 additions & 12 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::memory;
use crate::opcode::*;
use crate::registers;

#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub struct CPU {
// integer registers
pub xregs: registers::XREGS,
Expand Down Expand Up @@ -54,7 +54,6 @@ impl CPU {
LB => exec_lb(self, instr),
LH => exec_lh(self, instr),
LW => exec_lw(self, instr),
LD => exec_ld(self, instr),
LBU => exec_lbu(self, instr),
LHU => exec_lhu(self, instr),
LWU => exec_lwu(self, instr),
Expand All @@ -64,7 +63,6 @@ impl CPU {
SB => exec_sb(self, instr),
SH => exec_sh(self, instr),
SW => exec_sw(self, instr),
SD => exec_sd(self, instr),
_ => panic!(),
},
I_TYPE => match funct3 {
Expand Down Expand Up @@ -115,7 +113,7 @@ impl CPU {
// see page 64 at https://riscv.org/wp-content/uploads/2016/06/riscv-spec-v2.1.pdf
pub fn exec_lui(cpu: &mut CPU, instr: u32) {
let imm = (imm_u(instr) as i32) as u32;
cpu.xregs.regs[rd(instr) as usize] = imm;
cpu.xregs.regs[rd(instr) as usize] = imm | (cpu.xregs.regs[rd(instr) as usize] & 0xfff);
}
pub fn exec_auipc(cpu: &mut CPU, instr: u32) {
let imm = imm_u(instr) as i32;
Expand Down Expand Up @@ -169,17 +167,50 @@ pub fn exec_bgeu(cpu: &mut CPU, instr: u32) {
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) {}
pub fn exec_ld(cpu: &mut CPU, instr: u32) {}
pub fn exec_lbu(cpu: &mut CPU, instr: u32) {}
pub fn exec_lhu(cpu: &mut CPU, instr: u32) {}
pub fn exec_lwu(cpu: &mut CPU, instr: u32) {}
pub fn exec_lb(cpu: &mut CPU, instr: u32) {
let imm = imm_i(instr) as i32;
let load_i8 = cpu.bus.load(
(cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32,
8,
) as i32;
cpu.xregs.regs[rd(instr) as usize] = ((load_i8 << 26) >> 26) as u32;
}
pub fn exec_lh(cpu: &mut CPU, instr: u32) {
let imm = imm_i(instr) as i32;
let load_i16 = cpu.bus.load(
(cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32,
16,
) as i32;
cpu.xregs.regs[rd(instr) as usize] = ((load_i16 << 16) >> 16) as u32;
}
pub fn exec_lw(cpu: &mut CPU, instr: u32) {
let imm = imm_i(instr) as i32;
cpu.xregs.regs[rd(instr) as usize] = cpu.bus.load(
(cpu.xregs.regs[rs1(instr) as usize] as i32).wrapping_add(imm) as u32,
32,
);
}
pub fn exec_lbu(cpu: &mut CPU, instr: u32) {
let imm = imm_i(instr) as u32;
cpu.xregs.regs[rd(instr) as usize] = cpu
.bus
.load(cpu.xregs.regs[rs1(instr) as usize].wrapping_add(imm), 8);
}
pub fn exec_lhu(cpu: &mut CPU, instr: u32) {
let imm = imm_i(instr) as u32;
cpu.xregs.regs[rd(instr) as usize] = cpu
.bus
.load(cpu.xregs.regs[rs1(instr) as usize].wrapping_add(imm), 16);
}
pub fn exec_lwu(cpu: &mut CPU, instr: u32) {
let imm = imm_i(instr) as u32;
cpu.xregs.regs[rd(instr) as usize] = cpu
.bus
.load(cpu.xregs.regs[rs1(instr) as usize].wrapping_add(imm), 32);
}
pub fn exec_sb(cpu: &mut CPU, instr: u32) {}
pub fn exec_sh(cpu: &mut CPU, instr: u32) {}
pub fn exec_sw(cpu: &mut CPU, instr: u32) {}
pub fn exec_sd(cpu: &mut CPU, instr: u32) {}
pub fn exec_addi(cpu: &mut CPU, instr: u32) {
let imm = imm_i(instr);
cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] + imm as u32;
Expand Down
4 changes: 2 additions & 2 deletions src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pub const MEM_BASE: u32 = 0x80000000; // defined in QEMU
pub const MEM_SIZE: u32 = 1024;

#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub struct BUS {
mem: MEMORY,
}
Expand All @@ -20,7 +20,7 @@ impl BUS {
}
}

#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub struct MEMORY {
mem: [u8; MEM_SIZE as usize],
}
Expand Down
1 change: 1 addition & 0 deletions src/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use core::fmt;

#[derive(Clone, Copy)]
pub struct XREGS {
pub regs: [u32; 32],
}
Expand Down
134 changes: 89 additions & 45 deletions tests/cpu_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod helper;
#[cfg(test)]
mod tests {
use crate::helper;
use emurv::{cpu, opcode::*};
use emurv::{cpu, memory::MEM_BASE, opcode::*};

#[test]
fn test_exec_lui() {
Expand Down Expand Up @@ -202,15 +202,61 @@ mod tests {
assert_eq!(cpu_test.pc as i32, (ori_pc as i32) + 12 - 4);
}
#[test]
fn test_exec_lb() {}
#[test]
fn test_exec_lh() {}
fn test_exec_lb() {
let mut cpu_test = cpu::CPU::new();
let offset = 3;
let val = (-2 as i32) as u32;
let rd = 5 + MEM_BASE;
cpu_test.bus.store(rd + offset, 8, val);
// set x1=5+MEM_BASE
helper::set_register_val(&mut cpu_test, 1, rd as i32);
// lb x31, x1, 3
let instr: u32 = helper::set_load_type_instruction(offset as i16, 1, LB as u8, 31);
cpu::exec_lb(&mut cpu_test, instr);
assert_eq!(cpu_test.xregs.regs[31], val);
}
#[test]
fn test_exec_lw() {}
fn test_exec_lh() {
let mut cpu_test = cpu::CPU::new();
let offset = 3;
let val = (-2 as i32) as u32;
let rd = 5 + MEM_BASE;
cpu_test.bus.store(rd + offset, 16, val);
// set x1=5+MEM_BASE
helper::set_register_val(&mut cpu_test, 1, rd as i32);
// lh x31, x1, 3
let instr: u32 = helper::set_load_type_instruction(offset as i16, 1, LH as u8, 31);
cpu::exec_lh(&mut cpu_test, instr);
assert_eq!(cpu_test.xregs.regs[31], val);
}
#[test]
fn test_exec_ld() {}
fn test_exec_lw() {
let mut cpu_test = cpu::CPU::new();
let offset = 3;
let val = 11;
let rd = 5 + MEM_BASE;
cpu_test.bus.store(rd + offset, 32, val);
// set x1=5+MEM_BASE
helper::set_register_val(&mut cpu_test, 1, rd as i32);
// lw x31, x1, 3
let instr: u32 = helper::set_load_type_instruction(offset as i16, 1, LW as u8, 31);
cpu::exec_lw(&mut cpu_test, instr);
assert_eq!(cpu_test.xregs.regs[31], val);
}
#[test]
fn test_exec_lbu() {}
fn test_exec_lbu() {
let mut cpu_test = cpu::CPU::new();
let offset = 3;
let val = 11;
let rd = 5 + MEM_BASE;
cpu_test.bus.store(rd + offset, 8, val);
// set x1=5+MEM_BASE
helper::set_register_val(&mut cpu_test, 1, rd as i32);
// lbu x31, x1, 3
let instr: u32 = helper::set_load_type_instruction(offset as i16, 1, LBU as u8, 31);
cpu::exec_lbu(&mut cpu_test, instr);
assert_eq!(cpu_test.xregs.regs[31], val);
}
#[test]
fn test_exec_lhu() {}
#[test]
Expand All @@ -222,8 +268,6 @@ mod tests {
#[test]
fn test_exec_sw() {}
#[test]
fn test_exec_sd() {}
#[test]
fn test_exec_addi() {
let mut cpu_test = cpu::CPU::new();

Expand Down Expand Up @@ -357,40 +401,40 @@ mod tests {
cpu::exec_sub(&mut cpu_test, instr);
assert_eq!(cpu_test.xregs.regs[31], 0xfffffffa); // 0xfffffffa is -6
}
#[test]
fn test_exec_sll() {}
#[test]
fn test_exec_slt() {}
#[test]
fn test_exec_sltu() {}
#[test]
fn test_exec_xor() {}
#[test]
fn test_exec_srl() {}
#[test]
fn test_exec_sra() {}
#[test]
fn test_exec_or() {}
#[test]
fn test_exec_and() {}
#[test]
fn test_exec_fence() {}
#[test]
fn test_exec_fence_i() {}
#[test]
fn test_exec_ecall() {}
#[test]
fn test_exec_ebreak() {}
#[test]
fn test_exec_csrrw() {}
#[test]
fn test_exec_csrrs() {}
#[test]
fn test_exec_csrrc() {}
#[test]
fn test_exec_csrrwi() {}
#[test]
fn test_exec_csrrsi() {}
#[test]
fn test_exec_csrrci() {}
// #[test]
// fn test_exec_sll() {}
// #[test]
// fn test_exec_slt() {}
// #[test]
// fn test_exec_sltu() {}
// #[test]
// fn test_exec_xor() {}
// #[test]
// fn test_exec_srl() {}
// #[test]
// fn test_exec_sra() {}
// #[test]
// fn test_exec_or() {}
// #[test]
// fn test_exec_and() {}
// #[test]
// fn test_exec_fence() {}
// #[test]
// fn test_exec_fence_i() {}
// #[test]
// fn test_exec_ecall() {}
// #[test]
// fn test_exec_ebreak() {}
// #[test]
// fn test_exec_csrrw() {}
// #[test]
// fn test_exec_csrrs() {}
// #[test]
// fn test_exec_csrrc() {}
// #[test]
// fn test_exec_csrrwi() {}
// #[test]
// fn test_exec_csrrsi() {}
// #[test]
// fn test_exec_csrrci() {}
}
19 changes: 16 additions & 3 deletions tests/helper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use emurv::{
cpu,
opcode::{B_TYPE, I_TYPE, R_TYPE},
opcode::{ADDI, B_TYPE, I_TYPE, LOAD, LUI, R_TYPE},
};

pub fn set_r_type_instruction(rs2: u8, rs1: u8, funct3: u8, rd: u8) -> u32 {
Expand All @@ -21,6 +21,15 @@ pub fn set_i_type_instruction(imm: i16, rs1: u8, funct3: u8, rd: u8) -> u32 {
| ((I_TYPE as u32) & 0x7f);
}

pub fn set_load_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)
| ((rs1 as u32 & 0x1f) << 15)
| ((funct3 as u32 & 0x7) << 12)
| ((rd as u32 & 0x1f) << 7)
| ((LOAD 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;
Expand Down Expand Up @@ -51,7 +60,11 @@ 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) {
let instr = set_i_type_instruction(val, 0x0, 0x0, rd);
pub fn set_register_val(cpu: &mut cpu::CPU, rd: u8, val: i32) {
// set lower 12 bits
let instr = set_i_type_instruction((val as u32 & 0xfff) as i16, 0x0, ADDI as u8, rd);
cpu::exec_addi(cpu, instr);
// set upper 20 bits
let instr: u32 = set_u_type_instruction((val as u32 & 0xfffff000) as i32, rd, LUI as u8);
cpu::exec_lui(cpu, instr);
}

0 comments on commit be76276

Please sign in to comment.