Put simif_t declaration in its own file. (#209)
[riscv-isa-sim.git] / riscv / mmu.cc
index f0adb2204c6867bd39e3fd4796dc33d3bc66a851..3a0bd39b89471470cef1155f201a646b673cbfab 100644 (file)
@@ -1,10 +1,10 @@
 // See LICENSE for license details.
 
 #include "mmu.h"
-#include "sim.h"
+#include "simif.h"
 #include "processor.h"
 
-mmu_t::mmu_t(sim_t* sim, processor_t* proc)
+mmu_t::mmu_t(simif_t* sim, processor_t* proc)
  : sim(sim), proc(proc),
   check_triggers_fetch(false),
   check_triggers_load(false),
@@ -159,11 +159,11 @@ tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_
 
 reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
 {
-  vm_info vm = decode_vm_info(proc->max_xlen, mode, proc->get_state()->sptbr);
+  vm_info vm = decode_vm_info(proc->max_xlen, mode, proc->get_state()->satp);
   if (vm.levels == 0)
     return addr & ((reg_t(2) << (proc->xlen-1))-1); // zero-extend from xlen
 
-  bool supervisor = mode == PRV_S;
+  bool s_mode = mode == PRV_S;
   bool sum = get_field(proc->state.mstatus, MSTATUS_SUM);
   bool mxr = get_field(proc->state.mstatus, MSTATUS_MXR);
 
@@ -182,14 +182,14 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
     // check that physical address of PTE is legal
     auto ppte = sim->addr_to_mem(base + idx * vm.ptesize);
     if (!ppte)
-      throw trap_load_access_fault(addr);
+      goto fail_access;
 
     reg_t pte = vm.ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte;
     reg_t ppn = pte >> PTE_PPN_SHIFT;
 
     if (PTE_TABLE(pte)) { // next level of page table
       base = ppn << PGSHIFT;
-    } else if ((pte & PTE_U) ? supervisor && !sum : !supervisor) {
+    } else if ((pte & PTE_U) ? s_mode && (type == FETCH || !sum) : !s_mode) {
       break;
     } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
       break;
@@ -197,6 +197,8 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
                type == LOAD ?  !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :
                                !((pte & PTE_R) && (pte & PTE_W))) {
       break;
+    } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
+      break;
     } else {
       reg_t ad = PTE_A | ((type == STORE) * PTE_D);
 #ifdef RISCV_ENABLE_DIRTY
@@ -221,6 +223,14 @@ fail:
     case STORE: throw trap_store_page_fault(addr);
     default: abort();
   }
+
+fail_access:
+  switch (type) {
+    case FETCH: throw trap_instruction_access_fault(addr);
+    case LOAD: throw trap_load_access_fault(addr);
+    case STORE: throw trap_store_access_fault(addr);
+    default: abort();
+  }
 }
 
 void mmu_t::register_memtracer(memtracer_t* t)