`timescale 1ns / 1ps `include "cam_params.svh" module cam_core_banked ( input logic clk, input logic rst_n, input logic wr_valid, output logic wr_ready, input logic [(`ROW_BITS)-1:0] wr_row, input logic [(`HASH_BITS)-1:0] wr_hash, input logic rd_valid_i, input logic [(`ROW_BITS)-1:0] rd_base_row_i, output logic rd_valid_o, output logic [(`LANES)*(`ROW_BITS)-1:0] rd_row_ids_o, output logic [(`LANES)*(`HASH_BITS)-1:0] rd_hashes_o, output logic [(`LANES)-1:0] rd_lane_valid_o ); localparam int BANKS = `LANES; localparam int BANK_DEPTH = `NUM_ROWS / `LANES; (* ram_style = "block" *) logic [(`HASH_BITS)-1:0] bank_mem [0:BANKS-1][0:BANK_DEPTH-1]; assign wr_ready = 1'b1; initial begin if (`NUM_ROWS % `LANES != 0) $fatal(1, "NUM_ROWS must be divisible by LANES"); end always_ff @(posedge clk) begin if (wr_valid) begin bank_mem[wr_row % `LANES][wr_row / `LANES] <= wr_hash; end end always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin rd_valid_o <= 1'b0; rd_row_ids_o <= '0; rd_hashes_o <= '0; rd_lane_valid_o <= '0; end else begin rd_valid_o <= rd_valid_i; rd_lane_valid_o <= rd_valid_i ? {`LANES{1'b1}} : '0; if (rd_valid_i && ((rd_base_row_i % `LANES) != 0)) begin $fatal(1, "rd_base_row_i must be LANES-aligned"); end for (int lane = 0; lane < `LANES; lane++) begin rd_row_ids_o[lane*`ROW_BITS +: `ROW_BITS] <= rd_base_row_i + lane[(`ROW_BITS)-1:0]; rd_hashes_o[lane*`HASH_BITS +: `HASH_BITS] <= bank_mem[lane][rd_base_row_i / `LANES]; end end end endmodule