aboutsummaryrefslogtreecommitdiff
path: root/riscv/mmu.cc
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2015-09-24 18:09:26 -0700
committerAndrew Waterman <waterman@cs.berkeley.edu>2015-09-24 18:10:00 -0700
commite78da5da4a6e6a38953cda9b35992c421768c776 (patch)
tree9191d1770f2cef9e0b748537ac3a612899f56133 /riscv/mmu.cc
parent3258ff6431d22da76bd1cd873789a6c82d0af3b0 (diff)
downloadspike-e78da5da4a6e6a38953cda9b35992c421768c776.zip
spike-e78da5da4a6e6a38953cda9b35992c421768c776.tar.gz
spike-e78da5da4a6e6a38953cda9b35992c421768c776.tar.bz2
Refactor memory access code; add MMIO support
Of course, it doesn't do anything yet.
Diffstat (limited to 'riscv/mmu.cc')
-rw-r--r--riscv/mmu.cc103
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;
}
}