Files
Mini-Nav/hw/rtl/match_engine.sv
SikongJueluo 2da17e101b feat(rtl): migrate CAM interface to handshake protocol with integrated noise generation
BREAKING CHANGE: CAM write and query interface replaced with standard valid/ready
handshake. wr_en/wr_row/wr_hash → wr_valid/wr_ready/wr_addr/write_hash.
External noise_mask_lanes_flat removed; noise generation now handled internally
by cam_noisy module with configurable rate via parameters.

- cam_top: add parameters (NOISE_EN, NOISE_RATE_NUM/DEN, NOISE_GEN/SAMPLE_BITS, NOISE_SEED)
- cam_top: replace cam_core with cam_noisy (integrated noise generation)
- match_engine: remove external noise_mask_lanes_flat input
- hw/sim: update Makefile with noise parameters and compile args
- hw/sim/model: add generate_write_flip_mask() and xorshift64() matching RTL behavior
- hw/sim/tests: adapt testbench to new handshake protocol
2026-05-04 18:03:06 +08:00

185 lines
6.0 KiB
Systemverilog

`timescale 1ns / 1ps
`include "cam_params.svh"
module match_engine (
input logic clk,
input logic rst_n,
// Query interface
input logic query_valid,
output logic query_ready,
input logic [(`HASH_BITS)-1:0] query_hash,
output logic result_valid,
input logic result_ready,
output logic [(`ROW_BITS)-1:0] result_row,
output logic [(`SCORE_BITS)-1:0] result_score,
output logic busy,
// To/from cam_core
output logic [(`LANES)*(`ROW_BITS)-1:0] rd_addr_lanes_flat,
input logic [(`LANES)*(`HASH_BITS)-1:0] rd_hash_lanes_flat
`ifdef SIM_DEBUG
,output logic [(`NUM_ROWS)*(`SCORE_BITS)-1:0] score_debug_flat
`endif
);
typedef enum logic [1:0] { // state_t
S_IDLE, // Waiting for query_valid
S_SCAN, // Scanning rows in LANES-wide batches
S_DONE // Result ready, waiting for result_ready
} state_t;
state_t state_q, state_d;
logic [(`HASH_BITS)-1:0] query_q;
logic [(`ROW_BITS)-1:0] base_row_q, base_row_d;
logic [(`ROW_BITS)-1:0] prev_best_idx [0:(`LANES)];
logic [(`ROW_BITS)-1:0] next_best_idx [0:(`LANES)-1];
logic [(`SCORE_BITS)-1:0] prev_best_score [0:(`LANES)];
logic [(`SCORE_BITS)-1:0] next_best_score [0:(`LANES)-1];
logic [(`SCORE_BITS)-1:0] lane_score [0:(`LANES)-1];
logic [(`ROW_BITS)-1:0] lane_row [0:(`LANES)-1];
logic lane_valid [0:(`LANES)-1];
logic [(`ROW_BITS)-1:0] batch_best_idx;
logic [(`SCORE_BITS)-1:0] batch_best_score;
logic [(`ROW_BITS)-1:0] best_idx_q, best_idx_d;
logic [(`SCORE_BITS)-1:0] best_score_q, best_score_d;
assign query_ready = (state_q == S_IDLE);
assign result_valid = (state_q == S_DONE);
assign result_row = best_idx_q;
assign result_score = best_score_q;
assign busy = (state_q == S_SCAN);
genvar lane;
generate
for (lane = 0; lane < `LANES; lane++) begin : gen_lanes
logic [(`HASH_BITS)-1:0] row_hash;
logic [(`HASH_BITS)-1:0] effective_hash;
logic [(`HASH_BITS)-1:0] match_bits;
assign lane_row[lane] = base_row_q + lane[(`ROW_BITS)-1:0];
assign lane_valid[lane] = (lane_row[lane] < `NUM_ROWS);
assign rd_addr_lanes_flat[lane*`ROW_BITS +: `ROW_BITS] = lane_row[lane];
assign row_hash = rd_hash_lanes_flat[lane*`HASH_BITS +: `HASH_BITS];
assign effective_hash = row_hash;
assign match_bits = ~(query_q ^ effective_hash);
popcount #(
.WIDTH(`HASH_BITS),
.GROUP(8),
.OUT_WIDTH(`SCORE_BITS)
) u_popcount (
.bits_i(match_bits),
.count_o(lane_score[lane])
);
argmax_update #(
.ROW_BITS(`ROW_BITS),
.SCORE_BITS(`SCORE_BITS)
) u_argmax_update (
.best_index_i(prev_best_idx[lane]),
.best_score_i(prev_best_score[lane]),
.cand_index_i(lane_row[lane]),
.cand_score_i(lane_valid[lane] ? lane_score[lane] : '0),
.best_index_o(next_best_idx[lane]),
.best_score_o(next_best_score[lane])
);
end
endgenerate
// Initialize chain with current batch seed
assign prev_best_idx[0] = best_idx_q;
assign prev_best_score[0] = best_score_q;
// Propagate per-lane results
for (genvar l = 0; l < `LANES; l++) begin : chain_link
assign prev_best_idx[l+1] = next_best_idx[l];
assign prev_best_score[l+1] = next_best_score[l];
end
assign batch_best_idx = prev_best_idx[`LANES];
assign batch_best_score = prev_best_score[`LANES];
always_comb begin
state_d = state_q;
base_row_d = base_row_q;
best_idx_d = best_idx_q;
best_score_d = best_score_q;
unique case (state_q)
S_IDLE: begin
if (query_valid) begin
state_d = S_SCAN;
base_row_d = '0;
best_idx_d = TIE_BREAK_SENTINEL; // Lower index wins tie-break
best_score_d = '0;
end
end
S_SCAN: begin
best_idx_d = batch_best_idx;
best_score_d = batch_best_score;
if (base_row_q + `LANES >= `NUM_ROWS) begin
state_d = S_DONE;
end else begin
base_row_d = base_row_q + `LANES;
end
end
S_DONE: begin
if (result_ready) begin
state_d = S_IDLE;
end
end
default: begin
state_d = S_IDLE;
end
endcase
end
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_IDLE;
query_q <= '0;
base_row_q <= '0;
best_idx_q <= '0;
best_score_q <= '0;
end else begin
state_q <= state_d;
base_row_q <= base_row_d;
best_idx_q <= best_idx_d;
best_score_q <= best_score_d;
if ((state_q == S_IDLE) && query_valid) begin
query_q <= query_hash;
end
`ifdef SIM_DEBUG
if (state_q == S_IDLE && query_valid) begin
score_debug_flat <= '0;
end else if (state_q == S_SCAN) begin
for (int l = 0; l < `LANES; l++) begin
if (lane_valid[l]) begin
score_debug_flat[lane_row[l]*`SCORE_BITS +: `SCORE_BITS] <= lane_score[l];
end
end
end
`endif
end
end
`ifdef SIM_DEBUG
initial begin
score_debug_flat = '0;
end
`endif
endmodule