e25e90a0b61d36d8413169357f426b697232240c
14 const reg_t LEVELS
= 4;
15 const reg_t PGSHIFT
= 12;
16 const reg_t PGSIZE
= 1 << PGSHIFT
;
17 const reg_t PTIDXBITS
= PGSHIFT
- (sizeof(pte_t
) == 8 ? 3 : 2);
18 const reg_t PPN_BITS
= 8*sizeof(reg_t
) - PGSHIFT
;
20 #define PTE_T 0x001 // Entry is a page Table descriptor
21 #define PTE_E 0x002 // Entry is a page table Entry
22 #define PTE_R 0x004 // Referenced
23 #define PTE_D 0x008 // Dirty
24 #define PTE_UX 0x010 // User eXecute permission
25 #define PTE_UW 0x020 // User Read permission
26 #define PTE_UR 0x040 // User Write permission
27 #define PTE_SX 0x080 // Supervisor eXecute permission
28 #define PTE_SW 0x100 // Supervisor Read permission
29 #define PTE_SR 0x200 // Supervisor Write permission
30 #define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX)
31 #define PTE_PERM_SHIFT 4
32 #define PTE_PPN_SHIFT 12
37 mmu_t(char* _mem
, size_t _memsz
);
40 #ifdef RISCV_ENABLE_ICSIM
41 # define dcsim_tick(dcsim, dtlbsim, addr, size, st) \
42 do { if(dcsim) (dcsim)->tick(addr, size, st); \
43 if(dtlbsim) (dtlbsim)->tick(addr, sizeof(reg_t), false); } while(0)
45 # define dcsim_tick(dcsim, dtlbsim, addr, size, st)
48 #define load_func(type) \
49 type##_t load_##type(reg_t addr) { \
50 if(unlikely(addr % sizeof(type##_t))) \
53 throw trap_load_address_misaligned; \
55 void* paddr = translate(addr, false, false); \
56 dcsim_tick(dcsim, dtlbsim, paddr-mem, sizeof(type##_t), false); \
57 return *(type##_t*)paddr; \
60 #define store_func(type) \
61 void store_##type(reg_t addr, type##_t val) { \
62 if(unlikely(addr % sizeof(type##_t))) \
65 throw trap_store_address_misaligned; \
67 void* paddr = translate(addr, true, false); \
68 dcsim_tick(dcsim, dtlbsim, paddr-mem, sizeof(type##_t), true); \
69 *(type##_t*)paddr = val; \
72 insn_t
__attribute__((always_inline
)) load_insn(reg_t addr
, bool rvc
,
77 #ifdef RISCV_ENABLE_RVC
78 if(addr
% 4 == 2 && rvc
) // fetch across word boundary
80 void* addr_lo
= translate(addr
, false, true);
81 insn
.bits
= *(uint16_t*)addr_lo
;
83 *func
= processor_t::dispatch_table
84 [insn
.bits
% processor_t::DISPATCH_TABLE_SIZE
];
86 if(!INSN_IS_RVC(insn
.bits
))
88 void* addr_hi
= translate(addr
+2, false, true);
89 insn
.bits
|= (uint32_t)*(uint16_t*)addr_hi
<< 16;
95 reg_t idx
= (addr
/sizeof(insn_t
)) % ICACHE_ENTRIES
;
96 insn_t data
= icache_data
[idx
];
97 *func
= icache_func
[idx
];
98 if(likely(icache_tag
[idx
] == addr
))
101 // the processor guarantees alignment based upon rvc mode
102 void* paddr
= translate(addr
, false, true);
103 insn
= *(insn_t
*)paddr
;
105 icache_tag
[idx
] = addr
;
106 icache_data
[idx
] = insn
;
107 icache_func
[idx
] = *func
= processor_t::dispatch_table
108 [insn
.bits
% processor_t::DISPATCH_TABLE_SIZE
];
111 #ifdef RISCV_ENABLE_ICSIM
113 icsim
->tick(addr
, insn_length(insn
.bits
), false);
115 itlbsim
->tick(addr
, sizeof(reg_t
), false);
136 reg_t
get_badvaddr() { return badvaddr
; }
137 reg_t
get_ptbr() { return ptbr
; }
139 void set_supervisor(bool sup
) { supervisor
= sup
; }
140 void set_vm_enabled(bool en
) { vm_enabled
= en
; }
141 void set_ptbr(reg_t addr
) { ptbr
= addr
& ~(PGSIZE
-1); flush_tlb(); }
143 void set_icsim(icsim_t
* _icsim
) { icsim
= _icsim
; }
144 void set_dcsim(icsim_t
* _dcsim
) { dcsim
= _dcsim
; }
145 void set_itlbsim(icsim_t
* _itlbsim
) { itlbsim
= _itlbsim
; }
146 void set_dtlbsim(icsim_t
* _dtlbsim
) { dtlbsim
= _dtlbsim
; }
160 static const reg_t TLB_ENTRIES
= 256;
161 long tlb_data
[TLB_ENTRIES
];
162 reg_t tlb_insn_tag
[TLB_ENTRIES
];
163 reg_t tlb_load_tag
[TLB_ENTRIES
];
164 reg_t tlb_store_tag
[TLB_ENTRIES
];
166 static const reg_t ICACHE_ENTRIES
= 256;
167 insn_t icache_data
[ICACHE_ENTRIES
];
168 insn_func_t icache_func
[ICACHE_ENTRIES
];
169 reg_t icache_tag
[ICACHE_ENTRIES
];
176 void* refill(reg_t addr
, bool store
, bool fetch
);
177 pte_t
walk(reg_t addr
);
179 void* translate(reg_t addr
, bool store
, bool fetch
)
181 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
183 reg_t
* tlb_tag
= fetch
? tlb_insn_tag
: store
? tlb_store_tag
:tlb_load_tag
;
184 reg_t expected_tag
= addr
& ~(PGSIZE
-1);
185 if(likely(tlb_tag
[idx
] == expected_tag
))
186 return (void*)(((long)addr
& (PGSIZE
-1)) | tlb_data
[idx
]);
188 return refill(addr
, store
, fetch
);
191 friend class processor_t
;