refactor(cam): remove read noise from noise architecture (Phase 2)

- Make cam_read_noise a pass-through module, removing all noise injection logic
- Switch write noise to use noise_mask_bernoulli instead of noise_mask_grouped
- Add state machine to cam_write_noise for mask generation timing
- Remove noise_mask_grouped.sv (no longer needed)
- Remove read noise parameters from cam_noisy and cam_top
- Update simulation and benchmark code to reflect read noise removal
- Sync documentation to reflect Phase 2 architecture
This commit is contained in:
2026-05-26 23:02:22 +08:00
parent e5d13917b2
commit 8b4d4c1b57
29 changed files with 277 additions and 863 deletions

View File

@@ -5,13 +5,7 @@ module cam_noisy #(
parameter bit WRITE_NOISE_EN = 1'b1,
parameter int WRITE_NOISE_RATE_NUM = 1,
parameter int WRITE_NOISE_RATE_DEN = 100,
parameter int WRITE_NOISE_BITS = 8,
parameter logic [63:0] WRITE_NOISE_SEED = 64'hB504_F32D_B504_F32D,
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
parameter logic [63:0] WRITE_NOISE_SEED = 64'hB504_F32D_B504_F32D
) (
input logic clk,
input logic rst_n,
@@ -42,7 +36,6 @@ module cam_noisy #(
.WRITE_NOISE_EN (WRITE_NOISE_EN),
.WRITE_NOISE_RATE_NUM (WRITE_NOISE_RATE_NUM),
.WRITE_NOISE_RATE_DEN (WRITE_NOISE_RATE_DEN),
.WRITE_NOISE_BITS (WRITE_NOISE_BITS),
.WRITE_NOISE_SEED (WRITE_NOISE_SEED)
) u_write_noise (
.clk (clk),
@@ -73,13 +66,7 @@ module cam_noisy #(
);
// ── Read noise pipeline ──
cam_read_noise #(
.READ_NOISE_EN (READ_NOISE_EN),
.READ_NOISE_RATE_NUM (READ_NOISE_RATE_NUM),
.READ_NOISE_RATE_DEN (READ_NOISE_RATE_DEN),
.READ_NOISE_BITS (READ_NOISE_BITS),
.READ_NOISE_SEED (READ_NOISE_SEED)
) u_read_noise (
cam_read_noise u_read_noise (
.clk (clk),
.rst_n (rst_n),
.valid_i (core_rd_valid),

View File

@@ -5,13 +5,7 @@ module cam_top #(
parameter bit WRITE_NOISE_EN = 1'b1,
parameter int WRITE_NOISE_RATE_NUM = 1,
parameter int WRITE_NOISE_RATE_DEN = 100,
parameter int WRITE_NOISE_BITS = 8,
parameter logic [63:0] WRITE_NOISE_SEED = 64'hB504_F32D_B504_F32D,
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
parameter logic [63:0] WRITE_NOISE_SEED = 64'hB504_F32D_B504_F32D
) (
input logic clk,
input logic rst_n,
@@ -77,13 +71,7 @@ module cam_top #(
.WRITE_NOISE_EN (WRITE_NOISE_EN),
.WRITE_NOISE_RATE_NUM (WRITE_NOISE_RATE_NUM),
.WRITE_NOISE_RATE_DEN (WRITE_NOISE_RATE_DEN),
.WRITE_NOISE_BITS (WRITE_NOISE_BITS),
.WRITE_NOISE_SEED (WRITE_NOISE_SEED),
.READ_NOISE_EN (READ_NOISE_EN),
.READ_NOISE_RATE_NUM (READ_NOISE_RATE_NUM),
.READ_NOISE_RATE_DEN (READ_NOISE_RATE_DEN),
.READ_NOISE_BITS (READ_NOISE_BITS),
.READ_NOISE_SEED (READ_NOISE_SEED)
.WRITE_NOISE_SEED (WRITE_NOISE_SEED)
) u_noisy (
.clk (clk),
.rst_n (rst_n),

View File

@@ -1,13 +1,7 @@
`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
) (
module cam_read_noise (
input logic clk,
input logic rst_n,
input logic valid_i,
@@ -19,69 +13,19 @@ module cam_read_noise #(
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];
`ifndef SYNTHESIS
initial begin
if (READ_NOISE_SEED == 64'd0) $fatal(1, "READ_NOISE_SEED must be nonzero");
end
`endif
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
valid_o <= valid_i;
row_ids_o <= row_ids_i;
hashes_noisy_o <= hashes_i;
lane_valid_o <= lane_valid_i;
end
end
endmodule

View File

@@ -5,7 +5,6 @@ module cam_write_noise #(
parameter bit WRITE_NOISE_EN = 1'b1,
parameter int WRITE_NOISE_RATE_NUM = 1,
parameter int WRITE_NOISE_RATE_DEN = 100,
parameter int WRITE_NOISE_BITS = 8,
parameter logic [63:0] WRITE_NOISE_SEED = 64'hB504_F32D_B504_F32D
) (
input logic clk,
@@ -18,30 +17,46 @@ module cam_write_noise #(
output logic [(`ROW_BITS)-1:0] core_wr_row,
output logic [(`HASH_BITS)-1:0] core_wr_hash
);
logic pending_q;
logic [(`ROW_BITS)-1:0] row_q;
logic [(`HASH_BITS)-1:0] hash_q;
logic [127:0] random_num;
localparam int PROB_BITS = 8;
localparam int SAMPLE_RANGE = 1 << PROB_BITS;
localparam int WRITE_NOISE_THRESHOLD_RAW =
(WRITE_NOISE_RATE_NUM * SAMPLE_RANGE) / WRITE_NOISE_RATE_DEN;
localparam int WRITE_NOISE_THRESHOLD =
(WRITE_NOISE_THRESHOLD_RAW > (SAMPLE_RANGE - 1)) ?
(SAMPLE_RANGE - 1) : WRITE_NOISE_THRESHOLD_RAW;
wire noise_active = WRITE_NOISE_EN && (WRITE_NOISE_RATE_NUM > 0) && (WRITE_NOISE_THRESHOLD > 0);
typedef enum logic [1:0] {
STATE_IDLE,
STATE_WAIT_MASK
} state_t;
state_t state_q;
logic mask_start_q;
logic mask_busy;
logic mask_done;
logic [(`HASH_BITS)-1:0] flip_mask;
logic [(`ROW_BITS)-1:0] row_q;
logic [(`HASH_BITS)-1:0] hash_q;
assign wr_ready = !pending_q;
assign wr_ready = (state_q == STATE_IDLE);
random128 u_random_write (
.clk (clk),
.rst_n (rst_n),
.enable(wr_valid && wr_ready && WRITE_NOISE_EN && (WRITE_NOISE_RATE_NUM > 0)),
.seed ({WRITE_NOISE_SEED, WRITE_NOISE_SEED}),
.out (random_num)
);
noise_mask_grouped #(
noise_mask_bernoulli #(
.HASH_BITS (`HASH_BITS),
.NOISE_BITS (WRITE_NOISE_BITS),
.NOISE_RATE_NUM (WRITE_NOISE_RATE_NUM),
.NOISE_RATE_DEN (WRITE_NOISE_RATE_DEN)
) u_mask (
.random_i(random_num),
.mask_o (flip_mask)
.PROB_BITS (PROB_BITS),
.PRNG_WORDS (2),
.BITS_PER_CYCLE (32),
.SEED (WRITE_NOISE_SEED)
) u_bernoulli_mask (
.clk (clk),
.rst_n (rst_n),
.start_i (mask_start_q),
.threshold_i (PROB_BITS'(WRITE_NOISE_THRESHOLD)),
.busy_o (mask_busy),
.done_o (mask_done),
.mask_o (flip_mask)
);
`ifndef SYNTHESIS
@@ -52,26 +67,47 @@ module cam_write_noise #(
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
pending_q <= 1'b0;
row_q <= '0;
hash_q <= '0;
state_q <= STATE_IDLE;
mask_start_q <= 1'b0;
row_q <= '0;
hash_q <= '0;
core_wr_valid <= 1'b0;
core_wr_row <= '0;
core_wr_hash <= '0;
core_wr_row <= '0;
core_wr_hash <= '0;
end else begin
core_wr_valid <= pending_q;
core_wr_row <= row_q;
if (WRITE_NOISE_EN && (WRITE_NOISE_RATE_NUM > 0)) begin
core_wr_hash <= hash_q ^ flip_mask;
end else begin
core_wr_hash <= hash_q;
end
core_wr_valid <= 1'b0;
mask_start_q <= 1'b0;
pending_q <= wr_valid && wr_ready;
if (wr_valid && wr_ready) begin
row_q <= wr_row;
hash_q <= wr_hash;
end
unique case (state_q)
STATE_IDLE: begin
if (wr_valid && wr_ready) begin
row_q <= wr_row;
hash_q <= wr_hash;
if (noise_active) begin
mask_start_q <= 1'b1;
state_q <= STATE_WAIT_MASK;
end else begin
// Noise inactive: pass through immediately (one-cycle)
core_wr_valid <= 1'b1;
core_wr_row <= wr_row;
core_wr_hash <= wr_hash;
end
end
end
STATE_WAIT_MASK: begin
if (mask_done) begin
core_wr_valid <= 1'b1;
core_wr_row <= row_q;
core_wr_hash <= hash_q ^ flip_mask;
state_q <= STATE_IDLE;
end
end
default: begin
state_q <= STATE_IDLE;
end
endcase
end
end
endmodule

View File

@@ -1,39 +0,0 @@
`timescale 1ns / 1ps
`include "cam_params.svh"
module noise_mask_grouped #(
parameter int HASH_BITS = `HASH_BITS,
parameter int NOISE_BITS = 8,
parameter int NOISE_RATE_NUM = 1,
parameter int NOISE_RATE_DEN = 100
) (
input logic [127:0] random_i,
output logic [HASH_BITS-1:0] mask_o
);
localparam int GROUP_BITS = HASH_BITS / NOISE_BITS;
localparam int BIT_INDEX_BITS = 6;
localparam int SAMPLE_BITS = 8;
localparam int GROUP_RAND_BITS = BIT_INDEX_BITS + SAMPLE_BITS;
localparam int SAMPLE_RANGE = 1 << SAMPLE_BITS;
localparam int THRESHOLD = (NOISE_RATE_NUM * SAMPLE_RANGE) / NOISE_RATE_DEN;
`ifndef SYNTHESIS
initial begin
if (NOISE_BITS <= 0) $fatal(1, "NOISE_BITS must be > 0");
if (HASH_BITS % NOISE_BITS != 0) $fatal(1, "HASH_BITS must be divisible by NOISE_BITS");
if (GROUP_BITS != 64) $fatal(1, "GROUP_BITS must be 64 for 6-bit grouped noise");
if (NOISE_BITS * GROUP_RAND_BITS > 128) $fatal(1, "NOISE_BITS consumes more than 128 random bits");
if (NOISE_RATE_DEN <= 0) $fatal(1, "NOISE_RATE_DEN must be > 0");
if (NOISE_RATE_NUM < 0 || NOISE_RATE_NUM > NOISE_RATE_DEN) $fatal(1, "NOISE_RATE_NUM out of range");
end
`endif
always_comb begin
mask_o = '0;
for (int i = 0; i < NOISE_BITS; i++) begin
if (random_i[i * GROUP_RAND_BITS + BIT_INDEX_BITS +: SAMPLE_BITS] < THRESHOLD) begin
mask_o[i * GROUP_BITS + random_i[i * GROUP_RAND_BITS +: BIT_INDEX_BITS]] = 1'b1;
end
end
end
endmodule