From 32acf3965e6f9143211651b9b0b92f6a05452ebd Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Tue, 13 Feb 2024 21:17:03 +0800 Subject: [PATCH 1/5] test: Fix u type tests --- tests/cpu_test.rs | 8 ++++---- tests/helper.rs | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/cpu_test.rs b/tests/cpu_test.rs index d0af4df..d9eeee0 100644 --- a/tests/cpu_test.rs +++ b/tests/cpu_test.rs @@ -10,12 +10,12 @@ mod tests { let mut cpu_test = cpu::CPU::new(); // lui x5, 4 - let instr: u32 = helper::set_u_type_instruction(4 << 12, 5, LUI as u8); + let instr: u32 = helper::set_u_type_instruction(4, 5, LUI as u8); cpu::exec_lui(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], 4 << 12); // lui x5, -4 - let instr: u32 = helper::set_u_type_instruction(-(4 << 12), 5, LUI as u8); + let instr: u32 = helper::set_u_type_instruction(-4, 5, LUI as u8); cpu::exec_lui(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], -(4 << 12) as u64); } @@ -25,12 +25,12 @@ mod tests { let ori_pc = cpu_test.pc; // auipc x5, 4 - let instr: u32 = helper::set_u_type_instruction(4 << 12, 5, AUIPC as u8); + let instr: u32 = helper::set_u_type_instruction(4, 5, AUIPC as u8); cpu::exec_auipc(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], ori_pc + (4 << 12)); // auipc x5, -4 - let instr: u32 = helper::set_u_type_instruction(-(4 << 12), 5, AUIPC as u8); + let instr: u32 = helper::set_u_type_instruction(-4, 5, AUIPC as u8); cpu::exec_auipc(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], (ori_pc as i64 + (-4 << 12)) as u64); } diff --git a/tests/helper.rs b/tests/helper.rs index 6eb37c2..4e255bb 100644 --- a/tests/helper.rs +++ b/tests/helper.rs @@ -13,7 +13,9 @@ pub fn set_i_type_instruction(imm: i16, rs1: u8, funct3: u8, rd: u8) -> u32 { } 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); + return ((imm << 12) as u32 & 0xfffff000) as u32 + | ((rd as u32 & 0x1f) << 7) + | ((opcode as u32) & 0x7f); } pub fn set_j_type_instruction(imm: i32, rd: u8, opcode: u8) -> u32 { From 146cc8d8c2e963f3683b4bde41bb2715d39352c8 Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Tue, 13 Feb 2024 21:49:45 +0800 Subject: [PATCH 2/5] refactor: Refactor to 32 bit architecture --- src/cpu.rs | 46 +++++++++++------------ src/memory.rs | 96 +++++++++++++++++++++++------------------------ src/opcode.rs | 32 ++++++++-------- src/registers.rs | 4 +- tests/cpu_test.rs | 8 ++-- 5 files changed, 93 insertions(+), 93 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 25049cc..89699ce 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -8,7 +8,7 @@ use crate::registers; pub struct CPU { // integer registers pub xregs: registers::XREGS, - pub pc: u64, + pub pc: u32, pub bus: memory::BUS, } @@ -114,22 +114,22 @@ impl CPU { // RV32I // 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 u64; + let imm = (imm_U(instr) as i32) as u32; cpu.xregs.regs[rd(instr) as usize] = imm; } pub fn exec_auipc(cpu: &mut CPU, instr: u32) { - let imm = (imm_U(instr) as i32) as i64; - cpu.xregs.regs[rd(instr) as usize] = (cpu.pc as i64 + imm) as u64; + let imm = imm_U(instr) as i32; + cpu.xregs.regs[rd(instr) as usize] = (cpu.pc as i32 + imm) as u32; } pub fn exec_jal(cpu: &mut CPU, instr: u32) { - let imm = (imm_J(instr) as i32) as i64; + let imm = imm_J(instr) as i32; cpu.xregs.regs[rd(instr) as usize] = cpu.pc + 4; - cpu.pc = (cpu.pc as i64 + imm) as u64; + cpu.pc = (cpu.pc as i32 + imm) as u32; } pub fn exec_jalr(cpu: &mut CPU, instr: u32) { - let imm = (imm_J(instr) as i32) as i64; + let imm = imm_J(instr) as i32; cpu.xregs.regs[rd(instr) as usize] = cpu.pc + 4; - cpu.pc = (cpu.pc as i64 + imm) as u64; + cpu.pc = (cpu.pc as i32 + imm) as u32; } pub fn exec_beq(cpu: &mut CPU, instr: u32) {} pub fn exec_bne(cpu: &mut CPU, instr: u32) {} @@ -150,50 +150,50 @@ 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 u64; + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] + imm as u32; } pub fn exec_slti(cpu: &mut CPU, instr: u32) { let imm = imm_I(instr); cpu.xregs.regs[rd(instr) as usize] = - ((cpu.xregs.regs[rs1(instr) as usize] as i64) < (imm as i64)) as u64; + ((cpu.xregs.regs[rs1(instr) as usize] as i32) < (imm as i32)) as u32; } pub fn exec_sltiu(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 u64) as u64; + cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] < imm as u32) as u32; } pub fn exec_xori(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 u64; + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] ^ imm as u32; } pub fn exec_ori(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 u64; + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] | imm as u32; } pub fn exec_andi(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 u64; + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] & imm as u32; } pub fn exec_slli(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 u64; + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] << imm as u32; } pub fn exec_srli(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 u64; + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] >> imm as u32; } pub fn exec_srai(cpu: &mut CPU, instr: u32) { let imm = imm_I(instr); - cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i64 >> imm) as u64; + cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i32 >> imm) as u32; } pub fn exec_add(cpu: &mut CPU, instr: u32) { - cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i64 - + cpu.xregs.regs[rs2(instr) as usize] as i64) - as u64; + cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i32 + + cpu.xregs.regs[rs2(instr) as usize] as i32) + as u32; } pub fn exec_sub(cpu: &mut CPU, instr: u32) { - cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i64 - - cpu.xregs.regs[rs2(instr) as usize] as i64) - as u64; + cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i32 + - cpu.xregs.regs[rs2(instr) as usize] as i32) + as u32; } pub fn exec_sll(cpu: &mut CPU, instr: u32) {} pub fn exec_slt(cpu: &mut CPU, instr: u32) {} diff --git a/src/memory.rs b/src/memory.rs index 0031ea8..68fb072 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,7 +1,7 @@ // pub mod memory; -pub const MEM_BASE: u64 = 0x80000000; // defined in QEMU -pub const MEM_SIZE: u64 = 1024; +pub const MEM_BASE: u32 = 0x80000000; // defined in QEMU +pub const MEM_SIZE: u32 = 1024; #[derive(Debug)] pub struct BUS { @@ -12,10 +12,10 @@ impl BUS { pub fn new() -> Self { BUS { mem: MEMORY::new() } } - pub fn load(self, addr: u64, size: u64) -> u32 { + pub fn load(self, addr: u32, size: u32) -> u32 { return self.mem.load(addr, size) as u32; } - pub fn store(&mut self, addr: u64, size: u64, value: u64) { + pub fn store(&mut self, addr: u32, size: u32, value: u32) { self.mem.store(addr, size, value); } } @@ -32,78 +32,78 @@ impl MEMORY { } } - fn load(self, addr: u64, size: u64) -> u64 { + fn load(self, addr: u32, size: u32) -> u32 { match size { 8 => return self.load8(addr), 16 => return self.load16(addr), 32 => return self.load32(addr), - 64 => return self.load64(addr), + // 64 => return self.load64(addr), _ => panic!("wrong load size"), } } - fn store(&mut self, addr: u64, size: u64, value: u64) { + fn store(&mut self, addr: u32, size: u32, value: u32) { match size { 8 => self.store8(addr, value), 16 => self.store16(addr, value), 32 => self.store32(addr, value), - 64 => self.store64(addr, value), + // 64 => self.store64(addr, value), _ => panic!("wrong store size"), } } // load funcs - fn load8(self, addr: u64) -> u64 { + fn load8(self, addr: u32) -> u32 { let index = (addr - MEM_BASE) as usize; - return self.mem[index] as u64; + return self.mem[index] as u32; } - fn load16(self, addr: u64) -> u64 { + fn load16(self, addr: u32) -> u32 { let index = (addr - MEM_BASE) as usize; - return self.mem[index] as u64 | ((self.mem[index + 1] as u64) << 8); + return self.mem[index] as u32 | ((self.mem[index + 1] as u32) << 8); } - fn load32(self, addr: u64) -> u64 { + fn load32(self, addr: u32) -> u32 { let index = (addr - MEM_BASE) as usize; - return self.mem[index] as u64 - | ((self.mem[index + 1] as u64) << 8) - | ((self.mem[index + 2] as u64) << 16) - | ((self.mem[index + 3] as u64) << 24); - } - fn load64(self, addr: u64) -> u64 { - let index = (addr - MEM_BASE) as usize; - return self.mem[index] as u64 - | ((self.mem[index + 1] as u64) << 8) - | ((self.mem[index + 2] as u64) << 16) - | ((self.mem[index + 3] as u64) << 24) - | ((self.mem[index + 4] as u64) << 32) - | ((self.mem[index + 5] as u64) << 40) - | ((self.mem[index + 6] as u64) << 48) - | ((self.mem[index + 7] as u64) << 56); + return self.mem[index] as u32 + | ((self.mem[index + 1] as u32) << 8) + | ((self.mem[index + 2] as u32) << 16) + | ((self.mem[index + 3] as u32) << 24); } + // fn load64(self, addr: u32) -> u32 { + // let index = (addr - MEM_BASE) as usize; + // return self.mem[index] as u32 + // | ((self.mem[index + 1] as u32) << 8) + // | ((self.mem[index + 2] as u32) << 16) + // | ((self.mem[index + 3] as u32) << 24) + // | ((self.mem[index + 4] as u32) << 32) + // | ((self.mem[index + 5] as u32) << 40) + // | ((self.mem[index + 6] as u32) << 48) + // | ((self.mem[index + 7] as u32) << 56); + // } // store funcs - fn store8(&mut self, addr: u64, value: u64) { - let index = (addr - MEM_BASE) as usize; - self.mem[index] = (value & (std::u8::MAX as u64)) as u8; - } - fn store16(&mut self, addr: u64, value: u64) { + fn store8(&mut self, addr: u32, value: u32) { let index = (addr - MEM_BASE) as usize; - self.mem[index] = (value & (std::u8::MAX as u64)) as u8; - self.mem[index + 1] = ((value >> 8) & (std::u8::MAX as u64)) as u8; + self.mem[index] = (value & (std::u8::MAX as u32)) as u8; } - fn store32(&mut self, addr: u64, value: u64) { + fn store16(&mut self, addr: u32, value: u32) { let index = (addr - MEM_BASE) as usize; - self.mem[index] = (value & (std::u8::MAX as u64)) as u8; - self.mem[index + 1] = ((value >> 8) & (std::u8::MAX as u64)) as u8; - self.mem[index + 2] = ((value >> 16) & (std::u8::MAX as u64)) as u8; + self.mem[index] = (value & (std::u8::MAX as u32)) as u8; + self.mem[index + 1] = ((value >> 8) & (std::u8::MAX as u32)) as u8; } - fn store64(&mut self, addr: u64, value: u64) { + fn store32(&mut self, addr: u32, value: u32) { let index = (addr - MEM_BASE) as usize; - self.mem[index] = (value & (std::u8::MAX as u64)) as u8; - self.mem[index + 1] = ((value >> 8) & (std::u8::MAX as u64)) as u8; - self.mem[index + 2] = ((value >> 16) & (std::u8::MAX as u64)) as u8; - self.mem[index + 3] = ((value >> 24) & (std::u8::MAX as u64)) as u8; - self.mem[index + 4] = ((value >> 32) & (std::u8::MAX as u64)) as u8; - self.mem[index + 5] = ((value >> 40) & (std::u8::MAX as u64)) as u8; - self.mem[index + 6] = ((value >> 48) & (std::u8::MAX as u64)) as u8; - self.mem[index + 7] = ((value >> 56) & (std::u8::MAX as u64)) as u8; + self.mem[index] = (value & (std::u8::MAX as u32)) as u8; + self.mem[index + 1] = ((value >> 8) & (std::u8::MAX as u32)) as u8; + self.mem[index + 2] = ((value >> 16) & (std::u8::MAX as u32)) as u8; } + // fn store64(&mut self, addr: u32, value: u32) { + // let index = (addr - MEM_BASE) as usize; + // self.mem[index] = (value & (std::u8::MAX as u32)) as u8; + // self.mem[index + 1] = ((value >> 8) & (std::u8::MAX as u32)) as u8; + // self.mem[index + 2] = ((value >> 16) & (std::u8::MAX as u32)) as u8; + // self.mem[index + 3] = ((value >> 24) & (std::u8::MAX as u32)) as u8; + // self.mem[index + 4] = ((value >> 32) & (std::u8::MAX as u32)) as u8; + // self.mem[index + 5] = ((value >> 40) & (std::u8::MAX as u32)) as u8; + // self.mem[index + 6] = ((value >> 48) & (std::u8::MAX as u32)) as u8; + // self.mem[index + 7] = ((value >> 56) & (std::u8::MAX as u32)) as u8; + // } } diff --git a/src/opcode.rs b/src/opcode.rs index 2d34b77..8bcfb89 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -103,22 +103,22 @@ pub fn shamt(instr: u32) -> u32 { return (imm_I(instr) & 0x1f) as u32; } -pub fn csr(instr: u32) -> u64 { +pub fn csr(instr: u32) -> u32 { // csr[11:0] = inst[31:20] - return ((instr & 0xfff00000) >> 20) as u64; + return ((instr & 0xfff00000) >> 20) as u32; } -pub fn imm_B(instr: u32) -> u64 { +pub fn imm_B(instr: u32) -> u32 { // imm[12|10:5|4:1|11] = inst[31|30:25|11:8|7] - return ((instr & 0x80000000) >> 19) as u64 - | ((instr & 0x80) << 4) as u64 // imm[11] - | ((instr >> 20) & 0x7e0) as u64 // imm[10:5] - | ((instr >> 7) & 0x1e) as u64; // imm[4:1] + return ((instr & 0x80000000) >> 19) as u32 + | ((instr & 0x80) << 4) as u32 // imm[11] + | ((instr >> 20) & 0x7e0) as u32 // imm[10:5] + | ((instr >> 7) & 0x1e) as u32; // imm[4:1] } -pub fn imm_S(instr: u32) -> u64 { +pub fn imm_S(instr: u32) -> u32 { // imm[11:5] = inst[31:25], imm[4:0] = inst[11:7] - return ((instr & 0xfe000000) >> 20) as u64 | ((instr >> 7) & 0x1f) as u64; + return ((instr & 0xfe000000) >> 20) as u32 | ((instr >> 7) & 0x1f) as u32; } pub fn imm_I(instr: u32) -> i32 { @@ -126,15 +126,15 @@ pub fn imm_I(instr: u32) -> i32 { return (instr & 0xfff00000) as i32 >> 20; } -pub fn imm_U(instr: u32) -> u64 { +pub fn imm_U(instr: u32) -> u32 { // imm[31:12] = inst[31:12] - return (instr & 0xfffff000) as u64; + return (instr & 0xfffff000) as u32; } -pub fn imm_J(instr: u32) -> u64 { +pub fn imm_J(instr: u32) -> u32 { // imm[20|10:1|11|19:12] = inst[31|30:21|20|19:12] - return (((instr & 0x80000000) as i32 as i64 >> 11) as u64)// imm[20] - | ((instr & 0x3ff00000) >> 20) as u64 // imm[10:1] - | ((instr & 0x80000) >> 9) as u64 // imm[11] - | (instr & 0xff000) as u64; // imm[19:12] + return (((instr & 0x80000000) as i32 >> 11) as u32)// imm[20] + | ((instr & 0x3ff00000) >> 20) as u32 // imm[10:1] + | ((instr & 0x80000) >> 9) as u32 // imm[11] + | (instr & 0xff000) as u32; // imm[19:12] } diff --git a/src/registers.rs b/src/registers.rs index f068579..8564a00 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -3,7 +3,7 @@ use core::fmt; pub struct XREGS { - pub regs: [u64; 32], + pub regs: [u32; 32], } impl XREGS { @@ -29,7 +29,7 @@ mod tests { fn xregs_debug() { let mut xregs = XREGS::new(); for i in 0..32 { - xregs.regs[i] = (i * 11) as u64; + xregs.regs[i] = (i * 11) as u32; } println!("{xregs:#?}") } diff --git a/tests/cpu_test.rs b/tests/cpu_test.rs index d9eeee0..f16050a 100644 --- a/tests/cpu_test.rs +++ b/tests/cpu_test.rs @@ -17,7 +17,7 @@ mod tests { // lui x5, -4 let instr: u32 = helper::set_u_type_instruction(-4, 5, LUI as u8); cpu::exec_lui(&mut cpu_test, instr); - assert_eq!(cpu_test.xregs.regs[5], -(4 << 12) as u64); + assert_eq!(cpu_test.xregs.regs[5], -(4 << 12) as u32); } #[test] fn test_exec_auipc() { @@ -32,7 +32,7 @@ mod tests { // auipc x5, -4 let instr: u32 = helper::set_u_type_instruction(-4, 5, AUIPC as u8); cpu::exec_auipc(&mut cpu_test, instr); - assert_eq!(cpu_test.xregs.regs[5], (ori_pc as i64 + (-4 << 12)) as u64); + assert_eq!(cpu_test.xregs.regs[5], (ori_pc as i64 + (-4 << 12)) as u32); } #[test] fn test_exec_jal() { @@ -187,7 +187,7 @@ mod tests { let instr: u32 = helper::set_i_type_instruction(2, 1, SRAI as u8, 31); cpu::exec_srai(&mut cpu_test, instr); // -2 >> 2 = -1 - assert_eq!(cpu_test.xregs.regs[31], std::u64::MAX); + assert_eq!(cpu_test.xregs.regs[31], std::u32::MAX); } #[test] fn test_exec_add() { @@ -213,7 +213,7 @@ mod tests { // sub x31, x5, x6 let instr: u32 = helper::set_r_type_instruction(SUB as u8, 6, 5, 31); cpu::exec_sub(&mut cpu_test, instr); - assert_eq!(cpu_test.xregs.regs[31], 18446744073709551610); // 18446744073709551610 is -6 + assert_eq!(cpu_test.xregs.regs[31], 0xfffffffa); // 0xfffffffa is -6 } #[test] fn test_exec_sll() {} From dfe9c9ef8ae149ce89d24d20b6848d3c7d487160 Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Tue, 13 Feb 2024 21:50:52 +0800 Subject: [PATCH 3/5] chore: Rename imm functions to lower case --- src/cpu.rs | 26 +++++++++++++------------- src/opcode.rs | 12 ++++++------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 89699ce..172e040 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -114,20 +114,20 @@ impl CPU { // RV32I // 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; + let imm = (imm_u(instr) as i32) as u32; cpu.xregs.regs[rd(instr) as usize] = imm; } pub fn exec_auipc(cpu: &mut CPU, instr: u32) { - let imm = imm_U(instr) as i32; + let imm = imm_u(instr) as i32; cpu.xregs.regs[rd(instr) as usize] = (cpu.pc as i32 + imm) as u32; } pub fn exec_jal(cpu: &mut CPU, instr: u32) { - let imm = imm_J(instr) as i32; + let imm = imm_j(instr) as i32; cpu.xregs.regs[rd(instr) as usize] = cpu.pc + 4; cpu.pc = (cpu.pc as i32 + imm) as u32; } pub fn exec_jalr(cpu: &mut CPU, instr: u32) { - let imm = imm_J(instr) as i32; + let imm = imm_j(instr) as i32; cpu.xregs.regs[rd(instr) as usize] = cpu.pc + 4; cpu.pc = (cpu.pc as i32 + imm) as u32; } @@ -149,40 +149,40 @@ 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); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] + imm as u32; } pub fn exec_slti(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = ((cpu.xregs.regs[rs1(instr) as usize] as i32) < (imm as i32)) as u32; } pub fn exec_sltiu(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] < imm as u32) as u32; } pub fn exec_xori(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] ^ imm as u32; } pub fn exec_ori(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] | imm as u32; } pub fn exec_andi(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] & imm as u32; } pub fn exec_slli(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] << imm as u32; } pub fn exec_srli(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] >> imm as u32; } pub fn exec_srai(cpu: &mut CPU, instr: u32) { - let imm = imm_I(instr); + let imm = imm_i(instr); cpu.xregs.regs[rd(instr) as usize] = (cpu.xregs.regs[rs1(instr) as usize] as i32 >> imm) as u32; } pub fn exec_add(cpu: &mut CPU, instr: u32) { diff --git a/src/opcode.rs b/src/opcode.rs index 8bcfb89..38c4d1a 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -100,7 +100,7 @@ pub fn rs2(instr: u32) -> u32 { pub fn shamt(instr: u32) -> u32 { // shamt[4:5] = imm[5:0] - return (imm_I(instr) & 0x1f) as u32; + return (imm_i(instr) & 0x1f) as u32; } pub fn csr(instr: u32) -> u32 { @@ -108,7 +108,7 @@ pub fn csr(instr: u32) -> u32 { return ((instr & 0xfff00000) >> 20) as u32; } -pub fn imm_B(instr: u32) -> u32 { +pub fn imm_b(instr: u32) -> u32 { // imm[12|10:5|4:1|11] = inst[31|30:25|11:8|7] return ((instr & 0x80000000) >> 19) as u32 | ((instr & 0x80) << 4) as u32 // imm[11] @@ -116,22 +116,22 @@ pub fn imm_B(instr: u32) -> u32 { | ((instr >> 7) & 0x1e) as u32; // imm[4:1] } -pub fn imm_S(instr: u32) -> u32 { +pub fn imm_s(instr: u32) -> u32 { // imm[11:5] = inst[31:25], imm[4:0] = inst[11:7] return ((instr & 0xfe000000) >> 20) as u32 | ((instr >> 7) & 0x1f) as u32; } -pub fn imm_I(instr: u32) -> i32 { +pub fn imm_i(instr: u32) -> i32 { // imm[11:0] = inst[31:20] return (instr & 0xfff00000) as i32 >> 20; } -pub fn imm_U(instr: u32) -> u32 { +pub fn imm_u(instr: u32) -> u32 { // imm[31:12] = inst[31:12] return (instr & 0xfffff000) as u32; } -pub fn imm_J(instr: u32) -> u32 { +pub fn imm_j(instr: u32) -> u32 { // imm[20|10:1|11|19:12] = inst[31|30:21|20|19:12] return (((instr & 0x80000000) as i32 >> 11) as u32)// imm[20] | ((instr & 0x3ff00000) >> 20) as u32 // imm[10:1] From 570ea7a774ff7d27ecbd0764682d922d9ee888a3 Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Tue, 13 Feb 2024 22:17:17 +0800 Subject: [PATCH 4/5] fix: Fix LUI and AUIPC --- src/cpu.rs | 2 +- tests/cpu_test.rs | 15 +++++++++------ tests/helper.rs | 4 +--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 172e040..b45b9bc 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -119,7 +119,7 @@ pub fn exec_lui(cpu: &mut CPU, instr: u32) { } pub fn exec_auipc(cpu: &mut CPU, instr: u32) { let imm = imm_u(instr) as i32; - cpu.xregs.regs[rd(instr) as usize] = (cpu.pc as i32 + imm) as u32; + cpu.xregs.regs[rd(instr) as usize] = (cpu.pc as i32).wrapping_add(imm) as u32; } pub fn exec_jal(cpu: &mut CPU, instr: u32) { let imm = imm_j(instr) as i32; diff --git a/tests/cpu_test.rs b/tests/cpu_test.rs index f16050a..4cab434 100644 --- a/tests/cpu_test.rs +++ b/tests/cpu_test.rs @@ -10,14 +10,14 @@ mod tests { let mut cpu_test = cpu::CPU::new(); // lui x5, 4 - let instr: u32 = helper::set_u_type_instruction(4, 5, LUI as u8); + let instr: u32 = helper::set_u_type_instruction(4 << 12, 5, LUI as u8); cpu::exec_lui(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], 4 << 12); // lui x5, -4 - let instr: u32 = helper::set_u_type_instruction(-4, 5, LUI as u8); + let instr: u32 = helper::set_u_type_instruction(-4 << 12, 5, LUI as u8); cpu::exec_lui(&mut cpu_test, instr); - assert_eq!(cpu_test.xregs.regs[5], -(4 << 12) as u32); + assert_eq!(cpu_test.xregs.regs[5], (-4 << 12) as u32); } #[test] fn test_exec_auipc() { @@ -25,14 +25,17 @@ mod tests { let ori_pc = cpu_test.pc; // auipc x5, 4 - let instr: u32 = helper::set_u_type_instruction(4, 5, AUIPC as u8); + let instr: u32 = helper::set_u_type_instruction(4 << 12, 5, AUIPC as u8); cpu::exec_auipc(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], ori_pc + (4 << 12)); // auipc x5, -4 - let instr: u32 = helper::set_u_type_instruction(-4, 5, AUIPC as u8); + let instr: u32 = helper::set_u_type_instruction(-4 << 12, 5, AUIPC as u8); cpu::exec_auipc(&mut cpu_test, instr); - assert_eq!(cpu_test.xregs.regs[5], (ori_pc as i64 + (-4 << 12)) as u32); + assert_eq!( + cpu_test.xregs.regs[5], + (ori_pc as i32).wrapping_add(-4 << 12) as u32 + ); } #[test] fn test_exec_jal() { diff --git a/tests/helper.rs b/tests/helper.rs index 4e255bb..6eb37c2 100644 --- a/tests/helper.rs +++ b/tests/helper.rs @@ -13,9 +13,7 @@ pub fn set_i_type_instruction(imm: i16, rs1: u8, funct3: u8, rd: u8) -> u32 { } pub fn set_u_type_instruction(imm: i32, rd: u8, opcode: u8) -> u32 { - return ((imm << 12) as u32 & 0xfffff000) as u32 - | ((rd as u32 & 0x1f) << 7) - | ((opcode as u32) & 0x7f); + return (imm as u32 & 0xfffff000) as u32 | ((rd as u32 & 0x1f) << 7) | ((opcode as u32) & 0x7f); } pub fn set_j_type_instruction(imm: i32, rd: u8, opcode: u8) -> u32 { From 4ad2bc424cfec572d7cdf5bcf6356346b890eb9f Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Tue, 13 Feb 2024 23:07:35 +0800 Subject: [PATCH 5/5] feat: Add JALR --- src/cpu.rs | 5 +++-- tests/cpu_test.rs | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index b45b9bc..518c536 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -127,9 +127,10 @@ pub fn exec_jal(cpu: &mut CPU, instr: u32) { cpu.pc = (cpu.pc as i32 + imm) as u32; } pub fn exec_jalr(cpu: &mut CPU, instr: u32) { - let imm = imm_j(instr) as i32; + let imm = imm_i(instr) as i32; cpu.xregs.regs[rd(instr) as usize] = cpu.pc + 4; - cpu.pc = (cpu.pc as i32 + imm) as 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) {} diff --git a/tests/cpu_test.rs b/tests/cpu_test.rs index 4cab434..cc9753b 100644 --- a/tests/cpu_test.rs +++ b/tests/cpu_test.rs @@ -9,12 +9,12 @@ mod tests { fn test_exec_lui() { let mut cpu_test = cpu::CPU::new(); - // lui x5, 4 + // lui x5, (4<<12) let instr: u32 = helper::set_u_type_instruction(4 << 12, 5, LUI as u8); cpu::exec_lui(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], 4 << 12); - // lui x5, -4 + // lui x5, (-4<<12) let instr: u32 = helper::set_u_type_instruction(-4 << 12, 5, LUI as u8); cpu::exec_lui(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], (-4 << 12) as u32); @@ -24,12 +24,12 @@ mod tests { let mut cpu_test = cpu::CPU::new(); let ori_pc = cpu_test.pc; - // auipc x5, 4 + // auipc x5, (4<<12) let instr: u32 = helper::set_u_type_instruction(4 << 12, 5, AUIPC as u8); cpu::exec_auipc(&mut cpu_test, instr); assert_eq!(cpu_test.xregs.regs[5], ori_pc + (4 << 12)); - // auipc x5, -4 + // auipc x5, (-4<<12) let instr: u32 = helper::set_u_type_instruction(-4 << 12, 5, AUIPC as u8); cpu::exec_auipc(&mut cpu_test, instr); assert_eq!( @@ -39,6 +39,7 @@ mod tests { } #[test] fn test_exec_jal() { + // TODO add test case for imm is a negative number let mut cpu_test = cpu::CPU::new(); let ori_pc = cpu_test.pc; @@ -49,7 +50,19 @@ mod tests { assert_eq!(cpu_test.pc, ori_pc + 12); } #[test] - fn test_exec_jalr() {} + fn test_exec_jalr() { + // TODO add test case for imm is a negative number + let mut cpu_test = cpu::CPU::new(); + + let ori_pc = cpu_test.pc; + // set x1=3 + helper::set_register_val(&mut cpu_test, 1, 3); + // jalr x5, 12 + let instr: u32 = helper::set_i_type_instruction(12, 1, JALR as u8, 5); + cpu::exec_jalr(&mut cpu_test, instr); + assert_eq!(cpu_test.xregs.regs[5], ori_pc + 4); + assert_eq!(cpu_test.pc, (3 + 12) & 0xfffffffe); + } #[test] fn test_exec_beq() {} #[test]