8 const reg_t LEVELS
= 4;
9 const reg_t PGSHIFT
= 12;
10 const reg_t PGSIZE
= 1 << PGSHIFT
;
11 const reg_t PPN_BITS
= 8*sizeof(reg_t
) - PGSHIFT
;
32 mmu_t(char* _mem
, size_t _memsz
)
33 : mem(_mem
), memsz(_memsz
), badvaddr(0),
34 ptbr(0), supervisor(true), vm_enabled(false),
35 icsim(NULL
), dcsim(NULL
), itlbsim(NULL
), dtlbsim(NULL
)
39 void set_icsim(icsim_t
* _icsim
) { icsim
= _icsim
; }
40 void set_dcsim(icsim_t
* _dcsim
) { dcsim
= _dcsim
; }
41 void set_itlbsim(icsim_t
* _itlbsim
) { itlbsim
= _itlbsim
; }
42 void set_dtlbsim(icsim_t
* _dtlbsim
) { dtlbsim
= _dtlbsim
; }
44 #ifdef RISCV_ENABLE_ICSIM
45 # define dcsim_tick(dcsim, dtlbsim, addr, size, st) \
46 do { if(dcsim) (dcsim)->tick(addr, size, st); \
47 if(dtlbsim) (dtlbsim)->tick(addr, sizeof(reg_t), false); } while(0)
49 # define dcsim_tick(dcsim, dtlbsim, addr, size, st)
52 #define load_func(type) \
53 type##_t load_##type(reg_t addr) { \
54 check_align(addr, sizeof(type##_t), false, false); \
55 addr = translate(addr, false, false); \
56 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), false); \
57 return *(type##_t*)(mem+addr); \
60 #define store_func(type) \
61 void store_##type(reg_t addr, type##_t val) { \
62 check_align(addr, sizeof(type##_t), true, false); \
63 addr = translate(addr, true, false); \
64 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), true); \
65 *(type##_t*)(mem+addr) = val; \
68 insn_t
load_insn(reg_t addr
, bool rvc
)
72 #ifdef RISCV_ENABLE_RVC
73 check_align(addr
, rvc
? 2 : 4, false, true);
75 reg_t paddr_lo
= translate(addr
, false, true);
76 insn
.bits
= *(uint16_t*)(mem
+paddr_lo
);
78 if(!INSN_IS_RVC(insn
.bits
))
80 reg_t paddr_hi
= translate(addr
+2, false, true);
81 insn
.bits
|= (uint32_t)*(uint16_t*)(mem
+paddr_hi
) << 16;
84 check_align(addr
, 4, false, true);
85 reg_t paddr
= translate(addr
, false, true);
86 insn
= *(insn_t
*)(mem
+paddr
);
89 #ifdef RISCV_ENABLE_ICSIM
91 icsim
->tick(addr
, insn_length(insn
), false);
93 itlbsim
->tick(addr
, sizeof(reg_t
), false);
114 reg_t
get_badvaddr() { return badvaddr
; }
115 void set_supervisor(bool sup
) { supervisor
= sup
; }
116 void set_vm_enabled(bool en
) { vm_enabled
= en
; }
117 void set_ptbr(reg_t addr
) { ptbr
= addr
& ~(PGSIZE
-1); }
128 static const reg_t TLB_ENTRIES
= 32;
129 pte_t tlb_data
[TLB_ENTRIES
];
130 reg_t tlb_tag
[TLB_ENTRIES
];
137 void check_align(reg_t addr
, int size
, bool store
, bool fetch
)
143 throw trap_instruction_address_misaligned
;
145 throw trap_store_address_misaligned
;
146 throw trap_load_address_misaligned
;
150 reg_t
translate(reg_t addr
, bool store
, bool fetch
)
152 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
153 pte_t pte
= tlb_data
[idx
];
154 reg_t tag
= tlb_tag
[idx
];
156 trap_t trap
= store
? trap_store_access_fault
157 : fetch
? trap_instruction_access_fault
158 : trap_load_access_fault
;
160 if(!pte
.v
|| tag
!= (addr
>> PGSHIFT
))
167 tlb_tag
[idx
] = addr
>> PGSHIFT
;
170 if(store
&& !(supervisor
? pte
.sw
: pte
.uw
) ||
171 !store
&& !fetch
&& !(supervisor
? pte
.sr
: pte
.ur
) ||
172 !store
&& !fetch
&& !(supervisor
? pte
.sr
: pte
.ur
))
175 return (addr
% PGSIZE
) | (pte
.ppn
<< PGSHIFT
);
178 pte_t
walk(reg_t addr
)
184 pte
.v
= addr
< memsz
;
187 pte
.ur
= pte
.uw
= pte
.ux
= pte
.sr
= pte
.sw
= pte
.sx
= 1;
188 pte
.ppn
= addr
>> PGSHIFT
;
194 int lg_ptesz
= sizeof(pte_t
) == 4 ? 2
195 : sizeof(pte_t
) == 8 ? 3
201 for(int i
= LEVELS
-1; i
>= 0; i
++)
203 reg_t idx
= addr
>> (PGSHIFT
+ i
*(PGSHIFT
- lg_ptesz
));
204 idx
&= (1<<(PGSHIFT
- lg_ptesz
)) - 1;
206 reg_t pte_addr
= base
+ idx
*sizeof(pte_t
);
207 if(pte_addr
>= memsz
)
210 pte
= *(pte_t
*)(mem
+pte_addr
);
214 base
= pte
.ppn
<< PGSHIFT
;
222 void check_bounds(reg_t addr
, int size
, bool store
, bool fetch
)
224 if(addr
>= memsz
|| addr
+ size
> memsz
)
228 throw trap_instruction_access_fault
;
229 throw store
? trap_store_access_fault
: trap_load_access_fault
;
233 friend class processor_t
;