`timescale 1ns / 1ps `include "cam_params.svh" module cam_read_noise #( parameter bit READ_NOISE_EN = 1'b1, parameter int READ_NOISE_RATE_NUM = 1, parameter int READ_NOISE_RATE_DEN = 100, parameter int READ_NOISE_BITS = 8, parameter logic [63:0] READ_NOISE_SEED = 64'h6A09_E667_F3BC_C909 ) ( input logic clk, input logic rst_n, input logic valid_i, input logic [(`LANES)*(`ROW_BITS)-1:0] row_ids_i, input logic [(`LANES)*(`HASH_BITS)-1:0] hashes_i, input logic [(`LANES)-1:0] lane_valid_i, output logic valid_o, output logic [(`LANES)*(`ROW_BITS)-1:0] row_ids_o, output logic [(`LANES)*(`HASH_BITS)-1:0] hashes_noisy_o, output logic [(`LANES)-1:0] lane_valid_o ); logic valid_q; logic [(`LANES)*(`ROW_BITS)-1:0] row_ids_q; logic [(`LANES)*(`HASH_BITS)-1:0] hashes_q; logic [(`LANES)-1:0] lane_valid_q; logic [127:0] random_num [0:`LANES-1]; logic [(`HASH_BITS)-1:0] mask [0:`LANES-1]; initial begin if (READ_NOISE_SEED == 64'd0) $fatal(1, "READ_NOISE_SEED must be nonzero"); end generate for (genvar lane = 0; lane < `LANES; lane++) begin : gen_lane_noise localparam logic [63:0] LANE_SALT = 64'(lane + 1) * 64'h9E37_79B9_7F4A_7C15; random128 u_random_read ( .clk (clk), .rst_n (rst_n), .enable(valid_i && lane_valid_i[lane] && READ_NOISE_EN && (READ_NOISE_RATE_NUM > 0)), .seed ({(READ_NOISE_SEED ^ LANE_SALT), (READ_NOISE_SEED ^ LANE_SALT)}), .out (random_num[lane]) ); noise_mask_grouped #( .HASH_BITS (`HASH_BITS), .NOISE_BITS (READ_NOISE_BITS), .NOISE_RATE_NUM (READ_NOISE_RATE_NUM), .NOISE_RATE_DEN (READ_NOISE_RATE_DEN) ) u_mask ( .random_i(random_num[lane]), .mask_o (mask[lane]) ); end endgenerate always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin valid_q <= 1'b0; row_ids_q <= '0; hashes_q <= '0; lane_valid_q <= '0; valid_o <= 1'b0; row_ids_o <= '0; hashes_noisy_o <= '0; lane_valid_o <= '0; end else begin valid_q <= valid_i; row_ids_q <= row_ids_i; hashes_q <= hashes_i; lane_valid_q <= lane_valid_i; valid_o <= valid_q; row_ids_o <= row_ids_q; lane_valid_o <= lane_valid_q; for (int lane = 0; lane < `LANES; lane++) begin if (READ_NOISE_EN && (READ_NOISE_RATE_NUM > 0) && lane_valid_q[lane]) begin hashes_noisy_o[lane*`HASH_BITS +: `HASH_BITS] <= hashes_q[lane*`HASH_BITS +: `HASH_BITS] ^ mask[lane]; end else begin hashes_noisy_o[lane*`HASH_BITS +: `HASH_BITS] <= hashes_q[lane*`HASH_BITS +: `HASH_BITS]; end end end end endmodule