Files
Mini-Nav/hw/rtl/cam_top.sv
SikongJueluo 8b4d4c1b57 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
2026-05-26 23:45:52 +08:00

128 lines
4.8 KiB
Systemverilog

`timescale 1ns/1ps
`include "cam_params.svh"
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 logic [63:0] WRITE_NOISE_SEED = 64'hB504_F32D_B504_F32D
) (
input logic clk,
input logic rst_n,
// Write interface (handshake)
input logic wr_valid,
output logic wr_ready,
input logic [(`ROW_BITS)-1:0] wr_addr,
input logic [(`HASH_BITS)-1:0] write_hash,
// Query interface
input logic query_valid,
output logic query_ready,
input logic [(`HASH_BITS)-1:0] query_hash,
// Result interface (serial Top-K)
output logic result_valid,
input logic result_ready,
output logic [((`TOPK_K <= 1) ? 1 : $clog2(`TOPK_K))-1:0] result_rank,
output logic [(`ROW_BITS)-1:0] result_row,
output logic [(`SCORE_BITS)-1:0] result_score,
output logic result_last,
// Legacy Top-1 aliases (captured from rank-0 serial beat)
output logic [(`ROW_BITS)-1:0] top1_index,
output logic [(`SCORE_BITS)-1:0] top1_score,
`ifdef SIM_DEBUG
output logic [(`NUM_ROWS)*(`SCORE_BITS)-1:0] score_debug_flat,
output logic [$clog2(`NUM_ROWS+1)-1:0] consumed_candidates_debug,
`endif
output logic busy
);
// ── Internal signals ──
logic storage_wr_ready; // cam_noisy write-side ready
logic match_query_ready; // match_engine_pipeline idle
logic match_busy; // match_engine_pipeline scanning/result pending
// ── Internal valid forwarding ──
logic storage_wr_valid;
logic match_query_valid;
// ── Half-duplex arbitration (write-priority) ──
// Active query scan blocks new writes.
assign wr_ready = storage_wr_ready && match_query_ready && !match_busy;
assign query_ready = storage_wr_ready && match_query_ready && !wr_valid;
assign busy = (!storage_wr_ready) || match_busy || (!match_query_ready);
// ── Internal valid forwarding (only assert to sub-modules when top-level accepts) ──
assign storage_wr_valid = wr_valid && wr_ready;
assign match_query_valid = query_valid && query_ready;
// ── Read request/response bus between cam_noisy and match_engine_pipeline ──
wire rd_req_valid;
wire [(`ROW_BITS)-1:0] rd_req_base_row;
wire rd_resp_valid;
wire [(`LANES)*(`ROW_BITS)-1:0] rd_resp_row_ids;
wire [(`LANES)*(`HASH_BITS)-1:0] rd_resp_hashes;
wire [(`LANES)-1:0] rd_resp_lane_valid;
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_SEED (WRITE_NOISE_SEED)
) u_noisy (
.clk (clk),
.rst_n (rst_n),
.wr_valid (storage_wr_valid),
.wr_ready (storage_wr_ready),
.wr_addr (wr_addr),
.write_hash (write_hash),
.rd_valid_i (rd_req_valid),
.rd_base_row_i (rd_req_base_row),
.rd_valid_o (rd_resp_valid),
.rd_row_ids_o (rd_resp_row_ids),
.rd_hashes_o (rd_resp_hashes),
.rd_lane_valid_o (rd_resp_lane_valid)
);
match_engine_pipeline u_match (
.clk (clk),
.rst_n (rst_n),
.query_valid (match_query_valid),
.query_ready (match_query_ready),
.query_hash (query_hash),
.result_valid (result_valid),
.result_ready (result_ready),
.result_rank (result_rank),
.result_row (result_row),
.result_score (result_score),
.result_last (result_last),
.busy (match_busy),
.rd_valid_o (rd_req_valid),
.rd_base_row_o (rd_req_base_row),
.rd_valid_i (rd_resp_valid),
.rd_row_ids_i (rd_resp_row_ids),
.rd_hashes_i (rd_resp_hashes),
.rd_lane_valid_i (rd_resp_lane_valid)
`ifdef SIM_DEBUG
,.score_debug_flat (score_debug_flat)
,.consumed_candidates_debug (consumed_candidates_debug)
`endif
);
// ── Rank-0 (Top-1) aliases ──
// Capture first serial beat (rank==0) into legacy top1_index/top1_score outputs.
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
top1_index <= '0;
top1_score <= '0;
end else if (result_valid && result_ready && (result_rank == '0)) begin
top1_index <= result_row;
top1_score <= result_score;
end
end
endmodule