Skip to content

Commit f7616ad

Browse files
committed
Eliminate the opcode cache
Just bucket the intruction lists, then search them. Simpler and faster.
1 parent 2ec106b commit f7616ad

File tree

2 files changed

+47
-81
lines changed

2 files changed

+47
-81
lines changed

riscv/processor.cc

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,8 @@ processor_t::processor_t(const char* isa_str, const char* priv_str,
6262
VU.vlenb = isa.get_vlen() / 8;
6363
VU.vstart_alu = 0;
6464

65-
register_base_instructions();
6665
mmu = new mmu_t(sim, cfg->endianness, this, cfg->cache_blocksz);
6766

68-
disassembler = new disassembler_t(&isa);
69-
for (auto e : isa.get_extensions())
70-
register_extension(find_extension(e.c_str())());
71-
7267
set_pmp_granularity(cfg->pmpgranularity);
7368
set_pmp_num(cfg->pmpregions);
7469

@@ -81,6 +76,12 @@ processor_t::processor_t(const char* isa_str, const char* priv_str,
8176
set_impl(IMPL_MMU_VMID, true);
8277

8378
reset();
79+
80+
register_base_instructions();
81+
82+
disassembler = new disassembler_t(&isa);
83+
for (auto e : isa.get_extensions())
84+
register_extension(find_extension(e.c_str())());
8485
}
8586

8687
processor_t::~processor_t()
@@ -663,47 +664,48 @@ reg_t processor_t::throw_instruction_address_misaligned(reg_t pc)
663664

664665
insn_func_t processor_t::decode_insn(insn_t insn)
665666
{
666-
if (!extension_enabled(EXT_ZCA) && insn_length(insn.bits()) % 4)
667-
return &::illegal_instruction;
668-
669-
// look up opcode in hash table
670-
size_t idx = insn.bits() % OPCODE_CACHE_SIZE;
671-
auto [hit, desc] = opcode_cache[idx].lookup(insn.bits());
667+
const auto& pool = opcode_map[insn.bits() % std::size(opcode_map)];
672668

673-
bool rve = extension_enabled('E');
674-
675-
if (unlikely(!hit)) {
676-
// fall back to linear search
677-
auto matching = [insn_bits = insn.bits()](const insn_desc_t &d) {
678-
return (insn_bits & d.mask) == d.match;
679-
};
680-
auto p = std::find_if(custom_instructions.begin(),
681-
custom_instructions.end(), matching);
682-
if (p == custom_instructions.end()) {
683-
p = std::find_if(instructions.begin(), instructions.end(), matching);
684-
assert(p != instructions.end());
669+
for (auto p = pool.begin(); ; ++p) {
670+
if ((insn.bits() & p->mask) == p->match) {
671+
return p->func;
685672
}
686-
desc = &*p;
687-
opcode_cache[idx].replace(insn.bits(), desc);
688673
}
689-
690-
return desc->func(xlen, rve, log_commits_enabled);
691674
}
692675

693-
void processor_t::register_insn(insn_desc_t desc, bool is_custom) {
676+
void processor_t::register_insn(insn_desc_t desc, std::vector<insn_desc_t>& pool) {
694677
assert(desc.fast_rv32i && desc.fast_rv64i && desc.fast_rv32e && desc.fast_rv64e &&
695678
desc.logged_rv32i && desc.logged_rv64i && desc.logged_rv32e && desc.logged_rv64e);
696679

697-
if (is_custom)
698-
custom_instructions.push_back(desc);
699-
else
700-
instructions.push_back(desc);
680+
pool.push_back(desc);
701681
}
702682

703683
void processor_t::build_opcode_map()
704684
{
705-
for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++)
706-
opcode_cache[i].reset();
685+
bool rve = extension_enabled('E');
686+
bool zca = extension_enabled(EXT_ZCA);
687+
const size_t N = std::size(opcode_map);
688+
689+
auto build_one = [&](const insn_desc_t& desc) {
690+
auto func = desc.func(xlen, rve, log_commits_enabled);
691+
if (!zca && insn_length(desc.match) % 4)
692+
func = &::illegal_instruction;
693+
694+
auto stride = std::min(N, size_t(1) << ctz(~desc.mask));
695+
for (size_t i = desc.match & (stride - 1); i < N; i += stride) {
696+
if ((desc.match % N) == (i & desc.mask))
697+
opcode_map[i].push_back({desc.match, desc.mask, func});
698+
}
699+
};
700+
701+
for (auto& p : opcode_map)
702+
p.clear();
703+
704+
for (auto& d : custom_instructions)
705+
build_one(d);
706+
707+
for (auto& d : instructions)
708+
build_one(d);
707709
}
708710

709711
void processor_t::register_extension(extension_t *x) {

riscv/processor.h

Lines changed: 11 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ struct insn_desc_t
6161
static const insn_desc_t illegal_instruction;
6262
};
6363

64+
struct opcode_map_entry_t
65+
{
66+
insn_bits_t match;
67+
insn_bits_t mask;
68+
insn_func_t func;
69+
};
70+
6471
// regnum, data
6572
typedef std::map<reg_t, freg_t> commit_log_reg_t;
6673

@@ -207,47 +214,6 @@ struct state_t
207214
void csr_init(processor_t* const proc, reg_t max_isa);
208215
};
209216

210-
class opcode_cache_entry_t {
211-
public:
212-
opcode_cache_entry_t()
213-
{
214-
reset();
215-
}
216-
217-
void reset()
218-
{
219-
for (size_t i = 0; i < associativity; i++) {
220-
tag[i] = 0;
221-
contents[i] = &insn_desc_t::illegal_instruction;
222-
}
223-
}
224-
225-
void replace(insn_bits_t opcode, const insn_desc_t* desc)
226-
{
227-
for (size_t i = associativity - 1; i > 0; i--) {
228-
tag[i] = tag[i-1];
229-
contents[i] = contents[i-1];
230-
}
231-
232-
tag[0] = opcode;
233-
contents[0] = desc;
234-
}
235-
236-
std::tuple<bool, const insn_desc_t*> lookup(insn_bits_t opcode)
237-
{
238-
for (size_t i = 0; i < associativity; i++)
239-
if (tag[i] == opcode)
240-
return std::tuple(true, contents[i]);
241-
242-
return std::tuple(false, nullptr);
243-
}
244-
245-
private:
246-
static const size_t associativity = 4;
247-
insn_bits_t tag[associativity];
248-
const insn_desc_t* contents[associativity];
249-
};
250-
251217
// this class represents one processor in a RISC-V machine.
252218
class processor_t : public abstract_device_t
253219
{
@@ -341,10 +307,10 @@ class processor_t : public abstract_device_t
341307
FILE *get_log_file() { return log_file; }
342308

343309
void register_base_insn(insn_desc_t insn) {
344-
register_insn(insn, false /* is_custom */);
310+
register_insn(insn, instructions);
345311
}
346312
void register_custom_insn(insn_desc_t insn) {
347-
register_insn(insn, true /* is_custom */);
313+
register_insn(insn, custom_instructions);
348314
}
349315
void register_extension(extension_t*);
350316
void build_opcode_map();
@@ -406,19 +372,17 @@ class processor_t : public abstract_device_t
406372
std::bitset<NUM_ISA_EXTENSIONS> extension_dynamic;
407373
mutable std::bitset<NUM_ISA_EXTENSIONS> extension_assumed_const;
408374

375+
std::vector<opcode_map_entry_t> opcode_map[128];
409376
std::vector<insn_desc_t> instructions;
410377
std::vector<insn_desc_t> custom_instructions;
411378
std::unordered_map<reg_t,uint64_t> pc_histogram;
412379

413-
static const size_t OPCODE_CACHE_SIZE = 4095;
414-
opcode_cache_entry_t opcode_cache[OPCODE_CACHE_SIZE];
415-
416380
void take_pending_interrupt() { take_interrupt(state.mip->read() & state.mie->read()); }
417381
void take_interrupt(reg_t mask); // take first enabled interrupt in mask
418382
void take_trap(trap_t& t, reg_t epc); // take an exception
419383
void take_trigger_action(triggers::action_t action, reg_t breakpoint_tval, reg_t epc, bool virt);
420384
void disasm(insn_t insn); // disassemble and print an instruction
421-
void register_insn(insn_desc_t, bool);
385+
void register_insn(insn_desc_t, std::vector<insn_desc_t>& pool);
422386

423387
void enter_debug_mode(uint8_t cause, uint8_t ext_cause);
424388

0 commit comments

Comments
 (0)