From: Andrew Waterman Date: Mon, 16 May 2011 21:34:11 +0000 (-0700) Subject: [sim,pk] cleanups & initial virtual memory support X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6e85b4332f8d5fa198b766afb73dde5506d5097f;p=riscv-isa-sim.git [sim,pk] cleanups & initial virtual memory support --- diff --git a/riscv/insns/fence_i.h b/riscv/insns/fence_i.h index e69de29..a2dbffe 100644 --- a/riscv/insns/fence_i.h +++ b/riscv/insns/fence_i.h @@ -0,0 +1 @@ +mmu.flush_icache(); diff --git a/riscv/insns/mfpcr.h b/riscv/insns/mfpcr.h index e9d5350..fe00f5f 100644 --- a/riscv/insns/mfpcr.h +++ b/riscv/insns/mfpcr.h @@ -27,7 +27,11 @@ switch(insn.rtype.rs2) break; case 8: - val = MEMSIZE >> 12; + val = MEMSIZE >> PGSHIFT; + break; + + case 9: + val = mmu.get_ptbr(); break; case 17: diff --git a/riscv/insns/mtpcr.h b/riscv/insns/mtpcr.h index 449f63d..f47781f 100644 --- a/riscv/insns/mtpcr.h +++ b/riscv/insns/mtpcr.h @@ -19,6 +19,10 @@ switch(insn.rtype.rs2) compare = RS1; break; + case 9: + mmu.set_ptbr(RS1); + break; + case 16: tohost = RS1; sim->set_tohost(RS1); diff --git a/riscv/mmu.cc b/riscv/mmu.cc new file mode 100644 index 0000000..4c29000 --- /dev/null +++ b/riscv/mmu.cc @@ -0,0 +1,12 @@ +#include "mmu.h" + +void mmu_t::flush_tlb() +{ + memset(tlb_data, 0, sizeof(tlb_data)); // TLB entry itself has valid bit + flush_icache(); +} + +void mmu_t::flush_icache() +{ + memset(icache_tag, 0, sizeof(icache_tag)); // I$ tag contains valid bit +} diff --git a/riscv/mmu.h b/riscv/mmu.h index 2f897ff..65186a5 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -36,11 +36,6 @@ public: { } - void set_icsim(icsim_t* _icsim) { icsim = _icsim; } - void set_dcsim(icsim_t* _dcsim) { dcsim = _dcsim; } - void set_itlbsim(icsim_t* _itlbsim) { itlbsim = _itlbsim; } - void set_dtlbsim(icsim_t* _dtlbsim) { dtlbsim = _dtlbsim; } - #ifdef RISCV_ENABLE_ICSIM # define dcsim_tick(dcsim, dtlbsim, addr, size, st) \ do { if(dcsim) (dcsim)->tick(addr, size, st); \ @@ -69,22 +64,32 @@ public: { insn_t insn; - #ifdef RISCV_ENABLE_RVC - check_align(addr, rvc ? 2 : 4, false, true); - - reg_t paddr_lo = translate(addr, false, true); - insn.bits = *(uint16_t*)(mem+paddr_lo); + reg_t idx = (addr/sizeof(insn_t)) % ICACHE_ENTRIES; + if(addr % 4 == 0 && icache_tag[idx] == (addr | 1)) + return icache_data[idx]; - if(!INSN_IS_RVC(insn.bits)) + #ifdef RISCV_ENABLE_RVC + if(addr % 4 == 2 && rvc) { - reg_t paddr_hi = translate(addr+2, false, true); - insn.bits |= (uint32_t)*(uint16_t*)(mem+paddr_hi) << 16; + reg_t paddr_lo = translate(addr, false, true); + insn.bits = *(uint16_t*)(mem+paddr_lo); + + if(!INSN_IS_RVC(insn.bits)) + { + reg_t paddr_hi = translate(addr+2, false, true); + insn.bits |= (uint32_t)*(uint16_t*)(mem+paddr_hi) << 16; + } } - #else - check_align(addr, 4, false, true); - reg_t paddr = translate(addr, false, true); - insn = *(insn_t*)(mem+paddr); + else #endif + { + check_align(addr, 4, false, true); + reg_t paddr = translate(addr, false, true); + insn = *(insn_t*)(mem+paddr); + + icache_tag[idx] = addr | 1; + icache_data[idx] = insn; + } #ifdef RISCV_ENABLE_ICSIM if(icsim) @@ -112,9 +117,19 @@ public: store_func(uint64) reg_t get_badvaddr() { return badvaddr; } + reg_t get_ptbr() { return ptbr; } + void set_supervisor(bool sup) { supervisor = sup; } void set_vm_enabled(bool en) { vm_enabled = en; } - void set_ptbr(reg_t addr) { ptbr = addr & ~(PGSIZE-1); } + void set_ptbr(reg_t addr) { ptbr = addr & ~(PGSIZE-1); flush_tlb(); } + + void set_icsim(icsim_t* _icsim) { icsim = _icsim; } + void set_dcsim(icsim_t* _dcsim) { dcsim = _dcsim; } + void set_itlbsim(icsim_t* _itlbsim) { itlbsim = _itlbsim; } + void set_dtlbsim(icsim_t* _dtlbsim) { dtlbsim = _dtlbsim; } + + void flush_tlb(); + void flush_icache(); private: char* mem; @@ -129,6 +144,10 @@ private: pte_t tlb_data[TLB_ENTRIES]; reg_t tlb_tag[TLB_ENTRIES]; + static const reg_t ICACHE_ENTRIES = 32; + insn_t icache_data[ICACHE_ENTRIES]; + reg_t icache_tag[ICACHE_ENTRIES]; + icsim_t* icsim; icsim_t* dcsim; icsim_t* itlbsim; @@ -172,13 +191,13 @@ private: !store && !fetch && !(supervisor ? pte.sr : pte.ur)) throw trap; - return (addr % PGSIZE) | (pte.ppn << PGSHIFT); + return (addr & (PGSIZE-1)) | (pte.ppn << PGSHIFT); } pte_t walk(reg_t addr) { pte_t pte; - + if(!vm_enabled) { pte.v = addr < memsz; @@ -190,45 +209,34 @@ private: else { pte.v = 0; - + int lg_ptesz = sizeof(pte_t) == 4 ? 2 : sizeof(pte_t) == 8 ? 3 : 0; assert(lg_ptesz); - + reg_t base = ptbr; - + for(int i = LEVELS-1; i >= 0; i++) { reg_t idx = addr >> (PGSHIFT + i*(PGSHIFT - lg_ptesz)); idx &= (1<<(PGSHIFT - lg_ptesz)) - 1; - + reg_t pte_addr = base + idx*sizeof(pte_t); if(pte_addr >= memsz) break; - + pte = *(pte_t*)(mem+pte_addr); if(!pte.v || pte.e) break; - + base = pte.ppn << PGSHIFT; } pte.v &= pte.e; } - + return pte; } - - void check_bounds(reg_t addr, int size, bool store, bool fetch) - { - if(addr >= memsz || addr + size > memsz) - { - badvaddr = addr; - if(fetch) - throw trap_instruction_access_fault; - throw store ? trap_store_access_fault : trap_load_access_fault; - } - } friend class processor_t; }; diff --git a/riscv/processor.cc b/riscv/processor.cc index 118d4d8..bb1a982 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -123,6 +123,7 @@ void processor_t::set_sr(uint32_t val) mmu.set_vm_enabled(sr & SR_VM); mmu.set_supervisor(sr & SR_S); + mmu.flush_tlb(); xprlen = ((sr & SR_S) ? (sr & SR_SX) : (sr & SR_UX)) ? 64 : 32; } diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index f53bc13..62d6046 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -19,6 +19,7 @@ riscv_srcs = \ sim.cc \ trap.cc \ icsim.cc \ + mmu.cc \ riscv_test_srcs =