X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=riscv%2Fmmu.h;h=b69de9c9020670f29e63e0bc78c5e82d8f7163b4;hb=04c2d491c4bbb424a59273d4ebee62ddfe3379f9;hp=9e1218cc0debbb46eafb2dc296f7947682527d46;hpb=0de1489e8ab4a527fbcb1440a8fd5b2d4c8c9260;p=riscv-isa-sim.git diff --git a/riscv/mmu.h b/riscv/mmu.h index 9e1218c..b69de9c 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -13,28 +13,14 @@ // virtual memory configuration typedef reg_t pte_t; -const reg_t LEVELS = sizeof(pte_t) == sizeof(uint64_t) ? 3 : 2; -const reg_t PGSHIFT = 13; +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 PGSIZE = 1 << PGSHIFT; -const reg_t PTIDXBITS = PGSHIFT - (sizeof(pte_t) == 8 ? 3 : 2); 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; -// page table entry (PTE) fields -#define PTE_T 0x001 // Entry is a page Table descriptor -#define PTE_E 0x002 // Entry is a page table Entry -#define PTE_R 0x004 // Referenced -#define PTE_D 0x008 // Dirty -#define PTE_UX 0x010 // User eXecute permission -#define PTE_UW 0x020 // User Read permission -#define PTE_UR 0x040 // User Write permission -#define PTE_SX 0x080 // Supervisor eXecute permission -#define PTE_SW 0x100 // Supervisor Read permission -#define PTE_SR 0x200 // Supervisor Write permission -#define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX) -#define PTE_PPN_SHIFT 13 // LSB of physical page number in the PTE - // this class implements a processor's port into the virtual memory system. // an MMU and instruction cache are maintained for simulator performance. class mmu_t @@ -47,16 +33,9 @@ public: #define load_func(type) \ type##_t load_##type(reg_t addr) { \ if(unlikely(addr % sizeof(type##_t))) \ - { \ - badvaddr = addr; \ - throw trap_load_address_misaligned; \ - } \ + throw trap_load_address_misaligned(addr); \ reg_t paddr = translate(addr, sizeof(type##_t), false, false); \ return *(type##_t*)(mem + paddr); \ - } \ - type##_t load_reserved_##type(reg_t addr) { \ - load_reservation = addr; \ - return load_##type(addr); \ } // load value from memory at aligned address; zero extend to register width @@ -75,18 +54,9 @@ public: #define store_func(type) \ void store_##type(reg_t addr, type##_t val) { \ if(unlikely(addr % sizeof(type##_t))) \ - { \ - badvaddr = addr; \ - throw trap_store_address_misaligned; \ - } \ + throw trap_store_address_misaligned(addr); \ reg_t paddr = translate(addr, sizeof(type##_t), true, false); \ *(type##_t*)(mem + paddr) = val; \ - } \ - reg_t store_conditional_##type(reg_t addr, type##_t val) { \ - if (addr == load_reservation) { \ - store_##type(addr, val); \ - return 0; \ - } else return 1; \ } // store value to memory at aligned address @@ -102,80 +72,45 @@ public: }; // load instruction from memory at aligned address. - // (needed because instruction alignment requirement is variable - // if RVC is supported) - // returns the instruction at the specified address, given the current - // RVC mode. func is set to a pointer to a function that knows how to - // execute the returned instruction. - inline insn_fetch_t load_insn(reg_t addr, bool rvc) + inline insn_fetch_t load_insn(reg_t addr) { - #ifdef RISCV_ENABLE_RVC - if(addr % 4 == 2 && rvc) // fetch across word boundary + reg_t idx = (addr/sizeof(insn_t::itype)) % ICACHE_ENTRIES; + if (unlikely(icache_tag[idx] != addr)) { - reg_t addr_lo = translate(addr, 2, false, true); + reg_t paddr = translate(addr, sizeof(insn_t::itype), false, true); insn_fetch_t fetch; - fetch.insn.bits = *(uint16_t*)(mem + addr_lo); + fetch.insn.itype = *(decltype(insn_t::itype)*)(mem + paddr); fetch.func = proc->decode_insn(fetch.insn); - if(!INSN_IS_RVC(fetch.insn.bits)) - { - reg_t addr_hi = translate(addr+2, 2, false, true); - fetch.insn.bits |= (uint32_t)*(uint16_t*)(mem + addr_hi) << 16; - } - return fetch; - } - else - #endif - { - reg_t idx = (addr/sizeof(insn_t::itype)) % ICACHE_ENTRIES; - insn_fetch_t fetch; - if (unlikely(icache_tag[idx] != addr)) + reg_t idx = (paddr/sizeof(insn_t::itype)) % ICACHE_ENTRIES; + icache_tag[idx] = addr; + icache_data[idx] = fetch; + + if (tracer.interested_in_range(paddr, paddr + sizeof(insn_t::itype), false, true)) { - reg_t paddr = translate(addr, sizeof(insn_t::itype), false, true); - fetch.insn.itype = *(decltype(insn_t::itype)*)(mem + paddr); - fetch.func = proc->decode_insn(fetch.insn); - - reg_t idx = (paddr/sizeof(insn_t::itype)) % ICACHE_ENTRIES; - icache_tag[idx] = addr; - icache_data[idx] = fetch.insn; - icache_func[idx] = fetch.func; - - if (tracer.interested_in_range(paddr, paddr + sizeof(insn_t::itype), false, true)) - { - icache_tag[idx] = -1; - tracer.trace(paddr, sizeof(insn_t::itype), false, true); - } + icache_tag[idx] = -1; + tracer.trace(paddr, sizeof(insn_t::itype), false, true); } - fetch.insn = icache_data[idx]; - fetch.func = icache_func[idx]; - return fetch; } + return icache_data[idx]; } - reg_t get_badvaddr() { return badvaddr; } - reg_t get_ptbr() { return ptbr; } - void set_ptbr(reg_t addr) { ptbr = addr & ~(PGSIZE-1); flush_tlb(); } void set_processor(processor_t* p) { proc = p; flush_tlb(); } void flush_tlb(); void flush_icache(); - void yield_load_reservation() { load_reservation = -1; } void register_memtracer(memtracer_t*); private: char* mem; size_t memsz; - reg_t load_reservation; - reg_t badvaddr; - reg_t ptbr; processor_t* proc; memtracer_list_t tracer; // implement an instruction cache for simulator performance static const reg_t ICACHE_ENTRIES = 256; - insn_t icache_data[ICACHE_ENTRIES]; - insn_func_t icache_func[ICACHE_ENTRIES]; + insn_fetch_t icache_data[ICACHE_ENTRIES]; // implement a TLB for simulator performance static const reg_t TLB_ENTRIES = 256;