From 6f9038152e2cf31388dad581cc6ced0b1d341de2 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 28 Jul 2026 15:03:31 -0700 Subject: [PATCH] Factor instruction-fetch logic out of refill_icache Also separate the case where the first fetch is a simple intrapage TLB hit, which will help with a subsequent change. Signed-off-by: Andrew Waterman --- riscv/mmu.cc | 4 ++-- riscv/mmu.h | 37 +++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 815e75a1..fa4bf385 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -99,7 +99,7 @@ inline mmu_t::insn_parcel_t mmu_t::perform_intrapage_fetch(reg_t vaddr, uintptr_ else if (!mmio_fetch(paddr, sizeof(res), (uint8_t*)&res)) throw trap_instruction_access_fault(proc->state.v, vaddr, 0, 0); - return res; + return from_le(res); } mmu_t::insn_parcel_t mmu_t::fetch_slow_path(reg_t vaddr) @@ -143,7 +143,7 @@ mmu_t::insn_parcel_t mmu_t::fetch_slow_path(reg_t vaddr) return res; check_triggers(triggers::OPERATION_EXECUTE, vaddr, - access_info.effective_virt, sizeof(insn_parcel_t), from_le(res)); + access_info.effective_virt, sizeof(insn_parcel_t), res); return res; } diff --git a/riscv/mmu.h b/riscv/mmu.h index 01a6eada..3e8cf4d8 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -303,7 +303,7 @@ public: T ALWAYS_INLINE fetch_jump_table(reg_t addr) { T res = 0; for (size_t i = 0; i < sizeof(T) / sizeof(insn_parcel_t); i++) - res |= (T)fetch_insn_parcel(addr + i * sizeof(insn_parcel_t)) << (i * sizeof(insn_parcel_t) * 8); + res |= (T)fetch_slow_path(addr + i * sizeof(insn_parcel_t)) << (i * sizeof(insn_parcel_t) * 8); // table accesses use data endianness, not instruction (little) endianness return target_big_endian ? to_be(res) : res; @@ -311,13 +311,7 @@ public: inline 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); - - for (unsigned pos = sizeof(insn_parcel_t); pos < length; pos += sizeof(insn_parcel_t)) { - insn |= (insn_bits_t)fetch_insn_parcel(addr + pos) << (8 * pos); - length = insn_length(insn); - } + auto [insn, length] = fetch_insn(addr); insn_fetch_t fetch = {proc->decode_insn(insn), insn}; entry->tag = addr; @@ -528,11 +522,30 @@ private: pte_cache[key % PTE_CACHE_ENTRIES] = {key, value}; } - inline insn_parcel_t fetch_insn_parcel(reg_t addr) { - if (auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_insn, addr); tlb_hit) - return from_le(*(insn_parcel_t*)host_addr); + std::tuple ALWAYS_INLINE fetch_insn(reg_t addr) + { + bool intrapage = addr % PGSIZE + sizeof(insn_bits_t) <= PGSIZE; + if (auto [tlb_hit, host_addr, paddr] = access_tlb(tlb_insn, addr); tlb_hit && intrapage) { + insn_bits_t insn = from_le(*(insn_parcel_t*)host_addr); + size_t length = insn_length(insn); + + for (size_t pos = sizeof(insn_parcel_t); pos < length; pos += sizeof(insn_parcel_t)) { + insn |= insn_bits_t(from_le(*(insn_parcel_t*)(host_addr + pos))) << (8 * pos); + length = insn_length(insn); + } + + return std::make_tuple(insn, length); + } + + insn_bits_t insn = fetch_slow_path(addr); + size_t length = insn_length(insn); + + for (size_t pos = sizeof(insn_parcel_t); pos < length; pos += sizeof(insn_parcel_t)) { + insn |= insn_bits_t(fetch_slow_path(addr + pos)) << (8 * pos); + length = insn_length(insn); + } - return from_le(fetch_slow_path(addr)); + return std::make_tuple(insn, length); } inline bool in_mprv() const