11 const reg_t LEVELS
= 4;
12 const reg_t PGSHIFT
= 12;
13 const reg_t PGSIZE
= 1 << PGSHIFT
;
14 const reg_t PTIDXBITS
= PGSHIFT
- (sizeof(pte_t
) == 8 ? 3 : 2);
15 const reg_t PPN_BITS
= 8*sizeof(reg_t
) - PGSHIFT
;
17 #define PTE_T 0x001 // Entry is a page Table descriptor
18 #define PTE_E 0x002 // Entry is a page table Entry
19 #define PTE_R 0x004 // Referenced
20 #define PTE_D 0x008 // Dirty
21 #define PTE_UX 0x010 // User eXecute permission
22 #define PTE_UW 0x020 // User Read permission
23 #define PTE_UR 0x040 // User Write permission
24 #define PTE_SX 0x080 // Supervisor eXecute permission
25 #define PTE_SW 0x100 // Supervisor Read permission
26 #define PTE_SR 0x200 // Supervisor Write permission
27 #define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX)
28 #define PTE_PERM_SHIFT 4
29 #define PTE_PPN_SHIFT 12
34 mmu_t(char* _mem
, size_t _memsz
)
35 : mem(_mem
), memsz(_memsz
), badvaddr(0),
36 ptbr(0), supervisor(true), vm_enabled(false),
37 icsim(NULL
), dcsim(NULL
), itlbsim(NULL
), dtlbsim(NULL
)
41 #ifdef RISCV_ENABLE_ICSIM
42 # define dcsim_tick(dcsim, dtlbsim, addr, size, st) \
43 do { if(dcsim) (dcsim)->tick(addr, size, st); \
44 if(dtlbsim) (dtlbsim)->tick(addr, sizeof(reg_t), false); } while(0)
46 # define dcsim_tick(dcsim, dtlbsim, addr, size, st)
49 #define load_func(type) \
50 type##_t load_##type(reg_t addr) { \
51 if(unlikely(addr % sizeof(type##_t))) \
54 throw trap_load_address_misaligned; \
56 addr = translate(addr, false, false); \
57 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), false); \
58 return *(type##_t*)(mem+addr); \
61 #define store_func(type) \
62 void store_##type(reg_t addr, type##_t val) { \
63 if(unlikely(addr % sizeof(type##_t))) \
66 throw trap_store_address_misaligned; \
68 addr = translate(addr, true, false); \
69 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), true); \
70 *(type##_t*)(mem+addr) = val; \
73 insn_t
__attribute__((always_inline
)) load_insn(reg_t addr
, bool rvc
)
77 reg_t idx
= (addr
/sizeof(insn_t
)) % ICACHE_ENTRIES
;
78 bool hit
= addr
% 4 == 0 && icache_tag
[idx
] == (addr
| 1);
80 return icache_data
[idx
];
82 #ifdef RISCV_ENABLE_RVC
83 if(addr
% 4 == 2 && rvc
)
85 reg_t paddr_lo
= translate(addr
, false, true);
86 insn
.bits
= *(uint16_t*)(mem
+paddr_lo
);
88 if(!INSN_IS_RVC(insn
.bits
))
90 reg_t paddr_hi
= translate(addr
+2, false, true);
91 insn
.bits
|= (uint32_t)*(uint16_t*)(mem
+paddr_hi
) << 16;
97 if(unlikely(addr
% 4))
100 throw trap_instruction_address_misaligned
;
102 reg_t paddr
= translate(addr
, false, true);
103 insn
= *(insn_t
*)(mem
+paddr
);
105 icache_tag
[idx
] = addr
| 1;
106 icache_data
[idx
] = insn
;
109 #ifdef RISCV_ENABLE_ICSIM
111 icsim
->tick(addr
, insn_length(insn
.bits
), false);
113 itlbsim
->tick(addr
, sizeof(reg_t
), false);
134 reg_t
get_badvaddr() { return badvaddr
; }
135 reg_t
get_ptbr() { return ptbr
; }
137 void set_supervisor(bool sup
) { supervisor
= sup
; }
138 void set_vm_enabled(bool en
) { vm_enabled
= en
; }
139 void set_ptbr(reg_t addr
) { ptbr
= addr
& ~(PGSIZE
-1); flush_tlb(); }
141 void set_icsim(icsim_t
* _icsim
) { icsim
= _icsim
; }
142 void set_dcsim(icsim_t
* _dcsim
) { dcsim
= _dcsim
; }
143 void set_itlbsim(icsim_t
* _itlbsim
) { itlbsim
= _itlbsim
; }
144 void set_dtlbsim(icsim_t
* _dtlbsim
) { dtlbsim
= _dtlbsim
; }
158 static const reg_t TLB_ENTRIES
= 256;
159 pte_t tlb_data
[TLB_ENTRIES
];
160 reg_t tlb_tag
[TLB_ENTRIES
];
162 static const reg_t ICACHE_ENTRIES
= 256;
163 insn_t icache_data
[ICACHE_ENTRIES
];
164 reg_t icache_tag
[ICACHE_ENTRIES
];
171 reg_t
translate(reg_t addr
, bool store
, bool fetch
)
173 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
174 pte_t pte
= tlb_data
[idx
];
175 reg_t tag
= tlb_tag
[idx
];
177 trap_t trap
= store
? trap_store_access_fault
178 : fetch
? trap_instruction_access_fault
179 : trap_load_access_fault
;
181 bool hit
= (pte
& PTE_E
) && tag
== (addr
>> PGSHIFT
);
192 tlb_tag
[idx
] = addr
>> PGSHIFT
;
195 reg_t access_type
= store
? PTE_UW
: fetch
? PTE_UX
: PTE_UR
;
198 if(unlikely(!(access_type
& pte
& PTE_PERM
)))
204 return (addr
& (PGSIZE
-1)) | ((pte
>> PTE_PPN_SHIFT
) << PGSHIFT
);
207 pte_t
walk(reg_t addr
)
214 pte
= PTE_E
| PTE_PERM
| ((addr
>> PGSHIFT
) << PTE_PPN_SHIFT
);
221 int ptshift
= (LEVELS
-1)*PTIDXBITS
;
222 for(reg_t i
= 0; i
< LEVELS
; i
++, ptshift
-= PTIDXBITS
)
224 reg_t idx
= (addr
>> (PGSHIFT
+ptshift
)) & ((1<<PTIDXBITS
)-1);
226 reg_t pte_addr
= base
+ idx
*sizeof(pte_t
);
227 if(pte_addr
>= memsz
)
230 ptd
= *(pte_t
*)(mem
+pte_addr
);
233 // if this PTE is from a larger PT, fake a leaf
234 // PTE so the TLB will work right
235 reg_t vpn
= addr
>> PGSHIFT
;
236 ptd
|= (vpn
& ((1<<(ptshift
))-1)) << PTE_PPN_SHIFT
;
238 // fault if physical addr is invalid
239 reg_t ppn
= ptd
>> PTE_PPN_SHIFT
;
240 if((ppn
<< PGSHIFT
) + (addr
& (PGSIZE
-1)) < memsz
)
244 else if(!(ptd
& PTE_T
))
247 base
= (ptd
>> PTE_PPN_SHIFT
) << PGSHIFT
;
254 friend class processor_t
;