From 44ded1a2588d93d6990d55eca93c8906ec658e95 Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Thu, 3 Oct 2024 09:47:52 +0100 Subject: [PATCH 1/2] RISC-V: dispatch run-fn from opcode --- src/riscv/lib/src/machine_state.rs | 401 +-- .../lib/src/machine_state/instruction.rs | 2175 +++++++++++++++++ 2 files changed, 2178 insertions(+), 398 deletions(-) create mode 100644 src/riscv/lib/src/machine_state/instruction.rs diff --git a/src/riscv/lib/src/machine_state.rs b/src/riscv/lib/src/machine_state.rs index 09507912d1f5..012261ba2ffc 100644 --- a/src/riscv/lib/src/machine_state.rs +++ b/src/riscv/lib/src/machine_state.rs @@ -11,6 +11,7 @@ pub mod bus; mod cache_layouts; pub mod csregisters; pub mod hart_state; +pub mod instruction; pub mod instruction_cache; pub mod mode; pub mod registers; @@ -19,9 +20,9 @@ pub mod reservation_set; #[cfg(test)] extern crate proptest; -use self::block_cache::BlockCache; pub use self::cache_layouts::{CacheLayouts, DefaultCacheLayouts, TestCacheLayouts}; use self::instruction_cache::InstructionCache; +use self::{block_cache::BlockCache, instruction::Instruction}; use crate::{ bits::u64, devicetree, @@ -123,83 +124,6 @@ pub struct StepManyResult { pub error: Option, } -/// Runs an R-type instruction over [`XRegisters`] -macro_rules! run_r_type_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .hart - .xregisters - .$run_fn($args.rs1, $args.rs2, $args.rd); - Ok(Next($instr.width())) - }}; -} - -/// Runs an I-type instruction over [`XRegisters`] -macro_rules! run_i_type_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .hart - .xregisters - .$run_fn($args.imm, $args.rs1, $args.rd); - Ok(Next($instr.width())) - }}; -} - -/// Runs a B-type instruction over [`HartState`] -macro_rules! run_b_type_instr { - ($state: ident, $args: ident, $run_fn: ident) => {{ - Ok($state.hart.$run_fn($args.imm, $args.rs1, $args.rs2)) - }}; -} - -/// Runs an U-type instruction over [`HartState`] -macro_rules! run_u_type_instr { - ($state: ident, $instr:ident, $args: ident, $($run_fn:ident).+) => {{ - // XXX: Funky syntax to capture xregister.run_fn identifier - // correctly since Rust doesn't like dots in macro arguments - $state.hart.$($run_fn).+($args.imm, $args.rd); - Ok(Next($instr.width())) - }}; -} - -/// Runs a load instruction -macro_rules! run_load_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .$run_fn($args.imm, $args.rs1, $args.rd) - .map(|_| Next($instr.width())) - }}; -} - -/// Runs a store instruction -macro_rules! run_store_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .$run_fn($args.imm, $args.rs1, $args.rs2) - .map(|_| Next($instr.width())) - }}; -} - -/// Runs a CSR instruction -macro_rules! run_csr_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .hart - .$run_fn($args.csr, $args.rs1, $args.rd) - .map(|_| Next($instr.width())) - }}; -} - -/// Runs a CSR imm instruction -macro_rules! run_csr_imm_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .hart - .$run_fn($args.csr, $args.imm as u64, $args.rd) - .map(|_| Next($instr.width())) - }}; -} - /// Runs a syscall instruction (ecall, ebreak) macro_rules! run_syscall_instr { ($state: ident, $run_fn: ident) => {{ @@ -222,82 +146,6 @@ macro_rules! run_no_args_instr { }}; } -/// Runs a F/D instruction over the hart state, touching both F & X registers. -macro_rules! run_f_x_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state.hart.$run_fn($args.rs1, $args.rd)?; - Ok(Next($instr.width())) - }}; - - ($state: ident, $instr: ident, $args: ident, $run_fn: ident, $rm:ident) => {{ - $state.hart.$run_fn($args.rs1, $args.$rm, $args.rd)?; - Ok(Next($instr.width())) - }}; -} - -/// Runs a F/D instruction over the hart state, touching both F & fcsr registers. -macro_rules! run_f_r_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state.hart.$run_fn($args.rs1, $args.rs2, $args.rd)?; - Ok(Next($instr.width())) - }}; - ($state: ident, $instr: ident, $args: ident, $run_fn: ident, $($field: ident),+) => {{ - $state.hart.$run_fn($args.rs1, $($args.$field,)* $args.rd)?; - Ok(Next($instr.width())) - }}; -} - -/// Runs an atomic instruction -/// Similar to R-type instructions, additionally passing the `rl` and `aq` bits -macro_rules! run_amo_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .$run_fn($args.rs1, $args.rs2, $args.rd, $args.rl, $args.aq) - .map(|_| Next($instr.width())) - }}; -} - -/// Runs a CR-type compressed instruction -macro_rules! run_cr_type_instr { - ($state: ident, $instr:ident, $args:ident, $run_fn: ident) => {{ - $state.hart.xregisters.$run_fn($args.rd_rs1, $args.rs2); - Ok(ProgramCounterUpdate::Next($instr.width())) - }}; -} - -/// Runs a CI-type compressed instruction -macro_rules! run_ci_type_instr { - ($state: ident, $instr:ident, $args:ident, $run_fn: ident) => {{ - $state.hart.xregisters.$run_fn($args.imm, $args.rd_rs1); - Ok(ProgramCounterUpdate::Next($instr.width())) - }}; -} - -/// Runs a CI-type compressed load instruction -macro_rules! run_ci_load_sp_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .$run_fn($args.imm, $args.rd_rs1) - .map(|_| Next($instr.width())) - }}; -} - -/// Runs a CI-type compressed load instruction -macro_rules! run_css_instr { - ($state: ident, $instr: ident, $args: ident, $run_fn: ident) => {{ - $state - .$run_fn($args.imm, $args.rs2) - .map(|_| Next($instr.width())) - }}; -} - -/// Runs a CB-type compressed instruction -macro_rules! run_cb_type_instr { - ($state: ident, $args: ident, $run_fn: ident) => {{ - Ok($state.hart.$run_fn($args.imm, $args.rd_rs1)) - }}; -} - impl MachineCoreState { /// Handle an [`Exception`] if one was risen during execution /// of an instruction (also known as synchronous exception) by taking a trap. @@ -386,250 +234,7 @@ impl MachineCoreStat where M: backend::ManagerReadWrite, { - use ProgramCounterUpdate::{Next, Set}; - - match instr { - // RV64I R-type instructions - InstrCacheable::Add(args) => run_r_type_instr!(self, instr, args, run_add), - InstrCacheable::Sub(args) => run_r_type_instr!(self, instr, args, run_sub), - InstrCacheable::Xor(args) => run_r_type_instr!(self, instr, args, run_xor), - InstrCacheable::Or(args) => run_r_type_instr!(self, instr, args, run_or), - InstrCacheable::And(args) => run_r_type_instr!(self, instr, args, run_and), - InstrCacheable::Sll(args) => run_r_type_instr!(self, instr, args, run_sll), - InstrCacheable::Srl(args) => run_r_type_instr!(self, instr, args, run_srl), - InstrCacheable::Sra(args) => run_r_type_instr!(self, instr, args, run_sra), - InstrCacheable::Slt(args) => run_r_type_instr!(self, instr, args, run_slt), - InstrCacheable::Sltu(args) => run_r_type_instr!(self, instr, args, run_sltu), - InstrCacheable::Addw(args) => run_r_type_instr!(self, instr, args, run_addw), - InstrCacheable::Subw(args) => run_r_type_instr!(self, instr, args, run_subw), - InstrCacheable::Sllw(args) => run_r_type_instr!(self, instr, args, run_sllw), - InstrCacheable::Srlw(args) => run_r_type_instr!(self, instr, args, run_srlw), - InstrCacheable::Sraw(args) => run_r_type_instr!(self, instr, args, run_sraw), - - // RV64I I-type instructions - InstrCacheable::Addi(args) => run_i_type_instr!(self, instr, args, run_addi), - InstrCacheable::Addiw(args) => run_i_type_instr!(self, instr, args, run_addiw), - InstrCacheable::Xori(args) => run_i_type_instr!(self, instr, args, run_xori), - InstrCacheable::Ori(args) => run_i_type_instr!(self, instr, args, run_ori), - InstrCacheable::Andi(args) => run_i_type_instr!(self, instr, args, run_andi), - InstrCacheable::Slli(args) => run_i_type_instr!(self, instr, args, run_slli), - InstrCacheable::Srli(args) => run_i_type_instr!(self, instr, args, run_srli), - InstrCacheable::Srai(args) => run_i_type_instr!(self, instr, args, run_srai), - InstrCacheable::Slliw(args) => run_i_type_instr!(self, instr, args, run_slliw), - InstrCacheable::Srliw(args) => run_i_type_instr!(self, instr, args, run_srliw), - InstrCacheable::Sraiw(args) => run_i_type_instr!(self, instr, args, run_sraiw), - InstrCacheable::Slti(args) => run_i_type_instr!(self, instr, args, run_slti), - InstrCacheable::Sltiu(args) => run_i_type_instr!(self, instr, args, run_sltiu), - InstrCacheable::Lb(args) => run_load_instr!(self, instr, args, run_lb), - InstrCacheable::Lh(args) => run_load_instr!(self, instr, args, run_lh), - InstrCacheable::Lw(args) => run_load_instr!(self, instr, args, run_lw), - InstrCacheable::Lbu(args) => run_load_instr!(self, instr, args, run_lbu), - InstrCacheable::Lhu(args) => run_load_instr!(self, instr, args, run_lhu), - InstrCacheable::Lwu(args) => run_load_instr!(self, instr, args, run_lwu), - InstrCacheable::Ld(args) => run_load_instr!(self, instr, args, run_ld), - - // RV64I S-type instructions - InstrCacheable::Sb(args) => run_store_instr!(self, instr, args, run_sb), - InstrCacheable::Sh(args) => run_store_instr!(self, instr, args, run_sh), - InstrCacheable::Sw(args) => run_store_instr!(self, instr, args, run_sw), - InstrCacheable::Sd(args) => run_store_instr!(self, instr, args, run_sd), - - // RV64I B-type instructions - InstrCacheable::Beq(args) => run_b_type_instr!(self, args, run_beq), - InstrCacheable::Bne(args) => run_b_type_instr!(self, args, run_bne), - InstrCacheable::Blt(args) => run_b_type_instr!(self, args, run_blt), - InstrCacheable::Bge(args) => run_b_type_instr!(self, args, run_bge), - InstrCacheable::Bltu(args) => run_b_type_instr!(self, args, run_bltu), - InstrCacheable::Bgeu(args) => run_b_type_instr!(self, args, run_bgeu), - - // RV64I U-type instructions - InstrCacheable::Lui(args) => run_u_type_instr!(self, instr, args, xregisters.run_lui), - InstrCacheable::Auipc(args) => run_u_type_instr!(self, instr, args, run_auipc), - - // RV64I jump instructions - InstrCacheable::Jal(args) => Ok(Set(self.hart.run_jal(args.imm, args.rd))), - InstrCacheable::Jalr(args) => Ok(Set(self.hart.run_jalr(args.imm, args.rs1, args.rd))), - - // RV64A atomic instructions - InstrCacheable::Lrw(args) => run_amo_instr!(self, instr, args, run_lrw), - InstrCacheable::Scw(args) => run_amo_instr!(self, instr, args, run_scw), - InstrCacheable::Amoswapw(args) => run_amo_instr!(self, instr, args, run_amoswapw), - InstrCacheable::Amoaddw(args) => run_amo_instr!(self, instr, args, run_amoaddw), - InstrCacheable::Amoxorw(args) => run_amo_instr!(self, instr, args, run_amoxorw), - InstrCacheable::Amoandw(args) => run_amo_instr!(self, instr, args, run_amoandw), - InstrCacheable::Amoorw(args) => run_amo_instr!(self, instr, args, run_amoorw), - InstrCacheable::Amominw(args) => run_amo_instr!(self, instr, args, run_amominw), - InstrCacheable::Amomaxw(args) => run_amo_instr!(self, instr, args, run_amomaxw), - InstrCacheable::Amominuw(args) => run_amo_instr!(self, instr, args, run_amominuw), - InstrCacheable::Amomaxuw(args) => run_amo_instr!(self, instr, args, run_amomaxuw), - InstrCacheable::Lrd(args) => run_amo_instr!(self, instr, args, run_lrd), - InstrCacheable::Scd(args) => run_amo_instr!(self, instr, args, run_scd), - InstrCacheable::Amoswapd(args) => run_amo_instr!(self, instr, args, run_amoswapd), - InstrCacheable::Amoaddd(args) => run_amo_instr!(self, instr, args, run_amoaddd), - InstrCacheable::Amoxord(args) => run_amo_instr!(self, instr, args, run_amoxord), - InstrCacheable::Amoandd(args) => run_amo_instr!(self, instr, args, run_amoandd), - InstrCacheable::Amoord(args) => run_amo_instr!(self, instr, args, run_amoord), - InstrCacheable::Amomind(args) => run_amo_instr!(self, instr, args, run_amomind), - InstrCacheable::Amomaxd(args) => run_amo_instr!(self, instr, args, run_amomaxd), - InstrCacheable::Amominud(args) => run_amo_instr!(self, instr, args, run_amominud), - InstrCacheable::Amomaxud(args) => run_amo_instr!(self, instr, args, run_amomaxud), - - // RV64M multiplication and division instructions - InstrCacheable::Rem(args) => run_r_type_instr!(self, instr, args, run_rem), - InstrCacheable::Remu(args) => run_r_type_instr!(self, instr, args, run_remu), - InstrCacheable::Remw(args) => run_r_type_instr!(self, instr, args, run_remw), - InstrCacheable::Remuw(args) => run_r_type_instr!(self, instr, args, run_remuw), - InstrCacheable::Div(args) => run_r_type_instr!(self, instr, args, run_div), - InstrCacheable::Divu(args) => run_r_type_instr!(self, instr, args, run_divu), - InstrCacheable::Divw(args) => run_r_type_instr!(self, instr, args, run_divw), - InstrCacheable::Divuw(args) => run_r_type_instr!(self, instr, args, run_divuw), - InstrCacheable::Mul(args) => run_r_type_instr!(self, instr, args, run_mul), - InstrCacheable::Mulh(args) => run_r_type_instr!(self, instr, args, run_mulh), - InstrCacheable::Mulhsu(args) => run_r_type_instr!(self, instr, args, run_mulhsu), - InstrCacheable::Mulhu(args) => run_r_type_instr!(self, instr, args, run_mulhu), - InstrCacheable::Mulw(args) => run_r_type_instr!(self, instr, args, run_mulw), - - // RV64F instructions - InstrCacheable::FclassS(args) => run_f_x_instr!(self, instr, args, run_fclass_s), - InstrCacheable::Feqs(args) => run_f_r_instr!(self, instr, args, run_feq_s), - InstrCacheable::Fles(args) => run_f_r_instr!(self, instr, args, run_fle_s), - InstrCacheable::Flts(args) => run_f_r_instr!(self, instr, args, run_flt_s), - InstrCacheable::Fadds(args) => run_f_r_instr!(self, instr, args, run_fadd_s, rs2, rm), - InstrCacheable::Fsubs(args) => run_f_r_instr!(self, instr, args, run_fsub_s, rs2, rm), - InstrCacheable::Fmuls(args) => run_f_r_instr!(self, instr, args, run_fmul_s, rs2, rm), - InstrCacheable::Fdivs(args) => run_f_r_instr!(self, instr, args, run_fdiv_s, rs2, rm), - InstrCacheable::Fsqrts(args) => run_f_r_instr!(self, instr, args, run_fsqrt_s, rm), - InstrCacheable::Fmins(args) => run_f_r_instr!(self, instr, args, run_fmin_s), - InstrCacheable::Fmaxs(args) => run_f_r_instr!(self, instr, args, run_fmax_s), - InstrCacheable::Fmadds(args) => { - run_f_r_instr!(self, instr, args, run_fmadd_s, rs2, rs3, rm) - } - InstrCacheable::Fmsubs(args) => { - run_f_r_instr!(self, instr, args, run_fmsub_s, rs2, rs3, rm) - } - InstrCacheable::Fnmsubs(args) => { - run_f_r_instr!(self, instr, args, run_fnmsub_s, rs2, rs3, rm) - } - InstrCacheable::Fnmadds(args) => { - run_f_r_instr!(self, instr, args, run_fnmadd_s, rs2, rs3, rm) - } - InstrCacheable::Flw(args) => run_load_instr!(self, instr, args, run_flw), - InstrCacheable::Fsw(args) => run_store_instr!(self, instr, args, run_fsw), - InstrCacheable::Fcvtsw(args) => run_f_x_instr!(self, instr, args, run_fcvt_s_w, rm), - InstrCacheable::Fcvtswu(args) => run_f_x_instr!(self, instr, args, run_fcvt_s_wu, rm), - InstrCacheable::Fcvtsl(args) => run_f_x_instr!(self, instr, args, run_fcvt_s_l, rm), - InstrCacheable::Fcvtslu(args) => run_f_x_instr!(self, instr, args, run_fcvt_s_lu, rm), - InstrCacheable::Fcvtws(args) => run_f_x_instr!(self, instr, args, run_fcvt_w_s, rm), - InstrCacheable::Fcvtwus(args) => run_f_x_instr!(self, instr, args, run_fcvt_wu_s, rm), - InstrCacheable::Fcvtls(args) => run_f_x_instr!(self, instr, args, run_fcvt_l_s, rm), - InstrCacheable::Fcvtlus(args) => run_f_x_instr!(self, instr, args, run_fcvt_lu_s, rm), - InstrCacheable::Fsgnjs(args) => run_f_r_instr!(self, instr, args, run_fsgnj_s), - InstrCacheable::Fsgnjns(args) => run_f_r_instr!(self, instr, args, run_fsgnjn_s), - InstrCacheable::Fsgnjxs(args) => run_f_r_instr!(self, instr, args, run_fsgnjx_s), - InstrCacheable::FmvXW(args) => run_f_x_instr!(self, instr, args, run_fmv_x_w), - InstrCacheable::FmvWX(args) => run_f_x_instr!(self, instr, args, run_fmv_w_x), - - // RV64D instructions - InstrCacheable::FclassD(args) => run_f_x_instr!(self, instr, args, run_fclass_d), - InstrCacheable::Feqd(args) => run_f_r_instr!(self, instr, args, run_feq_d), - InstrCacheable::Fled(args) => run_f_r_instr!(self, instr, args, run_fle_d), - InstrCacheable::Fltd(args) => run_f_r_instr!(self, instr, args, run_flt_d), - InstrCacheable::Faddd(args) => run_f_r_instr!(self, instr, args, run_fadd_d, rs2, rm), - InstrCacheable::Fsubd(args) => run_f_r_instr!(self, instr, args, run_fsub_d, rs2, rm), - InstrCacheable::Fmuld(args) => run_f_r_instr!(self, instr, args, run_fmul_d, rs2, rm), - InstrCacheable::Fdivd(args) => run_f_r_instr!(self, instr, args, run_fdiv_d, rs2, rm), - InstrCacheable::Fsqrtd(args) => run_f_r_instr!(self, instr, args, run_fsqrt_d, rm), - InstrCacheable::Fmind(args) => run_f_r_instr!(self, instr, args, run_fmin_d), - InstrCacheable::Fmaxd(args) => run_f_r_instr!(self, instr, args, run_fmax_d), - InstrCacheable::Fmaddd(args) => { - run_f_r_instr!(self, instr, args, run_fmadd_d, rs2, rs3, rm) - } - InstrCacheable::Fmsubd(args) => { - run_f_r_instr!(self, instr, args, run_fmsub_d, rs2, rs3, rm) - } - InstrCacheable::Fnmsubd(args) => { - run_f_r_instr!(self, instr, args, run_fnmsub_d, rs2, rs3, rm) - } - InstrCacheable::Fnmaddd(args) => { - run_f_r_instr!(self, instr, args, run_fnmadd_d, rs2, rs3, rm) - } - InstrCacheable::Fld(args) => run_load_instr!(self, instr, args, run_fld), - InstrCacheable::Fsd(args) => run_store_instr!(self, instr, args, run_fsd), - InstrCacheable::Fcvtdw(args) => run_f_x_instr!(self, instr, args, run_fcvt_d_w, rm), - InstrCacheable::Fcvtdwu(args) => run_f_x_instr!(self, instr, args, run_fcvt_d_wu, rm), - InstrCacheable::Fcvtdl(args) => run_f_x_instr!(self, instr, args, run_fcvt_d_l, rm), - InstrCacheable::Fcvtdlu(args) => run_f_x_instr!(self, instr, args, run_fcvt_d_lu, rm), - InstrCacheable::Fcvtds(args) => run_f_r_instr!(self, instr, args, run_fcvt_d_s, rm), - InstrCacheable::Fcvtsd(args) => run_f_r_instr!(self, instr, args, run_fcvt_s_d, rm), - InstrCacheable::Fcvtwd(args) => run_f_x_instr!(self, instr, args, run_fcvt_w_d, rm), - InstrCacheable::Fcvtwud(args) => run_f_x_instr!(self, instr, args, run_fcvt_wu_d, rm), - InstrCacheable::Fcvtld(args) => run_f_x_instr!(self, instr, args, run_fcvt_l_d, rm), - InstrCacheable::Fcvtlud(args) => run_f_x_instr!(self, instr, args, run_fcvt_lu_d, rm), - InstrCacheable::Fsgnjd(args) => run_f_r_instr!(self, instr, args, run_fsgnj_d), - InstrCacheable::Fsgnjnd(args) => run_f_r_instr!(self, instr, args, run_fsgnjn_d), - InstrCacheable::Fsgnjxd(args) => run_f_r_instr!(self, instr, args, run_fsgnjx_d), - InstrCacheable::FmvXD(args) => run_f_x_instr!(self, instr, args, run_fmv_x_d), - InstrCacheable::FmvDX(args) => run_f_x_instr!(self, instr, args, run_fmv_d_x), - - // Zicsr instructions - InstrCacheable::Csrrw(args) => run_csr_instr!(self, instr, args, run_csrrw), - InstrCacheable::Csrrs(args) => run_csr_instr!(self, instr, args, run_csrrs), - InstrCacheable::Csrrc(args) => run_csr_instr!(self, instr, args, run_csrrc), - InstrCacheable::Csrrwi(args) => run_csr_imm_instr!(self, instr, args, run_csrrwi), - InstrCacheable::Csrrsi(args) => run_csr_imm_instr!(self, instr, args, run_csrrsi), - InstrCacheable::Csrrci(args) => run_csr_imm_instr!(self, instr, args, run_csrrci), - - // RV32C compressed instructions - InstrCacheable::CLw(args) => run_load_instr!(self, instr, args, run_clw), - InstrCacheable::CLwsp(args) => run_ci_load_sp_instr!(self, instr, args, run_clwsp), - InstrCacheable::CSw(args) => run_store_instr!(self, instr, args, run_csw), - InstrCacheable::CSwsp(args) => run_css_instr!(self, instr, args, run_cswsp), - InstrCacheable::CJ(args) => Ok(Set(self.hart.run_cj(args.imm))), - InstrCacheable::CJr(args) => Ok(Set(self.hart.run_cjr(args.rs1))), - InstrCacheable::CJalr(args) => Ok(Set(self.hart.run_cjalr(args.rs1))), - InstrCacheable::CBeqz(args) => run_cb_type_instr!(self, args, run_cbeqz), - InstrCacheable::CBnez(args) => run_cb_type_instr!(self, args, run_cbnez), - InstrCacheable::CLi(args) => run_ci_type_instr!(self, instr, args, run_cli), - InstrCacheable::CLui(args) => run_ci_type_instr!(self, instr, args, run_clui), - InstrCacheable::CAddi(args) => run_ci_type_instr!(self, instr, args, run_caddi), - InstrCacheable::CAddi16sp(args) => { - self.hart.xregisters.run_caddi16sp(args.imm); - Ok(ProgramCounterUpdate::Next(instr.width())) - } - InstrCacheable::CAddi4spn(args) => run_ci_type_instr!(self, instr, args, run_caddi4spn), - InstrCacheable::CSlli(args) => run_ci_type_instr!(self, instr, args, run_cslli), - InstrCacheable::CSrli(args) => run_ci_type_instr!(self, instr, args, run_csrli), - InstrCacheable::CSrai(args) => run_ci_type_instr!(self, instr, args, run_csrai), - InstrCacheable::CAndi(args) => run_ci_type_instr!(self, instr, args, run_candi), - InstrCacheable::CMv(args) => run_cr_type_instr!(self, instr, args, run_cmv), - InstrCacheable::CAdd(args) => run_cr_type_instr!(self, instr, args, run_cadd), - InstrCacheable::CAnd(args) => run_cr_type_instr!(self, instr, args, run_cand), - InstrCacheable::CXor(args) => run_cr_type_instr!(self, instr, args, run_cxor), - InstrCacheable::COr(args) => run_cr_type_instr!(self, instr, args, run_cor), - InstrCacheable::CSub(args) => run_cr_type_instr!(self, instr, args, run_csub), - InstrCacheable::CNop => { - self.run_cnop(); - Ok(ProgramCounterUpdate::Next(instr.width())) - } - - // RV64C compressed instructions - InstrCacheable::CLd(args) => run_load_instr!(self, instr, args, run_cld), - InstrCacheable::CLdsp(args) => run_ci_load_sp_instr!(self, instr, args, run_cldsp), - InstrCacheable::CSd(args) => run_store_instr!(self, instr, args, run_csd), - InstrCacheable::CSdsp(args) => run_css_instr!(self, instr, args, run_csdsp), - InstrCacheable::CAddiw(args) => run_ci_type_instr!(self, instr, args, run_caddiw), - InstrCacheable::CAddw(args) => run_cr_type_instr!(self, instr, args, run_caddw), - InstrCacheable::CSubw(args) => run_cr_type_instr!(self, instr, args, run_csubw), - - // RV64DC compressed instructions - InstrCacheable::CFld(args) => run_load_instr!(self, instr, args, run_cfld), - InstrCacheable::CFldsp(args) => run_ci_load_sp_instr!(self, instr, args, run_cfldsp), - InstrCacheable::CFsd(args) => run_store_instr!(self, instr, args, run_cfsd), - InstrCacheable::CFsdsp(args) => run_css_instr!(self, instr, args, run_cfsdsp), - - InstrCacheable::Unknown { instr: _ } => Err(Exception::IllegalInstruction), - InstrCacheable::UnknownCompressed { instr: _ } => Err(Exception::IllegalInstruction), - } + Instruction::from(instr).run(self) } } diff --git a/src/riscv/lib/src/machine_state/instruction.rs b/src/riscv/lib/src/machine_state/instruction.rs new file mode 100644 index 000000000000..03f0c5896dc7 --- /dev/null +++ b/src/riscv/lib/src/machine_state/instruction.rs @@ -0,0 +1,2175 @@ +// SPDX-FileCopyrightText: 2024 TriliTech +// +// SPDX-License-Identifier: MIT + +//! A replacement for [`InstrCacheable`] instructions. +//! +//! Rather than dispatching on a giant instruction enum, we instead split the instruction into +//! two: an [`OpCode`] and an [`Args`]. +//! +//! This allows us to dispatch the operation over the state directly from the opcode - both a +//! simpler match statement and, ultimately, paves the way to pre-dispatch these functions +//! when blocks are built in the block cache. This avoids the runtime overhead caused by +//! dispatching every time an instruction is run. + +use super::{ + bus::main_memory::MainMemoryLayout, + csregisters::CSRegister, + registers::{FRegister, XRegister}, + MachineCoreState, ProgramCounterUpdate, +}; +use crate::{ + machine_state::ProgramCounterUpdate::{Next, Set}, + parser::instruction::{ + AmoArgs, CIBDTypeArgs, CIBTypeArgs, CJTypeArgs, CRJTypeArgs, CRTypeArgs, CSSDTypeArgs, + CSSTypeArgs, CsrArgs, CsriArgs, FCmpArgs, FLoadArgs, FR1ArgWithRounding, + FR2ArgsWithRounding, FR3ArgsWithRounding, FRArgs, FRegToXRegArgs, + FRegToXRegArgsWithRounding, FStoreArgs, ITypeArgs, InstrCacheable, InstrRoundingMode, + InstrWidth, RTypeArgs, SBTypeArgs, UJTypeArgs, XRegToFRegArgs, XRegToFRegArgsWithRounding, + }, + state_backend::{ManagerBase, ManagerReadWrite}, + traps::Exception, +}; +use serde::{Deserialize, Serialize}; + +/// An instruction formed of an opcode and flat arguments. +/// +/// This is preferred within the caches, as it enables 'pre-dispatch' of functions +/// at block construction, rather than during block execution. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub struct Instruction { + /// The operation (over the machine state) that this instruction represents. + pub opcode: OpCode, + /// Arguments that are passed to the opcode-function. As a flat structure, it contains + /// all possible arguments. Each instruction will only use a subset. + pub args: Args, +} + +/// Opcodes map to the operation performed over the state - allowing us to +/// decouple these from the parsed instructions down the line. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +pub enum OpCode { + // RV64I R-type instructions + Add, + Sub, + Xor, + Or, + And, + Sll, + Srl, + Sra, + Slt, + Sltu, + Addw, + Subw, + Sllw, + Srlw, + Sraw, + + // RV64I I-type instructions + Addi, + Addiw, + Xori, + Ori, + Andi, + Slli, + Srli, + Srai, + Slliw, + Srliw, + Sraiw, + Slti, + Sltiu, + Lb, + Lh, + Lw, + Lbu, + Lhu, + Lwu, + Ld, + + // RV64I S-type instructions + Sb, + Sh, + Sw, + Sd, + + // RV64I B-type instructions + Beq, + Bne, + Blt, + Bge, + Bltu, + Bgeu, + + // RV64I U-type instructions + Lui, + Auipc, + + // RV64I jump instructions + Jal, + Jalr, + + // RV64A R-type atomic instructions + Lrw, + Scw, + Amoswapw, + Amoaddw, + Amoxorw, + Amoandw, + Amoorw, + Amominw, + Amomaxw, + Amominuw, + Amomaxuw, + Lrd, + Scd, + Amoswapd, + Amoaddd, + Amoxord, + Amoandd, + Amoord, + Amomind, + Amomaxd, + Amominud, + Amomaxud, + + // RV64M division instructions + Rem, + Remu, + Remw, + Remuw, + Div, + Divu, + Divw, + Divuw, + Mul, + Mulh, + Mulhsu, + Mulhu, + Mulw, + + // RV64F instructions + FclassS, + Feqs, + Fles, + Flts, + Fadds, + Fsubs, + Fmuls, + Fdivs, + Fsqrts, + Fmins, + Fmaxs, + Fmadds, + Fmsubs, + Fnmsubs, + Fnmadds, + Flw, + Fsw, + Fcvtsw, + Fcvtswu, + Fcvtsl, + Fcvtslu, + Fcvtws, + Fcvtwus, + Fcvtls, + Fcvtlus, + Fsgnjs, + Fsgnjns, + Fsgnjxs, + FmvXW, + FmvWX, + + // RV64D instructions + FclassD, + Feqd, + Fled, + Fltd, + Faddd, + Fsubd, + Fmuld, + Fdivd, + Fsqrtd, + Fmind, + Fmaxd, + Fmaddd, + Fmsubd, + Fnmsubd, + Fnmaddd, + Fld, + Fsd, + Fcvtdw, + Fcvtdwu, + Fcvtdl, + Fcvtdlu, + Fcvtds, + Fcvtsd, + Fcvtwd, + Fcvtwud, + Fcvtld, + Fcvtlud, + Fsgnjd, + Fsgnjnd, + Fsgnjxd, + FmvXD, + FmvDX, + + // Zicsr instructions + Csrrw, + Csrrs, + Csrrc, + Csrrwi, + Csrrsi, + Csrrci, + + // RV32C compressed instructions + CLw, + CLwsp, + CSw, + CSwsp, + CJ, + CJr, + CJalr, + CBeqz, + CBnez, + CLi, + CLui, + CAddi, + CAddi16sp, + CAddi4spn, + CSlli, + CSrli, + CSrai, + CAndi, + CMv, + CAdd, + CAnd, + COr, + CXor, + CSub, + CAddw, + CSubw, + CNop, + + // RV64C compressed instructions + CLd, + CLdsp, + CSd, + CSdsp, + CAddiw, + + // RV64DC compressed instructions + CFld, + CFldsp, + CFsd, + CFsdsp, + + Unknown, + UnknownCompressed, +} + +impl OpCode { + /// Dispatch an opcode to the function that will run over the machine state. + #[inline(always)] + fn to_run( + self, + ) -> fn(&Args, &mut MachineCoreState) -> Result { + match self { + Self::Add => Args::run_add, + Self::Sub => Args::run_sub, + Self::Xor => Args::run_xor, + Self::Or => Args::run_or, + Self::And => Args::run_and, + Self::Sll => Args::run_sll, + Self::Srl => Args::run_srl, + Self::Sra => Args::run_sra, + Self::Slt => Args::run_slt, + Self::Sltu => Args::run_sltu, + Self::Addw => Args::run_addw, + Self::Subw => Args::run_subw, + Self::Sllw => Args::run_sllw, + Self::Srlw => Args::run_srlw, + Self::Sraw => Args::run_sraw, + Self::Addi => Args::run_addi, + Self::Addiw => Args::run_addiw, + Self::Xori => Args::run_xori, + Self::Ori => Args::run_ori, + Self::Andi => Args::run_andi, + Self::Slli => Args::run_slli, + Self::Srli => Args::run_srli, + Self::Srai => Args::run_srai, + Self::Slliw => Args::run_slliw, + Self::Srliw => Args::run_srliw, + Self::Sraiw => Args::run_sraiw, + Self::Slti => Args::run_slti, + Self::Sltiu => Args::run_sltiu, + Self::Lb => Args::run_lb, + Self::Lh => Args::run_lh, + Self::Lw => Args::run_lw, + Self::Lbu => Args::run_lbu, + Self::Lhu => Args::run_lhu, + Self::Lwu => Args::run_lwu, + Self::Ld => Args::run_ld, + Self::Sb => Args::run_sb, + Self::Sh => Args::run_sh, + Self::Sw => Args::run_sw, + Self::Sd => Args::run_sd, + Self::Beq => Args::run_beq, + Self::Bne => Args::run_bne, + Self::Blt => Args::run_blt, + Self::Bge => Args::run_bge, + Self::Bltu => Args::run_bltu, + Self::Bgeu => Args::run_bgeu, + Self::Lui => Args::run_lui, + Self::Auipc => Args::run_auipc, + Self::Jal => Args::run_jal, + Self::Jalr => Args::run_jalr, + Self::Lrw => Args::run_lrw, + Self::Scw => Args::run_scw, + Self::Amoswapw => Args::run_amoswapw, + Self::Amoaddw => Args::run_amoaddw, + Self::Amoxorw => Args::run_amoxorw, + Self::Amoandw => Args::run_amoandw, + Self::Amoorw => Args::run_amoorw, + Self::Amominw => Args::run_amominw, + Self::Amomaxw => Args::run_amomaxw, + Self::Amominuw => Args::run_amominuw, + Self::Amomaxuw => Args::run_amomaxuw, + Self::Lrd => Args::run_lrd, + Self::Scd => Args::run_scd, + Self::Amoswapd => Args::run_amoswapd, + Self::Amoaddd => Args::run_amoaddd, + Self::Amoxord => Args::run_amoxord, + Self::Amoandd => Args::run_amoandd, + Self::Amoord => Args::run_amoord, + Self::Amomind => Args::run_amomind, + Self::Amomaxd => Args::run_amomaxd, + Self::Amominud => Args::run_amominud, + Self::Amomaxud => Args::run_amomaxud, + Self::Rem => Args::run_rem, + Self::Remu => Args::run_remu, + Self::Remw => Args::run_remw, + Self::Remuw => Args::run_remuw, + Self::Div => Args::run_div, + Self::Divu => Args::run_divu, + Self::Divw => Args::run_divw, + Self::Divuw => Args::run_divuw, + Self::Mul => Args::run_mul, + Self::Mulh => Args::run_mulh, + Self::Mulhsu => Args::run_mulhsu, + Self::Mulhu => Args::run_mulhu, + Self::Mulw => Args::run_mulw, + Self::FclassS => Args::run_fclass_s, + Self::Feqs => Args::run_feq_s, + Self::Fles => Args::run_fle_s, + Self::Flts => Args::run_flt_s, + Self::Fadds => Args::run_fadd_s, + Self::Fsubs => Args::run_fsub_s, + Self::Fmuls => Args::run_fmul_s, + Self::Fdivs => Args::run_fdiv_s, + Self::Fsqrts => Args::run_fsqrt_s, + Self::Fmins => Args::run_fmin_s, + Self::Fmaxs => Args::run_fmax_s, + Self::Fmadds => Args::run_fmadd_s, + Self::Fmsubs => Args::run_fmsub_s, + Self::Fnmsubs => Args::run_fnmsub_s, + Self::Fnmadds => Args::run_fnmadd_s, + Self::Flw => Args::run_flw, + Self::Fsw => Args::run_fsw, + Self::Fcvtsw => Args::run_fcvt_s_w, + Self::Fcvtswu => Args::run_fcvt_s_wu, + Self::Fcvtsl => Args::run_fcvt_s_l, + Self::Fcvtslu => Args::run_fcvt_s_lu, + Self::Fcvtws => Args::run_fcvt_w_s, + Self::Fcvtwus => Args::run_fcvt_wu_s, + Self::Fcvtls => Args::run_fcvt_l_s, + Self::Fcvtlus => Args::run_fcvt_lu_s, + Self::Fsgnjs => Args::run_fsgnj_s, + Self::Fsgnjns => Args::run_fsgnjn_s, + Self::Fsgnjxs => Args::run_fsgnjx_s, + Self::FmvXW => Args::run_fmv_x_w, + Self::FmvWX => Args::run_fmv_w_x, + Self::FclassD => Args::run_fclass_d, + Self::Feqd => Args::run_feq_d, + Self::Fled => Args::run_fle_d, + Self::Fltd => Args::run_flt_d, + Self::Faddd => Args::run_fadd_d, + Self::Fsubd => Args::run_fsub_d, + Self::Fmuld => Args::run_fmul_d, + Self::Fdivd => Args::run_fdiv_d, + Self::Fsqrtd => Args::run_fsqrt_d, + Self::Fmind => Args::run_fmin_d, + Self::Fmaxd => Args::run_fmax_d, + Self::Fmaddd => Args::run_fmadd_d, + Self::Fmsubd => Args::run_fmsub_d, + Self::Fnmsubd => Args::run_fnmsub_d, + Self::Fnmaddd => Args::run_fnmadd_d, + Self::Fld => Args::run_fld, + Self::Fsd => Args::run_fsd, + Self::Fcvtdw => Args::run_fcvt_d_w, + Self::Fcvtdwu => Args::run_fcvt_d_wu, + Self::Fcvtdl => Args::run_fcvt_d_l, + Self::Fcvtdlu => Args::run_fcvt_d_lu, + Self::Fcvtds => Args::run_fcvt_d_s, + Self::Fcvtsd => Args::run_fcvt_s_d, + Self::Fcvtwd => Args::run_fcvt_w_d, + Self::Fcvtwud => Args::run_fcvt_wu_d, + Self::Fcvtld => Args::run_fcvt_l_d, + Self::Fcvtlud => Args::run_fcvt_lu_d, + Self::Fsgnjd => Args::run_fsgnj_d, + Self::Fsgnjnd => Args::run_fsgnjn_d, + Self::Fsgnjxd => Args::run_fsgnjx_d, + Self::FmvXD => Args::run_fmv_x_d, + Self::FmvDX => Args::run_fmv_d_x, + Self::Csrrw => Args::run_csrrw, + Self::Csrrs => Args::run_csrrs, + Self::Csrrc => Args::run_csrrc, + Self::Csrrwi => Args::run_csrrwi, + Self::Csrrsi => Args::run_csrrsi, + Self::Csrrci => Args::run_csrrci, + Self::CLw => Args::run_clw, + Self::CLwsp => Args::run_clwsp, + Self::CSw => Args::run_csw, + Self::CSwsp => Args::run_cswsp, + Self::CJ => Args::run_cj, + Self::CJr => Args::run_cjr, + Self::CJalr => Args::run_cjalr, + Self::CBeqz => Args::run_cbeqz, + Self::CBnez => Args::run_cbnez, + Self::CLi => Args::run_cli, + 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::CSrli => Args::run_csrli, + Self::CSrai => Args::run_csrai, + Self::CAndi => Args::run_candi, + Self::CMv => Args::run_cmv, + Self::CAdd => Args::run_cadd, + Self::CAnd => Args::run_cand, + Self::COr => Args::run_cor, + Self::CXor => Args::run_cxor, + Self::CSub => Args::run_csub, + Self::CAddw => Args::run_caddw, + Self::CSubw => Args::run_csubw, + Self::CNop => Args::run_cnop, + Self::CLd => Args::run_cld, + Self::CLdsp => Args::run_cldsp, + Self::CSd => Args::run_csd, + Self::CSdsp => Args::run_csdsp, + Self::CAddiw => Args::run_caddiw, + Self::CFld => Args::run_cfld, + Self::CFldsp => Args::run_cfldsp, + Self::CFsd => Args::run_cfsd, + Self::CFsdsp => Args::run_cfsdsp, + Self::Unknown => Args::run_illegal, + Self::UnknownCompressed => Args::run_illegal, + } + } +} + +impl Instruction { + /// Run an instruction over the machine core state. + pub(super) fn run( + &self, + core: &mut MachineCoreState, + ) -> Result { + (self.opcode.to_run())(&self.args, core) + } +} + +/// Contains all possible arguments used by opcode-functions. +/// +/// Each opcode will only touch a subset of these. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +pub struct Args { + pub rd: XRegister, + pub rs1: XRegister, + pub rs2: XRegister, + pub imm: i64, + pub csr: CSRegister, + pub rdf: FRegister, + pub rs1f: FRegister, + pub rs2f: FRegister, + pub rs3f: FRegister, + pub rm: InstrRoundingMode, + pub aq: bool, + pub rl: bool, +} + +impl Default for Args { + fn default() -> Self { + Self { + rd: XRegister::x0, + rs1: XRegister::x0, + rs2: XRegister::x0, + imm: 0, + csr: CSRegister::fflags, + rdf: FRegister::f0, + rs1f: FRegister::f0, + rs2f: FRegister::f0, + rs3f: FRegister::f0, + rm: InstrRoundingMode::Dynamic, + aq: false, + rl: false, + } + } +} + +macro_rules! impl_r_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.xregisters.$fn(self.rs1, self.rs2, self.rd); + + Ok(Next(InstrWidth::Uncompressed)) + } + }; +} + +macro_rules! impl_i_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.xregisters.$fn(self.imm, self.rs1, self.rd); + + Ok(Next(InstrWidth::Uncompressed)) + } + }; +} + +macro_rules! impl_fload_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rdf) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; + ($fn: ident, $width: expr) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rdf).map(|_| Next($width)) + } + }; +} +macro_rules! impl_load_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rd) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; + ($fn: ident, $width: expr) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rd).map(|_| Next($width)) + } + }; +} +macro_rules! impl_cload_sp_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rd) + .map(|_| Next(InstrWidth::Compressed)) + } + }; +} +macro_rules! impl_cfload_sp_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rdf) + .map(|_| Next(InstrWidth::Compressed)) + } + }; +} + +macro_rules! impl_store_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rs2) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; + ($fn: ident, $width: expr) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rs2).map(|_| Next($width)) + } + }; +} +macro_rules! impl_fstore_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rs2f) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; + ($fn: ident, $width: expr) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs1, self.rs2f) + .map(|_| Next($width)) + } + }; +} + +macro_rules! impl_b_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + Ok(core.hart.$fn(self.imm, self.rs1, self.rs2)) + } + }; +} + +macro_rules! impl_amo_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.rs1, self.rs2, self.rd, self.rl, self.aq) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; +} + +macro_rules! impl_ci_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.xregisters.$fn(self.imm, self.rd); + Ok(ProgramCounterUpdate::Next(InstrWidth::Compressed)) + } + }; +} + +macro_rules! impl_cr_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.xregisters.$fn(self.rd, self.rs2); + Ok(ProgramCounterUpdate::Next(InstrWidth::Compressed)) + } + }; +} + +macro_rules! impl_cb_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + Ok(core.hart.$fn(self.imm, self.rd)) + } + }; +} + +macro_rules! impl_css_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs2) + .map(|_| Next(InstrWidth::Compressed)) + } + }; +} + +macro_rules! impl_fcss_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.$fn(self.imm, self.rs2f) + .map(|_| Next(InstrWidth::Compressed)) + } + }; +} + +macro_rules! impl_csr_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart + .$fn(self.csr, self.rs1, self.rd) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; +} + +macro_rules! impl_csr_imm_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart + .$fn(self.csr, self.imm as u64, self.rd) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; +} + +macro_rules! impl_f_x_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart + .$fn(self.rs1, self.rdf) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; + + ($fn:ident, rm) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart + .$fn(self.rs1, self.rm, self.rdf) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; +} + +macro_rules! impl_x_f_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart + .$fn(self.rs1f, self.rd) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; + + ($fn:ident, rm) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart + .$fn(self.rs1f, self.rm, self.rd) + .map(|_| Next(InstrWidth::Uncompressed)) + } + }; +} + +macro_rules! impl_f_r_type { + ($fn: ident) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.$fn(self.rs1f, self.rs2f, self.rdf).map(|_| Next(InstrWidth::Uncompressed)) + } + }; + + ($fn: ident, rd) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.$fn(self.rs1f, self.rs2f, self.rd).map(|_| Next(InstrWidth::Uncompressed)) + } + }; + + ($fn:ident, $($field: ident),+) => { + fn $fn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.$fn(self.rs1f, $(self.$field,)* self.rdf).map(|_| Next(InstrWidth::Uncompressed)) + } + }; +} + +impl Args { + // RV64I R-type instructions + impl_r_type!(run_add); + impl_r_type!(run_sub); + impl_r_type!(run_xor); + impl_r_type!(run_or); + impl_r_type!(run_and); + impl_r_type!(run_sll); + impl_r_type!(run_srl); + impl_r_type!(run_sra); + impl_r_type!(run_slt); + impl_r_type!(run_sltu); + impl_r_type!(run_addw); + impl_r_type!(run_subw); + impl_r_type!(run_sllw); + impl_r_type!(run_srlw); + impl_r_type!(run_sraw); + + // RV64I I-type instructions + impl_i_type!(run_addi); + impl_i_type!(run_addiw); + impl_i_type!(run_xori); + impl_i_type!(run_ori); + impl_i_type!(run_andi); + impl_i_type!(run_slli); + impl_i_type!(run_srli); + impl_i_type!(run_srai); + impl_i_type!(run_slliw); + impl_i_type!(run_srliw); + impl_i_type!(run_sraiw); + impl_i_type!(run_slti); + impl_i_type!(run_sltiu); + impl_load_type!(run_lb); + impl_load_type!(run_lh); + impl_load_type!(run_lw); + impl_load_type!(run_lbu); + impl_load_type!(run_lhu); + impl_load_type!(run_lwu); + impl_load_type!(run_ld); + + // RV64I S-type instructions + impl_store_type!(run_sb); + impl_store_type!(run_sh); + impl_store_type!(run_sw); + impl_store_type!(run_sd); + + // RV64I B-type instructions + impl_b_type!(run_beq); + impl_b_type!(run_bne); + impl_b_type!(run_blt); + impl_b_type!(run_bge); + impl_b_type!(run_bltu); + impl_b_type!(run_bgeu); + + // RV64I U-type instructions + fn run_lui( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.xregisters.run_lui(self.imm, self.rd); + Ok(Next(InstrWidth::Uncompressed)) + } + + fn run_auipc( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.run_auipc(self.imm, self.rd); + Ok(Next(InstrWidth::Uncompressed)) + } + + // RV64I jump instructions + fn run_jal( + &self, + core: &mut MachineCoreState, + ) -> Result { + Ok(Set(core.hart.run_jal(self.imm, self.rd))) + } + + fn run_jalr( + &self, + core: &mut MachineCoreState, + ) -> Result { + Ok(Set(core.hart.run_jalr(self.imm, self.rs1, self.rd))) + } + + // RV64A atomic instructions + impl_amo_type!(run_lrw); + impl_amo_type!(run_scw); + impl_amo_type!(run_amoswapw); + impl_amo_type!(run_amoaddw); + impl_amo_type!(run_amoxorw); + impl_amo_type!(run_amoandw); + impl_amo_type!(run_amoorw); + impl_amo_type!(run_amominw); + impl_amo_type!(run_amomaxw); + impl_amo_type!(run_amominuw); + impl_amo_type!(run_amomaxuw); + impl_amo_type!(run_lrd); + impl_amo_type!(run_scd); + impl_amo_type!(run_amoswapd); + impl_amo_type!(run_amoaddd); + impl_amo_type!(run_amoxord); + impl_amo_type!(run_amoandd); + impl_amo_type!(run_amoord); + impl_amo_type!(run_amomind); + impl_amo_type!(run_amomaxd); + impl_amo_type!(run_amominud); + impl_amo_type!(run_amomaxud); + + // RV64M multiplication and division instructions + impl_r_type!(run_rem); + impl_r_type!(run_remu); + impl_r_type!(run_remw); + impl_r_type!(run_remuw); + impl_r_type!(run_div); + impl_r_type!(run_divu); + impl_r_type!(run_divw); + impl_r_type!(run_divuw); + impl_r_type!(run_mul); + impl_r_type!(run_mulh); + impl_r_type!(run_mulhsu); + impl_r_type!(run_mulhu); + impl_r_type!(run_mulw); + + // RV64F instructions + impl_fload_type!(run_flw); + impl_fstore_type!(run_fsw); + impl_f_r_type!(run_feq_s, rd); + impl_f_r_type!(run_fle_s, rd); + impl_f_r_type!(run_flt_s, rd); + impl_f_r_type!(run_fadd_s, rs2f, rm); + impl_f_r_type!(run_fsub_s, rs2f, rm); + impl_f_r_type!(run_fmul_s, rs2f, rm); + impl_f_r_type!(run_fdiv_s, rs2f, rm); + impl_f_r_type!(run_fsqrt_s, rm); + impl_f_r_type!(run_fmin_s); + impl_f_r_type!(run_fmax_s); + impl_f_r_type!(run_fsgnj_s); + impl_f_r_type!(run_fsgnjn_s); + impl_f_r_type!(run_fsgnjx_s); + impl_f_r_type!(run_fmadd_s, rs2f, rs3f, rm); + impl_f_r_type!(run_fmsub_s, rs2f, rs3f, rm); + impl_f_r_type!(run_fnmsub_s, rs2f, rs3f, rm); + impl_f_r_type!(run_fnmadd_s, rs2f, rs3f, rm); + impl_x_f_type!(run_fclass_s); + impl_x_f_type!(run_fmv_x_w); + impl_f_x_type!(run_fmv_w_x); + impl_f_x_type!(run_fcvt_s_w, rm); + impl_f_x_type!(run_fcvt_s_wu, rm); + impl_f_x_type!(run_fcvt_s_l, rm); + impl_f_x_type!(run_fcvt_s_lu, rm); + impl_x_f_type!(run_fcvt_w_s, rm); + impl_x_f_type!(run_fcvt_wu_s, rm); + impl_x_f_type!(run_fcvt_l_s, rm); + impl_x_f_type!(run_fcvt_lu_s, rm); + + // RV64D instructions + impl_fload_type!(run_fld); + impl_fstore_type!(run_fsd); + impl_f_r_type!(run_feq_d, rd); + impl_f_r_type!(run_fle_d, rd); + impl_f_r_type!(run_flt_d, rd); + impl_f_r_type!(run_fadd_d, rs2f, rm); + impl_f_r_type!(run_fsub_d, rs2f, rm); + impl_f_r_type!(run_fmul_d, rs2f, rm); + impl_f_r_type!(run_fdiv_d, rs2f, rm); + impl_f_r_type!(run_fsqrt_d, rm); + impl_f_r_type!(run_fmin_d); + impl_f_r_type!(run_fmax_d); + impl_f_r_type!(run_fsgnj_d); + impl_f_r_type!(run_fsgnjn_d); + impl_f_r_type!(run_fsgnjx_d); + impl_f_r_type!(run_fcvt_d_s, rm); + impl_f_r_type!(run_fcvt_s_d, rm); + impl_f_r_type!(run_fmadd_d, rs2f, rs3f, rm); + impl_f_r_type!(run_fmsub_d, rs2f, rs3f, rm); + impl_f_r_type!(run_fnmsub_d, rs2f, rs3f, rm); + impl_f_r_type!(run_fnmadd_d, rs2f, rs3f, rm); + impl_x_f_type!(run_fclass_d); + impl_f_x_type!(run_fcvt_d_w, rm); + impl_f_x_type!(run_fcvt_d_wu, rm); + impl_f_x_type!(run_fcvt_d_l, rm); + impl_f_x_type!(run_fcvt_d_lu, rm); + impl_x_f_type!(run_fcvt_w_d, rm); + impl_x_f_type!(run_fcvt_wu_d, rm); + impl_x_f_type!(run_fcvt_l_d, rm); + impl_x_f_type!(run_fcvt_lu_d, rm); + impl_x_f_type!(run_fmv_x_d); + impl_f_x_type!(run_fmv_d_x); + + // Zicsr instructions + impl_csr_type!(run_csrrw); + impl_csr_type!(run_csrrs); + impl_csr_type!(run_csrrc); + impl_csr_imm_type!(run_csrrwi); + impl_csr_imm_type!(run_csrrsi); + impl_csr_imm_type!(run_csrrci); + + // RV32C compressed instructions + impl_load_type!(run_clw, InstrWidth::Compressed); + impl_cload_sp_type!(run_clwsp); + impl_store_type!(run_csw, InstrWidth::Compressed); + impl_cb_type!(run_cbeqz); + impl_cb_type!(run_cbnez); + impl_ci_type!(run_cli); + impl_ci_type!(run_clui); + impl_ci_type!(run_caddi); + impl_ci_type!(run_caddi4spn); + impl_ci_type!(run_cslli); + impl_ci_type!(run_csrli); + impl_ci_type!(run_csrai); + impl_ci_type!(run_candi); + impl_cr_type!(run_cmv); + impl_cr_type!(run_cadd); + impl_cr_type!(run_cand); + impl_cr_type!(run_cxor); + impl_cr_type!(run_cor); + impl_cr_type!(run_csub); + impl_css_type!(run_cswsp); + + fn run_caddi16spn( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.hart.xregisters.run_caddi16sp(self.imm); + Ok(Next(InstrWidth::Compressed)) + } + + fn run_cj( + &self, + core: &mut MachineCoreState, + ) -> Result { + Ok(Set(core.hart.run_cj(self.imm))) + } + + fn run_cjr( + &self, + core: &mut MachineCoreState, + ) -> Result { + Ok(Set(core.hart.run_cjr(self.rs1))) + } + + fn run_cjalr( + &self, + core: &mut MachineCoreState, + ) -> Result { + Ok(Set(core.hart.run_cjalr(self.rs1))) + } + + fn run_cnop( + &self, + core: &mut MachineCoreState, + ) -> Result { + core.run_cnop(); + Ok(Next(InstrWidth::Compressed)) + } + + // RV64C compressed instructions + impl_store_type!(run_csd, InstrWidth::Compressed); + impl_css_type!(run_csdsp); + impl_load_type!(run_cld, InstrWidth::Compressed); + impl_cload_sp_type!(run_cldsp); + impl_ci_type!(run_caddiw); + impl_cr_type!(run_caddw); + impl_cr_type!(run_csubw); + + // RV64C compressed instructions + impl_fload_type!(run_cfld, InstrWidth::Compressed); + impl_cfload_sp_type!(run_cfldsp); + impl_fstore_type!(run_cfsd, InstrWidth::Compressed); + impl_fcss_type!(run_cfsdsp); + + // Unknown + fn run_illegal( + &self, + _core: &mut MachineCoreState, + ) -> Result { + Err(Exception::IllegalInstruction) + } +} + +impl From<&InstrCacheable> for Instruction { + fn from(value: &InstrCacheable) -> Self { + match value { + // RV64I R-type instructions + InstrCacheable::Add(args) => Instruction { + opcode: OpCode::Add, + args: args.into(), + }, + InstrCacheable::Sub(args) => Instruction { + opcode: OpCode::Sub, + args: args.into(), + }, + InstrCacheable::Xor(args) => Instruction { + opcode: OpCode::Xor, + args: args.into(), + }, + InstrCacheable::Or(args) => Instruction { + opcode: OpCode::Or, + args: args.into(), + }, + InstrCacheable::And(args) => Instruction { + opcode: OpCode::And, + args: args.into(), + }, + InstrCacheable::Sll(args) => Instruction { + opcode: OpCode::Sll, + args: args.into(), + }, + InstrCacheable::Srl(args) => Instruction { + opcode: OpCode::Srl, + args: args.into(), + }, + InstrCacheable::Sra(args) => Instruction { + opcode: OpCode::Sra, + args: args.into(), + }, + InstrCacheable::Slt(args) => Instruction { + opcode: OpCode::Slt, + args: args.into(), + }, + InstrCacheable::Sltu(args) => Instruction { + opcode: OpCode::Sltu, + args: args.into(), + }, + InstrCacheable::Addw(args) => Instruction { + opcode: OpCode::Addw, + args: args.into(), + }, + InstrCacheable::Subw(args) => Instruction { + opcode: OpCode::Subw, + args: args.into(), + }, + InstrCacheable::Sllw(args) => Instruction { + opcode: OpCode::Sllw, + args: args.into(), + }, + InstrCacheable::Srlw(args) => Instruction { + opcode: OpCode::Srlw, + args: args.into(), + }, + InstrCacheable::Sraw(args) => Instruction { + opcode: OpCode::Sraw, + args: args.into(), + }, + + // RV64I I-type instructions + InstrCacheable::Addi(args) => Instruction { + opcode: OpCode::Addi, + args: args.into(), + }, + InstrCacheable::Addiw(args) => Instruction { + opcode: OpCode::Addiw, + args: args.into(), + }, + InstrCacheable::Xori(args) => Instruction { + opcode: OpCode::Xori, + args: args.into(), + }, + InstrCacheable::Ori(args) => Instruction { + opcode: OpCode::Ori, + args: args.into(), + }, + InstrCacheable::Andi(args) => Instruction { + opcode: OpCode::Andi, + args: args.into(), + }, + InstrCacheable::Slli(args) => Instruction { + opcode: OpCode::Slli, + args: args.into(), + }, + InstrCacheable::Srli(args) => Instruction { + opcode: OpCode::Srli, + args: args.into(), + }, + InstrCacheable::Srai(args) => Instruction { + opcode: OpCode::Srai, + args: args.into(), + }, + InstrCacheable::Slliw(args) => Instruction { + opcode: OpCode::Slliw, + args: args.into(), + }, + InstrCacheable::Srliw(args) => Instruction { + opcode: OpCode::Srliw, + args: args.into(), + }, + InstrCacheable::Sraiw(args) => Instruction { + opcode: OpCode::Sraiw, + args: args.into(), + }, + InstrCacheable::Slti(args) => Instruction { + opcode: OpCode::Slti, + args: args.into(), + }, + InstrCacheable::Sltiu(args) => Instruction { + opcode: OpCode::Sltiu, + args: args.into(), + }, + InstrCacheable::Lb(args) => Instruction { + opcode: OpCode::Lb, + args: args.into(), + }, + InstrCacheable::Lh(args) => Instruction { + opcode: OpCode::Lh, + args: args.into(), + }, + InstrCacheable::Lw(args) => Instruction { + opcode: OpCode::Lw, + args: args.into(), + }, + InstrCacheable::Lbu(args) => Instruction { + opcode: OpCode::Lbu, + args: args.into(), + }, + InstrCacheable::Lhu(args) => Instruction { + opcode: OpCode::Lhu, + args: args.into(), + }, + InstrCacheable::Lwu(args) => Instruction { + opcode: OpCode::Lwu, + args: args.into(), + }, + InstrCacheable::Ld(args) => Instruction { + opcode: OpCode::Ld, + args: args.into(), + }, + // RV64I S-type instructions + InstrCacheable::Sb(args) => Instruction { + opcode: OpCode::Sb, + args: args.into(), + }, + InstrCacheable::Sh(args) => Instruction { + opcode: OpCode::Sh, + args: args.into(), + }, + InstrCacheable::Sw(args) => Instruction { + opcode: OpCode::Sw, + args: args.into(), + }, + InstrCacheable::Sd(args) => Instruction { + opcode: OpCode::Sd, + args: args.into(), + }, + + // RV64I B-type instructions + InstrCacheable::Beq(args) => Instruction { + opcode: OpCode::Beq, + args: args.into(), + }, + InstrCacheable::Bne(args) => Instruction { + opcode: OpCode::Bne, + args: args.into(), + }, + InstrCacheable::Blt(args) => Instruction { + opcode: OpCode::Blt, + args: args.into(), + }, + InstrCacheable::Bge(args) => Instruction { + opcode: OpCode::Bge, + args: args.into(), + }, + InstrCacheable::Bltu(args) => Instruction { + opcode: OpCode::Bltu, + args: args.into(), + }, + InstrCacheable::Bgeu(args) => Instruction { + opcode: OpCode::Bgeu, + args: args.into(), + }, + + // RV64I U-type instructions + InstrCacheable::Lui(args) => Instruction { + opcode: OpCode::Lui, + args: args.into(), + }, + InstrCacheable::Auipc(args) => Instruction { + opcode: OpCode::Auipc, + args: args.into(), + }, + + // RV64I jump instructions + InstrCacheable::Jal(args) => Instruction { + opcode: OpCode::Jal, + args: args.into(), + }, + InstrCacheable::Jalr(args) => Instruction { + opcode: OpCode::Jalr, + args: args.into(), + }, + + // RV64A atomic instructions + InstrCacheable::Lrw(args) => Instruction { + opcode: OpCode::Lrw, + args: args.into(), + }, + InstrCacheable::Scw(args) => Instruction { + opcode: OpCode::Scw, + args: args.into(), + }, + InstrCacheable::Amoswapw(args) => Instruction { + opcode: OpCode::Amoswapw, + args: args.into(), + }, + InstrCacheable::Amoaddw(args) => Instruction { + opcode: OpCode::Amoaddw, + args: args.into(), + }, + InstrCacheable::Amoxorw(args) => Instruction { + opcode: OpCode::Amoxorw, + args: args.into(), + }, + InstrCacheable::Amoandw(args) => Instruction { + opcode: OpCode::Amoandw, + args: args.into(), + }, + InstrCacheable::Amoorw(args) => Instruction { + opcode: OpCode::Amoorw, + args: args.into(), + }, + InstrCacheable::Amominw(args) => Instruction { + opcode: OpCode::Amominw, + args: args.into(), + }, + InstrCacheable::Amomaxw(args) => Instruction { + opcode: OpCode::Amomaxw, + args: args.into(), + }, + InstrCacheable::Amominuw(args) => Instruction { + opcode: OpCode::Amominuw, + args: args.into(), + }, + InstrCacheable::Amomaxuw(args) => Instruction { + opcode: OpCode::Amomaxuw, + args: args.into(), + }, + InstrCacheable::Lrd(args) => Instruction { + opcode: OpCode::Lrd, + args: args.into(), + }, + InstrCacheable::Scd(args) => Instruction { + opcode: OpCode::Scd, + args: args.into(), + }, + InstrCacheable::Amoswapd(args) => Instruction { + opcode: OpCode::Amoswapd, + args: args.into(), + }, + InstrCacheable::Amoaddd(args) => Instruction { + opcode: OpCode::Amoaddd, + args: args.into(), + }, + InstrCacheable::Amoxord(args) => Instruction { + opcode: OpCode::Amoxord, + args: args.into(), + }, + InstrCacheable::Amoandd(args) => Instruction { + opcode: OpCode::Amoandd, + args: args.into(), + }, + InstrCacheable::Amoord(args) => Instruction { + opcode: OpCode::Amoord, + args: args.into(), + }, + InstrCacheable::Amomind(args) => Instruction { + opcode: OpCode::Amomind, + args: args.into(), + }, + InstrCacheable::Amomaxd(args) => Instruction { + opcode: OpCode::Amomaxd, + args: args.into(), + }, + InstrCacheable::Amominud(args) => Instruction { + opcode: OpCode::Amominud, + args: args.into(), + }, + InstrCacheable::Amomaxud(args) => Instruction { + opcode: OpCode::Amomaxud, + args: args.into(), + }, + + // RV64M multiplication and division instructions + InstrCacheable::Rem(args) => Instruction { + opcode: OpCode::Rem, + args: args.into(), + }, + InstrCacheable::Remu(args) => Instruction { + opcode: OpCode::Remu, + args: args.into(), + }, + InstrCacheable::Remw(args) => Instruction { + opcode: OpCode::Remw, + args: args.into(), + }, + InstrCacheable::Remuw(args) => Instruction { + opcode: OpCode::Remuw, + args: args.into(), + }, + InstrCacheable::Div(args) => Instruction { + opcode: OpCode::Div, + args: args.into(), + }, + InstrCacheable::Divu(args) => Instruction { + opcode: OpCode::Divu, + args: args.into(), + }, + InstrCacheable::Divw(args) => Instruction { + opcode: OpCode::Divw, + args: args.into(), + }, + InstrCacheable::Divuw(args) => Instruction { + opcode: OpCode::Divuw, + args: args.into(), + }, + InstrCacheable::Mul(args) => Instruction { + opcode: OpCode::Mul, + args: args.into(), + }, + InstrCacheable::Mulh(args) => Instruction { + opcode: OpCode::Mulh, + args: args.into(), + }, + InstrCacheable::Mulhsu(args) => Instruction { + opcode: OpCode::Mulhsu, + args: args.into(), + }, + InstrCacheable::Mulhu(args) => Instruction { + opcode: OpCode::Mulhu, + args: args.into(), + }, + InstrCacheable::Mulw(args) => Instruction { + opcode: OpCode::Mulw, + args: args.into(), + }, + + // RV64F instructions + InstrCacheable::Flw(args) => Instruction { + opcode: OpCode::Flw, + args: args.into(), + }, + InstrCacheable::Fsw(args) => Instruction { + opcode: OpCode::Fsw, + args: args.into(), + }, + InstrCacheable::Feqs(args) => Instruction { + opcode: OpCode::Feqs, + args: args.into(), + }, + InstrCacheable::Fles(args) => Instruction { + opcode: OpCode::Fles, + args: args.into(), + }, + InstrCacheable::Flts(args) => Instruction { + opcode: OpCode::Flts, + args: args.into(), + }, + InstrCacheable::Fadds(args) => Instruction { + opcode: OpCode::Fadds, + args: args.into(), + }, + InstrCacheable::Fsubs(args) => Instruction { + opcode: OpCode::Fsubs, + args: args.into(), + }, + InstrCacheable::Fmuls(args) => Instruction { + opcode: OpCode::Fmuls, + args: args.into(), + }, + InstrCacheable::Fdivs(args) => Instruction { + opcode: OpCode::Fdivs, + args: args.into(), + }, + InstrCacheable::Fsqrts(args) => Instruction { + opcode: OpCode::Fsqrts, + args: args.into(), + }, + InstrCacheable::Fmins(args) => Instruction { + opcode: OpCode::Fmins, + args: args.into(), + }, + InstrCacheable::Fmaxs(args) => Instruction { + opcode: OpCode::Fmaxs, + args: args.into(), + }, + InstrCacheable::Fsgnjs(args) => Instruction { + opcode: OpCode::Fsgnjs, + args: args.into(), + }, + InstrCacheable::Fsgnjns(args) => Instruction { + opcode: OpCode::Fsgnjns, + args: args.into(), + }, + InstrCacheable::Fsgnjxs(args) => Instruction { + opcode: OpCode::Fsgnjxs, + args: args.into(), + }, + InstrCacheable::Fmadds(args) => Instruction { + opcode: OpCode::Fmadds, + args: args.into(), + }, + InstrCacheable::Fmsubs(args) => Instruction { + opcode: OpCode::Fmsubs, + args: args.into(), + }, + InstrCacheable::Fnmsubs(args) => Instruction { + opcode: OpCode::Fnmsubs, + args: args.into(), + }, + InstrCacheable::Fnmadds(args) => Instruction { + opcode: OpCode::Fnmadds, + args: args.into(), + }, + InstrCacheable::FclassS(args) => Instruction { + opcode: OpCode::FclassS, + args: args.into(), + }, + InstrCacheable::FmvXW(args) => Instruction { + opcode: OpCode::FmvXW, + args: args.into(), + }, + InstrCacheable::FmvWX(args) => Instruction { + opcode: OpCode::FmvWX, + args: args.into(), + }, + InstrCacheable::Fcvtsw(args) => Instruction { + opcode: OpCode::Fcvtsw, + args: args.into(), + }, + InstrCacheable::Fcvtswu(args) => Instruction { + opcode: OpCode::Fcvtswu, + args: args.into(), + }, + InstrCacheable::Fcvtsl(args) => Instruction { + opcode: OpCode::Fcvtsl, + args: args.into(), + }, + InstrCacheable::Fcvtslu(args) => Instruction { + opcode: OpCode::Fcvtslu, + args: args.into(), + }, + InstrCacheable::Fcvtws(args) => Instruction { + opcode: OpCode::Fcvtws, + args: args.into(), + }, + InstrCacheable::Fcvtwus(args) => Instruction { + opcode: OpCode::Fcvtwus, + args: args.into(), + }, + InstrCacheable::Fcvtls(args) => Instruction { + opcode: OpCode::Fcvtls, + args: args.into(), + }, + InstrCacheable::Fcvtlus(args) => Instruction { + opcode: OpCode::Fcvtlus, + args: args.into(), + }, + + // RV64D instructions + InstrCacheable::Fld(args) => Instruction { + opcode: OpCode::Fld, + args: args.into(), + }, + InstrCacheable::Fsd(args) => Instruction { + opcode: OpCode::Fsd, + args: args.into(), + }, + InstrCacheable::Feqd(args) => Instruction { + opcode: OpCode::Feqd, + args: args.into(), + }, + InstrCacheable::Fled(args) => Instruction { + opcode: OpCode::Fled, + args: args.into(), + }, + InstrCacheable::Fltd(args) => Instruction { + opcode: OpCode::Fltd, + args: args.into(), + }, + InstrCacheable::Faddd(args) => Instruction { + opcode: OpCode::Faddd, + args: args.into(), + }, + InstrCacheable::Fsubd(args) => Instruction { + opcode: OpCode::Fsubd, + args: args.into(), + }, + InstrCacheable::Fmuld(args) => Instruction { + opcode: OpCode::Fmuld, + args: args.into(), + }, + InstrCacheable::Fdivd(args) => Instruction { + opcode: OpCode::Fdivd, + args: args.into(), + }, + InstrCacheable::Fsqrtd(args) => Instruction { + opcode: OpCode::Fsqrtd, + args: args.into(), + }, + InstrCacheable::Fmind(args) => Instruction { + opcode: OpCode::Fmind, + args: args.into(), + }, + InstrCacheable::Fmaxd(args) => Instruction { + opcode: OpCode::Fmaxd, + args: args.into(), + }, + InstrCacheable::Fsgnjd(args) => Instruction { + opcode: OpCode::Fsgnjd, + args: args.into(), + }, + InstrCacheable::Fsgnjnd(args) => Instruction { + opcode: OpCode::Fsgnjnd, + args: args.into(), + }, + InstrCacheable::Fsgnjxd(args) => Instruction { + opcode: OpCode::Fsgnjxd, + args: args.into(), + }, + InstrCacheable::Fcvtds(args) => Instruction { + opcode: OpCode::Fcvtds, + args: args.into(), + }, + InstrCacheable::Fcvtsd(args) => Instruction { + opcode: OpCode::Fcvtsd, + args: args.into(), + }, + InstrCacheable::Fmaddd(args) => Instruction { + opcode: OpCode::Fmaddd, + args: args.into(), + }, + InstrCacheable::Fmsubd(args) => Instruction { + opcode: OpCode::Fmsubd, + args: args.into(), + }, + InstrCacheable::Fnmsubd(args) => Instruction { + opcode: OpCode::Fnmsubd, + args: args.into(), + }, + InstrCacheable::Fnmaddd(args) => Instruction { + opcode: OpCode::Fnmaddd, + args: args.into(), + }, + InstrCacheable::FclassD(args) => Instruction { + opcode: OpCode::FclassD, + args: args.into(), + }, + InstrCacheable::Fcvtdw(args) => Instruction { + opcode: OpCode::Fcvtdw, + args: args.into(), + }, + InstrCacheable::Fcvtdwu(args) => Instruction { + opcode: OpCode::Fcvtdwu, + args: args.into(), + }, + InstrCacheable::Fcvtdl(args) => Instruction { + opcode: OpCode::Fcvtdl, + args: args.into(), + }, + InstrCacheable::Fcvtdlu(args) => Instruction { + opcode: OpCode::Fcvtdlu, + args: args.into(), + }, + InstrCacheable::Fcvtwd(args) => Instruction { + opcode: OpCode::Fcvtwd, + args: args.into(), + }, + InstrCacheable::Fcvtwud(args) => Instruction { + opcode: OpCode::Fcvtwud, + args: args.into(), + }, + InstrCacheable::Fcvtld(args) => Instruction { + opcode: OpCode::Fcvtld, + args: args.into(), + }, + InstrCacheable::Fcvtlud(args) => Instruction { + opcode: OpCode::Fcvtlud, + args: args.into(), + }, + InstrCacheable::FmvXD(args) => Instruction { + opcode: OpCode::FmvXD, + args: args.into(), + }, + InstrCacheable::FmvDX(args) => Instruction { + opcode: OpCode::FmvDX, + args: args.into(), + }, + + // Zicsr instructions + InstrCacheable::Csrrw(args) => Instruction { + opcode: OpCode::Csrrw, + args: args.into(), + }, + InstrCacheable::Csrrs(args) => Instruction { + opcode: OpCode::Csrrs, + args: args.into(), + }, + InstrCacheable::Csrrc(args) => Instruction { + opcode: OpCode::Csrrc, + args: args.into(), + }, + InstrCacheable::Csrrwi(args) => Instruction { + opcode: OpCode::Csrrwi, + args: args.into(), + }, + InstrCacheable::Csrrsi(args) => Instruction { + opcode: OpCode::Csrrsi, + args: args.into(), + }, + InstrCacheable::Csrrci(args) => Instruction { + opcode: OpCode::Csrrci, + args: args.into(), + }, + + // RV32C compressed instructions + InstrCacheable::CLw(args) => Instruction { + opcode: OpCode::CLw, + args: args.into(), + }, + InstrCacheable::CLwsp(args) => Instruction { + opcode: OpCode::CLwsp, + args: args.into(), + }, + InstrCacheable::CSw(args) => Instruction { + opcode: OpCode::CSw, + args: args.into(), + }, + InstrCacheable::CSwsp(args) => Instruction { + opcode: OpCode::CSwsp, + args: args.into(), + }, + InstrCacheable::CJ(args) => Instruction { + opcode: OpCode::CJ, + args: args.into(), + }, + InstrCacheable::CJr(args) => Instruction { + opcode: OpCode::CJr, + args: args.into(), + }, + InstrCacheable::CJalr(args) => Instruction { + opcode: OpCode::CJalr, + args: args.into(), + }, + InstrCacheable::CBeqz(args) => Instruction { + opcode: OpCode::CBeqz, + args: args.into(), + }, + InstrCacheable::CBnez(args) => Instruction { + opcode: OpCode::CBnez, + args: args.into(), + }, + InstrCacheable::CLi(args) => Instruction { + opcode: OpCode::CLi, + args: args.into(), + }, + InstrCacheable::CLui(args) => 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::CSlli(args) => Instruction { + opcode: OpCode::CSlli, + args: args.into(), + }, + InstrCacheable::CSrli(args) => Instruction { + opcode: OpCode::CSrli, + args: args.into(), + }, + InstrCacheable::CSrai(args) => Instruction { + opcode: OpCode::CSrai, + args: args.into(), + }, + InstrCacheable::CAndi(args) => Instruction { + opcode: OpCode::CAndi, + args: args.into(), + }, + InstrCacheable::CMv(args) => Instruction { + opcode: OpCode::CMv, + args: args.into(), + }, + InstrCacheable::CAdd(args) => Instruction { + opcode: OpCode::CAdd, + args: args.into(), + }, + InstrCacheable::CAnd(args) => Instruction { + opcode: OpCode::CAnd, + args: args.into(), + }, + InstrCacheable::CXor(args) => Instruction { + opcode: OpCode::CXor, + args: args.into(), + }, + InstrCacheable::COr(args) => Instruction { + opcode: OpCode::COr, + args: args.into(), + }, + InstrCacheable::CSub(args) => Instruction { + opcode: OpCode::CSub, + args: args.into(), + }, + InstrCacheable::CNop => Instruction { + opcode: OpCode::CNop, + args: Default::default(), + }, + + // RV64C compressed instructions + InstrCacheable::CLd(args) => Instruction { + opcode: OpCode::CLd, + args: args.into(), + }, + InstrCacheable::CLdsp(args) => Instruction { + opcode: OpCode::CLdsp, + args: args.into(), + }, + InstrCacheable::CSd(args) => Instruction { + opcode: OpCode::CSd, + args: args.into(), + }, + InstrCacheable::CSdsp(args) => Instruction { + opcode: OpCode::CSdsp, + args: args.into(), + }, + InstrCacheable::CAddiw(args) => Instruction { + opcode: OpCode::CAddiw, + args: args.into(), + }, + InstrCacheable::CAddw(args) => Instruction { + opcode: OpCode::CAddw, + args: args.into(), + }, + InstrCacheable::CSubw(args) => Instruction { + opcode: OpCode::CSubw, + args: args.into(), + }, + + // RV64DC compressed instructions + InstrCacheable::CFld(args) => Instruction { + opcode: OpCode::CFld, + args: args.into(), + }, + InstrCacheable::CFldsp(args) => Instruction { + opcode: OpCode::CFldsp, + args: args.into(), + }, + InstrCacheable::CFsd(args) => Instruction { + opcode: OpCode::CFsd, + args: args.into(), + }, + InstrCacheable::CFsdsp(args) => Instruction { + opcode: OpCode::CFsdsp, + args: args.into(), + }, + + InstrCacheable::Unknown { instr: _ } => Instruction { + opcode: OpCode::Unknown, + args: Default::default(), + }, + InstrCacheable::UnknownCompressed { instr: _ } => Instruction { + opcode: OpCode::UnknownCompressed, + args: Default::default(), + }, + } + } +} + +impl From<&RTypeArgs> for Args { + fn from(value: &RTypeArgs) -> Self { + Self { + rd: value.rd, + rs1: value.rs1, + rs2: value.rs2, + ..Default::default() + } + } +} + +impl From<&ITypeArgs> for Args { + fn from(value: &ITypeArgs) -> Self { + Self { + rd: value.rd, + rs1: value.rs1, + imm: value.imm, + ..Default::default() + } + } +} + +impl From<&SBTypeArgs> for Args { + fn from(value: &SBTypeArgs) -> Self { + Self { + rs1: value.rs1, + rs2: value.rs2, + imm: value.imm, + ..Default::default() + } + } +} + +impl From<&UJTypeArgs> for Args { + fn from(value: &UJTypeArgs) -> Self { + Self { + rd: value.rd, + imm: value.imm, + ..Default::default() + } + } +} + +impl From<&AmoArgs> for Args { + fn from(value: &AmoArgs) -> Self { + Self { + rd: value.rd, + rs1: value.rs1, + rs2: value.rs2, + aq: value.aq, + rl: value.rl, + ..Default::default() + } + } +} + +impl From<&CIBTypeArgs> for Args { + fn from(value: &CIBTypeArgs) -> Self { + Self { + rd: value.rd_rs1, + imm: value.imm, + ..Default::default() + } + } +} + +impl From<&CRTypeArgs> for Args { + fn from(value: &CRTypeArgs) -> Self { + Self { + rd: value.rd_rs1, + rs2: value.rs2, + ..Default::default() + } + } +} + +impl From<&CJTypeArgs> for Args { + fn from(value: &CJTypeArgs) -> Self { + Self { + imm: value.imm, + ..Default::default() + } + } +} + +impl From<&CRJTypeArgs> for Args { + fn from(value: &CRJTypeArgs) -> Self { + Self { + rs1: value.rs1, + ..Default::default() + } + } +} + +impl From<&CSSTypeArgs> for Args { + fn from(value: &CSSTypeArgs) -> Self { + Self { + rs2: value.rs2, + imm: value.imm, + ..Default::default() + } + } +} + +impl From<&CsrArgs> for Args { + fn from(value: &CsrArgs) -> Self { + Self { + rd: value.rd, + rs1: value.rs1, + csr: value.csr, + ..Default::default() + } + } +} + +impl From<&CsriArgs> for Args { + fn from(value: &CsriArgs) -> Self { + Self { + rd: value.rd, + imm: value.imm, + csr: value.csr, + ..Default::default() + } + } +} + +impl From<&FLoadArgs> for Args { + fn from(value: &FLoadArgs) -> Self { + Self { + imm: value.imm, + rdf: value.rd, + rs1: value.rs1, + ..Default::default() + } + } +} + +impl From<&FStoreArgs> for Args { + fn from(value: &FStoreArgs) -> Self { + Self { + imm: value.imm, + rs1: value.rs1, + rs2f: value.rs2, + ..Default::default() + } + } +} + +impl From<&CSSDTypeArgs> for Args { + fn from(value: &CSSDTypeArgs) -> Self { + Self { + imm: value.imm, + rs2f: value.rs2, + ..Default::default() + } + } +} + +impl From<&CIBDTypeArgs> for Args { + fn from(value: &CIBDTypeArgs) -> Self { + Self { + imm: value.imm, + rdf: value.rd_rs1, + ..Default::default() + } + } +} + +impl From<&XRegToFRegArgs> for Args { + fn from(value: &XRegToFRegArgs) -> Self { + Self { + rdf: value.rd, + rs1: value.rs1, + ..Default::default() + } + } +} + +impl From<&XRegToFRegArgsWithRounding> for Args { + fn from(value: &XRegToFRegArgsWithRounding) -> Self { + Self { + rdf: value.rd, + rs1: value.rs1, + rm: value.rm, + ..Default::default() + } + } +} + +impl From<&FRegToXRegArgs> for Args { + fn from(value: &FRegToXRegArgs) -> Self { + Self { + rd: value.rd, + rs1f: value.rs1, + ..Default::default() + } + } +} + +impl From<&FRegToXRegArgsWithRounding> for Args { + fn from(value: &FRegToXRegArgsWithRounding) -> Self { + Self { + rd: value.rd, + rs1f: value.rs1, + rm: value.rm, + ..Default::default() + } + } +} + +impl From<&FR3ArgsWithRounding> for Args { + fn from(value: &FR3ArgsWithRounding) -> Self { + Self { + rdf: value.rd, + rs1f: value.rs1, + rs2f: value.rs2, + rs3f: value.rs3, + rm: value.rm, + ..Default::default() + } + } +} + +impl From<&FRArgs> for Args { + fn from(value: &FRArgs) -> Self { + Self { + rdf: value.rd, + rs1f: value.rs1, + rs2f: value.rs2, + ..Default::default() + } + } +} + +impl From<&FR1ArgWithRounding> for Args { + fn from(value: &FR1ArgWithRounding) -> Self { + Self { + rdf: value.rd, + rs1f: value.rs1, + rm: value.rm, + ..Default::default() + } + } +} + +impl From<&FR2ArgsWithRounding> for Args { + fn from(value: &FR2ArgsWithRounding) -> Self { + Self { + rdf: value.rd, + rs1f: value.rs1, + rs2f: value.rs2, + rm: value.rm, + ..Default::default() + } + } +} + +impl From<&FCmpArgs> for Args { + fn from(value: &FCmpArgs) -> Self { + Self { + rd: value.rd, + rs1f: value.rs1, + rs2f: value.rs2, + ..Default::default() + } + } +} -- GitLab From b50e5f51da118c8f3875fea42f10c02f4fe71195 Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Wed, 6 Nov 2024 13:28:36 +0000 Subject: [PATCH 2/2] RISC-V: switch to opcode instructions in caches --- src/riscv/lib/src/machine_state.rs | 94 ++++++++----- .../lib/src/machine_state/block_cache.rs | 96 ++++++++----- .../lib/src/machine_state/instruction.rs | 130 +++++++++++------- .../src/machine_state/instruction_cache.rs | 58 +++++--- src/riscv/lib/tests/expected/jstz/state_hash | 2 +- 5 files changed, 254 insertions(+), 126 deletions(-) diff --git a/src/riscv/lib/src/machine_state.rs b/src/riscv/lib/src/machine_state.rs index 012261ba2ffc..49579d6f9390 100644 --- a/src/riscv/lib/src/machine_state.rs +++ b/src/riscv/lib/src/machine_state.rs @@ -453,7 +453,7 @@ impl self.core.run_instr_cacheable(instr), + Some(instr) => instr.run(&mut self.core), None => self .fetch_instr(current_mode, satp, instr_pc, phys_addr) .and_then(|instr| self.run_instr(&instr)), @@ -669,11 +669,13 @@ pub enum MachineError { mod tests { use std::ops::Bound; + use super::instruction::{Args, Instruction, OpCode}; use super::{bus, bus::main_memory::tests::T1K, MachineState, MachineStateLayout}; use crate::{ backend_test, bits::{u16, Bits64, FixedWidthBits}, create_state, + default::ConstDefault, machine_state::{ address_translation::{ pte::{PPNField, PageTableEntry}, @@ -694,10 +696,7 @@ mod tests { DefaultCacheLayouts, TestCacheLayouts, }, parser::{ - instruction::{ - CIBTypeArgs, CJTypeArgs, ITypeArgs, Instr, InstrCacheable, RTypeArgs, SBTypeArgs, - UJTypeArgs, - }, + instruction::{CIBTypeArgs, ITypeArgs, Instr, InstrCacheable, SBTypeArgs}, parse_block, }, state_backend::test_helpers::{assert_eq_struct, copy_via_serde, TestBackendFactory}, @@ -1226,11 +1225,15 @@ mod tests { let mut state = create_state!(MachineState, MachineStateLayout, F, M8K, TestCacheLayouts); let uncompressed_bytes = 0x5307b3; - let uncompressed = InstrCacheable::Add(RTypeArgs { - rd: a5, - rs1: t1, - rs2: t0, - }); + let uncompressed = Instruction { + opcode: OpCode::Add, + args: Args { + rd: a5, + rs1: t1, + rs2: t0, + ..Args::DEFAULT + }, + }; let start_ram = start_of_main_memory::(); @@ -1288,8 +1291,21 @@ mod tests { let block_a = [ // Store current instruction counter - InstrCacheable::Auipc(UJTypeArgs { rd: a0, imm: 0 }), - InstrCacheable::CJ(CJTypeArgs { imm: 128 - 4 }), + Instruction { + opcode: OpCode::Auipc, + args: Args { + rd: a0, + imm: 0, + ..Args::DEFAULT + }, + }, + Instruction { + opcode: OpCode::CJ, + args: Args { + imm: 128 - 4, + ..Args::DEFAULT + }, + }, ]; // InstrCacheable::CJ(CJTypeArgs { imm: 1024 }) @@ -1300,25 +1316,41 @@ mod tests { let csw_bytes: u16 = 0xc10c; let jalr_bytes: u32 = 0x50067; let block_b = [ - InstrCacheable::CLui(CIBTypeArgs { - rd_rs1: a1, - imm: (u16::bits_subset(overwrite_bytes, 15, 12) as i64) << 12, - }), - InstrCacheable::Addiw(ITypeArgs { - rd: a1, - rs1: a1, - imm: u16::bits_subset(overwrite_bytes, 11, 0) as i64, - }), - InstrCacheable::CSw(SBTypeArgs { - rs1: a0, - rs2: a1, - imm: 0, - }), - InstrCacheable::Jalr(ITypeArgs { - rd: zero, - rs1: a0, - imm: 0, - }), + Instruction { + opcode: OpCode::CLui, + args: Args { + rd: a1, + imm: (u16::bits_subset(overwrite_bytes, 15, 12) as i64) << 12, + ..Args::DEFAULT + }, + }, + Instruction { + opcode: OpCode::Addiw, + args: Args { + rd: a1, + rs1: a1, + imm: u16::bits_subset(overwrite_bytes, 11, 0) as i64, + ..Args::DEFAULT + }, + }, + Instruction { + opcode: OpCode::CSw, + args: Args { + rs1: a0, + rs2: a1, + imm: 0, + ..Args::DEFAULT + }, + }, + Instruction { + opcode: OpCode::Jalr, + args: Args { + rd: zero, + rs1: a0, + imm: 0, + ..Args::DEFAULT + }, + }, ]; let phys_addr = start_of_main_memory::(); diff --git a/src/riscv/lib/src/machine_state/block_cache.rs b/src/riscv/lib/src/machine_state/block_cache.rs index 5e6272e38f6b..86313956e5c7 100644 --- a/src/riscv/lib/src/machine_state/block_cache.rs +++ b/src/riscv/lib/src/machine_state/block_cache.rs @@ -73,20 +73,18 @@ use super::address_translation::PAGE_OFFSET_WIDTH; use super::bus::main_memory::MainMemoryLayout; +use super::instruction::Instruction; use super::instruction_cache::ValidatedCacheEntry; use super::MachineCoreState; use super::{bus::Address, ProgramCounterUpdate}; +use crate::cache_utils::FenceCounter; use crate::cache_utils::Sizes; +use crate::default::ConstDefault; use crate::state_backend::{self, ManagerAlloc, ManagerClone}; -use crate::traps::EnvironException; -use crate::{ - cache_utils::FenceCounter, - parser::instruction::InstrCacheable, - state_backend::{ - AllocatedOf, Atom, Cell, ManagerBase, ManagerRead, ManagerReadWrite, ManagerWrite, Ref, - }, - traps::Exception, +use crate::state_backend::{ + AllocatedOf, Atom, Cell, ManagerBase, ManagerRead, ManagerReadWrite, ManagerWrite, Ref, }; +use crate::traps::{EnvironException, Exception}; use std::marker::PhantomData; /// Mask for getting the offset within a page @@ -110,7 +108,7 @@ pub type CachedLayout = ( Atom
, Atom, Atom, - [Atom; CACHE_INSTR], + [Atom; CACHE_INSTR], MLCapture, ); @@ -122,7 +120,7 @@ pub struct Cached { address: Cell, fence_counter: Cell, len_instr: Cell, - instr: [Cell; CACHE_INSTR], + instr: [Cell; CACHE_INSTR], _pd: PhantomData, } @@ -154,7 +152,7 @@ impl Cached { self.len_instr.write(0); self.instr .iter_mut() - .for_each(|lc| lc.write(InstrCacheable::Unknown { instr: 0 })); + .for_each(|lc| lc.write(Instruction::DEFAULT)); } fn start_block(&mut self, block_addr: Address, fence_counter: FenceCounter) @@ -453,7 +451,7 @@ impl, ML: MainMemoryLayout, M: Mana /// Add the instruction into a block. /// /// If the block is full, a new block will be started. - fn cache_inner(&mut self, phys_addr: Address, instr: InstrCacheable) + fn cache_inner(&mut self, phys_addr: Address, instr: Instruction) where M: ManagerReadWrite, { @@ -579,7 +577,7 @@ impl, ML: MainMemoryLayout, M: Mana let range = progress as usize..entry.len_instr.read() as usize; for i in entry.instr[range].iter() { - match core.run_instr_cacheable(i.as_ref()) { + match i.as_ref().run(core) { Ok(ProgramCounterUpdate::Next(width)) => { instr_pc += width as u64; core.hart.pc.write(instr_pc); @@ -645,7 +643,7 @@ impl, ML: MainMemoryLayout, M: Mana /// A block fetched from the block cache, that can be executed against the machine state. pub struct Block<'a, ML: MainMemoryLayout, M: ManagerBase> { - instr: &'a mut [Cell], + instr: &'a mut [Cell], _pd: PhantomData, } @@ -690,7 +688,7 @@ impl<'a, ML: MainMemoryLayout, M: ManagerRead> Block<'a, ML, M> { M: ManagerReadWrite, { for i in self.instr.iter() { - match core.run_instr_cacheable(i.as_ref()) { + match i.as_ref().run(core) { Ok(ProgramCounterUpdate::Next(width)) => { *instr_pc += width as u64; core.hart.pc.write(*instr_pc); @@ -722,7 +720,7 @@ impl<'a, ML: MainMemoryLayout, M: ManagerRead> Block<'a, ML, M> { /// Retrieve the underlying instructions contained in the given block. #[cfg(test)] - pub(super) fn to_vec(&self) -> Vec + pub(super) fn to_vec(&self) -> Vec where M: ManagerRead, { @@ -738,11 +736,11 @@ mod tests { machine_state::{ address_translation::PAGE_SIZE, bus, + instruction::{Args, Instruction, OpCode}, main_memory::tests::T1K, registers::{a0, a1, t0, t1}, MachineCoreState, MachineCoreStateLayout, }, - parser::instruction::{CIBTypeArgs, ITypeArgs, SBTypeArgs}, }; pub type TestLayout = Layout; @@ -751,11 +749,15 @@ mod tests { backend_test!(test_writing_full_block_fetchable_uncompressed, F, { let mut state = create_state!(BlockCache, TestLayout, F, TestLayout, T1K); - let uncompressed = InstrCacheable::Sd(SBTypeArgs { - rs1: t1, - rs2: t0, - imm: 8, - }); + let uncompressed = Instruction { + opcode: OpCode::Sd, + args: Args { + rs1: t1, + rs2: t0, + imm: 8, + ..Args::DEFAULT + }, + }; let phys_addr = 10; @@ -772,7 +774,14 @@ mod tests { backend_test!(test_writing_full_block_fetchable_compressed, F, { let mut state = create_state!(BlockCache, TestLayout, F, TestLayout, T1K); - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); + let compressed = Instruction { + opcode: OpCode::CLi, + args: Args { + rd: a0, + imm: 1, + ..Args::DEFAULT + }, + }; let phys_addr = 10; @@ -790,7 +799,14 @@ mod tests { backend_test!(test_writing_half_block_fetchable_compressed, F, { let mut state = create_state!(BlockCache, TestLayout, F, TestLayout, T1K); - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); + let compressed = Instruction { + opcode: OpCode::CLi, + args: Args { + rd: a0, + imm: 1, + ..Args::DEFAULT + }, + }; let phys_addr = 10; @@ -807,7 +823,14 @@ mod tests { backend_test!(test_writing_two_blocks_fetchable_compressed, F, { let mut state = create_state!(BlockCache, TestLayout, F, TestLayout, T1K); - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); + let compressed = Instruction { + opcode: OpCode::CLi, + args: Args { + rd: a0, + imm: 1, + ..Args::DEFAULT + }, + }; let phys_addr = 10; @@ -829,7 +852,14 @@ mod tests { backend_test!(test_crossing_page_exactly_creates_new_block, F, { let mut state = create_state!(BlockCache, TestLayout, F, TestLayout, T1K); - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); + let compressed = Instruction { + opcode: OpCode::CLi, + args: Args { + rd: a0, + imm: 1, + ..Args::DEFAULT + }, + }; let phys_addr = PAGE_SIZE - 10; @@ -851,11 +881,15 @@ mod tests { let mut core_state = create_state!(MachineCoreState, MachineCoreStateLayout, F, T1K); let mut block_state = create_state!(BlockCache, TestLayout, F, TestLayout, T1K); - let addiw = InstrCacheable::Addiw(ITypeArgs { - rd: a1, - rs1: a1, - imm: 257, - }); + let addiw = Instruction { + opcode: OpCode::Addiw, + args: Args { + rd: a1, + rs1: a1, + imm: 257, + ..Args::DEFAULT + }, + }; let block_addr = bus::start_of_main_memory::(); diff --git a/src/riscv/lib/src/machine_state/instruction.rs b/src/riscv/lib/src/machine_state/instruction.rs index 03f0c5896dc7..6fb9d6da97cc 100644 --- a/src/riscv/lib/src/machine_state/instruction.rs +++ b/src/riscv/lib/src/machine_state/instruction.rs @@ -19,6 +19,7 @@ use super::{ MachineCoreState, ProgramCounterUpdate, }; use crate::{ + default::ConstDefault, machine_state::ProgramCounterUpdate::{Next, Set}, parser::instruction::{ AmoArgs, CIBDTypeArgs, CIBTypeArgs, CJTypeArgs, CRJTypeArgs, CRTypeArgs, CSSDTypeArgs, @@ -36,6 +37,8 @@ use serde::{Deserialize, Serialize}; /// /// This is preferred within the caches, as it enables 'pre-dispatch' of functions /// at block construction, rather than during block execution. +/// +/// Instructions are constructable from [`InstrCacheable`] instructions. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct Instruction { /// The operation (over the machine state) that this instruction represents. @@ -45,6 +48,43 @@ pub struct Instruction { pub args: Args, } +impl Instruction { + /// Returns the width of the instruction: either compressed or uncompressed. + pub const fn width(&self) -> InstrWidth { + use OpCode::*; + match self.opcode { + Add | Sub | Xor | Or | And | Sll | Srl | Sra | Slt | Sltu | Addw | Subw | Sllw + | Srlw | Sraw | Addi | Addiw | Xori | Ori | Andi | Slli | Srli | Srai | Slliw + | Srliw | Sraiw | Slti | Sltiu | Lb | Lh | Lw | Lbu | Lhu | Lwu | Ld | Sb | Sh | Sw + | Sd | Beq | Bne | Blt | Bge | Bltu | Bgeu | Lui | Auipc | 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 | FclassS | Feqs | Fles | Flts | Fadds + | Fsubs | Fmuls | Fdivs | Fsqrts | Fmins | Fmaxs | Fmadds | Fmsubs | Fnmsubs + | Fnmadds | Flw | Fsw | Fcvtsw | Fcvtswu | Fcvtsl | Fcvtslu | Fcvtws | Fcvtwus + | Fcvtls | Fcvtlus | Fsgnjs | Fsgnjns | Fsgnjxs | FmvXW | FmvWX | FclassD | Feqd + | Fled | Fltd | Faddd | Fsubd | Fmuld | Fdivd | Fsqrtd | Fmind | Fmaxd | Fmaddd + | Fmsubd | Fnmsubd | Fnmaddd | Fld | Fsd | Fcvtdw | Fcvtdwu | Fcvtdl | Fcvtdlu + | Fcvtds | Fcvtsd | Fcvtwd | Fcvtwud | Fcvtld | Fcvtlud | Fsgnjd | Fsgnjnd + | Fsgnjxd | FmvXD | FmvDX | Csrrw | Csrrs | Csrrc | Csrrwi | Csrrsi | Csrrci + | Unknown => InstrWidth::Uncompressed, + + CLw | CLwsp | CSw | CSwsp | CJ | CJr | CJalr | CBeqz | CBnez | CLi | CLui | CAddi + | CAddi16sp | CAddi4spn | CSlli | CSrli | CSrai | CAndi | CMv | CAdd | CAnd | COr + | CXor | CSub | CAddw | CSubw | CNop | CLd | CLdsp | CSd | CSdsp | CAddiw | CFld + | CFldsp | CFsd | CFsdsp | UnknownCompressed => InstrWidth::Compressed, + } + } +} + +impl ConstDefault for Instruction { + const DEFAULT: Self = Instruction { + opcode: OpCode::Unknown, + args: Args::DEFAULT, + }; +} + /// Opcodes map to the operation performed over the state - allowing us to /// decouple these from the parsed instructions down the line. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] @@ -272,7 +312,7 @@ pub enum OpCode { impl OpCode { /// Dispatch an opcode to the function that will run over the machine state. #[inline(always)] - fn to_run( + pub(super) fn to_run( self, ) -> fn(&Args, &mut MachineCoreState) -> Result { match self { @@ -499,23 +539,21 @@ pub struct Args { pub rl: bool, } -impl Default for Args { - fn default() -> Self { - Self { - rd: XRegister::x0, - rs1: XRegister::x0, - rs2: XRegister::x0, - imm: 0, - csr: CSRegister::fflags, - rdf: FRegister::f0, - rs1f: FRegister::f0, - rs2f: FRegister::f0, - rs3f: FRegister::f0, - rm: InstrRoundingMode::Dynamic, - aq: false, - rl: false, - } - } +impl ConstDefault for Args { + const DEFAULT: Self = Self { + rd: XRegister::x0, + rs1: XRegister::x0, + rs2: XRegister::x0, + imm: 0, + csr: CSRegister::fflags, + rdf: FRegister::f0, + rs1f: FRegister::f0, + rs2f: FRegister::f0, + rs3f: FRegister::f0, + rm: InstrRoundingMode::Dynamic, + aq: false, + rl: false, + }; } macro_rules! impl_r_type { @@ -1843,7 +1881,7 @@ impl From<&InstrCacheable> for Instruction { }, InstrCacheable::CNop => Instruction { opcode: OpCode::CNop, - args: Default::default(), + args: Args::DEFAULT, }, // RV64C compressed instructions @@ -1896,11 +1934,11 @@ impl From<&InstrCacheable> for Instruction { InstrCacheable::Unknown { instr: _ } => Instruction { opcode: OpCode::Unknown, - args: Default::default(), + args: Args::DEFAULT, }, InstrCacheable::UnknownCompressed { instr: _ } => Instruction { opcode: OpCode::UnknownCompressed, - args: Default::default(), + args: Args::DEFAULT, }, } } @@ -1912,7 +1950,7 @@ impl From<&RTypeArgs> for Args { rd: value.rd, rs1: value.rs1, rs2: value.rs2, - ..Default::default() + ..Self::DEFAULT } } } @@ -1923,7 +1961,7 @@ impl From<&ITypeArgs> for Args { rd: value.rd, rs1: value.rs1, imm: value.imm, - ..Default::default() + ..Self::DEFAULT } } } @@ -1934,7 +1972,7 @@ impl From<&SBTypeArgs> for Args { rs1: value.rs1, rs2: value.rs2, imm: value.imm, - ..Default::default() + ..Self::DEFAULT } } } @@ -1944,7 +1982,7 @@ impl From<&UJTypeArgs> for Args { Self { rd: value.rd, imm: value.imm, - ..Default::default() + ..Self::DEFAULT } } } @@ -1957,7 +1995,7 @@ impl From<&AmoArgs> for Args { rs2: value.rs2, aq: value.aq, rl: value.rl, - ..Default::default() + ..Self::DEFAULT } } } @@ -1967,7 +2005,7 @@ impl From<&CIBTypeArgs> for Args { Self { rd: value.rd_rs1, imm: value.imm, - ..Default::default() + ..Self::DEFAULT } } } @@ -1977,7 +2015,7 @@ impl From<&CRTypeArgs> for Args { Self { rd: value.rd_rs1, rs2: value.rs2, - ..Default::default() + ..Self::DEFAULT } } } @@ -1986,7 +2024,7 @@ impl From<&CJTypeArgs> for Args { fn from(value: &CJTypeArgs) -> Self { Self { imm: value.imm, - ..Default::default() + ..Self::DEFAULT } } } @@ -1995,7 +2033,7 @@ impl From<&CRJTypeArgs> for Args { fn from(value: &CRJTypeArgs) -> Self { Self { rs1: value.rs1, - ..Default::default() + ..Self::DEFAULT } } } @@ -2005,7 +2043,7 @@ impl From<&CSSTypeArgs> for Args { Self { rs2: value.rs2, imm: value.imm, - ..Default::default() + ..Self::DEFAULT } } } @@ -2016,7 +2054,7 @@ impl From<&CsrArgs> for Args { rd: value.rd, rs1: value.rs1, csr: value.csr, - ..Default::default() + ..Self::DEFAULT } } } @@ -2027,7 +2065,7 @@ impl From<&CsriArgs> for Args { rd: value.rd, imm: value.imm, csr: value.csr, - ..Default::default() + ..Self::DEFAULT } } } @@ -2038,7 +2076,7 @@ impl From<&FLoadArgs> for Args { imm: value.imm, rdf: value.rd, rs1: value.rs1, - ..Default::default() + ..Self::DEFAULT } } } @@ -2049,7 +2087,7 @@ impl From<&FStoreArgs> for Args { imm: value.imm, rs1: value.rs1, rs2f: value.rs2, - ..Default::default() + ..Self::DEFAULT } } } @@ -2059,7 +2097,7 @@ impl From<&CSSDTypeArgs> for Args { Self { imm: value.imm, rs2f: value.rs2, - ..Default::default() + ..Self::DEFAULT } } } @@ -2069,7 +2107,7 @@ impl From<&CIBDTypeArgs> for Args { Self { imm: value.imm, rdf: value.rd_rs1, - ..Default::default() + ..Self::DEFAULT } } } @@ -2079,7 +2117,7 @@ impl From<&XRegToFRegArgs> for Args { Self { rdf: value.rd, rs1: value.rs1, - ..Default::default() + ..Self::DEFAULT } } } @@ -2090,7 +2128,7 @@ impl From<&XRegToFRegArgsWithRounding> for Args { rdf: value.rd, rs1: value.rs1, rm: value.rm, - ..Default::default() + ..Self::DEFAULT } } } @@ -2100,7 +2138,7 @@ impl From<&FRegToXRegArgs> for Args { Self { rd: value.rd, rs1f: value.rs1, - ..Default::default() + ..Self::DEFAULT } } } @@ -2111,7 +2149,7 @@ impl From<&FRegToXRegArgsWithRounding> for Args { rd: value.rd, rs1f: value.rs1, rm: value.rm, - ..Default::default() + ..Self::DEFAULT } } } @@ -2124,7 +2162,7 @@ impl From<&FR3ArgsWithRounding> for Args { rs2f: value.rs2, rs3f: value.rs3, rm: value.rm, - ..Default::default() + ..Self::DEFAULT } } } @@ -2135,7 +2173,7 @@ impl From<&FRArgs> for Args { rdf: value.rd, rs1f: value.rs1, rs2f: value.rs2, - ..Default::default() + ..Self::DEFAULT } } } @@ -2146,7 +2184,7 @@ impl From<&FR1ArgWithRounding> for Args { rdf: value.rd, rs1f: value.rs1, rm: value.rm, - ..Default::default() + ..Self::DEFAULT } } } @@ -2158,7 +2196,7 @@ impl From<&FR2ArgsWithRounding> for Args { rs1f: value.rs1, rs2f: value.rs2, rm: value.rm, - ..Default::default() + ..Self::DEFAULT } } } @@ -2169,7 +2207,7 @@ impl From<&FCmpArgs> for Args { rd: value.rd, rs1f: value.rs1, rs2f: value.rs2, - ..Default::default() + ..Self::DEFAULT } } } diff --git a/src/riscv/lib/src/machine_state/instruction_cache.rs b/src/riscv/lib/src/machine_state/instruction_cache.rs index 7ad656d9840e..3070ff8a3a20 100644 --- a/src/riscv/lib/src/machine_state/instruction_cache.rs +++ b/src/riscv/lib/src/machine_state/instruction_cache.rs @@ -33,10 +33,12 @@ //! translation changes - as the upper address may no longer point //! to the same relative physical address. +use super::instruction::{Args, Instruction, OpCode}; use crate::cache_utils::{FenceCounter, Sizes}; +use crate::default::ConstDefault; use crate::machine_state::address_translation::PAGE_SIZE; use crate::machine_state::bus::Address; -use crate::parser::instruction::{Instr, InstrCacheable}; +use crate::parser::instruction::Instr; use crate::parser::{parse_compressed_instruction, parse_uncompressed_instruction}; use crate::state_backend::{ self, AllocatedOf, Atom, Cell, ManagerBase, ManagerClone, ManagerRead, ManagerReadWrite, @@ -49,11 +51,11 @@ use crate::state_backend::{ /// - the parsed instruction corresponds to the unparsed bytes /// - the instruction does not cross a page boundary (only possible for an uncompressed /// instruction). -pub struct ValidatedCacheEntry(Address, InstrCacheable); +pub struct ValidatedCacheEntry(Address, Instruction); impl ValidatedCacheEntry { /// Access the address & instruction (both parsed & unparsed). - pub fn to_inner(self) -> (Address, InstrCacheable) { + pub fn to_inner(self) -> (Address, Instruction) { (self.0, self.1) } @@ -62,7 +64,7 @@ impl ValidatedCacheEntry { /// # Panics /// Panics if the validity checks fail. See [`ValidatedCacheEntry`]. #[cfg(test)] - pub fn from_raw(phys_addr: Address, instr: InstrCacheable) -> Self { + pub fn from_raw(phys_addr: Address, instr: Instruction) -> Self { use crate::parser::instruction::InstrWidth; assert!( @@ -75,13 +77,13 @@ impl ValidatedCacheEntry { } /// The layout of an entry in the instruction cache. -pub type CachedLayout = (Atom, Atom, Atom); +pub type CachedLayout = (Atom, Atom, Atom); /// An entry in the instruction cache - containing both the physical address & instruction. pub struct Cached { fence_counter: Cell, phys_addr: Cell, - instr: Cell, + instr: Cell, } impl Cached { @@ -101,7 +103,10 @@ impl Cached { { self.fence_counter.write(FenceCounter::INITIAL); self.phys_addr.write(0); - self.instr.write(InstrCacheable::Unknown { instr: 0 }); + self.instr.write(Instruction { + opcode: OpCode::Unknown, + args: Args::DEFAULT, + }); } /// Obatin a structure with references to the bound regions of this type. @@ -279,7 +284,7 @@ impl InstructionCache { /// Fetch the cached instruction at the given address, if an entry exists. #[inline(always)] - pub fn fetch_instr(&mut self, phys_addr: Address) -> Option<&InstrCacheable> + pub fn fetch_instr(&mut self, phys_addr: Address) -> Option<&Instruction> where M: ManagerRead, { @@ -312,6 +317,7 @@ impl InstructionCache { let instr = parse_compressed_instruction(raw); if let Instr::Cacheable(instr) = instr { + let instr = (&instr).into(); self.cache_inner(phys_addr, instr); push_to_block(ValidatedCacheEntry(phys_addr, instr)); }; @@ -335,6 +341,7 @@ impl InstructionCache { let instr = parse_uncompressed_instruction(raw); match instr { Instr::Cacheable(instr) if cacheable_uncompressed(phys_addr) => { + let instr = Instruction::from(&instr); self.cache_inner(phys_addr, instr); push_to_block(ValidatedCacheEntry(phys_addr, instr)); } @@ -345,7 +352,7 @@ impl InstructionCache { } #[inline] - fn cache_inner(&mut self, phys_addr: Address, instr: InstrCacheable) + fn cache_inner(&mut self, phys_addr: Address, instr: Instruction) where M: ManagerReadWrite, { @@ -382,7 +389,6 @@ mod tests { use crate::{ backend_test, create_state, machine_state::registers::{a0, t0, t1}, - parser::instruction::{CIBTypeArgs, InstrCacheable, SBTypeArgs}, state_backend::test_helpers::copy_via_serde, }; @@ -422,7 +428,14 @@ mod tests { ); let compressed_bytes = 0x4505; - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); + let compressed = Instruction { + opcode: OpCode::CLi, + args: Args { + rd: a0, + imm: 1, + ..Args::DEFAULT + }, + }; let uncompressed_bytes = 0x00533423; @@ -443,14 +456,25 @@ mod tests { // - able to cache possibly overlapping instructions backend_test!(test_rebind, F, { let compressed_bytes = 0x4505; - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); + let compressed = Instruction { + opcode: OpCode::CLi, + args: Args { + rd: a0, + imm: 1, + ..Args::DEFAULT + }, + }; let uncompressed_bytes = 0x00533423; - let uncompressed = InstrCacheable::Sd(SBTypeArgs { - rs1: t1, - rs2: t0, - imm: 8, - }); + let uncompressed = Instruction { + opcode: OpCode::Sd, + args: Args { + rs1: t1, + rs2: t0, + imm: 8, + ..Args::DEFAULT + }, + }; let phys_addr_uncompressed = 6; let phys_addr_compressed = 8; diff --git a/src/riscv/lib/tests/expected/jstz/state_hash b/src/riscv/lib/tests/expected/jstz/state_hash index bcd6cec76ede..b520d10b6766 100644 --- a/src/riscv/lib/tests/expected/jstz/state_hash +++ b/src/riscv/lib/tests/expected/jstz/state_hash @@ -1 +1 @@ -Hash { digest: [7, 20, 23, 163, 229, 118, 28, 96, 127, 160, 136, 225, 112, 123, 102, 141, 104, 149, 4, 219, 161, 32, 83, 121, 21, 57, 115, 106, 96, 2, 232, 21] } +Hash { digest: [88, 19, 129, 212, 172, 251, 71, 21, 236, 150, 120, 153, 93, 250, 125, 172, 102, 184, 13, 103, 59, 13, 231, 51, 187, 54, 196, 222, 169, 42, 7, 226] } -- GitLab