mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-13 04:25:32 +08:00
- 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
127 lines
4.3 KiB
Systemverilog
127 lines
4.3 KiB
Systemverilog
`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
|