diff --git a/src/riscv/lib/src/interpreter/rv32a.rs b/src/riscv/lib/src/interpreter/rv32a.rs index a26cf1409a27be039145448d77394fdc08a23c4d..a699646474e8bc7b89a4f8cb883bf4c80e8724d0 100644 --- a/src/riscv/lib/src/interpreter/rv32a.rs +++ b/src/riscv/lib/src/interpreter/rv32a.rs @@ -234,6 +234,7 @@ mod test { macro_rules! test_lrsc { ($name:ident, $lr: ident, $sc: ident, $align: expr, $t: ident) => { backend_test!($name, F, { + use $crate::machine_state::registers::nz; let state = create_state!(MachineCoreState, MachineCoreStateLayout, F, T1K); let state_cell = std::cell::RefCell::new(state); @@ -256,7 +257,7 @@ mod test { // Correct sequence of LR.x / SC.y instructions // SC.x succeeds and stores the expected value state.$lr(a0, a1, a2, false, false)?; - state.hart.xregisters.run_addi(imm, a2, a1); + state.hart.xregisters.run_addi(imm, nz::a2, nz::a1); state.$sc(a0, a1, a2, false, false)?; let res = state.hart.xregisters.read(a2); let val: $t = state.read_from_address(r1_addr)?; diff --git a/src/riscv/lib/src/interpreter/rv32c.rs b/src/riscv/lib/src/interpreter/rv32c.rs index 0ef6d48ce5d20e26f6b42c375c5c352e72bc7ec7..a7b33946122f12c48e5fc3a8596fb940090426b6 100644 --- a/src/riscv/lib/src/interpreter/rv32c.rs +++ b/src/riscv/lib/src/interpreter/rv32c.rs @@ -103,39 +103,6 @@ impl XRegisters where M: backend::ManagerReadWrite, { - /// `C.ADDI` CI-type compressed instruction - /// - /// Adds the non-zero sign-extended 6-bit `imm` to the value in `rd_rs1` then - /// writes the result to `rd_rs1`. - pub fn run_caddi(&mut self, imm: i64, rd_rs1: NonZeroXRegister) { - // Return the lower XLEN (64 bits in our case) bits of the addition - // Irrespective of sign, the result is the same, casting to u64 for addition - let rval = self.read_nz(rd_rs1); - let result = rval.wrapping_add(imm as u64); - self.write_nz(rd_rs1, result) - } - - /// `C.ADDI16SP` CI-type compressed instruction - /// - /// Adds the non-zero immediate to the value in the stack pointer. - /// The immediate is obtained by sign-extending and scaling by 16 the value - /// encoded in the instruction (see U:C-16.5). - pub fn run_caddi16sp(&mut self, imm: i64) { - debug_assert!(imm != 0 && imm % 16 == 0); - self.run_addi(imm, sp, sp) - } - - /// `C.ADDI4SPN` CIW-type compressed instruction - /// - /// Adds the non-zero immediate to the stack pointer and writes the result - /// to `rd`. - /// The immediate is obtained by zero-extending and scaling by 4 the value - /// encoded in the instruction (see U:C-16.5). - pub fn run_caddi4spn(&mut self, imm: i64, rd: XRegister) { - debug_assert!(imm > 0 && imm % 4 == 0); - self.run_addi(imm, sp, rd) - } - /// `C.SLLI` CI-type compressed instruction /// /// Performs a logical left shift of the value in register `rd_rs1` @@ -330,24 +297,6 @@ mod tests { } }); - backend_test!(run_caddi, F, { - let state = create_state!(MachineCoreState, MachineCoreStateLayout, F, T1K); - let state_cell = std::cell::RefCell::new(state); - - proptest!(|( - rd_val in any::(), - imm in any::(), - )| { - let mut state = state_cell.borrow_mut(); - state.reset(); - - state.hart.xregisters.write_nz(nz::a1, rd_val); - state.hart.xregisters.run_caddi(imm, nz::a1); - let res = state.hart.xregisters.read_nz(nz::a1); - prop_assert_eq!(res, rd_val.wrapping_add(imm as u64)); - }); - }); - backend_test!(test_run_cli, F, { let imm_rdrs1_res = [ (0_i64, nz::t3, 0_u64), diff --git a/src/riscv/lib/src/interpreter/rv32i.rs b/src/riscv/lib/src/interpreter/rv32i.rs index eac17756e78ce409b4305d43835ac9246a1a04cc..136cf2127f2ad90c7b868e01a5762bbacd10ee9b 100644 --- a/src/riscv/lib/src/interpreter/rv32i.rs +++ b/src/riscv/lib/src/interpreter/rv32i.rs @@ -23,15 +23,19 @@ impl XRegisters where M: backend::ManagerReadWrite, { - /// `ADDI` I-type instruction - /// /// Add `imm` to val(rs1) and store the result in `rd` - pub fn run_addi(&mut self, imm: i64, rs1: XRegister, rd: XRegister) { + /// + /// Relevant RISC-V opcodes: + /// - `ADDI` + /// - `C.ADDI` + /// - `C.ADDI4SPN` + /// - `C.ADDI16SP` + pub fn run_addi(&mut self, imm: i64, rs1: NonZeroXRegister, rd: NonZeroXRegister) { // Return the lower XLEN (64 bits in our case) bits of the addition // Irrespective of sign, the result is the same, casting to u64 for addition - let rval = self.read(rs1); + let rval = self.read_nz(rs1); let result = rval.wrapping_add(imm as u64); - self.write(rd, result) + self.write_nz(rd, result) } /// `SUB` R-type instruction @@ -396,7 +400,7 @@ mod tests { main_memory::{tests::T1K, Address}, mode::Mode, registers::{ - a0, a1, a2, a3, a4, fa0, nz, t0, t1, t2, t3, t4, XRegisters, XRegistersLayout, + a0, a1, a2, a3, a4, fa0, nz, t0, t1, t2, t3, XRegisters, XRegistersLayout, }, MachineCoreState, MachineCoreStateLayout, ProgramCounterUpdate, }, @@ -410,20 +414,20 @@ mod tests { backend_test!(test_add_sub, F, { let imm_rs1_rd_res = [ - (0_i64, 0_u64, t3, 0_u64), - (0, 0xFFF0_0420, t2, 0xFFF0_0420), - (-1, 0, t4, 0xFFFF_FFFF_FFFF_FFFF), + (0_i64, 0_u64, nz::t3, 0_u64), + (0, 0xFFF0_0420, nz::t2, 0xFFF0_0420), + (-1, 0, nz::t4, 0xFFFF_FFFF_FFFF_FFFF), ( 1_000_000, -123_000_987_i64 as u64, - a2, + nz::a2, -122_000_987_i64 as u64, ), - (1_000_000, 123_000_987, a2, 124_000_987), + (1_000_000, 123_000_987, nz::a2, 124_000_987), ( -1, -321_000_000_000_i64 as u64, - a1, + nz::a1, -321_000_000_001_i64 as u64, ), ]; @@ -433,8 +437,8 @@ mod tests { state.hart.xregisters.write(a0, rs1); state.hart.xregisters.write(t0, imm as u64); - state.hart.xregisters.run_addi(imm, a0, rd); - assert_eq!(state.hart.xregisters.read(rd), res); + state.hart.xregisters.run_addi(imm, nz::a0, rd); + assert_eq!(state.hart.xregisters.read_nz(rd), res); run_add(&mut state, nz::a0, nz::t0, nz::a0); assert_eq!(state.hart.xregisters.read(a0), res); // test sub with: res - imm = rs1 and res - rs1 = imm diff --git a/src/riscv/lib/src/machine_state.rs b/src/riscv/lib/src/machine_state.rs index b981f5a9a6af5e0675fa151599fa60ac4ae8c770..8b7e6382effb2da811e4c7b9d5bd6b8b7152ca7c 100644 --- a/src/riscv/lib/src/machine_state.rs +++ b/src/riscv/lib/src/machine_state.rs @@ -687,9 +687,10 @@ mod tests { }, parser::{ instruction::{ - CIBNZTypeArgs, ITypeArgs, Instr, InstrCacheable, InstrWidth, SBTypeArgs, + CIBNZTypeArgs, Instr, InstrCacheable, InstrWidth, SBTypeArgs, SplitITypeArgs, }, parse_block, + XRegisterParsed::*, }, state_backend::{ test_helpers::{assert_eq_struct, copy_via_serde, TestBackendFactory}, @@ -884,9 +885,9 @@ mod tests { const I_LOAD_6_INTO_T2: u32 = 0b11000000000001110010011; assert_eq!( parse_block(&I_LOAD_6_INTO_T2.to_le_bytes()), - [Instr::Cacheable(InstrCacheable::Addi(ITypeArgs { - rd: t2, - rs1: zero, + [Instr::Cacheable(InstrCacheable::Addi(SplitITypeArgs { + rd: NonZero(nz::t2), + rs1: X0, imm: 6, }))] ); @@ -895,9 +896,9 @@ mod tests { const I_LOAD_5_INTO_T2: u32 = 0b10100000000001110010011; assert_eq!( parse_block(&I_LOAD_5_INTO_T2.to_le_bytes()), - [Instr::Cacheable(InstrCacheable::Addi(ITypeArgs { - rd: t2, - rs1: zero, + [Instr::Cacheable(InstrCacheable::Addi(SplitITypeArgs { + rd: NonZero(nz::t2), + rs1: X0, imm: 5, }))] ); diff --git a/src/riscv/lib/src/machine_state/instruction.rs b/src/riscv/lib/src/machine_state/instruction.rs index bf1d84b1a03d831e4d3b3ea9d48b95192cba27a2..fede7d369dbb3c0dc7f5339900cb69a994d79d5e 100644 --- a/src/riscv/lib/src/machine_state/instruction.rs +++ b/src/riscv/lib/src/machine_state/instruction.rs @@ -335,9 +335,6 @@ pub enum OpCode { CJr, CJalr, CLui, - CAddi, - CAddi16sp, - CAddi4spn, CSlli, CAnd, COr, @@ -543,9 +540,6 @@ impl OpCode { Self::Bnez => Args::run_bnez, Self::Li => Args::run_li, Self::CLui => Args::run_clui, - Self::CAddi => Args::run_caddi, - Self::CAddi16sp => Args::run_caddi16spn, - Self::CAddi4spn => Args::run_caddi4spn, Self::CSlli => Args::run_cslli, Self::Mv => Args::run_mv, Self::CAnd => Args::run_cand, @@ -672,8 +666,8 @@ impl ConstDefault for Args { macro_rules! impl_r_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -684,8 +678,8 @@ macro_rules! impl_r_type { }; ($fn: ident, non_zero_rd) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -698,8 +692,8 @@ macro_rules! impl_r_type { }; ($impl: path, $fn: ident, non_zero) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn(&self, icb: &mut I) -> ::IResult { $impl(icb, self.rs1.nzx, self.rs2.nzx, self.rd.nzx); icb.ok(Next(self.width)) @@ -708,21 +702,23 @@ macro_rules! impl_r_type { } macro_rules! impl_i_type { - ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + ($fn: ident, non_zero) => { + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, ) -> Result { - core.hart.xregisters.$fn(self.imm, self.rs1.x, self.rd.x); + core.hart + .xregisters + .$fn(self.imm, self.rs1.nzx, self.rd.nzx); Ok(Next(self.width)) } }; ($fn: ident, non_zero_rd) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -735,8 +731,8 @@ macro_rules! impl_i_type { macro_rules! impl_fload_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -748,8 +744,8 @@ macro_rules! impl_fload_type { } macro_rules! impl_load_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -761,8 +757,8 @@ macro_rules! impl_load_type { } macro_rules! impl_cload_sp_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -773,8 +769,8 @@ macro_rules! impl_cload_sp_type { } macro_rules! impl_cfload_sp_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -786,8 +782,8 @@ macro_rules! impl_cfload_sp_type { macro_rules! impl_store_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -799,8 +795,8 @@ macro_rules! impl_store_type { } macro_rules! impl_fstore_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -813,8 +809,8 @@ macro_rules! impl_fstore_type { macro_rules! impl_b_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -826,8 +822,8 @@ macro_rules! impl_b_type { macro_rules! impl_amo_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -840,8 +836,8 @@ macro_rules! impl_amo_type { macro_rules! impl_ci_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -852,8 +848,8 @@ macro_rules! impl_ci_type { }; ($fn: ident, non_zero) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -866,8 +862,8 @@ macro_rules! impl_ci_type { macro_rules! impl_cr_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -880,8 +876,8 @@ macro_rules! impl_cr_type { macro_rules! impl_cr_nz_type { ($impl: path, $fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn(&self, icb: &mut I) -> ::IResult { $impl(icb, self.rd.nzx, self.rs2.nzx); icb.ok(Next(self.width)) @@ -891,8 +887,8 @@ macro_rules! impl_cr_nz_type { macro_rules! impl_cb_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -904,8 +900,8 @@ macro_rules! impl_cb_type { macro_rules! impl_css_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -917,8 +913,8 @@ macro_rules! impl_css_type { macro_rules! impl_fcss_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -930,8 +926,8 @@ macro_rules! impl_fcss_type { macro_rules! impl_csr_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -945,8 +941,8 @@ macro_rules! impl_csr_type { macro_rules! impl_csr_imm_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -960,8 +956,8 @@ macro_rules! impl_csr_imm_type { macro_rules! impl_f_x_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -973,8 +969,8 @@ macro_rules! impl_f_x_type { }; ($fn:ident, rm) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -988,8 +984,8 @@ macro_rules! impl_f_x_type { macro_rules! impl_x_f_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -1001,8 +997,8 @@ macro_rules! impl_x_f_type { }; ($fn:ident, rm) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -1016,8 +1012,8 @@ macro_rules! impl_x_f_type { macro_rules! impl_f_r_type { ($fn: ident) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -1029,8 +1025,8 @@ macro_rules! impl_f_r_type { }; ($fn: ident, (rd, x)) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -1042,8 +1038,8 @@ macro_rules! impl_f_r_type { }; ($fn: ident, rm) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -1055,8 +1051,8 @@ macro_rules! impl_f_r_type { }; ($fn: ident, (rs2, f), $($field: ident),+) => { - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn $fn( &self, core: &mut MachineCoreState, @@ -1087,7 +1083,7 @@ impl Args { impl_r_type!(run_sraw, non_zero_rd); // RV64I I-type instructions - impl_i_type!(run_addi); + impl_i_type!(run_addi, non_zero); impl_i_type!(run_addiw, non_zero_rd); impl_i_type!(run_xori, non_zero_rd); impl_i_type!(run_ori, non_zero_rd); @@ -1124,8 +1120,8 @@ impl Args { // RV64I U-type instructions // - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn run_lui( &self, core: &mut MachineCoreState, @@ -1134,8 +1130,8 @@ impl Args { Ok(Next(self.width)) } - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn run_auipc( &self, core: &mut MachineCoreState, @@ -1146,8 +1142,8 @@ impl Args { // RV64I jump instructions // - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn run_jal( &self, core: &mut MachineCoreState, @@ -1155,8 +1151,8 @@ impl Args { Ok(Set(core.hart.run_jal(self.imm, self.rd.x))) } - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn run_jalr( &self, core: &mut MachineCoreState, @@ -1286,8 +1282,6 @@ impl Args { impl_cb_type!(run_bnez); impl_ci_type!(run_li, non_zero); impl_ci_type!(run_clui, non_zero); - impl_ci_type!(run_caddi, non_zero); - impl_ci_type!(run_caddi4spn); impl_ci_type!(run_cslli, non_zero); impl_cr_type!(run_cand); impl_cr_type!(run_cxor); @@ -1295,16 +1289,6 @@ impl Args { impl_cr_type!(run_csub); impl_css_type!(run_cswsp); - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. - unsafe fn run_caddi16spn( - &self, - core: &mut MachineCoreState, - ) -> Result { - core.hart.xregisters.run_caddi16sp(self.imm); - Ok(Next(self.width)) - } - fn run_j( &self, core: &mut MachineCoreState, @@ -1312,8 +1296,8 @@ impl Args { Ok(Set(core.hart.run_j(self.imm))) } - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn run_cjr( &self, core: &mut MachineCoreState, @@ -1321,8 +1305,8 @@ impl Args { Ok(Set(core.hart.run_cjr(self.rs1.nzx))) } - // SAFETY: This function must only be called on an `Args` belonging - // to the same OpCode as the OpCode used to derive this function. + /// SAFETY: This function must only be called on an `Args` belonging + /// to the same OpCode as the OpCode used to derive this function. unsafe fn run_cjalr( &self, core: &mut MachineCoreState, @@ -1422,10 +1406,7 @@ impl From<&InstrCacheable> for Instruction { }, // RV64I I-type instructions - InstrCacheable::Addi(args) => Instruction { - opcode: OpCode::Addi, - args: args.to_args(InstrWidth::Uncompressed), - }, + InstrCacheable::Addi(args) => Instruction::from_ic_addi(args), InstrCacheable::Addiw(args) => Instruction { opcode: OpCode::Addiw, args: args.to_args(InstrWidth::Uncompressed), @@ -2032,18 +2013,16 @@ impl From<&InstrCacheable> for Instruction { opcode: OpCode::CLui, args: args.into(), }, - InstrCacheable::CAddi(args) => Instruction { - opcode: OpCode::CAddi, - args: args.into(), - }, - InstrCacheable::CAddi16sp(args) => Instruction { - opcode: OpCode::CAddi16sp, - args: args.into(), - }, - InstrCacheable::CAddi4spn(args) => Instruction { - opcode: OpCode::CAddi4spn, - args: args.into(), - }, + InstrCacheable::CAddi(args) => { + Instruction::new_addi(args.rd_rs1, args.rd_rs1, args.imm, InstrWidth::Compressed) + } + InstrCacheable::CAddi16sp(args) => Instruction::new_addi( + NonZeroXRegister::x2, + NonZeroXRegister::x2, + args.imm, + InstrWidth::Compressed, + ), + InstrCacheable::CAddi4spn(args) => Instruction::from_ic_caddi4spn(args), InstrCacheable::CSlli(args) => Instruction { opcode: OpCode::CSlli, args: args.into(), diff --git a/src/riscv/lib/src/machine_state/instruction/constructors.rs b/src/riscv/lib/src/machine_state/instruction/constructors.rs index c5d6b8249b7a80a4ceca0909e86ba43e17000ffb..c993571090bc7ad3c09e5f67807226594998c547 100644 --- a/src/riscv/lib/src/machine_state/instruction/constructors.rs +++ b/src/riscv/lib/src/machine_state/instruction/constructors.rs @@ -5,9 +5,9 @@ use super::{Args, Instruction, OpCode}; use crate::{ default::ConstDefault, - machine_state::registers::NonZeroXRegister, + machine_state::registers::{nz, NonZeroXRegister}, parser::{ - instruction::{InstrWidth, NonZeroRdRTypeArgs}, + instruction::{CIBTypeArgs, InstrWidth, NonZeroRdRTypeArgs, SplitITypeArgs}, split_x0, XRegisterParsed, }, }; @@ -54,7 +54,7 @@ impl Instruction { opcode: OpCode::Li, args: Args { rd: rd.into(), - // We are adding a default values for rs1 and rs2 as NonZeroXRegister::x1 + // We are adding default values for rs1 and rs2 as NonZeroXRegister::x1 // to be explicit that it is of NonZeroXRegister type. rs1: NonZeroXRegister::x1.into(), rs2: NonZeroXRegister::x1.into(), @@ -70,7 +70,7 @@ impl Instruction { Self { opcode: OpCode::Nop, args: Args { - // We are adding a default values for rd, rs1 and rs2 as NonZeroXRegister::x1 + // We are adding default values for rd, rs1 and rs2 as NonZeroXRegister::x1 // to be explicit that they are of NonZeroXRegister type. rd: NonZeroXRegister::x1.into(), rs1: NonZeroXRegister::x1.into(), @@ -80,6 +80,28 @@ impl Instruction { }, } } + + /// Create a new [`Instruction`] with the appropriate [`ArgsShape`] for the `Addi` [`OpCode`]. + pub(crate) fn new_addi( + rd: NonZeroXRegister, + rs1: NonZeroXRegister, + imm: i64, + width: InstrWidth, + ) -> Self { + Self { + opcode: OpCode::Addi, + args: Args { + rd: rd.into(), + rs1: rs1.into(), + // We are adding a default value for rs2 as NonZeroXRegister::x1 + // to be explicit that it is of NonZeroXRegister type. + rs2: NonZeroXRegister::x1.into(), + imm, + width, + ..Args::DEFAULT + }, + } + } } impl Instruction { @@ -96,4 +118,27 @@ impl Instruction { } } } + + /// Convert [`InstrCacheable::Addi`] according to whether registers are non-zero. + pub(super) fn from_ic_addi(args: &SplitITypeArgs) -> Instruction { + use XRegisterParsed as X; + match (args.rd, args.rs1) { + (X::X0, _) => Instruction::new_nop(InstrWidth::Uncompressed), + (X::NonZero(rd), X::X0) => Instruction::new_li(rd, args.imm, InstrWidth::Uncompressed), + (X::NonZero(rd), X::NonZero(rs1)) => { + Instruction::new_addi(rd, rs1, args.imm, InstrWidth::Uncompressed) + } + } + } + + /// Convert [`InstrCacheable::CAddi4spn`] according to whether register is non-zero. + pub(super) fn from_ic_caddi4spn(args: &CIBTypeArgs) -> Instruction { + use XRegisterParsed as X; + match split_x0(args.rd_rs1) { + X::X0 => Instruction::new_nop(InstrWidth::Compressed), + X::NonZero(rd_rs1) => { + Instruction::new_addi(rd_rs1, nz::sp, args.imm, InstrWidth::Compressed) + } + } + } } diff --git a/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs b/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs index eeb77fa39ff07b34371ea0a128c1fd50adab0c45..fa2515688e9441fb093d5662c20763a6853adced 100644 --- a/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs +++ b/src/riscv/lib/src/machine_state/instruction/tagged_instruction.rs @@ -329,14 +329,15 @@ pub enum ArgsShape { pub fn opcode_to_argsshape(opcode: &OpCode) -> ArgsShape { use OpCode::*; match opcode { - Addi | Lb | Lh | Lw | Lbu | Lhu | Lwu | Ld | Sb | Sh | Sw | Sd | Beq | Bne | Blt | Bge - | Bltu | Bgeu | Jal | Jalr | Lrw | Scw | Amoswapw | Amoaddw | Amoxorw | Amoandw - | Amoorw | Amominw | Amomaxw | Amominuw | Amomaxuw | Lrd | Scd | Amoswapd | Amoaddd - | Amoxord | Amoandd | Amoord | Amomind | Amomaxd | Amominud | Amomaxud | Rem | Remu - | Remw | Remuw | Div | Divu | Divw | Divuw | Mul | Mulh | Mulhsu | Mulhu | Mulw | Csrrw - | Csrrs | Csrrc | Csrrwi | Csrrsi | Csrrci | CLw | CSw | CSwsp | CAddi16sp | CAddi4spn - | CAnd | COr | CXor | CSub | CAddw | CSubw | CLd | CSd | CSdsp | Unknown | Beqz | Bnez - | J => ArgsShape::XSrcXDest, + Lb | Lh | Lw | Lbu | Lhu | Lwu | Ld | Sb | Sh | Sw | Sd | Beq | Bne | Blt | Bge | Bltu + | Bgeu | Jal | Jalr | Lrw | Scw | Amoswapw | Amoaddw | Amoxorw | Amoandw | Amoorw + | Amominw | Amomaxw | Amominuw | Amomaxuw | Lrd | Scd | Amoswapd | Amoaddd | Amoxord + | Amoandd | Amoord | Amomind | Amomaxd | Amominud | Amomaxud | Rem | Remu | Remw + | Remuw | Div | Divu | Divw | Divuw | Mul | Mulh | Mulhsu | Mulhu | Mulw | Csrrw + | Csrrs | Csrrc | Csrrwi | Csrrsi | Csrrci | CLw | CSw | CSwsp | CAnd | COr | CXor + | CSub | CAddw | CSubw | CLd | CSd | CSdsp | Unknown | Beqz | Bnez | J => { + ArgsShape::XSrcXDest + } Fadds | Fsubs | Fmuls | Fdivs | Fsqrts | Fmins | Fmaxs | Fsgnjs | Fsgnjns | Fsgnjxs | Fmadds | Fmsubs | Fnmsubs | Fnmadds | Faddd | Fsubd | Fmuld | Fdivd | Fsqrtd | Fmind @@ -351,7 +352,7 @@ pub fn opcode_to_argsshape(opcode: &OpCode) -> ArgsShape { Fsw | Fsd | CFsd | CFsdsp => ArgsShape::XSrcFSrc, - Add | Mv | CJr | CJalr | CAddi | CAddiw | Li | CLui | CSlli | CLdsp | CLwsp | Nop => { + Addi | Add | Mv | CJr | CJalr | CAddiw | Li | CLui | CSlli | CLdsp | CLwsp | Nop => { ArgsShape::NZXSrcNZXDest } diff --git a/src/riscv/lib/src/machine_state/registers.rs b/src/riscv/lib/src/machine_state/registers.rs index 7590f2de122424c35290b0e37cfceb5c559eb857..26fa52f9bc811731e154a06cd7bd8e9ec0474aab 100644 --- a/src/riscv/lib/src/machine_state/registers.rs +++ b/src/riscv/lib/src/machine_state/registers.rs @@ -333,7 +333,6 @@ impl NonZeroXRegister { } /// ABI register names for NonZeroXRegister types used in backend tests. -#[cfg(test)] pub mod nz { use super::NonZeroXRegister; diff --git a/src/riscv/lib/src/parser.rs b/src/riscv/lib/src/parser.rs index a32eaafbc827d4f99dce311dad3d2bc7696e7472..13bda6e2d5cf85a5ed8826ea70d1ce68dd3f6f96 100644 --- a/src/riscv/lib/src/parser.rs +++ b/src/riscv/lib/src/parser.rs @@ -508,7 +508,6 @@ pub const fn parse_uncompressed_instruction(instr: u32) -> Instr { // RV64I (Chapter 5.4) and RV64C (Chapter 16.7) describe the code points associated // with HINT instructions. We do not implement any HINT logic, but decode all these // as `Hint` or `HintCompresssed` opcodes, which we translate to NOPs in `machine_state`. - // TODO: RV-422: Pass known NonZero `rd` values to Args constructors. use XRegisterParsed::*; let i = match opcode(instr) { // R-type instructions @@ -612,10 +611,13 @@ pub const fn parse_uncompressed_instruction(instr: u32) -> Instr { OP_ARITH_I => match (funct3(instr), split_x0(rd(instr))) { (F3_0, X0) => match (split_x0(rs1(instr)), i_imm(instr)) { (X0, _) | (_, 0) => Hint { instr }, - (_rs1, _imm) => i_instr!(Addi, instr), + (rs1, imm) => Addi(instruction::SplitITypeArgs { rd: X0, rs1, imm }), }, - // TODO: RV-427 Deduplicate Addi and introduce specific constructor for its cases. - (F3_0, _rd) => i_instr!(Addi, instr), + (F3_0, rd) => Addi(instruction::SplitITypeArgs { + rd, + rs1: split_x0(rs1(instr)), + imm: i_imm(instr), + }), (F3_4, X0) => Hint { instr }, (F3_4, NonZero(rd)) => i_instr!(Xori, instr, rd), (F3_6, X0) => Hint { instr }, @@ -1403,10 +1405,10 @@ mod tests { use super::{ instruction::{ - CsrArgs, ITypeArgs, Instr, InstrCacheable::*, NonZeroRdITypeArgs, SBTypeArgs, - UJTypeArgs, + CsrArgs, Instr, InstrCacheable::*, NonZeroRdITypeArgs, SBTypeArgs, UJTypeArgs, }, parse_block, + XRegisterParsed::*, }; use crate::{ machine_state::{ @@ -1416,6 +1418,7 @@ mod tests { parser::{ instruction::{CIBNZTypeArgs, CIBTypeArgs, InstrUncacheable}, parse_compressed_instruction, parse_compressed_instruction_inner, NonZeroRdUJTypeArgs, + SplitITypeArgs, }, }; @@ -1439,9 +1442,9 @@ mod tests { rs1: x0, csr: mcause, })), - Instr::Cacheable(Addi(ITypeArgs { - rd: x31, - rs1: x0, + Instr::Cacheable(Addi(SplitITypeArgs { + rd: NonZero(NonZeroXRegister::x31), + rs1: X0, imm: 0x8, })), ]; @@ -1465,9 +1468,9 @@ mod tests { 0x0, 0x9b, 0x83, 0x3, 0x34, 0x63, 0x10, 0x74, 0x12, ]; let expected = [ - Instr::Cacheable(Addi(ITypeArgs { - rd: x3, - rs1: x0, + Instr::Cacheable(Addi(SplitITypeArgs { + rd: NonZero(NonZeroXRegister::x3), + rs1: X0, imm: 21, })), Instr::Cacheable(CLui(CIBNZTypeArgs { diff --git a/src/riscv/lib/src/parser/instruction.rs b/src/riscv/lib/src/parser/instruction.rs index 67a9c35933e2cdd151e98e69d6175ea4413c164f..7041955b22e8251df2baac4c8f5571f2bbc06561 100644 --- a/src/riscv/lib/src/parser/instruction.rs +++ b/src/riscv/lib/src/parser/instruction.rs @@ -3,6 +3,7 @@ // // SPDX-License-Identifier: MIT +use super::XRegisterParsed; use crate::{ default::ConstDefault, interpreter::float::RoundingMode, @@ -37,6 +38,13 @@ pub struct ITypeArgs { pub imm: i64, } +/// Intermediate representation of Args for I-type instructions with parsed split of registers. +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, serde::Serialize, serde::Deserialize)] +pub struct SplitITypeArgs { + pub(crate) rd: XRegisterParsed, + pub(crate) rs1: XRegisterParsed, + pub imm: i64, +} /// Intermediate representation of Args for I-type instructions with guaranteed `rd` != `x0`. #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, serde::Serialize, serde::Deserialize)] pub struct NonZeroRdITypeArgs { @@ -288,7 +296,8 @@ pub enum InstrCacheable { Sraw(NonZeroRdRTypeArgs), // RV64I I-type instructions - Addi(ITypeArgs), + /// `ADDI` - Add `imm` to val(rs1) and store the result in `rd`. + Addi(SplitITypeArgs), Addiw(NonZeroRdITypeArgs), Xori(NonZeroRdITypeArgs), Ori(NonZeroRdITypeArgs), @@ -457,8 +466,16 @@ pub enum InstrCacheable { /// `C.LI` - Loads the sign-extended 6-bit immediate into register `rd_rs1`. CLi(CIBNZTypeArgs), CLui(CIBNZTypeArgs), + /// `C.ADDI` - Adds the non-zero sign-extended 6-bit `imm` + /// to the value in `rd_rs1` then writes the result to `rd_rs1`. CAddi(CIBNZTypeArgs), + /// `C.ADDI16SP` - Adds the non-zero immediate to the value in the stack pointer. + /// The immediate is obtained by sign-extending and scaling by 16 the value + /// encoded in the instruction (see U:C-16.5). CAddi16sp(CJTypeArgs), + /// `C.ADDI4SPN`- Adds the non-zero immediate to the stack pointer and writes the result + /// to `rd`. The immediate is obtained by zero-extending and scaling by 4 the value + /// encoded in the instruction (see U:C-16.5). CAddi4spn(CIBTypeArgs), CSlli(CIBNZTypeArgs), CSrli(CIBTypeArgs), diff --git a/src/riscv/lib/tests/expected/jstz/state_hash_final b/src/riscv/lib/tests/expected/jstz/state_hash_final index 300e3c9e75242a6aba0ccd62e4eea3a56f58e8e2..a0f1a1470324fc7dae1ac9de053498f9342fc7ab 100644 --- a/src/riscv/lib/tests/expected/jstz/state_hash_final +++ b/src/riscv/lib/tests/expected/jstz/state_hash_final @@ -1 +1 @@ -Hash { digest: [134, 251, 171, 73, 20, 75, 244, 189, 12, 157, 121, 210, 196, 228, 1, 77, 175, 210, 206, 24, 56, 72, 50, 136, 90, 128, 142, 191, 126, 255, 140, 95] } +Hash { digest: [18, 125, 128, 4, 255, 142, 132, 177, 117, 110, 101, 2, 209, 79, 113, 172, 197, 114, 30, 60, 227, 163, 136, 60, 53, 99, 101, 63, 133, 57, 51, 177] }