diff options
Diffstat (limited to 'riscv/processor.cc')
-rw-r--r-- | riscv/processor.cc | 115 |
1 files changed, 55 insertions, 60 deletions
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(); } |