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))) \
52 throw trap_load_address_misaligned; \
53 addr = translate(addr, false, false); \
54 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), false); \
55 return *(type##_t*)(mem+addr); \
58 #define store_func(type) \
59 void store_##type(reg_t addr, type##_t val) { \
60 if(unlikely(addr % sizeof(type##_t))) \
61 throw trap_store_address_misaligned; \
62 addr = translate(addr, true, false); \
63 dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), true); \
64 *(type##_t*)(mem+addr) = val; \
67 insn_t
__attribute__((always_inline
)) load_insn(reg_t addr
, bool rvc
)
71 reg_t idx
= (addr
/sizeof(insn_t
)) % ICACHE_ENTRIES
;
72 bool hit
= addr
% 4 == 0 && icache_tag
[idx
] == (addr
| 1);
74 return icache_data
[idx
];
76 #ifdef RISCV_ENABLE_RVC
77 if(addr
% 4 == 2 && rvc
)
79 reg_t paddr_lo
= translate(addr
, false, true);
80 insn
.bits
= *(uint16_t*)(mem
+paddr_lo
);
82 if(!INSN_IS_RVC(insn
.bits
))
84 reg_t paddr_hi
= translate(addr
+2, false, true);
85 insn
.bits
|= (uint32_t)*(uint16_t*)(mem
+paddr_hi
) << 16;
91 if(unlikely(addr
% 4))
92 throw trap_instruction_address_misaligned
;
93 reg_t paddr
= translate(addr
, false, true);
94 insn
= *(insn_t
*)(mem
+paddr
);
96 icache_tag
[idx
] = addr
| 1;
97 icache_data
[idx
] = insn
;
100 #ifdef RISCV_ENABLE_ICSIM
102 icsim
->tick(addr
, insn_length(insn
.bits
), false);
104 itlbsim
->tick(addr
, sizeof(reg_t
), false);
125 reg_t
get_badvaddr() { return badvaddr
; }
126 reg_t
get_ptbr() { return ptbr
; }
128 void set_supervisor(bool sup
) { supervisor
= sup
; }
129 void set_vm_enabled(bool en
) { vm_enabled
= en
; }
130 void set_ptbr(reg_t addr
) { ptbr
= addr
& ~(PGSIZE
-1); flush_tlb(); }
132 void set_icsim(icsim_t
* _icsim
) { icsim
= _icsim
; }
133 void set_dcsim(icsim_t
* _dcsim
) { dcsim
= _dcsim
; }
134 void set_itlbsim(icsim_t
* _itlbsim
) { itlbsim
= _itlbsim
; }
135 void set_dtlbsim(icsim_t
* _dtlbsim
) { dtlbsim
= _dtlbsim
; }
149 static const reg_t TLB_ENTRIES
= 256;
150 pte_t tlb_data
[TLB_ENTRIES
];
151 reg_t tlb_tag
[TLB_ENTRIES
];
153 static const reg_t ICACHE_ENTRIES
= 256;
154 insn_t icache_data
[ICACHE_ENTRIES
];
155 reg_t icache_tag
[ICACHE_ENTRIES
];
162 reg_t
translate(reg_t addr
, bool store
, bool fetch
)
164 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
165 pte_t pte
= tlb_data
[idx
];
166 reg_t tag
= tlb_tag
[idx
];
168 trap_t trap
= store
? trap_store_access_fault
169 : fetch
? trap_instruction_access_fault
170 : trap_load_access_fault
;
172 bool hit
= (pte
& PTE_E
) && tag
== (addr
>> PGSHIFT
);
180 tlb_tag
[idx
] = addr
>> PGSHIFT
;
183 reg_t access_type
= store
? PTE_UW
: fetch
? PTE_UX
: PTE_UR
;
186 if(unlikely(!(access_type
& pte
& PTE_PERM
)))
189 return (addr
& (PGSIZE
-1)) | ((pte
>> PTE_PPN_SHIFT
) << PGSHIFT
);
192 pte_t
walk(reg_t addr
)
199 pte
= PTE_E
| PTE_PERM
| ((addr
>> PGSHIFT
) << PTE_PPN_SHIFT
);
206 int ptshift
= (LEVELS
-1)*PTIDXBITS
;
207 for(reg_t i
= 0; i
< LEVELS
; i
++, ptshift
-= PTIDXBITS
)
209 reg_t idx
= (addr
>> (PGSHIFT
+ptshift
)) & ((1<<PTIDXBITS
)-1);
211 reg_t pte_addr
= base
+ idx
*sizeof(pte_t
);
212 if(pte_addr
>= memsz
)
215 ptd
= *(pte_t
*)(mem
+pte_addr
);
218 // if this PTE is from a larger PT, fake a leaf
219 // PTE so the TLB will work right
220 reg_t vpn
= addr
>> PGSHIFT
;
221 pte
|= ptd
| (vpn
& ((1<<(ptshift
))-1)) << PTE_PPN_SHIFT
;
224 else if(!(ptd
& PTE_T
))
227 base
= (ptd
>> PTE_PPN_SHIFT
) << PGSHIFT
;
234 friend class processor_t
;