Skip to content

Commit 06b02fd

Browse files
committed
feat: add Zbc extension
1 parent c439434 commit 06b02fd

4 files changed

Lines changed: 118 additions & 41 deletions

File tree

src/interpret.cpp

Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
33753432
template <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

38693926
template <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

38883948
template <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

39043967
template <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);

src/riscv-constants.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ enum MISA_shifts {
135135
/// \brief Supported RISC-V ISA extensions, used by the Device Tree during boot.
136136
/// \details See also
137137
/// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/riscv/extensions.yaml
138-
constexpr const char ISA_string[] = "rv64imafdc_zicntr_zicsr_zifencei_zihpm_zba_zbs";
138+
constexpr const char ISA_string[] = "rv64imafdc_zicntr_zicsr_zifencei_zihpm_zba_zbc_zbs";
139139

140140
/// \brief misa masks
141141
enum MISA_masks : uint64_t {
@@ -675,24 +675,30 @@ enum insn_AMO_funct7_sr2 : uint32_t {
675675
/// \brief funct7 constants for ADD, MUL, SUB instructions
676676
enum insn_ADD_MUL_SUB_funct7 : uint32_t { ADD = 0b0000000, MUL = 0b0000001, SUB = 0b0100000 };
677677

678-
/// \brief funct7 constants for SLL, MULH, BCLR, BINV, BSET instructions
679-
enum insn_SLL_MULH_BCLR_BINV_BSET_funct7 : uint32_t {
678+
/// \brief funct7 constants for SLL, MULH, CLMUL, BCLR, BINV, BSET instructions
679+
enum insn_SLL_MULH_CLMUL_BCLR_BINV_BSET_funct7 : uint32_t {
680680
SLL = 0b0000000,
681681
MULH = 0b0000001,
682+
CLMUL = 0b0000101,
682683
BCLR = 0b0100100,
683684
BINV = 0b0110100,
684685
BSET = 0b0010100,
685686
};
686687

687-
/// \brief funct7 constants for SLT, MULHSU, SH1ADD instructions
688-
enum insn_SLT_MULHSU_SH1ADD_funct7 : uint32_t {
688+
/// \brief funct7 constants for SLT, MULHSU, SH1ADD, CLMULR instructions
689+
enum insn_SLT_MULHSU_SH1ADD_CLMULR_funct7 : uint32_t {
689690
SLT = 0b0000000,
690691
MULHSU = 0b0000001,
691692
SH1ADD = 0b0010000,
693+
CLMULR = 0b0000101,
692694
};
693695

694-
/// \brief funct7 constants for SLTU, MULHU instructions
695-
enum insn_SLTU_MULHU_funct7 : uint32_t { SLTU = 0b0000000, MULHU = 0b0000001 };
696+
/// \brief funct7 constants for SLTU, MULHU, CLMULH instructions
697+
enum insn_SLTU_MULHU_CLMULH_funct7 : uint32_t {
698+
SLTU = 0b0000000,
699+
MULHU = 0b0000001,
700+
CLMULH = 0b0000101,
701+
};
696702

697703
/// \brief funct7 constants for XOR, DIV, SH2ADD instructions
698704
enum insn_XOR_DIV_SH2ADD_funct7 : uint32_t {

tests/lua/cartesi-machine-tests.lua

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,12 @@ local riscv_tests = {
283283
{ "rv64uzba-v-sh3add.bin", 8246 },
284284
{ "rv64uzba-v-sh3add_uw.bin", 8250 },
285285
{ "rv64uzba-v-slli_uw.bin", 8051 },
286+
{ "rv64uzbc-p-clmul.bin", 500 },
287+
{ "rv64uzbc-p-clmulh.bin", 505 },
288+
{ "rv64uzbc-p-clmulr.bin", 503 },
289+
{ "rv64uzbc-v-clmul.bin", 8292 },
290+
{ "rv64uzbc-v-clmulh.bin", 8297 },
291+
{ "rv64uzbc-v-clmulr.bin", 8295 },
286292
{ "rv64uzbs-p-bclr.bin", 699 },
287293
{ "rv64uzbs-p-bclri.bin", 354 },
288294
{ "rv64uzbs-p-bext.bin", 634 },
@@ -353,12 +359,6 @@ local riscv_tests = {
353359
-- { "rv64uzbb-v-sext_h.bin", 10000 },
354360
-- { "rv64uzbb-v-xnor.bin", 10000 },
355361
-- { "rv64uzbb-v-zext_h.bin", 10000 },
356-
-- { "rv64uzbc-p-clmul.bin", 10000 },
357-
-- { "rv64uzbc-p-clmulh.bin", 10000 },
358-
-- { "rv64uzbc-p-clmulr.bin", 10000 },
359-
-- { "rv64uzbc-v-clmul.bin", 10000 },
360-
-- { "rv64uzbc-v-clmulh.bin", 10000 },
361-
-- { "rv64uzbc-v-clmulr.bin", 10000 },
362362
-- { "rv64uzfh-p-fadd.bin", 10000 },
363363
-- { "rv64uzfh-p-fclass.bin", 10000 },
364364
-- { "rv64uzfh-p-fcmp.bin", 10000 },

tools/gen-interpret-jump-table.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ local insns = {
9898
{ bits = "0010000__________110_____0111011", name = "SH3ADD.UW", rd0_special = true },
9999
{ bits = "000010___________001_____0011011", name = "SLLI.UW", rd0_special = true },
100100

101+
-- Zbc extension
102+
{ bits = "0000101__________001_____0110011", name = "CLMUL", rd0_special = true },
103+
{ bits = "0000101__________011_____0110011", name = "CLMULH", rd0_special = true },
104+
{ bits = "0000101__________010_____0110011", name = "CLMULR", rd0_special = true },
105+
101106
-- Zbs extension
102107
{ bits = "0100100__________001_____0110011", name = "BCLR", rd0_special = true },
103108
{ bits = "010010___________001_____0010011", name = "BCLRI", rd0_special = true },

0 commit comments

Comments
 (0)