diff options
author | Andrew Waterman <andrew@sifive.com> | 2022-10-05 18:09:53 -0700 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2022-10-06 19:30:28 -0700 |
commit | 749ead90a5c254ca23d54ef3e0669e51df127a5d (patch) | |
tree | f73112f017ae2e780def75d810b0137a7576a005 /riscv/mmu.cc | |
parent | d7edd7ac550dab81b84f2001793e04b663330658 (diff) | |
download | spike-749ead90a5c254ca23d54ef3e0669e51df127a5d.zip spike-749ead90a5c254ca23d54ef3e0669e51df127a5d.tar.gz spike-749ead90a5c254ca23d54ef3e0669e51df127a5d.tar.bz2 |
Move all uncommon-case load functionality into load_slow_path
As a side effect, misaligned loads now behave the same as aligned loads
with respect to triggers: only the first byte is checked.
Diffstat (limited to 'riscv/mmu.cc')
-rw-r--r-- | riscv/mmu.cc | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 38a7241..49889df 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -139,12 +139,13 @@ bool mmu_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes) return sim->mmio_store(addr, len, bytes); } -void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate_flags) +void mmu_t::load_slow_path_intrapage(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate_flags) { - if (!matched_trigger) { - matched_trigger = trigger_exception(triggers::OPERATION_LOAD, addr, false); - if (matched_trigger) - throw *matched_trigger; + reg_t vpn = addr >> PGSHIFT; + if (xlate_flags == 0 && vpn == (tlb_load_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) { + auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr; + memcpy(bytes, host_addr, len); + return; } reg_t paddr = translate(addr, len, LOAD, xlate_flags); @@ -158,6 +159,32 @@ void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate } else if (!mmio_load(paddr, len, bytes)) { throw trap_load_access_fault((proc) ? proc->state.v : false, addr, 0, 0); } +} + +void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate_flags, bool UNUSED require_alignment) +{ + if (!matched_trigger) { + matched_trigger = trigger_exception(triggers::OPERATION_LOAD, addr, false); + if (matched_trigger) + throw *matched_trigger; + } + + if ((addr & (len - 1)) == 0) { + load_slow_path_intrapage(addr, len, bytes, xlate_flags); + } else { + bool gva = ((proc) ? proc->state.v : false) || (RISCV_XLATE_VIRT & xlate_flags); +#ifndef RISCV_ENABLE_MISALIGNED + throw trap_load_address_misaligned(gva, addr, 0, 0); +#else + if (require_alignment) + throw trap_load_access_fault(gva, addr, 0, 0); + + reg_t len_page0 = std::min(len, PGSIZE - addr % PGSIZE); + load_slow_path_intrapage(addr, len_page0, bytes, xlate_flags); + if (len_page0 != len) + load_slow_path_intrapage(addr + len_page0, len - len_page0, bytes + len_page0, xlate_flags); +#endif + } if (!matched_trigger) { reg_t data = reg_from_bytes(len, bytes); |