X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=riscv%2Fmmu.h;h=66454bed09ebd8f5a010f5c80623eebd108f6701;hb=a80c695b1961ac40086494920f82e85a085ff358;hp=1f8d34b3a9ad2f0bfcc5793640c74524e04f532b;hpb=d49dd8b60eb1809ecc7b42e0fb615d64402aa47f;p=riscv-isa-sim.git diff --git a/riscv/mmu.h b/riscv/mmu.h index 1f8d34b..66454be 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -105,12 +105,35 @@ public: store_slow_path(addr, sizeof(type##_t), (const uint8_t*)&val); \ } + // template for functions that perform an atomic memory operation + #define amo_func(type) \ + template \ + type##_t amo_##type(reg_t addr, op f) { \ + if (addr & (sizeof(type##_t)-1)) \ + throw trap_store_address_misaligned(addr); \ + try { \ + auto lhs = load_##type(addr); \ + store_##type(addr, f(lhs)); \ + return lhs; \ + } catch (trap_load_page_fault& t) { \ + /* AMO faults should be reported as store faults */ \ + throw trap_store_page_fault(t.get_badaddr()); \ + } catch (trap_load_access_fault& t) { \ + /* AMO faults should be reported as store faults */ \ + throw trap_store_access_fault(t.get_badaddr()); \ + } \ + } + // store value to memory at aligned address store_func(uint8) store_func(uint16) store_func(uint32) store_func(uint64) + // perform an atomic memory operation at an aligned address + amo_func(uint32) + amo_func(uint64) + static const reg_t ICACHE_ENTRIES = 1024; inline size_t icache_index(reg_t addr) @@ -182,7 +205,7 @@ private: static const reg_t TLB_ENTRIES = 256; // If a TLB tag has TLB_CHECK_TRIGGERS set, then the MMU must check for a // trigger match before completing an access. - static const reg_t TLB_CHECK_TRIGGERS = 1L<<63; + static const reg_t TLB_CHECK_TRIGGERS = reg_t(1) << 63; char* tlb_data[TLB_ENTRIES]; reg_t tlb_insn_tag[TLB_ENTRIES]; reg_t tlb_load_tag[TLB_ENTRIES]; @@ -240,4 +263,35 @@ private: friend class processor_t; }; +struct vm_info { + int levels; + int idxbits; + int ptesize; + reg_t ptbase; +}; + +inline vm_info decode_vm_info(int xlen, reg_t prv, reg_t sptbr) +{ + if (prv == PRV_M) { + return {0, 0, 0, 0}; + } else if (prv <= PRV_S && xlen == 32) { + switch (get_field(sptbr, SPTBR32_MODE)) { + case SPTBR_MODE_OFF: return {0, 0, 0, 0}; + case SPTBR_MODE_SV32: return {2, 10, 4, (sptbr & SPTBR32_PPN) << PGSHIFT}; + default: abort(); + } + } else if (prv <= PRV_S && xlen == 64) { + switch (get_field(sptbr, SPTBR64_MODE)) { + case SPTBR_MODE_OFF: return {0, 0, 0, 0}; + case SPTBR_MODE_SV39: return {3, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + case SPTBR_MODE_SV48: return {4, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + case SPTBR_MODE_SV57: return {5, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + case SPTBR_MODE_SV64: return {6, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + default: abort(); + } + } else { + abort(); + } +} + #endif