aboutsummaryrefslogtreecommitdiff
path: root/riscv/processor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/processor.cc')
-rw-r--r--riscv/processor.cc115
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();
}