Implement RVC draft
[riscv-isa-sim.git] / riscv / mmu.h
index c3d8f41b78ce458595add5b378e23b6b61b9f4e6..d6f446bb294c5b91a7b8c5d4a437ed63c6871050 100644 (file)
@@ -4,7 +4,6 @@
 #define _RISCV_MMU_H
 
 #include "decode.h"
-#include "icache.h"
 #include "trap.h"
 #include "common.h"
 #include "config.h"
 // virtual memory configuration
 typedef reg_t pte_t;
 const reg_t LEVELS = sizeof(pte_t) == 8 ? 3 : 2;
-const reg_t PTIDXBITS = 10;
-const reg_t PGSHIFT = PTIDXBITS + (sizeof(pte_t) == 8 ? 3 : 2);
+const reg_t PGSHIFT = 12;
+const reg_t PTIDXBITS = PGSHIFT - (sizeof(pte_t) == 8 ? 3 : 2);
 const reg_t PGSIZE = 1 << PGSHIFT;
 const reg_t VPN_BITS = PTIDXBITS * LEVELS;
-const reg_t PPN_BITS = 8*sizeof(reg_t) - PGSHIFT;
 const reg_t VA_BITS = VPN_BITS + PGSHIFT;
 
 struct insn_fetch_t
 {
   insn_func_t func;
-  union {
-    insn_t insn;
-    uint_fast32_t pad;
-  } insn;
+  insn_t insn;
 };
 
 struct icache_entry_t {
@@ -77,27 +72,51 @@ public:
   store_func(uint32)
   store_func(uint64)
 
+  static const reg_t ICACHE_ENTRIES = 1024;
+
+  inline size_t icache_index(reg_t addr)
+  {
+    // for instruction sizes != 4, this hash still works but is suboptimal
+    return (addr / 4) % ICACHE_ENTRIES;
+  }
+
   // load instruction from memory at aligned address.
-  inline icache_entry_t* access_icache(reg_t addr)
+  icache_entry_t* access_icache(reg_t addr) __attribute__((always_inline))
   {
-    reg_t idx = (addr / sizeof(insn_t)) % ICACHE_SIZE;
+    reg_t idx = icache_index(addr);
     icache_entry_t* entry = &icache[idx];
     if (likely(entry->tag == addr))
       return entry;
 
-    void* iaddr = translate(addr, sizeof(insn_t), false, true);
-    insn_fetch_t fetch;
-    fetch.insn.pad = *(decltype(fetch.insn.insn.bits())*)iaddr;
-    fetch.func = proc->decode_insn(fetch.insn.insn);
+    char* iaddr = (char*)translate(addr, 1, false, true);
+    insn_bits_t insn = *(uint16_t*)iaddr;
+
+    if (likely(insn_length(insn) == 4)) {
+      if (likely(addr % PGSIZE < PGSIZE-2))
+        insn |= (insn_bits_t)*(int16_t*)(iaddr + 2) << 16;
+      else
+        insn |= (insn_bits_t)*(int16_t*)translate(addr + 2, 1, false, true) << 16;
+    } else if (insn_length(insn) == 2) {
+      insn = (int16_t)insn;
+    } else if (insn_length(insn) == 6) {
+      insn |= (insn_bits_t)*(int16_t*)translate(addr + 4, 1, false, true) << 32;
+      insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 1, false, true) << 16;
+    } else {
+      static_assert(sizeof(insn_bits_t) == 8, "insn_bits_t must be uint64_t");
+      insn |= (insn_bits_t)*(int16_t*)translate(addr + 6, 1, false, true) << 48;
+      insn |= (insn_bits_t)*(uint16_t*)translate(addr + 4, 1, false, true) << 32;
+      insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 1, false, true) << 16;
+    }
 
+    insn_fetch_t fetch = {proc->decode_insn(insn), insn};
     icache[idx].tag = addr;
     icache[idx].data = fetch;
 
-    reg_t paddr = (char*)iaddr - mem;
-    if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + sizeof(insn_t), false, true))
+    reg_t paddr = iaddr - mem;
+    if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + 1, false, true))
     {
       icache[idx].tag = -1;
-      tracer.trace(paddr, sizeof(insn_t), false, true);
+      tracer.trace(paddr, 1, false, true);
     }
     return &icache[idx];
   }
@@ -121,7 +140,7 @@ private:
   memtracer_list_t tracer;
 
   // implement an instruction cache for simulator performance
-  icache_entry_t icache[ICACHE_SIZE];
+  icache_entry_t icache[ICACHE_ENTRIES];
 
   // implement a TLB for simulator performance
   static const reg_t TLB_ENTRIES = 256;
@@ -133,8 +152,8 @@ private:
   // finish translation on a TLB miss and upate the TLB
   void* refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch);
 
-  // perform a page table walk for a given virtual address
-  pte_t walk(reg_t addr);
+  // perform a page table walk for a given VA; set referenced/dirty bits
+  pte_t walk(reg_t addr, bool supervisor, bool store, bool fetch);
 
   // translate a virtual address to a physical address
   void* translate(reg_t addr, reg_t bytes, bool store, bool fetch)
@@ -147,7 +166,9 @@ private:
     void* data = tlb_data[idx] + addr;
 
     if (unlikely(addr & (bytes-1)))
-      store ? throw trap_store_address_misaligned(addr) : throw trap_load_address_misaligned(addr);
+      store ? throw trap_store_address_misaligned(addr) :
+      fetch ? throw trap_instruction_address_misaligned(addr) :
+      throw trap_load_address_misaligned(addr);
 
     if (likely(tag == expected_tag))
       return data;