diff options
Diffstat (limited to 'riscv/mmu.cc')
-rw-r--r-- | riscv/mmu.cc | 103 |
1 files changed, 56 insertions, 47 deletions
diff --git a/riscv/mmu.cc b/riscv/mmu.cc index cc21113..6173b43 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -29,55 +29,70 @@ void mmu_t::flush_tlb() flush_icache(); } -void* mmu_t::refill_tlb(reg_t addr, reg_t bytes, access_type type) +reg_t mmu_t::translate(reg_t addr, access_type type) { - reg_t idx = (addr >> PGSHIFT) % TLB_ENTRIES; - reg_t expected_tag = addr >> PGSHIFT; - - reg_t pgbase; - if (unlikely(!proc)) { - pgbase = addr & -PGSIZE; - } else { - reg_t mode = get_field(proc->state.mstatus, MSTATUS_PRV); - if (type != FETCH && get_field(proc->state.mstatus, MSTATUS_MPRV)) - mode = get_field(proc->state.mstatus, MSTATUS_PRV1); - if (get_field(proc->state.mstatus, MSTATUS_VM) == VM_MBARE) - mode = PRV_M; - - if (mode == PRV_M) { - reg_t msb_mask = (reg_t(2) << (proc->xlen-1))-1; // zero-extend from xlen - pgbase = addr & -PGSIZE & msb_mask; - } else { - pgbase = walk(addr, mode > PRV_U, type); - } + if (!proc) + return addr; + + reg_t mode = get_field(proc->state.mstatus, MSTATUS_PRV); + if (type != FETCH && get_field(proc->state.mstatus, MSTATUS_MPRV)) + mode = get_field(proc->state.mstatus, MSTATUS_PRV1); + if (get_field(proc->state.mstatus, MSTATUS_VM) == VM_MBARE) + mode = PRV_M; + + if (mode == PRV_M) { + reg_t msb_mask = (reg_t(2) << (proc->xlen-1))-1; // zero-extend from xlen + return addr & msb_mask; } + return walk(addr, mode > PRV_U, type) | (addr & (PGSIZE-1)); +} - reg_t pgoff = addr & (PGSIZE-1); - reg_t paddr = pgbase + pgoff; +const uint16_t* mmu_t::fetch_slow_path(reg_t addr) +{ + reg_t paddr = translate(addr, FETCH); + if (paddr >= memsz) + throw trap_instruction_access_fault(addr); + return (const uint16_t*)(mem + paddr); +} - if (pgbase >= memsz) { - if (type == FETCH) throw trap_instruction_access_fault(addr); - else if (type == STORE) throw trap_store_access_fault(addr); - else throw trap_load_access_fault(addr); +void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes) +{ + reg_t paddr = translate(addr, LOAD); + if (paddr < memsz) { + memcpy(bytes, mem + paddr, len); + if (!tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) + refill_tlb(addr, paddr, LOAD); + } else if (!proc || !proc->sim->mmio_load(addr, len, bytes)) { + throw trap_load_access_fault(addr); } +} - bool trace = tracer.interested_in_range(pgbase, pgbase + PGSIZE, type); - if (unlikely(type != FETCH && trace)) - tracer.trace(paddr, bytes, type); - else - { - if (tlb_load_tag[idx] != expected_tag) tlb_load_tag[idx] = -1; - if (tlb_store_tag[idx] != expected_tag) tlb_store_tag[idx] = -1; - if (tlb_insn_tag[idx] != expected_tag) tlb_insn_tag[idx] = -1; +void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes) +{ + reg_t paddr = translate(addr, STORE); + if (paddr < memsz) { + memcpy(mem + paddr, bytes, len); + if (!tracer.interested_in_range(paddr, paddr + PGSIZE, STORE)) + refill_tlb(addr, paddr, STORE); + } else if (!proc || !proc->sim->mmio_store(addr, len, bytes)) { + throw trap_store_access_fault(addr); + } +} + +void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type) +{ + reg_t idx = (vaddr >> PGSHIFT) % TLB_ENTRIES; + reg_t expected_tag = vaddr >> PGSHIFT; - if (type == FETCH) tlb_insn_tag[idx] = expected_tag; - else if (type == STORE) tlb_store_tag[idx] = expected_tag; - else tlb_load_tag[idx] = expected_tag; + if (tlb_load_tag[idx] != expected_tag) tlb_load_tag[idx] = -1; + if (tlb_store_tag[idx] != expected_tag) tlb_store_tag[idx] = -1; + if (tlb_insn_tag[idx] != expected_tag) tlb_insn_tag[idx] = -1; - tlb_data[idx] = mem + pgbase - (addr & -PGSIZE); - } + if (type == FETCH) tlb_insn_tag[idx] = expected_tag; + else if (type == STORE) tlb_store_tag[idx] = expected_tag; + else tlb_load_tag[idx] = expected_tag; - return mem + paddr; + tlb_data[idx] = mem + paddr - vaddr; } reg_t mmu_t::walk(reg_t addr, bool supervisor, access_type type) @@ -121,13 +136,7 @@ reg_t mmu_t::walk(reg_t addr, bool supervisor, access_type type) *(uint32_t*)ppte |= PTE_R | ((type == STORE) * PTE_D); // for superpage mappings, make a fake leaf PTE for the TLB's benefit. reg_t vpn = addr >> PGSHIFT; - reg_t addr = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; - - // check that physical address is legal - if (addr >= memsz) - break; - - return addr; + return (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; } } |