diff options
author | Akif Ejaz <81078376+akifejaz@users.noreply.github.com> | 2024-06-12 10:25:11 +0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-12 10:25:11 +0500 |
commit | 22748de594631552f8b82bb895fcd7c33a91aa18 (patch) | |
tree | fef9f3669624536805eb93e7e803f2a804e39e60 | |
parent | dc8ea5921556e174f0393940465fb0fde99fe680 (diff) | |
parent | 9e6253f8b13bfd0ded2ececd8b0ac23902e0eac7 (diff) | |
download | riscv-isa-sim-22748de594631552f8b82bb895fcd7c33a91aa18.zip riscv-isa-sim-22748de594631552f8b82bb895fcd7c33a91aa18.tar.gz riscv-isa-sim-22748de594631552f8b82bb895fcd7c33a91aa18.tar.bz2 |
Merge branch 'master' into vector-crypto
-rw-r--r-- | riscv/check-opcode-overlap.t.cc | 45 | ||||
-rw-r--r-- | riscv/execute.cc | 4 | ||||
-rw-r--r-- | riscv/insn_template.h | 1 | ||||
-rw-r--r-- | riscv/insns/c_flw.h | 11 | ||||
-rw-r--r-- | riscv/insns/c_flwsp.h | 12 | ||||
-rw-r--r-- | riscv/insns/c_fsw.h | 11 | ||||
-rw-r--r-- | riscv/insns/c_fswsp.h | 11 | ||||
-rw-r--r-- | riscv/insns/c_jalr.h | 1 | ||||
-rw-r--r-- | riscv/insns/c_jr.h | 1 | ||||
-rw-r--r-- | riscv/insns/c_ld.h | 2 | ||||
-rw-r--r-- | riscv/insns/c_ldsp.h | 3 | ||||
-rw-r--r-- | riscv/insns/c_sd.h | 2 | ||||
-rw-r--r-- | riscv/insns/c_sdsp.h | 2 | ||||
-rw-r--r-- | riscv/insns/jalr.h | 1 | ||||
-rw-r--r-- | riscv/insns/mret.h | 1 | ||||
-rw-r--r-- | riscv/overlap_list.h | 33 | ||||
-rw-r--r-- | riscv/processor.cc | 115 | ||||
-rw-r--r-- | riscv/processor.h | 57 | ||||
-rw-r--r-- | riscv/riscv.mk.in | 22 | ||||
-rw-r--r-- | riscv/triggers.cc | 3 |
20 files changed, 199 insertions, 139 deletions
diff --git a/riscv/check-opcode-overlap.t.cc b/riscv/check-opcode-overlap.t.cc index 2922001..e1a3b06 100644 --- a/riscv/check-opcode-overlap.t.cc +++ b/riscv/check-opcode-overlap.t.cc @@ -1,6 +1,6 @@ #include "decode.h" #include "common.h" -#include <unordered_set> +#include <unordered_map> #include <vector> #include <string> #include <cstdio> @@ -11,13 +11,9 @@ struct opcode { std::string name; }; -static void check_overlap(const opcode& a, const opcode& b) +static bool overlaps(const opcode& a, const opcode& b) { - if ((a.match & b.mask) == b.match) { - fprintf(stderr, "Instruction %s (%" PRIx64 ") overlaps instruction %s (%" PRIx64 ", mask %" PRIx64 ")\n", - a.name.c_str(), a.match, b.name.c_str(), b.match, b.mask); - exit(-1); - } + return (a.mask & b.mask & (a.match ^ b.match)) == 0; } int main() @@ -34,24 +30,47 @@ int main() #undef DEFINE_INSN }; - std::unordered_set<std::string> overlap_list; + std::unordered_map<std::string, bool> overlap_list; #define DECLARE_OVERLAP_INSN(name, ext) \ - overlap_list.insert(std::string(#name)); + overlap_list[std::string(#name)] = false; #include "overlap_list.h" #undef DECLARE_OVERLAP_INSN std::vector<const opcode*> list; - for (size_t i = 0; i < sizeof(static_list) / sizeof(static_list[0]); i++) { + for (size_t i = 0; i < std::size(static_list); i++) { if (!overlap_list.count(static_list[i].name)) list.push_back(&static_list[i]); } + bool ok = true; + for (size_t i = 1; i < list.size(); i++) { for (size_t j = 0; j < i; j++) { - check_overlap(*list[i], *list[j]); - check_overlap(*list[j], *list[i]); + if (overlaps(*list[i], *list[j])) { + fprintf(stderr, "Instruction %s (%" PRIx64 ") overlaps instruction %s (%" PRIx64 ", mask %" PRIx64 ")\n", + list[i]->name.c_str(), list[i]->match, list[j]->name.c_str(), list[j]->match, list[j]->mask); + ok = false; + } + } + } + + // make sure nothing in the overlap list is unused + for (size_t i = 1; i < std::size(static_list); i++) { + for (size_t j = 0; j < i; j++) { + if (overlaps(static_list[i], static_list[j])) { + overlap_list[static_list[i].name] = true; + overlap_list[static_list[j].name] = true; + } + } + } + + for (auto const& [name, used] : overlap_list) { + if (!used) { + fprintf(stderr, "Instruction %s overlaps nothing, so overlap list entry has no effect\n", + name.c_str()); + ok = false; } } - return 0; + return ok ? 0 : -1; } diff --git a/riscv/execute.cc b/riscv/execute.cc index b2532c9..f263dce 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -247,6 +247,8 @@ void processor_t::step(size_t n) { take_pending_interrupt(); + check_if_lpad_required(); + if (unlikely(slow_path())) { // Main simulation loop, slow path. @@ -280,7 +282,6 @@ void processor_t::step(size_t n) in_wfi = false; insn_fetch_t fetch = mmu->load_insn(pc); - execute_insn_prehook(fetch.insn); if (debug && !state.serialized) disasm(fetch.insn); pc = execute_insn_logged(this, pc, fetch); @@ -292,7 +293,6 @@ void processor_t::step(size_t n) // Main simulation loop, fast path. for (auto ic_entry = _mmu->access_icache(pc); ; ) { auto fetch = ic_entry->data; - execute_insn_prehook(fetch.insn); pc = execute_insn_fast(this, pc, fetch); ic_entry = ic_entry->next; if (unlikely(ic_entry->tag != pc)) diff --git a/riscv/insn_template.h b/riscv/insn_template.h index 88a41c2..bf9d9d7 100644 --- a/riscv/insn_template.h +++ b/riscv/insn_template.h @@ -8,4 +8,5 @@ #include "specialize.h" #include "tracer.h" #include "v_ext_macros.h" +#include "debug_defines.h" #include <assert.h> diff --git a/riscv/insns/c_flw.h b/riscv/insns/c_flw.h index 95ae260..aa64bf1 100644 --- a/riscv/insns/c_flw.h +++ b/riscv/insns/c_flw.h @@ -1,8 +1,3 @@ -if (xlen == 32) { - require_extension(EXT_ZCF); - require_fp; - WRITE_RVC_FRS2S(f32(MMU.load<uint32_t>(RVC_RS1S + insn.rvc_lw_imm()))); -} else { // c.ld - require_extension(EXT_ZCA); - WRITE_RVC_RS2S(MMU.load<int64_t>(RVC_RS1S + insn.rvc_ld_imm())); -} +require_extension(EXT_ZCF); +require_fp; +WRITE_RVC_FRS2S(f32(MMU.load<uint32_t>(RVC_RS1S + insn.rvc_lw_imm()))); diff --git a/riscv/insns/c_flwsp.h b/riscv/insns/c_flwsp.h index eea0ec5..caea77c 100644 --- a/riscv/insns/c_flwsp.h +++ b/riscv/insns/c_flwsp.h @@ -1,9 +1,3 @@ -if (xlen == 32) { - require_extension(EXT_ZCF); - require_fp; - WRITE_FRD(f32(MMU.load<uint32_t>(RVC_SP + insn.rvc_lwsp_imm()))); -} else { // c.ldsp - require_extension(EXT_ZCA); - require(insn.rvc_rd() != 0); - WRITE_RD(MMU.load<int64_t>(RVC_SP + insn.rvc_ldsp_imm())); -} +require_extension(EXT_ZCF); +require_fp; +WRITE_FRD(f32(MMU.load<uint32_t>(RVC_SP + insn.rvc_lwsp_imm()))); diff --git a/riscv/insns/c_fsw.h b/riscv/insns/c_fsw.h index d7d6fed..dda411a 100644 --- a/riscv/insns/c_fsw.h +++ b/riscv/insns/c_fsw.h @@ -1,8 +1,3 @@ -if (xlen == 32) { - require_extension(EXT_ZCF); - require_fp; - MMU.store<uint32_t>(RVC_RS1S + insn.rvc_lw_imm(), RVC_FRS2S.v[0]); -} else { // c.sd - require_extension(EXT_ZCA); - MMU.store<uint64_t>(RVC_RS1S + insn.rvc_ld_imm(), RVC_RS2S); -} +require_extension(EXT_ZCF); +require_fp; +MMU.store<uint32_t>(RVC_RS1S + insn.rvc_lw_imm(), RVC_FRS2S.v[0]); diff --git a/riscv/insns/c_fswsp.h b/riscv/insns/c_fswsp.h index 5952251..6ea5c05 100644 --- a/riscv/insns/c_fswsp.h +++ b/riscv/insns/c_fswsp.h @@ -1,8 +1,3 @@ -if (xlen == 32) { - require_extension(EXT_ZCF); - require_fp; - MMU.store<uint32_t>(RVC_SP + insn.rvc_swsp_imm(), RVC_FRS2.v[0]); -} else { // c.sdsp - require_extension(EXT_ZCA); - MMU.store<uint64_t>(RVC_SP + insn.rvc_sdsp_imm(), RVC_RS2); -} +require_extension(EXT_ZCF); +require_fp; +MMU.store<uint32_t>(RVC_SP + insn.rvc_swsp_imm(), RVC_FRS2.v[0]); diff --git a/riscv/insns/c_jalr.h b/riscv/insns/c_jalr.h index 12bc7f9..694f183 100644 --- a/riscv/insns/c_jalr.h +++ b/riscv/insns/c_jalr.h @@ -6,4 +6,5 @@ WRITE_REG(X_RA, tmp); if (ZICFILP_xLPE(STATE.v, STATE.prv)) { STATE.elp = ZICFILP_IS_LP_EXPECTED(insn.rvc_rs1()); + serialize(); } diff --git a/riscv/insns/c_jr.h b/riscv/insns/c_jr.h index c5162e9..af43dd3 100644 --- a/riscv/insns/c_jr.h +++ b/riscv/insns/c_jr.h @@ -4,4 +4,5 @@ set_pc(RVC_RS1 & ~reg_t(1)); if (ZICFILP_xLPE(STATE.v, STATE.prv)) { STATE.elp = ZICFILP_IS_LP_EXPECTED(insn.rvc_rs1()); + serialize(); } diff --git a/riscv/insns/c_ld.h b/riscv/insns/c_ld.h new file mode 100644 index 0000000..988ea98 --- /dev/null +++ b/riscv/insns/c_ld.h @@ -0,0 +1,2 @@ +require_extension(EXT_ZCA); +WRITE_RVC_RS2S(MMU.load<int64_t>(RVC_RS1S + insn.rvc_ld_imm())); diff --git a/riscv/insns/c_ldsp.h b/riscv/insns/c_ldsp.h new file mode 100644 index 0000000..f196040 --- /dev/null +++ b/riscv/insns/c_ldsp.h @@ -0,0 +1,3 @@ +require_extension(EXT_ZCA); +require(insn.rvc_rd() != 0); +WRITE_RD(MMU.load<int64_t>(RVC_SP + insn.rvc_ldsp_imm())); diff --git a/riscv/insns/c_sd.h b/riscv/insns/c_sd.h new file mode 100644 index 0000000..ff8f77d --- /dev/null +++ b/riscv/insns/c_sd.h @@ -0,0 +1,2 @@ +require_extension(EXT_ZCA); +MMU.store<uint64_t>(RVC_RS1S + insn.rvc_ld_imm(), RVC_RS2S); diff --git a/riscv/insns/c_sdsp.h b/riscv/insns/c_sdsp.h new file mode 100644 index 0000000..f7b8a28 --- /dev/null +++ b/riscv/insns/c_sdsp.h @@ -0,0 +1,2 @@ +require_extension(EXT_ZCA); +MMU.store<uint64_t>(RVC_SP + insn.rvc_sdsp_imm(), RVC_RS2); diff --git a/riscv/insns/jalr.h b/riscv/insns/jalr.h index 0622a22..0606f67 100644 --- a/riscv/insns/jalr.h +++ b/riscv/insns/jalr.h @@ -4,4 +4,5 @@ WRITE_RD(tmp); if (ZICFILP_xLPE(STATE.v, STATE.prv)) { STATE.elp = ZICFILP_IS_LP_EXPECTED(insn.rs1()); + serialize(); } diff --git a/riscv/insns/mret.h b/riscv/insns/mret.h index 6d4d59f..3fe920c 100644 --- a/riscv/insns/mret.h +++ b/riscv/insns/mret.h @@ -15,4 +15,5 @@ if (ZICFILP_xLPE(prev_virt, prev_prv)) { s = set_field(s, MSTATUS_MPELP, elp_t::NO_LP_EXPECTED); STATE.mstatus->write(s); if (STATE.mstatush) STATE.mstatush->write(s >> 32); // log mstatush change +STATE.tcontrol->write((STATE.tcontrol->read() & CSR_TCONTROL_MPTE) ? (CSR_TCONTROL_MPTE | CSR_TCONTROL_MTE) : 0); p->set_privilege(prev_prv, prev_virt); diff --git a/riscv/overlap_list.h b/riscv/overlap_list.h index 04ae443..253be45 100644 --- a/riscv/overlap_list.h +++ b/riscv/overlap_list.h @@ -1,6 +1,10 @@ -DECLARE_OVERLAP_INSN(c_fsdsp, EXT_ZCD) -DECLARE_OVERLAP_INSN(c_fld, EXT_ZCD) -DECLARE_OVERLAP_INSN(c_fldsp, EXT_ZCD) +// these overlap c.ld[sp]/c.sd[sp] +DECLARE_OVERLAP_INSN(c_flw, EXT_ZCF) +DECLARE_OVERLAP_INSN(c_flwsp, EXT_ZCF) +DECLARE_OVERLAP_INSN(c_fsw, EXT_ZCF) +DECLARE_OVERLAP_INSN(c_fswsp, EXT_ZCF) + +// these overlap c.fsdsp DECLARE_OVERLAP_INSN(cm_push, EXT_ZCMP) DECLARE_OVERLAP_INSN(cm_pop, EXT_ZCMP) DECLARE_OVERLAP_INSN(cm_popret, EXT_ZCMP) @@ -8,20 +12,23 @@ DECLARE_OVERLAP_INSN(cm_popretz, EXT_ZCMP) DECLARE_OVERLAP_INSN(cm_mva01s, EXT_ZCMP) DECLARE_OVERLAP_INSN(cm_mvsa01, EXT_ZCMP) DECLARE_OVERLAP_INSN(cm_jalt, EXT_ZCMT) -DECLARE_OVERLAP_INSN(c_fsd, EXT_ZCD) + +// c.ebreak and c.jalr overlap c.add DECLARE_OVERLAP_INSN(c_ebreak, EXT_ZCA) DECLARE_OVERLAP_INSN(c_jalr, EXT_ZCA) + +// c.jr overlaps c.mv DECLARE_OVERLAP_INSN(c_jr, EXT_ZCA) -DECLARE_OVERLAP_INSN(vaesdf_vv, EXT_ZVKNED) -DECLARE_OVERLAP_INSN(vghsh_vv, EXT_ZVKG) -DECLARE_OVERLAP_INSN(vsha2ms_vv, EXT_ZVKNHA) -DECLARE_OVERLAP_INSN(vsha2ms_vv, EXT_ZVKNHB) -DECLARE_OVERLAP_INSN(vsm3me_vv, EXT_ZVKSH) + +// lpad overlaps auipc DECLARE_OVERLAP_INSN(lpad, EXT_ZICFILP) -DECLARE_OVERLAP_INSN(mop_r_28, EXT_ZIMOP) -DECLARE_OVERLAP_INSN(mop_r_N, EXT_ZIMOP) -DECLARE_OVERLAP_INSN(mop_rr_7, EXT_ZIMOP) -DECLARE_OVERLAP_INSN(mop_rr_N, EXT_ZIMOP) + +// these overlap Zimop/Zcmop +DECLARE_OVERLAP_INSN(ssrdp, EXT_ZICFISS) +DECLARE_OVERLAP_INSN(sspush_x1, EXT_ZICFISS) +DECLARE_OVERLAP_INSN(sspush_x5, EXT_ZICFISS) +DECLARE_OVERLAP_INSN(sspopchk_x1, EXT_ZICFISS) +DECLARE_OVERLAP_INSN(sspopchk_x5, EXT_ZICFISS) DECLARE_OVERLAP_INSN(c_sspush_x1, EXT_ZICFISS) DECLARE_OVERLAP_INSN(c_sspopchk_x5, EXT_ZICFISS) DECLARE_OVERLAP_INSN(c_mop_N, EXT_ZCMOP) diff --git a/riscv/processor.cc b/riscv/processor.cc index 7a63f3c..a813068 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -11,6 +11,7 @@ #include "disasm.h" #include "platform.h" #include "vector_unit.h" +#include "debug_defines.h" #include <cinttypes> #include <cmath> #include <cstdlib> @@ -94,14 +95,6 @@ processor_t::~processor_t() delete disassembler; } -static void zicfilp_check_if_lpad_required(const elp_t elp, insn_t insn) -{ - if (unlikely(elp == elp_t::LP_EXPECTED)) { - // also see riscv/lpad.h for more checks performed - software_check((insn.bits() & MASK_LPAD) == MATCH_LPAD, LANDING_PAD_FAULT); - } -} - static void bad_option_string(const char *option, const char *value, const char *msg) { @@ -411,11 +404,13 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_TDATA2] = tdata2 = std::make_shared<tdata2_csr_t>(proc, CSR_TDATA2); csrmap[CSR_TDATA3] = std::make_shared<tdata3_csr_t>(proc, CSR_TDATA3); csrmap[CSR_TINFO] = std::make_shared<tinfo_csr_t>(proc, CSR_TINFO); + csrmap[CSR_TCONTROL] = tcontrol = std::make_shared<masked_csr_t>(proc, CSR_TCONTROL, CSR_TCONTROL_MPTE | CSR_TCONTROL_MTE, 0); } else { csrmap[CSR_TDATA1] = std::make_shared<const_csr_t>(proc, CSR_TDATA1, 0); csrmap[CSR_TDATA2] = tdata2 = std::make_shared<const_csr_t>(proc, CSR_TDATA2, 0); csrmap[CSR_TDATA3] = std::make_shared<const_csr_t>(proc, CSR_TDATA3, 0); csrmap[CSR_TINFO] = std::make_shared<const_csr_t>(proc, CSR_TINFO, 0); + csrmap[CSR_TCONTROL] = tcontrol = std::make_shared<const_csr_t>(proc, CSR_TCONTROL, 0); } unsigned scontext_length = (xlen == 32 ? 16 : 32); // debug spec suggests 16-bit for RV32 and 32-bit for RV64 csrmap[CSR_SCONTEXT] = scontext = std::make_shared<masked_csr_t>(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0); @@ -959,6 +954,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc) state.elp = elp_t::NO_LP_EXPECTED; state.mstatus->write(s); if (state.mstatush) state.mstatush->write(s >> 32); // log mstatush change + state.tcontrol->write((state.tcontrol->read() & CSR_TCONTROL_MTE) ? CSR_TCONTROL_MPTE : 0); set_privilege(PRV_M, false); } } @@ -991,10 +987,12 @@ const char* processor_t::get_symbol(uint64_t addr) return sim->get_symbol(addr); } -void processor_t::execute_insn_prehook(insn_t insn) +void processor_t::check_if_lpad_required() { - if (extension_enabled(EXT_ZICFILP)) { - zicfilp_check_if_lpad_required(state.elp, insn); + if (unlikely(state.elp == elp_t::LP_EXPECTED)) { + // also see insns/lpad.h for more checks performed + insn_fetch_t fetch = mmu->load_insn(state.pc); + software_check((fetch.insn.bits() & MASK_LPAD) == MATCH_LPAD, LANDING_PAD_FAULT); } } @@ -1066,6 +1064,12 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) throw trap_illegal_instruction(insn.bits()); } +const insn_desc_t insn_desc_t::illegal_instruction = { + 0, 0, + &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, + &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction +}; + reg_t illegal_instruction(processor_t UNUSED *p, insn_t insn, reg_t UNUSED pc) { // The illegal instruction can be longer than ILEN bits, where the tval will @@ -1074,51 +1078,30 @@ reg_t illegal_instruction(processor_t UNUSED *p, insn_t insn, reg_t UNUSED pc) throw trap_illegal_instruction(insn.bits() & 0xffffffffULL); } -static insn_desc_t -propagate_instruction_in_vector(std::vector<insn_desc_t> &instructions, - std::vector<insn_desc_t>::iterator it) { - assert(it != instructions.end()); - insn_desc_t desc = *it; - if (it->mask != 0 && it != instructions.begin() && - std::next(it) != instructions.end()) { - if (it->match != std::prev(it)->match && - it->match != std::next(it)->match) { - // move to front of opcode list to reduce miss penalty - while (--it >= instructions.begin()) - *std::next(it) = *it; - instructions[0] = desc; - } - } - return desc; -} - insn_func_t processor_t::decode_insn(insn_t insn) { // look up opcode in hash table size_t idx = insn.bits() % OPCODE_CACHE_SIZE; - insn_desc_t desc = opcode_cache[idx]; + auto [hit, desc] = opcode_cache[idx].lookup(insn.bits()); bool rve = extension_enabled('E'); - if (unlikely(insn.bits() != desc.match)) { + if (unlikely(!hit)) { // fall back to linear search auto matching = [insn_bits = insn.bits()](const insn_desc_t &d) { return (insn_bits & d.mask) == d.match; }; auto p = std::find_if(custom_instructions.begin(), custom_instructions.end(), matching); - if (p != custom_instructions.end()) { - desc = propagate_instruction_in_vector(custom_instructions, p); - } else { + if (p == custom_instructions.end()) { p = std::find_if(instructions.begin(), instructions.end(), matching); assert(p != instructions.end()); - desc = propagate_instruction_in_vector(instructions, p); } - opcode_cache[idx] = desc; - opcode_cache[idx].match = insn.bits(); + desc = &*p; + opcode_cache[idx].replace(insn.bits(), desc); } - return desc.func(xlen, rve, log_commits_enabled); + return desc->func(xlen, rve, log_commits_enabled); } void processor_t::register_insn(insn_desc_t desc, bool is_custom) { @@ -1133,19 +1116,8 @@ void processor_t::register_insn(insn_desc_t desc, bool is_custom) { void processor_t::build_opcode_map() { - struct cmp { - bool operator()(const insn_desc_t& lhs, const insn_desc_t& rhs) { - if (lhs.match == rhs.match) - return lhs.mask > rhs.mask; - return lhs.match > rhs.match; - } - }; - - std::sort(instructions.begin(), instructions.end(), cmp()); - std::sort(custom_instructions.begin(), custom_instructions.end(), cmp()); - for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++) - opcode_cache[i] = insn_desc_t::illegal(); + opcode_cache[i].reset(); } void processor_t::register_extension(extension_t *x) { @@ -1167,15 +1139,12 @@ void processor_t::register_base_instructions() { #define DECLARE_INSN(name, match, mask) \ insn_bits_t name##_match = (match), name##_mask = (mask); \ - bool name##_supported = true; + isa_extension_t name##_ext = NUM_ISA_EXTENSIONS; \ + bool name##_overlapping = false; #include "encoding.h" #undef DECLARE_INSN - #define DECLARE_OVERLAP_INSN(name, ext) { name##_supported = isa->extension_enabled(ext); } - #include "overlap_list.h" - #undef DECLARE_OVERLAP_INSN - #define DEFINE_INSN(name) \ extern reg_t fast_rv32i_##name(processor_t*, insn_t, reg_t); \ extern reg_t fast_rv64i_##name(processor_t*, insn_t, reg_t); \ @@ -1184,8 +1153,14 @@ void processor_t::register_base_instructions() extern reg_t logged_rv32i_##name(processor_t*, insn_t, reg_t); \ extern reg_t logged_rv64i_##name(processor_t*, insn_t, reg_t); \ extern reg_t logged_rv32e_##name(processor_t*, insn_t, reg_t); \ - extern reg_t logged_rv64e_##name(processor_t*, insn_t, reg_t); \ - if (name##_supported) { \ + extern reg_t logged_rv64e_##name(processor_t*, insn_t, reg_t); + #include "insn_list.h" + #undef DEFINE_INSN + + // add overlapping instructions first, in order + #define DECLARE_OVERLAP_INSN(name, ext) \ + name##_overlapping = true; \ + if (isa->extension_enabled(ext)) \ register_base_insn((insn_desc_t) { \ name##_match, \ name##_mask, \ @@ -1196,11 +1171,31 @@ void processor_t::register_base_instructions() logged_rv32i_##name, \ logged_rv64i_##name, \ logged_rv32e_##name, \ - logged_rv64e_##name}); \ - } + logged_rv64e_##name}); + #include "overlap_list.h" + #undef DECLARE_OVERLAP_INSN + + // add all other instructions. since they are non-overlapping, the order + // does not affect correctness, but more frequent instructions should + // appear earlier to improve search time on opcode_cache misses. + #define DEFINE_INSN(name) \ + if (!name##_overlapping) \ + register_base_insn((insn_desc_t) { \ + name##_match, \ + name##_mask, \ + fast_rv32i_##name, \ + fast_rv64i_##name, \ + fast_rv32e_##name, \ + fast_rv64e_##name, \ + logged_rv32i_##name, \ + logged_rv64i_##name, \ + logged_rv32e_##name, \ + logged_rv64e_##name}); #include "insn_list.h" + #undef DEFINE_INSN + // terminate instruction list with a catch-all - register_base_insn(insn_desc_t::illegal()); + register_base_insn(insn_desc_t::illegal_instruction); build_opcode_map(); } diff --git a/riscv/processor.h b/riscv/processor.h index f3e5294..9b776e2 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -43,7 +43,7 @@ struct insn_desc_t insn_func_t logged_rv32e; insn_func_t logged_rv64e; - insn_func_t func(int xlen, bool rve, bool logged) + insn_func_t func(int xlen, bool rve, bool logged) const { if (logged) if (rve) @@ -57,12 +57,7 @@ struct insn_desc_t return xlen == 64 ? fast_rv64i : fast_rv32i; } - static insn_desc_t illegal() - { - return {0, 0, - &illegal_instruction, &illegal_instruction, &illegal_instruction, &illegal_instruction, - &illegal_instruction, &illegal_instruction, &illegal_instruction, &illegal_instruction}; - } + static const insn_desc_t illegal_instruction; }; // regnum, data @@ -141,6 +136,7 @@ struct state_t dcsr_csr_t_p dcsr; csr_t_p tselect; csr_t_p tdata2; + csr_t_p tcontrol; csr_t_p scontext; csr_t_p mcontext; @@ -195,6 +191,47 @@ struct state_t elp_t elp; }; +class opcode_cache_entry_t { + public: + opcode_cache_entry_t() + { + reset(); + } + + void reset() + { + for (size_t i = 0; i < associativity; i++) { + tag[i] = 0; + contents[i] = &insn_desc_t::illegal_instruction; + } + } + + void replace(insn_bits_t opcode, const insn_desc_t* desc) + { + for (size_t i = associativity - 1; i > 0; i--) { + tag[i] = tag[i-1]; + contents[i] = contents[i-1]; + } + + tag[0] = opcode; + contents[0] = desc; + } + + std::tuple<bool, const insn_desc_t*> lookup(insn_bits_t opcode) + { + for (size_t i = 0; i < associativity; i++) + if (tag[i] == opcode) + return std::tuple(true, contents[i]); + + return std::tuple(false, nullptr); + } + + private: + static const size_t associativity = 4; + insn_bits_t tag[associativity]; + const insn_desc_t* contents[associativity]; +}; + // this class represents one processor in a RISC-V machine. class processor_t : public abstract_device_t { @@ -319,7 +356,7 @@ public: void clear_waiting_for_interrupt() { in_wfi = false; }; bool is_waiting_for_interrupt() { return in_wfi; }; - void execute_insn_prehook(insn_t insn); + void check_if_lpad_required(); private: const isa_parser_t * const isa; @@ -350,8 +387,8 @@ private: std::vector<insn_desc_t> custom_instructions; std::unordered_map<reg_t,uint64_t> pc_histogram; - static const size_t OPCODE_CACHE_SIZE = 8191; - insn_desc_t opcode_cache[OPCODE_CACHE_SIZE]; + static const size_t OPCODE_CACHE_SIZE = 4095; + opcode_cache_entry_t opcode_cache[OPCODE_CACHE_SIZE]; void take_pending_interrupt() { take_interrupt(state.mip->read() & state.mie->read()); } void take_interrupt(reg_t mask); // take first enabled interrupt in mask diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index 469c48d..60723b5 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -182,6 +182,8 @@ riscv_insn_ext_c = \ c_jr \ c_li \ c_lui \ + c_ld \ + c_ldsp \ c_lw \ c_lwsp \ c_mv \ @@ -191,6 +193,8 @@ riscv_insn_ext_c = \ c_srli \ c_sub \ c_subw \ + c_sd \ + c_sdsp \ c_sw \ c_swsp \ c_xor \ @@ -1061,6 +1065,9 @@ riscv_insn_ext_zimop = \ mop_r_N \ mop_rr_N \ +riscv_insn_ext_zcmop = \ + c_mop_N \ + riscv_insn_ext_zicfilp = \ lpad @@ -1085,20 +1092,20 @@ riscv_insn_ext_zvk = \ $(riscv_insn_ext_zvksh) \ riscv_insn_list = \ - $(if $(HAVE_INT128),$(riscv_insn_ext_v),) \ - $(riscv_insn_ext_a) \ + $(riscv_insn_ext_i) \ + $(riscv_insn_ext_c) \ + $(riscv_insn_ext_f) \ + $(riscv_insn_ext_d) \ + $(riscv_insn_ext_m) \ $(riscv_insn_ext_b) \ + $(riscv_insn_ext_a) \ + $(if $(HAVE_INT128),$(riscv_insn_ext_v),) \ $(riscv_insn_ext_bf16) \ - $(riscv_insn_ext_c) \ $(riscv_insn_ext_cmo) \ - $(riscv_insn_ext_d) \ $(riscv_insn_ext_d_zfa) \ - $(riscv_insn_ext_f) \ $(riscv_insn_ext_f_zfa) \ $(riscv_insn_ext_h) \ - $(riscv_insn_ext_i) \ $(riscv_insn_ext_k) \ - $(riscv_insn_ext_m) \ $(riscv_insn_ext_q) \ $(riscv_insn_ext_q_zfa) \ $(riscv_insn_ext_zacas) \ @@ -1114,6 +1121,7 @@ riscv_insn_list = \ $(riscv_insn_smrnmi) \ $(riscv_insn_svinval) \ $(riscv_insn_ext_zimop) \ + $(riscv_insn_ext_zcmop) \ $(riscv_insn_ext_zicfilp) \ $(riscv_insn_ext_zicfiss) \ diff --git a/riscv/triggers.cc b/riscv/triggers.cc index 1d0ed8b..aa258bd 100644 --- a/riscv/triggers.cc +++ b/riscv/triggers.cc @@ -59,7 +59,8 @@ bool trigger_t::common_match(processor_t * const proc, bool use_prev_prv) const auto state = proc->get_state(); auto prv = use_prev_prv ? state->prev_prv : state->prv; auto v = use_prev_prv ? state->prev_v : state->v; - return mode_match(prv, v) && textra_match(proc); + auto m_enabled = get_action() != 0 || (state->tcontrol->read() & CSR_TCONTROL_MTE); + return (prv < PRV_M || m_enabled) && mode_match(prv, v) && textra_match(proc); } bool trigger_t::mode_match(reg_t prv, bool v) const noexcept |