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