#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
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_SIZE;
+ return (addr / 4) % ICACHE_ENTRIES;
}
// load instruction from memory at aligned address.
if (likely(entry->tag == addr))
return entry;
- char* iaddr = (char*)translate(addr, 2, false, true);
+ char* iaddr = (char*)translate(addr, 1, false, true);
insn_bits_t insn = *(uint16_t*)iaddr;
- if (unlikely(insn_length(insn) == 2)) {
- insn = (int16_t)insn;
- } else if (likely(insn_length(insn) == 4)) {
- if (likely((addr & (PGSIZE-1)) < PGSIZE-2))
+ 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, 2, false, true) << 16;
+ 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, 2, false, true) << 32;
- insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 2, false, true) << 16;
+ 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, 2, false, true) << 48;
- insn |= (insn_bits_t)*(uint16_t*)translate(addr + 4, 2, false, true) << 32;
- insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 2, false, true) << 16;
+ 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};
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;
// 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)
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;