mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-13 04:25:32 +08:00
feat(cam): add Bernoulli noise mask module and cocotb tests
- Add noise_mask_bernoulli.sv RTL module for probabilistic masking - Add cocotb test suite with reset, threshold, determinism, and distribution checks - Update rtl-sources.mk to include new module - Fix PYTHONPATH in devenv.nix shell hook
This commit is contained in:
126
hw/rtl/noise/noise_mask_bernoulli.sv
Normal file
126
hw/rtl/noise/noise_mask_bernoulli.sv
Normal file
@@ -0,0 +1,126 @@
|
||||
`timescale 1ns / 1ps
|
||||
`include "cam_params.svh"
|
||||
|
||||
module noise_mask_bernoulli #(
|
||||
parameter int HASH_BITS = `HASH_BITS,
|
||||
parameter int PROB_BITS = 8,
|
||||
parameter int PRNG_WORDS = 2,
|
||||
parameter int BITS_PER_CYCLE = 32,
|
||||
parameter logic [63:0] SEED = 64'hD1B5_4A32_9E37_79B9
|
||||
) (
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic start_i,
|
||||
input logic [PROB_BITS-1:0] threshold_i,
|
||||
output logic busy_o,
|
||||
output logic done_o,
|
||||
output logic [HASH_BITS-1:0] mask_o
|
||||
);
|
||||
|
||||
localparam int RANDOM_BITS = PRNG_WORDS * 128;
|
||||
localparam int BLOCKS = HASH_BITS / BITS_PER_CYCLE;
|
||||
localparam int BLOCK_INDEX_BITS = (BLOCKS <= 1) ? 1 : $clog2(BLOCKS);
|
||||
localparam logic [BLOCK_INDEX_BITS-1:0] LAST_BLOCK_IDX = BLOCK_INDEX_BITS'(BLOCKS - 1);
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_PRIME,
|
||||
STATE_RUN
|
||||
} state_t;
|
||||
|
||||
state_t state_q;
|
||||
logic [BLOCK_INDEX_BITS-1:0] block_idx_q;
|
||||
logic [PROB_BITS-1:0] threshold_q;
|
||||
logic [HASH_BITS-1:0] mask_q;
|
||||
logic prng_en;
|
||||
logic [RANDOM_BITS-1:0] random_bits;
|
||||
logic [BITS_PER_CYCLE-1:0] mask_slice;
|
||||
|
||||
assign busy_o = (state_q != STATE_IDLE);
|
||||
assign mask_o = mask_q;
|
||||
assign prng_en = (state_q == STATE_PRIME) ||
|
||||
((state_q == STATE_RUN) && (block_idx_q != LAST_BLOCK_IDX));
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
initial begin
|
||||
if (HASH_BITS <= 0) $fatal(1, "HASH_BITS must be > 0");
|
||||
if (PROB_BITS <= 0) $fatal(1, "PROB_BITS must be > 0");
|
||||
if (PRNG_WORDS <= 0) $fatal(1, "PRNG_WORDS must be > 0");
|
||||
if (BITS_PER_CYCLE <= 0) $fatal(1, "BITS_PER_CYCLE must be > 0");
|
||||
if (HASH_BITS % BITS_PER_CYCLE != 0) $fatal(1, "HASH_BITS must be divisible by BITS_PER_CYCLE");
|
||||
if (RANDOM_BITS != BITS_PER_CYCLE * PROB_BITS) $fatal(1, "PRNG_WORDS*128 must equal BITS_PER_CYCLE*PROB_BITS");
|
||||
if (SEED == 64'h0) $fatal(1, "SEED must be non-zero");
|
||||
for (int w = 0; w < PRNG_WORDS; w++) begin
|
||||
if ({SEED, SEED ^ (64'(w+1))} == 128'h0) $fatal(1, "PRNG seed must be non-zero");
|
||||
for (int w2 = w+1; w2 < PRNG_WORDS; w2++) begin
|
||||
if ({SEED, SEED ^ (64'(w+1))} == {SEED, SEED ^ (64'(w2+1))})
|
||||
$fatal(1, "PRNG seeds must differ");
|
||||
end
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
always_ff @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state_q <= STATE_IDLE;
|
||||
block_idx_q <= '0;
|
||||
threshold_q <= '0;
|
||||
mask_q <= '0;
|
||||
done_o <= 1'b0;
|
||||
end else begin
|
||||
done_o <= 1'b0;
|
||||
|
||||
unique case (state_q)
|
||||
STATE_IDLE: begin
|
||||
block_idx_q <= '0;
|
||||
if (start_i) begin
|
||||
threshold_q <= threshold_i;
|
||||
mask_q <= '0;
|
||||
state_q <= STATE_PRIME;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_PRIME: begin
|
||||
state_q <= STATE_RUN;
|
||||
end
|
||||
|
||||
STATE_RUN: begin
|
||||
mask_q[block_idx_q * BITS_PER_CYCLE +: BITS_PER_CYCLE] <= mask_slice;
|
||||
|
||||
if (block_idx_q == LAST_BLOCK_IDX) begin
|
||||
state_q <= STATE_IDLE;
|
||||
block_idx_q <= '0;
|
||||
done_o <= 1'b1;
|
||||
end else begin
|
||||
block_idx_q <= block_idx_q + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
state_q <= STATE_IDLE;
|
||||
block_idx_q <= '0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
generate
|
||||
for (genvar w = 0; w < PRNG_WORDS; w++) begin : gen_prng
|
||||
localparam logic [127:0] PRNG_SEED = {SEED, SEED ^ (64'(w+1))};
|
||||
random128 prng_inst (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.enable (prng_en),
|
||||
.seed (PRNG_SEED),
|
||||
.out (random_bits[w*128 +: 128])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
for (genvar i = 0; i < BITS_PER_CYCLE; i++) begin : gen_bernoulli
|
||||
assign mask_slice[i] = (random_bits[i*PROB_BITS +: PROB_BITS] < threshold_q);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user