diff options
| -rw-r--r-- | riscv/mmu.h | 27 | ||||
| -rw-r--r-- | riscv/processor.cc | 11 | ||||
| -rw-r--r-- | riscv/processor.h | 12 |
3 files changed, 36 insertions, 14 deletions
diff --git a/riscv/mmu.h b/riscv/mmu.h index 5ba0854..3920e72 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -293,7 +293,7 @@ public: return target_big_endian ? to_be(res) : res; } - inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry) + icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry) { insn_bits_t insn = fetch_insn_parcel(addr); unsigned length = insn_length(insn); @@ -319,13 +319,36 @@ public: return entry; } - inline icache_entry_t* access_icache(reg_t addr) + icache_entry_t* ALWAYS_INLINE access_icache(reg_t addr) { icache_entry_t* entry = &icache[icache_index(addr)]; if (likely(entry->tag == addr)){ MMU_OBSERVE_FETCH(addr, entry->data.insn, insn_length(entry->data.insn.bits())); return entry; } + + // As a special case, optimize for short instructions that don't span pages + uint32_t insn; + bool might_span_page = addr % PGSIZE + sizeof(insn) > PGSIZE; + auto [tlb_hit, host_addr, _] = access_tlb(tlb_insn, addr); + + if (likely(tlb_hit && !might_span_page)) { + memcpy(&insn, (const void*)host_addr, sizeof(insn)); + static_assert(sizeof(insn) == 2 * sizeof(insn_parcel_t)); + if (insn_length(insn) == sizeof(insn_parcel_t)) + insn = (insn_parcel_t)insn; + + if (likely(insn_length(insn) <= sizeof(insn))) { + insn_fetch_t fetch = {proc->decode_insn(insn), insn}; + entry->tag = addr; + entry->next = &icache[icache_index(addr + insn_length(insn))]; + entry->data = fetch; + + MMU_OBSERVE_FETCH(addr, insn, length); + return entry; + } + } + return refill_icache(addr, entry); } diff --git a/riscv/processor.cc b/riscv/processor.cc index 80a47d9..5c4bfe2 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -653,17 +653,6 @@ reg_t processor_t::throw_instruction_address_misaligned(reg_t pc) throw trap_instruction_address_misaligned(state.v, pc, 0, 0); } -insn_func_t processor_t::decode_insn(insn_t insn) -{ - const auto& pool = opcode_map[insn.bits() % std::size(opcode_map)]; - - for (auto p = pool.begin(); ; ++p) { - if ((insn.bits() & p->mask) == p->match) { - return p->func; - } - } -} - 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); diff --git a/riscv/processor.h b/riscv/processor.h index cb05210..db7b8ba 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -404,7 +404,17 @@ private: void parse_priv_string(const char*); void register_base_instructions(); - insn_func_t decode_insn(insn_t insn); + + insn_func_t ALWAYS_INLINE decode_insn(insn_t insn) + { + const auto& pool = opcode_map[insn.bits() % std::size(opcode_map)]; + + for (auto p = pool.begin(); ; ++p) { + if ((insn.bits() & p->mask) == p->match) { + return p->func; + } + } + } // Track repeated executions for processor_t::disasm() uint64_t last_pc, last_bits, executions; |
