13 const reg_t LEVELS
= 4;
14 const reg_t PGSHIFT
= 12;
15 const reg_t PGSIZE
= 1 << PGSHIFT
;
16 const reg_t PTIDXBITS
= PGSHIFT
- (sizeof(pte_t
) == 8 ? 3 : 2);
17 const reg_t PPN_BITS
= 8*sizeof(reg_t
) - PGSHIFT
;
19 #define PTE_T 0x001 // Entry is a page Table descriptor
20 #define PTE_E 0x002 // Entry is a page table Entry
21 #define PTE_R 0x004 // Referenced
22 #define PTE_D 0x008 // Dirty
23 #define PTE_UX 0x010 // User eXecute permission
24 #define PTE_UW 0x020 // User Read permission
25 #define PTE_UR 0x040 // User Write permission
26 #define PTE_SX 0x080 // Supervisor eXecute permission
27 #define PTE_SW 0x100 // Supervisor Read permission
28 #define PTE_SR 0x200 // Supervisor Write permission
29 #define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX)
30 #define PTE_PERM_SHIFT 4
31 #define PTE_PPN_SHIFT 12
36 mmu_t(char* _mem
, size_t _memsz
);
39 #ifdef RISCV_ENABLE_ICSIM
40 # define dcsim_tick(dcsim, dtlbsim, addr, size, st) \
41 do { if(dcsim) (dcsim)->tick(addr, size, st); \
42 if(dtlbsim) (dtlbsim)->tick(addr, sizeof(reg_t), false); } while(0)
44 # define dcsim_tick(dcsim, dtlbsim, addr, size, st)
47 #define load_func(type) \
48 type##_t load_##type(reg_t addr) { \
49 if(unlikely(addr % sizeof(type##_t))) \
52 throw trap_load_address_misaligned; \
54 void* paddr = translate(addr, false, false); \
55 dcsim_tick(dcsim, dtlbsim, paddr-mem, sizeof(type##_t), false); \
56 return *(type##_t*)paddr; \
59 #define store_func(type) \
60 void store_##type(reg_t addr, type##_t val) { \
61 if(unlikely(addr % sizeof(type##_t))) \
64 throw trap_store_address_misaligned; \
66 void* paddr = translate(addr, true, false); \
67 dcsim_tick(dcsim, dtlbsim, paddr-mem, sizeof(type##_t), true); \
68 *(type##_t*)paddr = val; \
71 insn_t
__attribute__((always_inline
)) load_insn(reg_t addr
, bool rvc
)
75 #ifdef RISCV_ENABLE_RVC
76 if(addr
% 4 == 2 && rvc
) // fetch across word boundary
78 void* addr_lo
= translate(addr
, false, true);
79 insn
.bits
= *(uint16_t*)addr_lo
;
81 if(!INSN_IS_RVC(insn
.bits
))
83 void* addr_hi
= translate(addr
+2, false, true);
84 insn
.bits
|= (uint32_t)*(uint16_t*)addr_hi
<< 16;
90 reg_t idx
= (addr
/sizeof(insn_t
)) % ICACHE_ENTRIES
;
91 bool hit
= icache_tag
[idx
] == addr
;
93 return icache_data
[idx
];
95 // the processor guarantees alignment based upon rvc mode
96 void* paddr
= translate(addr
, false, true);
97 insn
= *(insn_t
*)paddr
;
99 icache_tag
[idx
] = addr
;
100 icache_data
[idx
] = insn
;
103 #ifdef RISCV_ENABLE_ICSIM
105 icsim
->tick(addr
, insn_length(insn
.bits
), false);
107 itlbsim
->tick(addr
, sizeof(reg_t
), false);
128 reg_t
get_badvaddr() { return badvaddr
; }
129 reg_t
get_ptbr() { return ptbr
; }
131 void set_supervisor(bool sup
) { supervisor
= sup
; }
132 void set_vm_enabled(bool en
) { vm_enabled
= en
; }
133 void set_ptbr(reg_t addr
) { ptbr
= addr
& ~(PGSIZE
-1); flush_tlb(); }
135 void set_icsim(icsim_t
* _icsim
) { icsim
= _icsim
; }
136 void set_dcsim(icsim_t
* _dcsim
) { dcsim
= _dcsim
; }
137 void set_itlbsim(icsim_t
* _itlbsim
) { itlbsim
= _itlbsim
; }
138 void set_dtlbsim(icsim_t
* _dtlbsim
) { dtlbsim
= _dtlbsim
; }
152 static const reg_t TLB_ENTRIES
= 256;
153 long tlb_data
[TLB_ENTRIES
];
154 reg_t tlb_insn_tag
[TLB_ENTRIES
];
155 reg_t tlb_load_tag
[TLB_ENTRIES
];
156 reg_t tlb_store_tag
[TLB_ENTRIES
];
158 static const reg_t ICACHE_ENTRIES
= 256;
159 insn_t icache_data
[ICACHE_ENTRIES
];
160 reg_t icache_tag
[ICACHE_ENTRIES
];
167 void* refill(reg_t addr
, bool store
, bool fetch
);
168 pte_t
walk(reg_t addr
);
170 void* translate(reg_t addr
, bool store
, bool fetch
)
172 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
174 reg_t
* tlb_tag
= fetch
? tlb_insn_tag
: store
? tlb_store_tag
:tlb_load_tag
;
175 reg_t expected_tag
= addr
& ~(PGSIZE
-1);
176 if(likely(tlb_tag
[idx
] == expected_tag
))
177 return (void*)(((long)addr
& (PGSIZE
-1)) | tlb_data
[idx
]);
179 return refill(addr
, store
, fetch
);
182 friend class processor_t
;