always_comb: handle if/else blocks
[sv2nmigen.git] / examples / mmu.sv
1 // Copyright 2018 ETH Zurich and University of Bologna.
2 // Copyright and related rights are licensed under the Solderpad Hardware
3 // License, Version 0.51 (the "License"); you may not use this file except in
4 // compliance with the License. You may obtain a copy of the License at
5 // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
6 // or agreed to in writing, software, hardware and materials distributed under
7 // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // specific language governing permissions and limitations under the License.
10 //
11 // Author: Florian Zaruba, ETH Zurich
12 // Date: 19/04/2017
13 // Description: Memory Management Unit for Ariane, contains TLB and
14 // address translation unit. SV39 as defined in RISC-V
15 // privilege specification 1.11-WIP
16
17 //import ariane_pkg::*;
18
19 module mmu #(
20 parameter int INSTR_TLB_ENTRIES = 4,
21 parameter int DATA_TLB_ENTRIES = 4,
22 parameter int ASID_WIDTH = 1
23 // parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
24 ) (
25 input logic clk_i,
26 input logic rst_ni,
27 input logic flush_i,
28 input logic enable_translation_i,
29 input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores
30 // IF interface
31 #docstring_begin
32 input icache_areq_o_t icache_areq_i,
33 output icache_areq_i_t icache_areq_o,
34 #docstring_end
35 // LSU interface
36 // this is a more minimalistic interface because the actual addressing logic is handled
37 // in the LSU as we distinguish load and stores, what we do here is simple address translation
38 //input exception_t misaligned_ex_i,
39 input logic lsu_req_i, // request address translation
40 input logic [63:0] lsu_vaddr_i, // virtual address in
41 input logic lsu_is_store_i, // the translation is requested by a store
42 // if we need to walk the page table we can't grant in the same cycle
43 // Cycle 0
44 output logic lsu_dtlb_hit_o, // sent in the same cycle as the request if translation hits in the DTLB
45 // Cycle 1
46 output logic lsu_valid_o, // translation is valid
47 output logic [63:0] lsu_paddr_o, // translated address
48 //output exception_t lsu_exception_o, // address translation threw an exception
49 // General control signals
50 //input riscv::priv_lvl_t priv_lvl_i,
51 //input riscv::priv_lvl_t ld_st_priv_lvl_i,
52 input logic sum_i,
53 input logic mxr_i,
54 // input logic flag_mprv_i,
55 input logic [43:0] satp_ppn_i,
56 input logic [ASID_WIDTH-1:0] asid_i,
57 input logic flush_tlb_i,
58 // Performance counters
59 output logic itlb_miss_o,
60 output logic dtlb_miss_o
61 // PTW memory interface
62 //input dcache_req_o_t req_port_i,
63 //output dcache_req_i_t req_port_o
64 );
65
66 #docstring_begin
67 logic iaccess_err; // insufficient privilege to access this instruction page
68 logic daccess_err; // insufficient privilege to access this data page
69 logic ptw_active; // PTW is currently walking a page table
70 logic walking_instr; // PTW is walking because of an ITLB miss
71 logic ptw_error; // PTW threw an exception
72
73 logic [38:0] update_vaddr;
74 tlb_update_t update_ptw_itlb, update_ptw_dtlb;
75
76 logic itlb_lu_access;
77 riscv::pte_t itlb_content;
78 logic itlb_is_2M;
79 logic itlb_is_1G;
80 logic itlb_lu_hit;
81
82 logic dtlb_lu_access;
83 riscv::pte_t dtlb_content;
84 logic dtlb_is_2M;
85 logic dtlb_is_1G;
86 logic dtlb_lu_hit;
87
88
89 // Assignments
90 assign itlb_lu_access = icache_areq_i.fetch_req;
91 assign dtlb_lu_access = lsu_req_i;
92
93
94 tlb #(
95 .TLB_ENTRIES ( INSTR_TLB_ENTRIES ),
96 .ASID_WIDTH ( ASID_WIDTH )
97 ) i_itlb (
98 .clk_i ( clk_i ),
99 .rst_ni ( rst_ni ),
100 .flush_i ( flush_tlb_i ),
101
102 .update_i ( update_ptw_itlb ),
103
104 .lu_access_i ( itlb_lu_access ),
105 .lu_asid_i ( asid_i ),
106 .lu_vaddr_i ( icache_areq_i.fetch_vaddr ),
107 .lu_content_o ( itlb_content ),
108
109 .lu_is_2M_o ( itlb_is_2M ),
110 .lu_is_1G_o ( itlb_is_1G ),
111 .lu_hit_o ( itlb_lu_hit )
112 );
113
114 tlb #(
115 .TLB_ENTRIES ( DATA_TLB_ENTRIES ),
116 .ASID_WIDTH ( ASID_WIDTH )
117 ) i_dtlb (
118 .clk_i ( clk_i ),
119 .rst_ni ( rst_ni ),
120 .flush_i ( flush_tlb_i ),
121
122 .update_i ( update_ptw_dtlb ),
123
124 .lu_access_i ( dtlb_lu_access ),
125 .lu_asid_i ( asid_i ),
126 .lu_vaddr_i ( lsu_vaddr_i ),
127 .lu_content_o ( dtlb_content ),
128
129 .lu_is_2M_o ( dtlb_is_2M ),
130 .lu_is_1G_o ( dtlb_is_1G ),
131 .lu_hit_o ( dtlb_lu_hit )
132 );
133
134
135 ptw #(
136 .ASID_WIDTH ( ASID_WIDTH )
137 ) i_ptw (
138 .clk_i ( clk_i ),
139 .rst_ni ( rst_ni ),
140 .ptw_active_o ( ptw_active ),
141 .walking_instr_o ( walking_instr ),
142 .ptw_error_o ( ptw_error ),
143 .enable_translation_i ( enable_translation_i ),
144
145 .update_vaddr_o ( update_vaddr ),
146 .itlb_update_o ( update_ptw_itlb ),
147 .dtlb_update_o ( update_ptw_dtlb ),
148
149 .itlb_access_i ( itlb_lu_access ),
150 .itlb_hit_i ( itlb_lu_hit ),
151 .itlb_vaddr_i ( icache_areq_i.fetch_vaddr ),
152
153 .dtlb_access_i ( dtlb_lu_access ),
154 .dtlb_hit_i ( dtlb_lu_hit ),
155 .dtlb_vaddr_i ( lsu_vaddr_i ),
156
157 .req_port_i ( req_port_i ),
158 .req_port_o ( req_port_o ),
159
160 .*
161 );
162
163 // ila_1 i_ila_1 (
164 // .clk(clk_i), // input wire clk
165 // .probe0({req_port_o.address_tag, req_port_o.address_index}),
166 // .probe1(req_port_o.data_req), // input wire [63:0] probe1
167 // .probe2(req_port_i.data_gnt), // input wire [0:0] probe2
168 // .probe3(req_port_i.data_rdata), // input wire [0:0] probe3
169 // .probe4(req_port_i.data_rvalid), // input wire [0:0] probe4
170 // .probe5(ptw_error), // input wire [1:0] probe5
171 // .probe6(update_vaddr), // input wire [0:0] probe6
172 // .probe7(update_ptw_itlb.valid), // input wire [0:0] probe7
173 // .probe8(update_ptw_dtlb.valid), // input wire [0:0] probe8
174 // .probe9(dtlb_lu_access), // input wire [0:0] probe9
175 // .probe10(lsu_vaddr_i), // input wire [0:0] probe10
176 // .probe11(dtlb_lu_hit), // input wire [0:0] probe11
177 // .probe12(itlb_lu_access), // input wire [0:0] probe12
178 // .probe13(icache_areq_i.fetch_vaddr), // input wire [0:0] probe13
179 // .probe14(itlb_lu_hit) // input wire [0:0] probe13
180 // );
181
182 //-----------------------
183 // Instruction Interface
184 //-----------------------
185 logic match_any_execute_region;
186 // The instruction interface is a simple request response interface
187 always_comb begin : instr_interface
188 // MMU disabled: just pass through
189 icache_areq_o.fetch_valid = icache_areq_i.fetch_req;
190 icache_areq_o.fetch_paddr = icache_areq_i.fetch_vaddr; // play through in case we disabled address translation
191 // two potential exception sources:
192 // 1. HPTW threw an exception -> signal with a page fault exception
193 // 2. We got an access error because of insufficient permissions -> throw an access exception
194 icache_areq_o.fetch_exception = '0;
195 // Check whether we are allowed to access this memory region from a fetch perspective
196 iaccess_err = icache_areq_i.fetch_req && (((priv_lvl_i == riscv::PRIV_LVL_U) && ~itlb_content.u)
197 || ((priv_lvl_i == riscv::PRIV_LVL_S) && itlb_content.u));
198
199 // MMU enabled: address from TLB, request delayed until hit. Error when TLB
200 // hit and no access right or TLB hit and translated address not valid (e.g.
201 // AXI decode error), or when PTW performs walk due to ITLB miss and raises
202 // an error.
203 if (enable_translation_i) begin
204 // we work with SV39, so if VM is enabled, check that all bits [63:38] are equal
205 if (icache_areq_i.fetch_req && !((&icache_areq_i.fetch_vaddr[63:38]) == 1'b1 || (|icache_areq_i.fetch_vaddr[63:38]) == 1'b0)) begin
206 icache_areq_o.fetch_exception = {riscv::INSTR_ACCESS_FAULT, icache_areq_i.fetch_vaddr, 1'b1};
207 end
208
209 icache_areq_o.fetch_valid = 1'b0;
210
211 // 4K page
212 icache_areq_o.fetch_paddr = {itlb_content.ppn, icache_areq_i.fetch_vaddr[11:0]};
213 // Mega page
214 if (itlb_is_2M) begin
215 icache_areq_o.fetch_paddr[20:12] = icache_areq_i.fetch_vaddr[20:12];
216 end
217 // Giga page
218 if (itlb_is_1G) begin
219 icache_areq_o.fetch_paddr[29:12] = icache_areq_i.fetch_vaddr[29:12];
220 end
221
222 // ---------
223 // ITLB Hit
224 // --------
225 // if we hit the ITLB output the request signal immediately
226 if (itlb_lu_hit) begin
227 icache_areq_o.fetch_valid = icache_areq_i.fetch_req;
228 // we got an access error
229 if (iaccess_err) begin
230 // throw a page fault
231 icache_areq_o.fetch_exception = {riscv::INSTR_PAGE_FAULT, icache_areq_i.fetch_vaddr, 1'b1};
232 end
233 end else
234 // ---------
235 // ITLB Miss
236 // ---------
237 // watch out for exceptions happening during walking the page table
238 if (ptw_active && walking_instr) begin
239 icache_areq_o.fetch_valid = ptw_error;
240 icache_areq_o.fetch_exception = {riscv::INSTR_PAGE_FAULT, {25'b0, update_vaddr}, 1'b1};
241 end
242 end
243 // if it didn't match any execute region throw an `Instruction Access Fault`
244 if (!match_any_execute_region) begin
245 icache_areq_o.fetch_exception = {riscv::INSTR_ACCESS_FAULT, icache_areq_o.fetch_paddr, 1'b1};
246 end
247 end
248
249 // check for execute flag on memory
250 assign match_any_execute_region = ariane_pkg::is_inside_execute_regions(ArianeCfg, icache_areq_o.fetch_paddr);
251
252 //-----------------------
253 // Data Interface
254 //-----------------------
255 logic [63:0] lsu_vaddr_n, lsu_vaddr_q;
256 riscv::pte_t dtlb_pte_n, dtlb_pte_q;
257 exception_t misaligned_ex_n, misaligned_ex_q;
258 logic lsu_req_n, lsu_req_q;
259 logic lsu_is_store_n, lsu_is_store_q;
260 logic dtlb_hit_n, dtlb_hit_q;
261 logic dtlb_is_2M_n, dtlb_is_2M_q;
262 logic dtlb_is_1G_n, dtlb_is_1G_q;
263
264 // check if we need to do translation or if we are always ready (e.g.: we are not translating anything)
265 assign lsu_dtlb_hit_o = (en_ld_st_translation_i) ? dtlb_lu_hit : 1'b1;
266
267 // The data interface is simpler and only consists of a request/response interface
268 always_comb begin : data_interface
269 // save request and DTLB response
270 lsu_vaddr_n = lsu_vaddr_i;
271 lsu_req_n = lsu_req_i;
272 misaligned_ex_n = misaligned_ex_i;
273 dtlb_pte_n = dtlb_content;
274 dtlb_hit_n = dtlb_lu_hit;
275 lsu_is_store_n = lsu_is_store_i;
276 dtlb_is_2M_n = dtlb_is_2M;
277 dtlb_is_1G_n = dtlb_is_1G;
278
279 lsu_paddr_o = lsu_vaddr_q;
280 lsu_valid_o = lsu_req_q;
281 lsu_exception_o = misaligned_ex_q;
282 // mute misaligned exceptions if there is no request otherwise they will throw accidental exceptions
283 misaligned_ex_n.valid = misaligned_ex_i.valid & lsu_req_i;
284
285 // Check if the User flag is set, then we may only access it in supervisor mode
286 // if SUM is enabled
287 daccess_err = (ld_st_priv_lvl_i == riscv::PRIV_LVL_S && !sum_i && dtlb_pte_q.u) || // SUM is not set and we are trying to access a user page in supervisor mode
288 (ld_st_priv_lvl_i == riscv::PRIV_LVL_U && !dtlb_pte_q.u); // this is not a user page but we are in user mode and trying to access it
289 // translation is enabled and no misaligned exception occurred
290 if (en_ld_st_translation_i && !misaligned_ex_q.valid) begin
291 lsu_valid_o = 1'b0;
292 // 4K page
293 lsu_paddr_o = {dtlb_pte_q.ppn, lsu_vaddr_q[11:0]};
294 // Mega page
295 if (dtlb_is_2M_q) begin
296 lsu_paddr_o[20:12] = lsu_vaddr_q[20:12];
297 end
298 // Giga page
299 if (dtlb_is_1G_q) begin
300 lsu_paddr_o[29:12] = lsu_vaddr_q[29:12];
301 end
302 // ---------
303 // DTLB Hit
304 // --------
305 if (dtlb_hit_q && lsu_req_q) begin
306 lsu_valid_o = 1'b1;
307 // this is a store
308 if (lsu_is_store_q) begin
309 // check if the page is write-able and we are not violating privileges
310 // also check if the dirty flag is set
311 if (!dtlb_pte_q.w || daccess_err || !dtlb_pte_q.d) begin
312 lsu_exception_o = {riscv::STORE_PAGE_FAULT, lsu_vaddr_q, 1'b1};
313 end
314
315 // this is a load, check for sufficient access privileges - throw a page fault if necessary
316 end else if (daccess_err) begin
317 lsu_exception_o = {riscv::LOAD_PAGE_FAULT, lsu_vaddr_q, 1'b1};
318 end
319 end else
320
321 // ---------
322 // DTLB Miss
323 // ---------
324 // watch out for exceptions
325 if (ptw_active && !walking_instr) begin
326 // page table walker threw an exception
327 if (ptw_error) begin
328 // an error makes the translation valid
329 lsu_valid_o = 1'b1;
330 // the page table walker can only throw page faults
331 if (lsu_is_store_q) begin
332 lsu_exception_o = {riscv::STORE_PAGE_FAULT, {25'b0, update_vaddr}, 1'b1};
333 end else begin
334 lsu_exception_o = {riscv::LOAD_PAGE_FAULT, {25'b0, update_vaddr}, 1'b1};
335 end
336 end
337 end
338 end
339 end
340 // ----------
341 // Registers
342 // ----------
343 always_ff @(posedge clk_i or negedge rst_ni) begin
344 if (~rst_ni) begin
345 lsu_vaddr_q <= '0;
346 lsu_req_q <= '0;
347 misaligned_ex_q <= '0;
348 dtlb_pte_q <= '0;
349 dtlb_hit_q <= '0;
350 lsu_is_store_q <= '0;
351 dtlb_is_2M_q <= '0;
352 dtlb_is_1G_q <= '0;
353 end else begin
354 lsu_vaddr_q <= lsu_vaddr_n;
355 lsu_req_q <= lsu_req_n;
356 misaligned_ex_q <= misaligned_ex_n;
357 dtlb_pte_q <= dtlb_pte_n;
358 dtlb_hit_q <= dtlb_hit_n;
359 lsu_is_store_q <= lsu_is_store_n;
360 dtlb_is_2M_q <= dtlb_is_2M_n;
361 dtlb_is_1G_q <= dtlb_is_1G_n;
362 end
363 end
364 #docstring_end
365 endmodule