Browse Source

Implement Zacas extension.

pull/1364/head
Gianluca Guida 3 years ago
parent
commit
f71bda9637
  1. 6
      disasm/disasm.cc
  2. 37
      riscv/insns/amocas_d.h
  3. 34
      riscv/insns/amocas_q.h
  4. 2
      riscv/insns/amocas_w.h
  5. 6
      riscv/isa_parser.cc
  6. 1
      riscv/isa_parser.h
  7. 11
      riscv/mmu.h
  8. 5
      riscv/processor.cc
  9. 6
      riscv/riscv.mk.in

6
disasm/disasm.cc

@ -815,6 +815,12 @@ void disassembler_t::add_instructions(const isa_parser_t* isa)
DEFINE_XAMO(sc_d)
}
if (isa->extension_enabled(EXT_ZACAS)) {
DEFINE_XAMO(amocas_w)
DEFINE_XAMO(amocas_d)
DEFINE_XAMO(amocas_q)
}
add_insn(new disasm_insn_t("j", match_jal, mask_jal | mask_rd, {&jump_target}));
add_insn(new disasm_insn_t("jal", match_jal | match_rd_ra, mask_jal | mask_rd, {&jump_target}));
add_insn(new disasm_insn_t("jal", match_jal, mask_jal, {&xrd, &jump_target}));

37
riscv/insns/amocas_d.h

@ -0,0 +1,37 @@
require_extension(EXT_ZACAS);
if (xlen == 32) {
// RV32: the spec defines two 32-bit comparisons. Since we're
// loading 64-bit for memory we have to adjust for endianness.
uint64_t comp, swap, res;
require_align(insn.rd(), 2);
require_align(insn.rs2(), 2);
if (insn.rd() == 0) {
comp = 0;
} else if (MMU.is_target_big_endian()) {
comp = (uint32_t)READ_REG(insn.rd() + 1) | (RD << 32);
} else {
comp = (uint32_t)RD | (READ_REG(insn.rd() + 1) << 32);
}
if (insn.rs2() == 0) {
swap = 0;
} else if (MMU.is_target_big_endian()) {
swap = (uint32_t)READ_REG(insn.rs2() + 1) | (RS2 << 32);
} else {
swap = (uint32_t)RS2 | (READ_REG(insn.rs2() + 1) << 32);
}
res = MMU.amo_compare_and_swap<uint64_t>(RS1, comp, swap);
if (insn.rd() != 0) {
if (MMU.is_target_big_endian()) {
WRITE_REG(insn.rd() + 1, sext32((uint32_t)res));
WRITE_REG(insn.rd(), sext32(res >> 32));
} else {
WRITE_REG(insn.rd(), sext32((uint32_t)res));
WRITE_REG(insn.rd() + 1, sext32(res >> 32));
}
}
} else {
// RV64
WRITE_RD(MMU.amo_compare_and_swap<uint64_t>(RS1, RD, RS2));
}

34
riscv/insns/amocas_q.h

@ -0,0 +1,34 @@
require_extension(EXT_ZACAS);
require_rv64;
require_align(insn.rd(), 2);
require_align(insn.rs2(), 2);
// The spec defines two 64-bit comparisons. Since we're loading
// 128-bit for memory we have to adjust for endianness.
uint128_t comp, swap, res;
if (insn.rd() == 0) {
comp = 0;
} else if (MMU.is_target_big_endian()) {
comp = READ_REG(insn.rd() + 1) | ((uint128_t)RD << 64);
} else {
comp = RD | ((uint128_t)READ_REG(insn.rd() + 1) << 64);
}
if (insn.rs2() == 0) {
swap = 0;
} else if (MMU.is_target_big_endian()) {
swap = READ_REG(insn.rs2() + 1) | ((uint128_t)RS2 << 64);
} else {
swap = RS2 | ((uint128_t)READ_REG(insn.rs2() + 1) << 64);
}
res = MMU.amo_compare_and_swap<uint128_t>(RS1, comp, swap);
if (insn.rd() != 0) {
if (MMU.is_target_big_endian()) {
WRITE_REG(insn.rd(), res >> 64);
WRITE_REG(insn.rd() + 1, res);
} else {
WRITE_REG(insn.rd(), res);
WRITE_REG(insn.rd() + 1, res >> 64);
}
}

2
riscv/insns/amocas_w.h

@ -0,0 +1,2 @@
require_extension(EXT_ZACAS);
WRITE_RD(sext32(MMU.amo_compare_and_swap<uint32_t>(RS1, RD, RS2)));

6
riscv/isa_parser.cc

@ -120,6 +120,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
// HINTs encoded in base-ISA instructions are always present.
} else if (ext_str == "zihintntl") {
// HINTs encoded in base-ISA instructions are always present.
} else if (ext_str == "zacas") {
extension_table[EXT_ZACAS] = true;
} else if (ext_str == "zmmul") {
extension_table[EXT_ZMMUL] = true;
} else if (ext_str == "zba") {
@ -301,6 +303,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
bad_isa_string(str, "'Zcf/Zcd/Zcb/Zcmp/Zcmt' extensions require 'Zca' extension");
}
if (extension_table[EXT_ZACAS] && !extension_table['A']) {
bad_isa_string(str, "'Zacas' extension requires 'A' extension");
}
std::string lowercase = strtolower(priv);
bool user = false, supervisor = false;

1
riscv/isa_parser.h

@ -61,6 +61,7 @@ typedef enum {
EXT_ZVFBFMIN,
EXT_ZVFBFWMA,
EXT_SSTC,
EXT_ZACAS,
EXT_INTERNAL_ZFH_MOVE,
NUM_ISA_EXTENSIONS
} isa_extension_t;

11
riscv/mmu.h

@ -187,6 +187,17 @@ public:
})
}
template<typename T>
T amo_compare_and_swap(reg_t addr, T comp, T swap) {
convert_load_traps_to_store_traps({
store_slow_path(addr, sizeof(T), nullptr, {false, false, false}, false, true);
auto lhs = load<T>(addr);
if (lhs == comp)
store<T>(addr, swap);
return lhs;
})
}
void store_float128(reg_t addr, float128_t val)
{
if (unlikely(addr & (sizeof(float128_t)-1)) && !is_misaligned_enabled()) {

5
riscv/processor.cc

@ -47,6 +47,11 @@ processor_t::processor_t(const isa_parser_t *isa, const cfg_t *cfg,
fprintf(stderr, "V extension is not supported on platforms without __int128 type\n");
abort();
}
if (isa->extension_enabled(EXT_ZACAS) && isa->get_max_xlen() == 64) {
fprintf(stderr, "Zacas extension is not supported on 64-bit platforms without __int128 type\n");
abort();
}
#endif
parse_varch_string(cfg->varch());

6
riscv/riscv.mk.in

@ -1335,6 +1335,11 @@ riscv_insn_ext_bf16 = \
$(riscv_insn_ext_zvfbfmin) \
$(riscv_insn_ext_zvfbfwma) \
riscv_insn_ext_zacas = \
amocas_w \
amocas_d \
$(if $(HAVE_INT128),amocas_q)
riscv_insn_list = \
$(riscv_insn_ext_a) \
$(riscv_insn_ext_c) \
@ -1360,6 +1365,7 @@ riscv_insn_list = \
$(riscv_insn_ext_cmo) \
$(riscv_insn_ext_zicond) \
$(riscv_insn_ext_bf16) \
$(riscv_insn_ext_zacas) \
riscv_gen_srcs = $(addsuffix .cc,$(riscv_insn_list))

Loading…
Cancel
Save