diff --git a/src/cpu.rs b/src/cpu.rs index 518c536..edfbba8 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -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, @@ -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), @@ -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 { @@ -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; @@ -132,23 +130,87 @@ 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_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_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) { + 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; @@ -176,15 +238,18 @@ pub fn exec_andi(cpu: &mut CPU, instr: 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 u32; + // shift-by-immediate takes only the lower 5 bits + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] << (imm & 0x1f) 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 u32; + // shift-by-immediate takes only the lower 5 bits + cpu.xregs.regs[rd(instr) as usize] = cpu.xregs.regs[rs1(instr) as usize] >> (imm & 0x1f) 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 i32 >> imm) as u32; + cpu.xregs.regs[rd(instr) as usize] = + (cpu.xregs.regs[rs1(instr) as usize] as i32 >> (imm & 0x1f)) 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 i32 diff --git a/src/memory.rs b/src/memory.rs index 68fb072..48a78de 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -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, } @@ -20,7 +20,7 @@ impl BUS { } } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct MEMORY { mem: [u8; MEM_SIZE as usize], } diff --git a/src/registers.rs b/src/registers.rs index 8564a00..6404faf 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -2,6 +2,7 @@ use core::fmt; +#[derive(Clone, Copy)] pub struct XREGS { pub regs: [u32; 32], } diff --git a/tests/cpu_test.rs b/tests/cpu_test.rs index cc9753b..977f76c 100644 --- a/tests/cpu_test.rs +++ b/tests/cpu_test.rs @@ -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() { @@ -64,27 +64,199 @@ mod tests { assert_eq!(cpu_test.pc, (3 + 12) & 0xfffffffe); } #[test] - fn test_exec_beq() {} - #[test] - fn test_exec_bne() {} + 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_blt() {} + 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_bge() {} + 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_bltu() {} + 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_bgeu() {} + 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_lb() {} + 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_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] @@ -96,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(); @@ -214,7 +384,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); } @@ -227,44 +397,44 @@ 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 } - #[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() {} } diff --git a/tests/helper.rs b/tests/helper.rs index 6eb37c2..cb79330 100644 --- a/tests/helper.rs +++ b/tests/helper.rs @@ -1,8 +1,17 @@ use emurv::{ cpu, - opcode::{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 { + // |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) @@ -12,8 +21,29 @@ 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_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; + 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 { @@ -26,16 +56,15 @@ 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) { - 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); }