Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / unused_please_ignore_completely / iommu / axi_rab / l2_tlb.py
1 # this file has been generated by sv2nmigen
2
3 from nmigen import Signal, Module, Const, Cat, Elaboratable
4
5
6 class l2_tlb(Elaboratable):
7
8 def __init__(self):
9 self.clk_i = Signal() # input
10 self.rst_ni = Signal() # input
11 self.we_i = Signal() # input
12 self.waddr_i = Signal(AXI_LITE_ADDR_WIDTH) # input
13 self.wdata_i = Signal(AXI_LITE_DATA_WIDTH) # input
14 self.start_i = Signal() # input
15 self.busy_o = Signal() # output
16 self.in_addr_i = Signal(AXI_S_ADDR_WIDTH) # input
17 self.rw_type_i = Signal() # input
18 self.out_ready_i = Signal() # input
19 self.out_valid_o = Signal() # output
20 self.hit_o = Signal() # output
21 self.miss_o = Signal() # output
22 self.prot_o = Signal() # output
23 self.multi_o = Signal() # output
24 self.cache_coherent_o = Signal() # output
25 self.out_addr_o = Signal(AXI_M_ADDR_WIDTH) # output
26
27 def elaborate(self, platform=None):
28 m = Module()
29 return m
30
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 # //`include "pulp_soc_defines.sv"
43 #
44 # ////import CfMath::log2;
45 #
46 # //`define MULTI_HIT_FULL_SET // Enable full multi hit detection. Always the entire set is searched.
47 # //`define MULTI_HIT_CUR_CYCLE // Enable partial multi hit detection. Only multi hits in the same search cycle are detected.
48 #
49 # //`ifdef MULTI_HIT_FULL_SET
50 # // `ifndef MULTI_HIT_CUR_CYCLE
51 # // `define MULTI_HIT_CUR_CYCLE
52 # // `endif
53 # //`endif
54 #
55 # module l2_tlb
56 # //#(
57 # // parameter AXI_S_ADDR_WIDTH = 32,
58 # // parameter AXI_M_ADDR_WIDTH = 40,
59 # // parameter AXI_LITE_DATA_WIDTH = 64,
60 # // parameter AXI_LITE_ADDR_WIDTH = 32,
61 # // parameter N_SETS = 32,
62 # // parameter N_OFFSETS = 4, //per port. There are 2 ports.
63 # // parameter PAGE_SIZE = 4096, // 4kB
64 # // parameter N_PAR_VA_RAMS = 4,
65 # // parameter HIT_OFFSET_STORE_WIDTH = 2 // Num of bits of VA RAM offset stored. This should not be greater than OFFSET_WIDTH
66 # // )
67 # (
68 # input logic clk_i,
69 # input logic rst_ni,
70 #
71 # input logic we_i,
72 # input logic [AXI_LITE_ADDR_WIDTH-1:0] waddr_i,
73 # input logic [AXI_LITE_DATA_WIDTH-1:0] wdata_i,
74 #
75 # input logic start_i,
76 # output logic busy_o,
77 # input logic [AXI_S_ADDR_WIDTH-1:0] in_addr_i,
78 # input logic rw_type_i, //1 => write, 0=> read
79 #
80 # input logic out_ready_i,
81 # output logic out_valid_o,
82 # output logic hit_o,
83 # output logic miss_o,
84 # output logic prot_o,
85 # output logic multi_o,
86 # output logic cache_coherent_o,
87 # output logic [AXI_M_ADDR_WIDTH-1:0] out_addr_o
88 # );
89 #
90 """ #docstring_begin
91
92 localparam VA_RAM_DEPTH = N_SETS * N_OFFSETS * 2;
93 localparam PA_RAM_DEPTH = VA_RAM_DEPTH * N_PAR_VA_RAMS;
94 localparam VA_RAM_ADDR_WIDTH = log2(VA_RAM_DEPTH);
95 localparam PA_RAM_ADDR_WIDTH = log2(PA_RAM_DEPTH);
96 localparam SET_WIDTH = log2(N_SETS);
97 localparam OFFSET_WIDTH = log2(N_OFFSETS);
98 localparam LL_WIDTH = log2(N_PAR_VA_RAMS);
99 localparam IGNORE_LSB = log2(PAGE_SIZE);
100
101 localparam VA_RAM_DATA_WIDTH = AXI_S_ADDR_WIDTH - IGNORE_LSB + 4;
102 localparam PA_RAM_DATA_WIDTH = AXI_M_ADDR_WIDTH - IGNORE_LSB;
103
104 logic [N_PAR_VA_RAMS-1:0] hit, prot, multi_hit, cache_coherent;
105 logic [N_PAR_VA_RAMS-1:0] ram_we;
106 logic last_search, last_search_next;
107 logic first_search, first_search_next;
108 logic [SET_WIDTH+OFFSET_WIDTH+1-1:0] ram_waddr;
109 logic [N_PAR_VA_RAMS-1:0][SET_WIDTH+OFFSET_WIDTH+1-1:0] hit_addr;
110 logic pa_ram_we;
111 logic [PA_RAM_ADDR_WIDTH-1:0] pa_port0_raddr, pa_port0_waddr; // PA RAM read, Write addr;
112 logic [PA_RAM_ADDR_WIDTH-1:0] pa_port0_raddr_reg_SN, pa_port0_raddr_reg_SP; // registered addresses, needed for WAIT_ON_WRITE;
113 logic [PA_RAM_ADDR_WIDTH-1:0] pa_port0_addr; // PA RAM addr
114 logic [PA_RAM_DATA_WIDTH-1:0] pa_port0_data, pa_data, pa_port0_data_reg; // PA RAM data
115 logic pa_ram_store_data_SN, pa_ram_store_data_SP;
116 logic hit_top, prot_top, multi_hit_top, first_hit_top;
117 logic output_sent;
118 int hit_block_num;
119
120 logic searching, search_done;
121 logic [SET_WIDTH+OFFSET_WIDTH+1-1:0] port0_addr, port0_raddr; // VA RAM port0 addr
122 logic [SET_WIDTH+OFFSET_WIDTH+1-1:0] port1_addr; // VA RAM port1 addr
123 logic [OFFSET_WIDTH-1:0] offset_addr, offset_addr_d;
124 logic [OFFSET_WIDTH-1:0] offset_start_addr, offset_end_addr;
125 logic [SET_WIDTH-1:0] set_num;
126
127 logic va_output_valid;
128 logic searching_q;
129
130 genvar z;
131
132 // Search FSM
133 typedef enum logic [1:0] {IDLE, SEARCH, DONE} search_state_t;
134 search_state_t search_SP; // Present state
135 search_state_t search_SN; // Next State
136
137 // Output FSM
138 typedef enum logic [1:0] {OUT_IDLE, SEND_OUTPUT, WAIT_ON_WRITE} out_state_t;
139 out_state_t out_SP; // Present state
140 out_state_t out_SN; // Next State
141
142 logic miss_next;
143 logic hit_next;
144 logic prot_next;
145 logic multi_next;
146 logic cache_coherent_next;
147
148 // Generate the VA Block rams and their surrounding logic
149 generate
150 for (z = 0; z < N_PAR_VA_RAMS; z++) begin : VA_RAMS
151 check_ram
152 #(
153 .ADDR_WIDTH ( AXI_S_ADDR_WIDTH ),
154 .RAM_DATA_WIDTH ( VA_RAM_DATA_WIDTH ),
155 .PAGE_SIZE ( PAGE_SIZE ),
156 .SET_WIDTH ( SET_WIDTH ),
157 .OFFSET_WIDTH ( OFFSET_WIDTH )
158 )
159 u_check_ram
160 (
161 .clk_i ( clk_i ),
162 .rst_ni ( rst_ni ),
163 .in_addr ( in_addr_i ),
164 .rw_type ( rw_type_i ),
165 .ram_we ( ram_we[z] ),
166 .port0_addr ( port0_addr ),
167 .port1_addr ( port1_addr ),
168 .ram_wdata ( wdata_i[VA_RAM_DATA_WIDTH-1:0] ),
169 .output_sent ( output_sent ),
170 .output_valid ( va_output_valid ),
171 .offset_addr_d ( offset_addr_d ),
172 .hit_addr ( hit_addr[z] ),
173 .master ( cache_coherent[z] ),
174 .hit ( hit[z] ),
175 .multi_hit ( multi_hit[z] ),
176 .prot ( prot[z] )
177 );
178 end // for (z = 0; z < N_PORTS; z++)
179 endgenerate
180
181 ////////////////// ---------------- Control and Address --------------- ////////////////////////
182 // FSM
183 always_ff @(posedge clk_i) begin
184 if (rst_ni == 0) begin
185 search_SP <= IDLE;
186 end else begin
187 search_SP <= search_SN;
188 end
189 end
190
191 always_comb begin : SEARCH_FSM
192 search_SN = search_SP;
193 busy_o = 1'b0;
194 searching = 1'b0;
195 search_done = 1'b0;
196 last_search_next = 1'b0;
197 first_search_next = first_search;
198
199 unique case (search_SP)
200 IDLE : begin
201 if (start_i) begin
202 search_SN = SEARCH;
203 first_search_next = 1'b1;
204 end
205 end
206
207 SEARCH : begin
208 busy_o = 1'b1;
209
210 // detect last search cycle
211 if ( (first_search == 1'b0) && (offset_addr == offset_end_addr) )
212 last_search_next = 1'b1;
213
214 // pause search during VA RAM reconfigration
215 if (|ram_we) begin
216 searching = 1'b0;
217 end else begin
218 searching = 1'b1;
219 first_search_next = 1'b0;
220 end
221
222 if (va_output_valid) begin
223 // stop search
224 `ifdef MULTI_HIT_FULL_SET
225 if (last_search | prot_top | multi_hit_top) begin
226 `else
227 if (last_search | prot_top | multi_hit_top | hit_top ) begin
228 `endif
229 search_SN = DONE;
230 search_done = 1'b1;
231 end
232 end
233 end
234
235 DONE : begin
236 busy_o = 1'b1;
237 if (out_valid_o & out_ready_i)
238 search_SN = IDLE;
239 end
240
241 default : begin
242 search_SN = IDLE;
243 end
244 endcase // case (prot_SP)
245 end // always_comb begin
246
247 always_ff @(posedge clk_i) begin
248 if (rst_ni == 0) begin
249 last_search <= 1'b0;
250 first_search <= 1'b0;
251 end else begin
252 last_search <= last_search_next;
253 first_search <= first_search_next;
254 end
255 end
256
257 /*
258 * VA RAM address generation
259 *
260 * The input address and set number, and thus the offset start address, are available in the
261 * cycle after the start signal. The buffered offset_addr becomes available one cycle later.
262 * During the first search cycle, we therefore directly use offset_addr_start for the lookup.
263 */
264 assign set_num = in_addr_i[SET_WIDTH+IGNORE_LSB -1 : IGNORE_LSB];
265
266 assign port0_raddr[OFFSET_WIDTH] = 1'b0;
267 assign port1_addr [OFFSET_WIDTH] = 1'b1;
268
269 assign port0_raddr[OFFSET_WIDTH-1:0] = first_search ? offset_start_addr : offset_addr;
270 assign port1_addr [OFFSET_WIDTH-1:0] = first_search ? offset_start_addr : offset_addr;
271
272 assign port0_raddr[SET_WIDTH+OFFSET_WIDTH : OFFSET_WIDTH+1] = set_num;
273 assign port1_addr [SET_WIDTH+OFFSET_WIDTH : OFFSET_WIDTH+1] = set_num;
274
275 assign port0_addr = ram_we ? ram_waddr : port0_raddr;
276
277 // The outputs of the BRAMs are only valid if in the previous cycle:
278 // 1. the inputs were valid, and
279 // 2. the BRAMs were not written to.
280 // Otherwise, the outputs must be ignored.
281 always_ff @(posedge clk_i) begin
282 if (rst_ni == 0) begin
283 searching_q <= 1'b0;
284 end else begin
285 searching_q <= searching;
286 end
287 end
288 assign va_output_valid = searching_q;
289
290 // Address offset for looking up the VA RAMs
291 always_ff @(posedge clk_i) begin
292 if (rst_ni == 0) begin
293 offset_addr <= 0;
294 end else if (first_search) begin
295 offset_addr <= offset_start_addr + 1'b1;
296 end else if (searching) begin
297 offset_addr <= offset_addr + 1'b1;
298 end
299 end
300
301 // Delayed address offest for looking up the PA RAM upon a hit in the VA RAMs
302 always_ff @(posedge clk_i) begin
303 if (rst_ni == 0) begin
304 offset_addr_d <= 0;
305 end else if (first_search) begin
306 offset_addr_d <= offset_start_addr;
307 end else if (searching) begin
308 offset_addr_d <= offset_addr_d + 1'b1;
309 end
310 end
311
312 // Store the offset addr for hit to reduce latency for next search.
313 generate
314 if (HIT_OFFSET_STORE_WIDTH > 0) begin : OFFSET_STORE
315 `ifndef MULTI_HIT_FULL_SET
316 logic [N_SETS-1:0][HIT_OFFSET_STORE_WIDTH-1:0] hit_offset_addr; // Contains offset addr for previous hit for every SET.
317 logic [SET_WIDTH+OFFSET_WIDTH+1-1:0] hit_addr_reg;
318
319 assign offset_start_addr = { hit_offset_addr[set_num] , {{OFFSET_WIDTH-HIT_OFFSET_STORE_WIDTH}{1'b0}} };
320 assign offset_end_addr = hit_offset_addr[set_num]-1'b1;
321
322 // Register the hit addr
323 always_ff @(posedge clk_i) begin
324 if (rst_ni == 0) begin
325 hit_addr_reg <= 0;
326 end else if (hit_top) begin
327 hit_addr_reg <= hit_addr[hit_block_num];
328 end
329 end
330
331 // Store hit addr for each set. The next search in the same set will start from the saved addr.
332 always_ff @(posedge clk_i) begin
333 if (rst_ni == 0) begin
334 hit_offset_addr <= 0;
335 end else if (hit_o) begin
336 hit_offset_addr[set_num][HIT_OFFSET_STORE_WIDTH-1:0] <= hit_addr_reg[OFFSET_WIDTH-1 : (OFFSET_WIDTH - HIT_OFFSET_STORE_WIDTH)];
337 end
338 end
339 `else // No need to store offset if full multi hit detection is enabled because the entire SET is searched.
340 assign offset_start_addr = 0;
341 assign offset_end_addr = {OFFSET_WIDTH{1'b1}};
342 `endif
343 end else begin // if (HIT_OFFSET_STORE_WIDTH > 0)
344 assign offset_start_addr = 0;
345 assign offset_end_addr = {OFFSET_WIDTH{1'b1}};
346 end
347 endgenerate
348
349 assign prot_top = |prot;
350
351 //////////////////////////////////////////////////////////////////////////////////////
352 // check for hit, multi hit
353 // In case of a multi hit, the hit_block_num indicates the lowest VA RAM with a hit.
354 // In case of a multi hit in the same VA RAM, Port 0 is given priority.
355 always_comb begin : HIT_CHECK
356 hit_top = |hit;
357 hit_block_num = 0;
358 first_hit_top = 1'b0;
359 multi_hit_top = 1'b0;
360 for (int i=N_PAR_VA_RAMS-1; i>=0; i--) begin
361 if (hit[i] == 1'b1) begin
362 `ifdef MULTI_HIT_CUR_CYCLE
363 if (multi_hit[i] | first_hit_top ) begin
364 multi_hit_top = 1'b1;
365 end
366 `endif
367 first_hit_top = 1'b1;
368 hit_block_num = i;
369 end
370 end // for (int i=0; i<N_PAR_VA_RAMS; i++)
371 end // always_comb begin
372
373 ///////////////////// ------------- Outputs ------------ //////////////////////////////////
374 //// FSM
375 always_ff @(posedge clk_i) begin
376 if (rst_ni == 0) begin
377 out_SP <= OUT_IDLE;
378 pa_ram_store_data_SP <= 1'b0;
379 pa_port0_raddr_reg_SP <= 'b0;
380 end else begin
381 out_SP <= out_SN;
382 pa_ram_store_data_SP <= pa_ram_store_data_SN;
383 pa_port0_raddr_reg_SP <= pa_port0_raddr_reg_SN;
384 end
385 end
386
387 always_comb begin : OUTPUT_FSM
388 out_SN = out_SP;
389
390 miss_next = miss_o;
391 prot_next = prot_o;
392 multi_next = multi_o;
393 hit_next = hit_o;
394 cache_coherent_next = cache_coherent_o;
395 pa_port0_raddr_reg_SN = pa_port0_raddr_reg_SP;
396
397 pa_port0_raddr = 'b0;
398 pa_ram_store_data_SN = 1'b0;
399
400 out_valid_o = 1'b0;
401 output_sent = 1'b0;
402
403 unique case (out_SP)
404 OUT_IDLE : begin
405 hit_next = 1'b0;
406 miss_next = 1'b0;
407 prot_next = 1'b0;
408 multi_next = 1'b0;
409 cache_coherent_next = 1'b0;
410
411 // abort transaction
412 if ((search_done & ~hit_top) | prot_top | multi_hit_top) begin
413 out_SN = SEND_OUTPUT;
414
415 if (search_done & ~hit_top) begin
416 miss_next = 1'b1;
417 end
418 if (prot_top) begin
419 prot_next = 1'b1;
420 hit_next = 1'b1;
421 end
422 if (multi_hit_top) begin
423 multi_next = 1'b1;
424 hit_next = 1'b1;
425 end
426
427 // read PA RAM
428 end else if (search_done & hit_top) begin
429 hit_next = 1'b1;
430 cache_coherent_next = cache_coherent[hit_block_num];
431 pa_port0_raddr = (N_PAR_VA_RAMS * hit_addr[hit_block_num]) + hit_block_num;
432 pa_port0_raddr_reg_SN = pa_port0_raddr;
433
434 // read PA RAM now
435 if (~pa_ram_we) begin
436 out_SN = SEND_OUTPUT;
437 pa_ram_store_data_SN = 1'b1;
438
439 // read PA RAM after PA RAM reconfiguration
440 end else begin // pa_ram_we
441 out_SN = WAIT_ON_WRITE;
442
443 end
444 end
445 end
446
447 WAIT_ON_WRITE : begin
448 if ( ~pa_ram_we ) begin
449 out_SN = SEND_OUTPUT;
450 pa_port0_raddr = pa_port0_raddr_reg_SP;
451 pa_ram_store_data_SN = 1'b1;
452 end
453 end
454
455 SEND_OUTPUT : begin
456 out_valid_o = 1'b1;
457 if (out_ready_i) begin
458 out_SN = OUT_IDLE;
459 output_sent = 1'b1;
460 end
461 end
462
463 default : begin
464 out_SN = OUT_IDLE;
465 end
466
467 endcase // case (out_SP)
468 end // always_comb begin
469
470 //// Output signals
471 always_ff @(posedge clk_i) begin
472 if (rst_ni == 0) begin
473 miss_o <= 1'b0;
474 prot_o <= 1'b0;
475 multi_o <= 1'b0;
476 hit_o <= 1'b0;
477 cache_coherent_o <= 1'b0;
478 end else begin
479 miss_o <= miss_next;
480 prot_o <= prot_next;
481 multi_o <= multi_next;
482 hit_o <= hit_next;
483 cache_coherent_o <= cache_coherent_next;
484 end
485 end
486
487 ///////////////////////////////////////////////////////////////////////////////////////////////////
488
489
490 ///////////////////// --------------- Physical Address -------------- ////////////////////////////
491
492 /// PA Block RAM
493 ram_tp_no_change #(
494 .ADDR_WIDTH( PA_RAM_ADDR_WIDTH ),
495 .DATA_WIDTH( PA_RAM_DATA_WIDTH )
496 )
497 pa_ram
498 (
499 .clk ( clk_i ),
500 .we ( pa_ram_we ),
501 .addr0 ( pa_port0_addr ),
502 .addr1 ( '0 ),
503 .d_i ( wdata_i[PA_RAM_DATA_WIDTH-1:0] ),
504 .d0_o ( pa_port0_data ),
505 .d1_o ( )
506 );
507
508 assign out_addr_o[IGNORE_LSB-1:0] = in_addr_i[IGNORE_LSB-1:0];
509 assign out_addr_o[AXI_M_ADDR_WIDTH-1:IGNORE_LSB] = pa_data;
510
511 always_ff @(posedge clk_i) begin
512 if (rst_ni == 0) begin
513 pa_port0_data_reg <= 0;
514 end else if (pa_ram_store_data_SP) begin
515 pa_port0_data_reg <= pa_port0_data;
516 end
517 end
518
519 assign pa_data = pa_ram_store_data_SP ? pa_port0_data : pa_port0_data_reg;
520
521 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
522
523 ///// Write enable for all block rams
524 generate if (LL_WIDTH != 0) begin
525 always_comb begin
526 var reg[LL_WIDTH:0] para;
527 var int para_int;
528 for (para = 0; para < N_PAR_VA_RAMS; para=para+1'b1) begin
529 para_int = int'(para);
530 ram_we[para_int] = we_i && (waddr_i[LL_WIDTH+VA_RAM_ADDR_WIDTH] == 1'b0) && (waddr_i[LL_WIDTH-1:0] == para);
531 end
532 end
533 end else begin
534 assign ram_we[0] = we_i && (waddr_i[LL_WIDTH+VA_RAM_ADDR_WIDTH] == 1'b0);
535 end
536
537 endgenerate
538
539 // Addresses are word, not byte addresses
540 assign pa_ram_we = we_i && (waddr_i[LL_WIDTH+VA_RAM_ADDR_WIDTH] == 1'b1); //waddr_i[LL_WIDTH+VA_RAM_ADDR_WIDTH] will be 0 for all VA writes and 1 for all PA writes
541 assign ram_waddr = waddr_i[LL_WIDTH+VA_RAM_ADDR_WIDTH-1:LL_WIDTH];
542 assign pa_port0_waddr = waddr_i[PA_RAM_ADDR_WIDTH-1:0];
543 assign pa_port0_addr = pa_ram_we ? pa_port0_waddr : pa_port0_raddr;
544
545 """
546 # endmodule
547 #
548 # // vim: ts=3 sw=3 sts=3 et nosmartindent autoindent foldmethod=marker tw=100
549 #
550 #