@@ -3370,6 +3370,63 @@ static FORCE_INLINE execute_status execute_SRAIW(const STATE_ACCESS a, uint64_t
33703370 });
33713371}
33723372
3373+ // / \brief Implementation of the CLMUL instruction from Zbc extension.
3374+ // / \details Carry-less multiply (low-part)
3375+ template <rd_kind rd_kind, typename STATE_ACCESS >
3376+ static FORCE_INLINE execute_status execute_CLMUL (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
3377+ [[maybe_unused]] auto note = dump_insn (a, pc, insn, " clmul" );
3378+ if constexpr (rd_kind == rd_kind::x0) {
3379+ return advance_to_next_insn (a, pc);
3380+ }
3381+ return execute_arithmetic (a, pc, insn, [](uint64_t rs1, uint64_t rs2) -> uint64_t {
3382+ uint64_t val = 0 ;
3383+ for (uint32_t i = 0 ; i < XLEN ; ++i) {
3384+ // Use a mask to make the algorithm branchless
3385+ const auto mask = -((rs2 >> i) & uint64_t {1 });
3386+ val ^= (rs1 << i) & mask;
3387+ }
3388+ return val;
3389+ });
3390+ }
3391+
3392+ // / \brief Implementation of the CLMULH instruction from Zbc extension.
3393+ // / \details Carry-less multiply (high-part)
3394+ template <rd_kind rd_kind, typename STATE_ACCESS >
3395+ static FORCE_INLINE execute_status execute_CLMULH (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
3396+ [[maybe_unused]] auto note = dump_insn (a, pc, insn, " clmulh" );
3397+ if constexpr (rd_kind == rd_kind::x0) {
3398+ return advance_to_next_insn (a, pc);
3399+ }
3400+ return execute_arithmetic (a, pc, insn, [](uint64_t rs1, uint64_t rs2) -> uint64_t {
3401+ uint64_t val = 0 ;
3402+ for (uint32_t i = 1 ; i < XLEN ; ++i) {
3403+ // Use a mask to make the algorithm branchless
3404+ const auto mask = -((rs2 >> i) & uint64_t {1 });
3405+ val ^= (rs1 >> (XLEN - i)) & mask;
3406+ }
3407+ return val;
3408+ });
3409+ }
3410+
3411+ // / \brief Implementation of the CLMULR instruction from Zbc extension.
3412+ // / \details Carry-less multiply (reversed)
3413+ template <rd_kind rd_kind, typename STATE_ACCESS >
3414+ static FORCE_INLINE execute_status execute_CLMULR (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
3415+ [[maybe_unused]] auto note = dump_insn (a, pc, insn, " clmulr" );
3416+ if constexpr (rd_kind == rd_kind::x0) {
3417+ return advance_to_next_insn (a, pc);
3418+ }
3419+ return execute_arithmetic (a, pc, insn, [](uint64_t rs1, uint64_t rs2) -> uint64_t {
3420+ uint64_t val = 0 ;
3421+ for (uint32_t i = 0 ; i < XLEN ; ++i) {
3422+ // Use a mask to make the algorithm branchless
3423+ const auto mask = -((rs2 >> i) & uint64_t {1 });
3424+ val ^= (rs1 >> (XLEN - i - 1 )) & mask;
3425+ }
3426+ return val;
3427+ });
3428+ }
3429+
33733430// / \brief Implementation of the BCLR instruction from Zbs extension.
33743431// / \details Single-Bit Clear (Register)
33753432template <rd_kind rd_kind, typename STATE_ACCESS >
@@ -3867,50 +3924,59 @@ static FORCE_INLINE execute_status execute_ADD_MUL_SUB(const STATE_ACCESS a, uin
38673924}
38683925
38693926template <rd_kind rd_kind, typename STATE_ACCESS >
3870- static FORCE_INLINE execute_status execute_SLL_MULH_BCLR_BINV_BSET (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
3927+ static FORCE_INLINE execute_status execute_SLL_MULH_CLMUL_BCLR_BINV_BSET (const STATE_ACCESS a, uint64_t &pc,
3928+ uint32_t insn) {
38713929 // Use ifs instead of a switch to produce fewer branches for the most frequent instructions
3872- const auto funct7 = static_cast <insn_SLL_MULH_BCLR_BINV_BSET_funct7 >(insn_get_funct7 (insn));
3930+ const auto funct7 = static_cast <insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7 >(insn_get_funct7 (insn));
38733931 switch (funct7) {
3874- case insn_SLL_MULH_BCLR_BINV_BSET_funct7 ::SLL :
3932+ case insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7 ::SLL :
38753933 return execute_SLL<rd_kind>(a, pc, insn);
3876- case insn_SLL_MULH_BCLR_BINV_BSET_funct7 ::MULH :
3934+ case insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7 ::MULH :
38773935 return execute_MULH<rd_kind>(a, pc, insn);
3878- case insn_SLL_MULH_BCLR_BINV_BSET_funct7 ::BCLR :
3936+ case insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7 ::BCLR :
38793937 return execute_BCLR<rd_kind>(a, pc, insn);
3880- case insn_SLL_MULH_BCLR_BINV_BSET_funct7 ::BINV :
3938+ case insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7 ::BINV :
38813939 return execute_BINV<rd_kind>(a, pc, insn);
3882- case insn_SLL_MULH_BCLR_BINV_BSET_funct7 ::BSET :
3940+ case insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7 ::BSET :
38833941 return execute_BSET<rd_kind>(a, pc, insn);
3942+ case insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7::CLMUL :
3943+ return execute_CLMUL<rd_kind>(a, pc, insn);
38843944 }
38853945 return raise_illegal_insn_exception (a, pc, insn);
38863946}
38873947
38883948template <rd_kind rd_kind, typename STATE_ACCESS >
3889- static FORCE_INLINE execute_status execute_SLT_MULHSU_SH1ADD (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
3949+ static FORCE_INLINE execute_status execute_SLT_MULHSU_SH1ADD_CLMULR (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
38903950 // Use ifs instead of a switch to produce fewer branches for the most frequent instructions
3891- const auto funct7 = static_cast <insn_SLT_MULHSU_SH1ADD_funct7 >(insn_get_funct7 (insn));
3892- if (funct7 == insn_SLT_MULHSU_SH1ADD_funct7 ::SLT ) {
3951+ const auto funct7 = static_cast <insn_SLT_MULHSU_SH1ADD_CLMULR_funct7 >(insn_get_funct7 (insn));
3952+ if (funct7 == insn_SLT_MULHSU_SH1ADD_CLMULR_funct7 ::SLT ) {
38933953 return execute_SLT<rd_kind>(a, pc, insn);
38943954 }
3895- if (funct7 == insn_SLT_MULHSU_SH1ADD_funct7 ::MULHSU ) {
3955+ if (funct7 == insn_SLT_MULHSU_SH1ADD_CLMULR_funct7 ::MULHSU ) {
38963956 return execute_MULHSU<rd_kind>(a, pc, insn);
38973957 }
3898- if (funct7 == insn_SLT_MULHSU_SH1ADD_funct7 ::SH1ADD ) {
3958+ if (funct7 == insn_SLT_MULHSU_SH1ADD_CLMULR_funct7 ::SH1ADD ) {
38993959 return execute_SH1ADD<rd_kind>(a, pc, insn);
39003960 }
3961+ if (funct7 == insn_SLT_MULHSU_SH1ADD_CLMULR_funct7::CLMULR ) {
3962+ return execute_CLMULR<rd_kind>(a, pc, insn);
3963+ }
39013964 return raise_illegal_insn_exception (a, pc, insn);
39023965}
39033966
39043967template <rd_kind rd_kind, typename STATE_ACCESS >
3905- static FORCE_INLINE execute_status execute_SLTU_MULHU (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
3968+ static FORCE_INLINE execute_status execute_SLTU_MULHU_CLMULH (const STATE_ACCESS a, uint64_t &pc, uint32_t insn) {
39063969 // Use ifs instead of a switch to produce fewer branches for the most frequent instructions
3907- const auto funct7 = static_cast <insn_SLTU_MULHU_funct7 >(insn_get_funct7 (insn));
3908- if (funct7 == insn_SLTU_MULHU_funct7 ::SLTU ) {
3970+ const auto funct7 = static_cast <insn_SLTU_MULHU_CLMULH_funct7 >(insn_get_funct7 (insn));
3971+ if (funct7 == insn_SLTU_MULHU_CLMULH_funct7 ::SLTU ) {
39093972 return execute_SLTU<rd_kind>(a, pc, insn);
39103973 }
3911- if (funct7 == insn_SLTU_MULHU_funct7 ::MULHU ) {
3974+ if (funct7 == insn_SLTU_MULHU_CLMULH_funct7 ::MULHU ) {
39123975 return execute_MULHU<rd_kind>(a, pc, insn);
39133976 }
3977+ if (funct7 == insn_SLTU_MULHU_CLMULH_funct7::CLMULH ) {
3978+ return execute_CLMULH<rd_kind>(a, pc, insn);
3979+ }
39143980 return raise_illegal_insn_exception (a, pc, insn);
39153981}
39163982
@@ -5925,14 +5991,14 @@ static NO_INLINE execute_status interpret_loop(const STATE_ACCESS a, uint64_t mc
59255991 INSN_CASE (ADD_MUL_SUB_rdN):
59265992 status = execute_ADD_MUL_SUB<rd_kind::xN>(a, pc, insn);
59275993 INSN_BREAK ();
5928- INSN_CASE (SLL_MULH_BCLR_BINV_BSET_rdN ):
5929- status = execute_SLL_MULH_BCLR_BINV_BSET <rd_kind::xN>(a, pc, insn);
5994+ INSN_CASE (SLL_MULH_CLMUL_BCLR_BINV_BSET_rdN ):
5995+ status = execute_SLL_MULH_CLMUL_BCLR_BINV_BSET <rd_kind::xN>(a, pc, insn);
59305996 INSN_BREAK ();
5931- INSN_CASE (SLT_MULHSU_SH1ADD_rdN ):
5932- status = execute_SLT_MULHSU_SH1ADD <rd_kind::xN>(a, pc, insn);
5997+ INSN_CASE (SLT_MULHSU_SH1ADD_CLMULR_rdN ):
5998+ status = execute_SLT_MULHSU_SH1ADD_CLMULR <rd_kind::xN>(a, pc, insn);
59335999 INSN_BREAK ();
5934- INSN_CASE (SLTU_MULHU_rdN ):
5935- status = execute_SLTU_MULHU <rd_kind::xN>(a, pc, insn);
6000+ INSN_CASE (SLTU_MULHU_CLMULH_rdN ):
6001+ status = execute_SLTU_MULHU_CLMULH <rd_kind::xN>(a, pc, insn);
59366002 INSN_BREAK ();
59376003 INSN_CASE (XOR_DIV_SH2ADD_rdN):
59386004 status = execute_XOR_DIV_SH2ADD<rd_kind::xN>(a, pc, insn);
@@ -6220,14 +6286,14 @@ static NO_INLINE execute_status interpret_loop(const STATE_ACCESS a, uint64_t mc
62206286 INSN_CASE (ADD_MUL_SUB_rd0):
62216287 status = execute_ADD_MUL_SUB<rd_kind::x0>(a, pc, insn);
62226288 INSN_BREAK ();
6223- INSN_CASE (SLL_MULH_BCLR_BINV_BSET_rd0 ):
6224- status = execute_SLL_MULH_BCLR_BINV_BSET <rd_kind::x0>(a, pc, insn);
6289+ INSN_CASE (SLL_MULH_CLMUL_BCLR_BINV_BSET_rd0 ):
6290+ status = execute_SLL_MULH_CLMUL_BCLR_BINV_BSET <rd_kind::x0>(a, pc, insn);
62256291 INSN_BREAK ();
6226- INSN_CASE (SLT_MULHSU_SH1ADD_rd0 ):
6227- status = execute_SLT_MULHSU_SH1ADD <rd_kind::x0>(a, pc, insn);
6292+ INSN_CASE (SLT_MULHSU_SH1ADD_CLMULR_rd0 ):
6293+ status = execute_SLT_MULHSU_SH1ADD_CLMULR <rd_kind::x0>(a, pc, insn);
62286294 INSN_BREAK ();
6229- INSN_CASE (SLTU_MULHU_rd0 ):
6230- status = execute_SLTU_MULHU <rd_kind::x0>(a, pc, insn);
6295+ INSN_CASE (SLTU_MULHU_CLMULH_rd0 ):
6296+ status = execute_SLTU_MULHU_CLMULH <rd_kind::x0>(a, pc, insn);
62316297 INSN_BREAK ();
62326298 INSN_CASE (XOR_DIV_SH2ADD_rd0):
62336299 status = execute_XOR_DIV_SH2ADD<rd_kind::x0>(a, pc, insn);
0 commit comments