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 #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 check_align(addr, sizeof(type##_t), false, false); \
50 addr = translate(addr, false, false); \
51 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), false); \
52 return *(type##_t*)(mem+addr); \
55 #define store_func(type) \
56 void store_##type(reg_t addr, type##_t val) { \
57 check_align(addr, sizeof(type##_t), true, false); \
58 addr = translate(addr, true, false); \
59 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), true); \
60 *(type##_t*)(mem+addr) = val; \
63 insn_t
load_insn(reg_t addr
, bool rvc
)
67 reg_t idx
= (addr
/sizeof(insn_t
)) % ICACHE_ENTRIES
;
68 if(addr
% 4 == 0 && icache_tag
[idx
] == (addr
| 1))
69 return icache_data
[idx
];
71 #ifdef RISCV_ENABLE_RVC
72 if(addr
% 4 == 2 && rvc
)
74 reg_t paddr_lo
= translate(addr
, false, true);
75 insn
.bits
= *(uint16_t*)(mem
+paddr_lo
);
77 if(!INSN_IS_RVC(insn
.bits
))
79 reg_t paddr_hi
= translate(addr
+2, false, true);
80 insn
.bits
|= (uint32_t)*(uint16_t*)(mem
+paddr_hi
) << 16;
86 check_align(addr
, 4, false, true);
87 reg_t paddr
= translate(addr
, false, true);
88 insn
= *(insn_t
*)(mem
+paddr
);
90 icache_tag
[idx
] = addr
| 1;
91 icache_data
[idx
] = insn
;
94 #ifdef RISCV_ENABLE_ICSIM
96 icsim
->tick(addr
, insn_length(insn
), false);
98 itlbsim
->tick(addr
, sizeof(reg_t
), false);
119 reg_t
get_badvaddr() { return badvaddr
; }
120 reg_t
get_ptbr() { return ptbr
; }
122 void set_supervisor(bool sup
) { supervisor
= sup
; }
123 void set_vm_enabled(bool en
) { vm_enabled
= en
; }
124 void set_ptbr(reg_t addr
) { ptbr
= addr
& ~(PGSIZE
-1); flush_tlb(); }
126 void set_icsim(icsim_t
* _icsim
) { icsim
= _icsim
; }
127 void set_dcsim(icsim_t
* _dcsim
) { dcsim
= _dcsim
; }
128 void set_itlbsim(icsim_t
* _itlbsim
) { itlbsim
= _itlbsim
; }
129 void set_dtlbsim(icsim_t
* _dtlbsim
) { dtlbsim
= _dtlbsim
; }
143 static const reg_t TLB_ENTRIES
= 32;
144 pte_t tlb_data
[TLB_ENTRIES
];
145 reg_t tlb_tag
[TLB_ENTRIES
];
147 static const reg_t ICACHE_ENTRIES
= 32;
148 insn_t icache_data
[ICACHE_ENTRIES
];
149 reg_t icache_tag
[ICACHE_ENTRIES
];
156 void check_align(reg_t addr
, int size
, bool store
, bool fetch
)
162 throw trap_instruction_address_misaligned
;
164 throw trap_store_address_misaligned
;
165 throw trap_load_address_misaligned
;
169 reg_t
translate(reg_t addr
, bool store
, bool fetch
)
171 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
172 pte_t pte
= tlb_data
[idx
];
173 reg_t tag
= tlb_tag
[idx
];
175 trap_t trap
= store
? trap_store_access_fault
176 : fetch
? trap_instruction_access_fault
177 : trap_load_access_fault
;
179 if(!pte
.v
|| tag
!= (addr
>> PGSHIFT
))
186 tlb_tag
[idx
] = addr
>> PGSHIFT
;
189 if(store
&& !(supervisor
? pte
.sw
: pte
.uw
) ||
190 !store
&& !fetch
&& !(supervisor
? pte
.sr
: pte
.ur
) ||
191 !store
&& !fetch
&& !(supervisor
? pte
.sr
: pte
.ur
))
194 return (addr
& (PGSIZE
-1)) | (pte
.ppn
<< PGSHIFT
);
197 pte_t
walk(reg_t addr
)
203 pte
.v
= addr
< memsz
;
206 pte
.ur
= pte
.uw
= pte
.ux
= pte
.sr
= pte
.sw
= pte
.sx
= 1;
207 pte
.ppn
= addr
>> PGSHIFT
;
213 int lg_ptesz
= sizeof(pte_t
) == 4 ? 2
214 : sizeof(pte_t
) == 8 ? 3
220 for(int i
= LEVELS
-1; i
>= 0; i
++)
222 reg_t idx
= addr
>> (PGSHIFT
+ i
*(PGSHIFT
- lg_ptesz
));
223 idx
&= (1<<(PGSHIFT
- lg_ptesz
)) - 1;
225 reg_t pte_addr
= base
+ idx
*sizeof(pte_t
);
226 if(pte_addr
>= memsz
)
229 pte
= *(pte_t
*)(mem
+pte_addr
);
233 base
= pte
.ppn
<< PGSHIFT
;
241 friend class processor_t
;