|
|
|
@ -62,13 +62,8 @@ processor_t::processor_t(const char* isa_str, const char* priv_str, |
|
|
|
VU.vlenb = isa.get_vlen() / 8; |
|
|
|
VU.vstart_alu = 0; |
|
|
|
|
|
|
|
register_base_instructions(); |
|
|
|
mmu = new mmu_t(sim, cfg->endianness, this, cfg->cache_blocksz); |
|
|
|
|
|
|
|
disassembler = new disassembler_t(&isa); |
|
|
|
for (auto e : isa.get_extensions()) |
|
|
|
register_extension(find_extension(e.c_str())()); |
|
|
|
|
|
|
|
set_pmp_granularity(cfg->pmpgranularity); |
|
|
|
set_pmp_num(cfg->pmpregions); |
|
|
|
|
|
|
|
@ -81,6 +76,12 @@ processor_t::processor_t(const char* isa_str, const char* priv_str, |
|
|
|
set_impl(IMPL_MMU_VMID, true); |
|
|
|
|
|
|
|
reset(); |
|
|
|
|
|
|
|
register_base_instructions(); |
|
|
|
|
|
|
|
disassembler = new disassembler_t(&isa); |
|
|
|
for (auto e : isa.get_extensions()) |
|
|
|
register_extension(find_extension(e.c_str())()); |
|
|
|
} |
|
|
|
|
|
|
|
processor_t::~processor_t() |
|
|
|
@ -146,6 +147,7 @@ void processor_t::enable_log_commits() |
|
|
|
{ |
|
|
|
log_commits_enabled = true; |
|
|
|
mmu->flush_tlb(); // the TLB caches this setting
|
|
|
|
build_opcode_map(); |
|
|
|
} |
|
|
|
|
|
|
|
void processor_t::reset() |
|
|
|
@ -662,47 +664,48 @@ reg_t processor_t::throw_instruction_address_misaligned(reg_t pc) |
|
|
|
|
|
|
|
insn_func_t processor_t::decode_insn(insn_t insn) |
|
|
|
{ |
|
|
|
if (!extension_enabled(EXT_ZCA) && insn_length(insn.bits()) % 4) |
|
|
|
return &::illegal_instruction; |
|
|
|
|
|
|
|
// look up opcode in hash table
|
|
|
|
size_t idx = insn.bits() % OPCODE_CACHE_SIZE; |
|
|
|
auto [hit, desc] = opcode_cache[idx].lookup(insn.bits()); |
|
|
|
const auto& pool = opcode_map[insn.bits() % std::size(opcode_map)]; |
|
|
|
|
|
|
|
bool rve = extension_enabled('E'); |
|
|
|
|
|
|
|
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()) { |
|
|
|
p = std::find_if(instructions.begin(), instructions.end(), matching); |
|
|
|
assert(p != instructions.end()); |
|
|
|
for (auto p = pool.begin(); ; ++p) { |
|
|
|
if ((insn.bits() & p->mask) == p->match) { |
|
|
|
return p->func; |
|
|
|
} |
|
|
|
desc = &*p; |
|
|
|
opcode_cache[idx].replace(insn.bits(), desc); |
|
|
|
} |
|
|
|
|
|
|
|
return desc->func(xlen, rve, log_commits_enabled); |
|
|
|
} |
|
|
|
|
|
|
|
void processor_t::register_insn(insn_desc_t desc, bool is_custom) { |
|
|
|
void processor_t::register_insn(insn_desc_t desc, std::vector<insn_desc_t>& pool) { |
|
|
|
assert(desc.fast_rv32i && desc.fast_rv64i && desc.fast_rv32e && desc.fast_rv64e && |
|
|
|
desc.logged_rv32i && desc.logged_rv64i && desc.logged_rv32e && desc.logged_rv64e); |
|
|
|
|
|
|
|
if (is_custom) |
|
|
|
custom_instructions.push_back(desc); |
|
|
|
else |
|
|
|
instructions.push_back(desc); |
|
|
|
pool.push_back(desc); |
|
|
|
} |
|
|
|
|
|
|
|
void processor_t::build_opcode_map() |
|
|
|
{ |
|
|
|
for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++) |
|
|
|
opcode_cache[i].reset(); |
|
|
|
bool rve = extension_enabled('E'); |
|
|
|
bool zca = extension_enabled(EXT_ZCA); |
|
|
|
const size_t N = std::size(opcode_map); |
|
|
|
|
|
|
|
auto build_one = [&](const insn_desc_t& desc) { |
|
|
|
auto func = desc.func(xlen, rve, log_commits_enabled); |
|
|
|
if (!zca && insn_length(desc.match) % 4) |
|
|
|
func = &::illegal_instruction; |
|
|
|
|
|
|
|
auto stride = std::min(N, size_t(1) << ctz(~desc.mask)); |
|
|
|
for (size_t i = desc.match & (stride - 1); i < N; i += stride) { |
|
|
|
if ((desc.match % N) == (i & desc.mask)) |
|
|
|
opcode_map[i].push_back({desc.match, desc.mask, func}); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
for (auto& p : opcode_map) |
|
|
|
p.clear(); |
|
|
|
|
|
|
|
for (auto& d : custom_instructions) |
|
|
|
build_one(d); |
|
|
|
|
|
|
|
for (auto& d : instructions) |
|
|
|
build_one(d); |
|
|
|
} |
|
|
|
|
|
|
|
void processor_t::register_extension(extension_t *x) { |
|
|
|
|