Skip to content

Commit c6c3d29

Browse files
authored
Merge pull request #2168 from riscv-software-src/simplify-opcode-map
Simplify instruction fetch by getting rid of opcode cache
2 parents bac3747 + f7616ad commit c6c3d29

File tree

3 files changed

+50
-82
lines changed

3 files changed

+50
-82
lines changed

riscv/csrs.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ bool misa_csr_t::unlogged_write(const reg_t val) noexcept {
778778
}
779779

780780
proc->get_mmu()->flush_tlb();
781+
proc->build_opcode_map();
781782

782783
return basic_csr_t::unlogged_write(new_misa);
783784
}

riscv/processor.cc

Lines changed: 37 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()
@@ -146,6 +147,7 @@ void processor_t::enable_log_commits()
146147
{
147148
log_commits_enabled = true;
148149
mmu->flush_tlb(); // the TLB caches this setting
150+
build_opcode_map();
149151
}
150152

151153
void processor_t::reset()
@@ -662,47 +664,48 @@ reg_t processor_t::throw_instruction_address_misaligned(reg_t pc)
662664

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

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

692-
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) {
693677
assert(desc.fast_rv32i && desc.fast_rv64i && desc.fast_rv32e && desc.fast_rv64e &&
694678
desc.logged_rv32i && desc.logged_rv64i && desc.logged_rv32e && desc.logged_rv64e);
695679

696-
if (is_custom)
697-
custom_instructions.push_back(desc);
698-
else
699-
instructions.push_back(desc);
680+
pool.push_back(desc);
700681
}
701682

702683
void processor_t::build_opcode_map()
703684
{
704-
for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++)
705-
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);
706709
}
707710

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

riscv/processor.h

Lines changed: 12 additions & 48 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,12 +307,13 @@ 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*);
316+
void build_opcode_map();
350317

351318
// MMIO slave interface
352319
bool load(reg_t addr, size_t len, uint8_t* bytes) override;
@@ -405,19 +372,17 @@ class processor_t : public abstract_device_t
405372
std::bitset<NUM_ISA_EXTENSIONS> extension_dynamic;
406373
mutable std::bitset<NUM_ISA_EXTENSIONS> extension_assumed_const;
407374

375+
std::vector<opcode_map_entry_t> opcode_map[128];
408376
std::vector<insn_desc_t> instructions;
409377
std::vector<insn_desc_t> custom_instructions;
410378
std::unordered_map<reg_t,uint64_t> pc_histogram;
411379

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

422387
void enter_debug_mode(uint8_t cause, uint8_t ext_cause);
423388

@@ -429,7 +394,6 @@ class processor_t : public abstract_device_t
429394
friend class extension_t;
430395

431396
void parse_priv_string(const char*);
432-
void build_opcode_map();
433397
void register_base_instructions();
434398
insn_func_t decode_insn(insn_t insn);
435399

0 commit comments

Comments
 (0)