1 # this file has been generated by sv2nmigen
3 from nmigen
import Signal
, Module
, Const
, Cat
, Elaboratable
6 class l2_tlb(Elaboratable
):
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
27 def elaborate(self
, platform
=None):
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.
42 # //`include "pulp_soc_defines.sv"
44 # ////import CfMath::log2;
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.
49 # //`ifdef MULTI_HIT_FULL_SET
50 # // `ifndef MULTI_HIT_CUR_CYCLE
51 # // `define MULTI_HIT_CUR_CYCLE
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
72 # input logic [AXI_LITE_ADDR_WIDTH-1:0] waddr_i,
73 # input logic [AXI_LITE_DATA_WIDTH-1:0] wdata_i,
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
80 # input logic out_ready_i,
81 # output logic out_valid_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
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);
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;
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;
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;
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;
127 logic va_output_valid;
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
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
146 logic cache_coherent_next;
148 // Generate the VA Block rams and their surrounding logic
150 for (z = 0; z < N_PAR_VA_RAMS; z++) begin : VA_RAMS
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 )
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] ),
175 .multi_hit ( multi_hit[z] ),
178 end // for (z = 0; z < N_PORTS; z++)
181 ////////////////// ---------------- Control and Address --------------- ////////////////////////
183 always_ff @(posedge clk_i) begin
184 if (rst_ni == 0) begin
187 search_SP <= search_SN;
191 always_comb begin : SEARCH_FSM
192 search_SN = search_SP;
196 last_search_next = 1'b0;
197 first_search_next = first_search;
199 unique case (search_SP)
203 first_search_next = 1'b1;
210 // detect last search cycle
211 if ( (first_search == 1'b0) && (offset_addr == offset_end_addr) )
212 last_search_next = 1'b1;
214 // pause search during VA RAM reconfigration
219 first_search_next = 1'b0;
222 if (va_output_valid) begin
224 `ifdef MULTI_HIT_FULL_SET
225 if (last_search | prot_top | multi_hit_top) begin
227 if (last_search | prot_top | multi_hit_top | hit_top ) begin
237 if (out_valid_o & out_ready_i)
244 endcase // case (prot_SP)
245 end // always_comb begin
247 always_ff @(posedge clk_i) begin
248 if (rst_ni == 0) begin
250 first_search <= 1'b0;
252 last_search <= last_search_next;
253 first_search <= first_search_next;
258 * VA RAM address generation
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.
264 assign set_num = in_addr_i[SET_WIDTH+IGNORE_LSB -1 : IGNORE_LSB];
266 assign port0_raddr[OFFSET_WIDTH] = 1'b0;
267 assign port1_addr [OFFSET_WIDTH] = 1'b1;
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;
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;
275 assign port0_addr = ram_we ? ram_waddr : port0_raddr;
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
285 searching_q <= searching;
288 assign va_output_valid = searching_q;
290 // Address offset for looking up the VA RAMs
291 always_ff @(posedge clk_i) begin
292 if (rst_ni == 0) begin
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;
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
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;
312 // Store the offset addr for hit to reduce latency for next search.
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;
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;
322 // Register the hit addr
323 always_ff @(posedge clk_i) begin
324 if (rst_ni == 0) begin
326 end else if (hit_top) begin
327 hit_addr_reg <= hit_addr[hit_block_num];
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)];
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}};
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}};
349 assign prot_top = |prot;
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
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;
367 first_hit_top = 1'b1;
370 end // for (int i=0; i<N_PAR_VA_RAMS; i++)
371 end // always_comb begin
373 ///////////////////// ------------- Outputs ------------ //////////////////////////////////
375 always_ff @(posedge clk_i) begin
376 if (rst_ni == 0) begin
378 pa_ram_store_data_SP <= 1'b0;
379 pa_port0_raddr_reg_SP <= 'b0;
382 pa_ram_store_data_SP <= pa_ram_store_data_SN;
383 pa_port0_raddr_reg_SP <= pa_port0_raddr_reg_SN;
387 always_comb begin : OUTPUT_FSM
392 multi_next = multi_o;
394 cache_coherent_next = cache_coherent_o;
395 pa_port0_raddr_reg_SN = pa_port0_raddr_reg_SP;
397 pa_port0_raddr = 'b0;
398 pa_ram_store_data_SN = 1'b0;
409 cache_coherent_next = 1'b0;
412 if ((search_done & ~hit_top) | prot_top | multi_hit_top) begin
413 out_SN = SEND_OUTPUT;
415 if (search_done & ~hit_top) begin
422 if (multi_hit_top) begin
428 end else if (search_done & hit_top) begin
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;
435 if (~pa_ram_we) begin
436 out_SN = SEND_OUTPUT;
437 pa_ram_store_data_SN = 1'b1;
439 // read PA RAM after PA RAM reconfiguration
440 end else begin // pa_ram_we
441 out_SN = WAIT_ON_WRITE;
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;
457 if (out_ready_i) begin
467 endcase // case (out_SP)
468 end // always_comb begin
471 always_ff @(posedge clk_i) begin
472 if (rst_ni == 0) begin
477 cache_coherent_o <= 1'b0;
481 multi_o <= multi_next;
483 cache_coherent_o <= cache_coherent_next;
487 ///////////////////////////////////////////////////////////////////////////////////////////////////
490 ///////////////////// --------------- Physical Address -------------- ////////////////////////////
494 .ADDR_WIDTH( PA_RAM_ADDR_WIDTH ),
495 .DATA_WIDTH( PA_RAM_DATA_WIDTH )
501 .addr0 ( pa_port0_addr ),
503 .d_i ( wdata_i[PA_RAM_DATA_WIDTH-1:0] ),
504 .d0_o ( pa_port0_data ),
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;
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;
519 assign pa_data = pa_ram_store_data_SP ? pa_port0_data : pa_port0_data_reg;
521 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
523 ///// Write enable for all block rams
524 generate if (LL_WIDTH != 0) begin
526 var reg[LL_WIDTH:0] para;
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);
534 assign ram_we[0] = we_i && (waddr_i[LL_WIDTH+VA_RAM_ADDR_WIDTH] == 1'b0);
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;
548 # // vim: ts=3 sw=3 sts=3 et nosmartindent autoindent foldmethod=marker tw=100