mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
refactor(cam): extract match engine into separate module and centralize parameters
- Split cam_core into pure memory (cam_core.sv) and match engine (match_engine.sv) - Add cam_params.svh with centralized parameter definitions (NUM_ROWS, HASH_BITS, LANES, etc.) - Update cam_top.sv to use shared parameters and compose match_engine - Update Makefile to include new match_engine module and correct Verilator define syntax
This commit is contained in:
@@ -1,80 +1,17 @@
|
|||||||
`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
||||||
|
`include "cam_params.svh"
|
||||||
|
|
||||||
module cam_core #(
|
module cam_core (
|
||||||
parameter int NUM_ROWS = 512,
|
input logic clk,
|
||||||
parameter int HASH_BITS = 512,
|
input logic rst_n,
|
||||||
parameter int LANES = 16,
|
input logic wr_en,
|
||||||
|
input logic [(`ROW_BITS)-1:0] wr_row,
|
||||||
parameter int ROW_BITS = $clog2(NUM_ROWS),
|
input logic [(`HASH_BITS)-1:0] wr_hash,
|
||||||
parameter int SCORE_BITS = $clog2(HASH_BITS + 1)
|
input logic [(`LANES)*(`ROW_BITS)-1:0] rd_addr_lanes_flat,
|
||||||
) (
|
output logic [(`LANES)*(`HASH_BITS)-1:0] rd_hash_lanes_flat
|
||||||
input logic clk,
|
|
||||||
input logic rst_n,
|
|
||||||
|
|
||||||
// Static load interface. In the first prototype, writes are expected
|
|
||||||
// before online queries begin.
|
|
||||||
input logic [ ROW_BITS-1:0] wr_row,
|
|
||||||
input logic [HASH_BITS-1:0] wr_hash,
|
|
||||||
input logic wr_en,
|
|
||||||
|
|
||||||
// Single-request blocking 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] top1_index,
|
|
||||||
output logic [SCORE_BITS-1:0] top1_score,
|
|
||||||
|
|
||||||
`ifdef SIM_NOISE
|
|
||||||
// Flattened for easier cocotb/Verilator handling:
|
|
||||||
// lane k mask = noise_mask_lanes_flat[k*HASH_BITS +: HASH_BITS]
|
|
||||||
input logic [LANES*HASH_BITS-1:0] noise_mask_lanes_flat,
|
|
||||||
`endif
|
|
||||||
|
|
||||||
`ifdef SIM_DEBUG
|
|
||||||
// Flattened for easier cocotb/Verilator handling:
|
|
||||||
// score[row] = score_debug_flat[row*SCORE_BITS +: SCORE_BITS]
|
|
||||||
output logic [NUM_ROWS*SCORE_BITS-1:0] score_debug_flat,
|
|
||||||
`endif
|
|
||||||
|
|
||||||
output logic busy
|
|
||||||
);
|
);
|
||||||
localparam int NUM_BATCHES = (NUM_ROWS + LANES - 1) / LANES;
|
|
||||||
|
|
||||||
typedef enum logic [1:0] {
|
logic [(`HASH_BITS)-1:0] cam_mem[0:(`NUM_ROWS)-1];
|
||||||
S_IDLE,
|
|
||||||
S_SCAN,
|
|
||||||
S_DONE
|
|
||||||
} state_t;
|
|
||||||
|
|
||||||
state_t state_q, state_d;
|
|
||||||
|
|
||||||
logic [HASH_BITS-1:0] cam_mem[NUM_ROWS];
|
|
||||||
|
|
||||||
logic [HASH_BITS-1: 0] query_q;
|
|
||||||
logic [ROW_BITS-1 : 0] base_row_q;
|
|
||||||
logic [ROW_BITS-1 : 0] base_row_d;
|
|
||||||
|
|
||||||
logic [ROW_BITS-1:0] best_index_q, best_index_d;
|
|
||||||
logic [SCORE_BITS-1:0] best_score_q, best_score_d;
|
|
||||||
|
|
||||||
logic [ ROW_BITS-1:0] lane_best_index;
|
|
||||||
logic [SCORE_BITS-1:0] lane_best_score;
|
|
||||||
|
|
||||||
logic [ ROW_BITS-1:0] lane_best_index_next[LANES+1];
|
|
||||||
logic [SCORE_BITS-1:0] lane_best_score_next[LANES+1];
|
|
||||||
|
|
||||||
logic [SCORE_BITS-1:0] lane_score [ LANES];
|
|
||||||
logic [ ROW_BITS-1:0] lane_row [ LANES];
|
|
||||||
logic lane_valid [ LANES];
|
|
||||||
|
|
||||||
assign query_ready = (state_q == S_IDLE);
|
|
||||||
assign result_valid = (state_q == S_DONE);
|
|
||||||
assign top1_index = best_index_q;
|
|
||||||
assign top1_score = best_score_q;
|
|
||||||
assign busy = (state_q == S_SCAN);
|
|
||||||
|
|
||||||
// Memory write path.
|
// Memory write path.
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
@@ -83,132 +20,13 @@ module cam_core #(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
`ifdef SIM_DEBUG
|
// Per-lane combinational read.
|
||||||
// Clear by default. Individual rows are overwritten during scan.
|
genvar l;
|
||||||
initial begin
|
|
||||||
score_debug_flat = '0;
|
|
||||||
end
|
|
||||||
`endif
|
|
||||||
|
|
||||||
genvar lane;
|
|
||||||
generate
|
generate
|
||||||
for (lane = 0; lane < LANES; lane++) begin : gen_lanes
|
for (l = 0; l < `LANES; l++) begin : rd_lane
|
||||||
logic [HASH_BITS-1:0] row_hash;
|
assign rd_hash_lanes_flat[l*`HASH_BITS +: `HASH_BITS] =
|
||||||
logic [HASH_BITS-1:0] effective_hash;
|
cam_mem[rd_addr_lanes_flat[l*`ROW_BITS +: `ROW_BITS]];
|
||||||
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[ROW_BITS-1:0]);
|
|
||||||
|
|
||||||
// This read is modeled behaviorally. Later this can be replaced
|
|
||||||
// by banked BRAM/URAM without changing the compare path.
|
|
||||||
assign row_hash = lane_valid[lane] ? cam_mem[lane_row[lane]] : '0;
|
|
||||||
|
|
||||||
`ifdef SIM_NOISE
|
|
||||||
logic [HASH_BITS-1:0] lane_noise_mask;
|
|
||||||
assign lane_noise_mask = noise_mask_lanes_flat[lane*HASH_BITS+:HASH_BITS];
|
|
||||||
assign effective_hash = row_hash ^ lane_noise_mask;
|
|
||||||
`else
|
|
||||||
assign effective_hash = row_hash;
|
|
||||||
`endif
|
|
||||||
|
|
||||||
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_lane (
|
|
||||||
.best_index_i(lane_best_index_next[lane]),
|
|
||||||
.best_score_i(lane_best_score_next[lane]),
|
|
||||||
.cand_index_i(lane_row[lane]),
|
|
||||||
.cand_score_i(lane_valid[lane] ? lane_score[lane] : '0),
|
|
||||||
.best_index_o(lane_best_index_next[lane+1]),
|
|
||||||
.best_score_o(lane_best_score_next[lane+1])
|
|
||||||
);
|
|
||||||
end
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
assign lane_best_index_next[0] = best_index_q;
|
|
||||||
assign lane_best_score_next[0] = best_score_q;
|
|
||||||
assign lane_best_index = lane_best_index_next[LANES];
|
|
||||||
assign lane_best_score = lane_best_score_next[LANES];
|
|
||||||
|
|
||||||
always_comb begin
|
|
||||||
state_d = state_q;
|
|
||||||
base_row_d = base_row_q;
|
|
||||||
best_index_d = best_index_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_index_d = {ROW_BITS{1'b1}};
|
|
||||||
best_score_d = '0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
S_SCAN: begin
|
|
||||||
best_index_d = lane_best_index;
|
|
||||||
best_score_d = lane_best_score;
|
|
||||||
|
|
||||||
if (base_row_q + LANES >= NUM_ROWS) begin
|
|
||||||
state_d = S_DONE;
|
|
||||||
end else begin
|
|
||||||
base_row_d = base_row_q + LANES[ROW_BITS-1:0];
|
|
||||||
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_index_q <= '0;
|
|
||||||
best_score_q <= '0;
|
|
||||||
end else begin
|
|
||||||
state_q <= state_d;
|
|
||||||
base_row_q <= base_row_d;
|
|
||||||
best_index_q <= best_index_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
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
54
hw/rtl/cam_params.svh
Normal file
54
hw/rtl/cam_params.svh
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
//==============================================================================
|
||||||
|
// CAM Parameter Definitions
|
||||||
|
//==============================================================================
|
||||||
|
// This file defines shared compile-time parameters for the Content-Addressable
|
||||||
|
// Memory (CAM) subsystem. All `define macros use `ifndef guards to allow
|
||||||
|
// command-line override via +define+.
|
||||||
|
//
|
||||||
|
// Macros:
|
||||||
|
// NUM_ROWS — Number of rows in the CAM array
|
||||||
|
// HASH_BITS — Width of the hash value in bits
|
||||||
|
// LANES — Number of parallel comparison lanes
|
||||||
|
// ROW_BITS — Bits needed to index NUM_ROWS rows ($clog2(NUM_ROWS))
|
||||||
|
// SCORE_BITS — Bits needed to represent HASH_BITS-bit scores ($clog2(HASH_BITS+1))
|
||||||
|
//
|
||||||
|
// The TIE_BREAK_SENTINEL localparam is a bitmask with all bits set to 1'b1,
|
||||||
|
// used as the initial / tie-breaking value in the row-priority arbiter.
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
`ifndef CAM_PARAMS_SVH
|
||||||
|
`define CAM_PARAMS_SVH
|
||||||
|
|
||||||
|
// Number of CAM rows.
|
||||||
|
`ifndef NUM_ROWS
|
||||||
|
`define NUM_ROWS 512
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Width of the hash value stored per row.
|
||||||
|
`ifndef HASH_BITS
|
||||||
|
`define HASH_BITS 512
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Number of parallel comparison lanes.
|
||||||
|
`ifndef LANES
|
||||||
|
`define LANES 16
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Bits required to represent a row index.
|
||||||
|
`ifndef ROW_BITS
|
||||||
|
`define ROW_BITS $clog2(`NUM_ROWS)
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Bits required to represent a full-score count.
|
||||||
|
`ifndef SCORE_BITS
|
||||||
|
`define SCORE_BITS $clog2(`HASH_BITS + 1)
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Tie-break sentinel: all ones in the row-index width.
|
||||||
|
// Used as the initial best-index value before any match is found.
|
||||||
|
localparam logic [(`ROW_BITS)-1:0] TIE_BREAK_SENTINEL = {(`ROW_BITS){1'b1}};
|
||||||
|
|
||||||
|
// Current fixed parameters require NUM_ROWS divisible by LANES.
|
||||||
|
// Non-divisible tail-group valid-mask is not implemented in this round.
|
||||||
|
|
||||||
|
`endif // CAM_PARAMS_SVH
|
||||||
@@ -1,64 +1,64 @@
|
|||||||
`timescale 1ns/1ps
|
`timescale 1ns/1ps
|
||||||
|
`include "cam_params.svh"
|
||||||
|
|
||||||
module cam_top #(
|
module cam_top (
|
||||||
parameter int NUM_ROWS = 512,
|
|
||||||
parameter int HASH_BITS = 512,
|
|
||||||
parameter int LANES = 16,
|
|
||||||
|
|
||||||
parameter int ROW_BITS = $clog2(NUM_ROWS),
|
|
||||||
parameter int SCORE_BITS = $clog2(HASH_BITS + 1)
|
|
||||||
) (
|
|
||||||
input logic clk,
|
input logic clk,
|
||||||
input logic rst_n,
|
input logic rst_n,
|
||||||
|
|
||||||
input logic wr_en,
|
input logic wr_en,
|
||||||
input logic [ROW_BITS-1:0] wr_row,
|
input logic [(`ROW_BITS)-1:0] wr_row,
|
||||||
input logic [HASH_BITS-1:0] wr_hash,
|
input logic [(`HASH_BITS)-1:0] wr_hash,
|
||||||
|
|
||||||
input logic query_valid,
|
input logic query_valid,
|
||||||
output logic query_ready,
|
output logic query_ready,
|
||||||
input logic [HASH_BITS-1:0] query_hash,
|
input logic [(`HASH_BITS)-1:0] query_hash,
|
||||||
|
|
||||||
output logic result_valid,
|
output logic result_valid,
|
||||||
input logic result_ready,
|
input logic result_ready,
|
||||||
output logic [ROW_BITS-1:0] top1_index,
|
output logic [(`ROW_BITS)-1:0] top1_index,
|
||||||
output logic [SCORE_BITS-1:0] top1_score,
|
output logic [(`SCORE_BITS)-1:0] top1_score,
|
||||||
|
|
||||||
`ifdef SIM_NOISE
|
`ifdef SIM_NOISE
|
||||||
input logic [LANES*HASH_BITS-1:0] noise_mask_lanes_flat,
|
input logic [(`LANES)*(`HASH_BITS)-1:0] noise_mask_lanes_flat,
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
`ifdef SIM_DEBUG
|
`ifdef SIM_DEBUG
|
||||||
output logic [NUM_ROWS*SCORE_BITS-1:0] score_debug_flat,
|
output logic [(`NUM_ROWS)*(`SCORE_BITS)-1:0] score_debug_flat,
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
output logic busy
|
output logic busy
|
||||||
);
|
);
|
||||||
cam_core #(
|
wire [(`LANES)*(`ROW_BITS)-1:0] rd_addr_lanes_flat;
|
||||||
.NUM_ROWS(NUM_ROWS),
|
wire [(`LANES)*(`HASH_BITS)-1:0] rd_hash_lanes_flat;
|
||||||
.HASH_BITS(HASH_BITS),
|
|
||||||
.LANES(LANES),
|
cam_core u_core (
|
||||||
.ROW_BITS(ROW_BITS),
|
.clk (clk),
|
||||||
.SCORE_BITS(SCORE_BITS)
|
.rst_n (rst_n),
|
||||||
) u_core (
|
.wr_en (wr_en),
|
||||||
.clk(clk),
|
.wr_row (wr_row),
|
||||||
.rst_n(rst_n),
|
.wr_hash (wr_hash),
|
||||||
.wr_row(wr_row),
|
.rd_addr_lanes_flat (rd_addr_lanes_flat),
|
||||||
.wr_hash(wr_hash),
|
.rd_hash_lanes_flat (rd_hash_lanes_flat)
|
||||||
.wr_en(wr_en),
|
);
|
||||||
.query_valid(query_valid),
|
|
||||||
.query_ready(query_ready),
|
match_engine u_match (
|
||||||
.query_hash(query_hash),
|
.clk (clk),
|
||||||
.result_valid(result_valid),
|
.rst_n (rst_n),
|
||||||
.result_ready(result_ready),
|
.query_valid (query_valid),
|
||||||
.top1_index(top1_index),
|
.query_ready (query_ready),
|
||||||
.top1_score(top1_score),
|
.query_hash (query_hash),
|
||||||
|
.result_valid (result_valid),
|
||||||
|
.result_ready (result_ready),
|
||||||
|
.result_row (top1_index),
|
||||||
|
.result_score (top1_score),
|
||||||
|
.busy (busy),
|
||||||
|
.rd_addr_lanes_flat (rd_addr_lanes_flat),
|
||||||
|
.rd_hash_lanes_flat (rd_hash_lanes_flat)
|
||||||
`ifdef SIM_NOISE
|
`ifdef SIM_NOISE
|
||||||
.noise_mask_lanes_flat(noise_mask_lanes_flat),
|
,.noise_mask_lanes_flat (noise_mask_lanes_flat)
|
||||||
`endif
|
`endif
|
||||||
`ifdef SIM_DEBUG
|
`ifdef SIM_DEBUG
|
||||||
.score_debug_flat(score_debug_flat),
|
,.score_debug_flat (score_debug_flat)
|
||||||
`endif
|
`endif
|
||||||
.busy(busy)
|
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
191
hw/rtl/match_engine.sv
Normal file
191
hw/rtl/match_engine.sv
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
`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_NOISE
|
||||||
|
,input logic [(`LANES)*(`HASH_BITS)-1:0] noise_mask_lanes_flat
|
||||||
|
`endif
|
||||||
|
`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];
|
||||||
|
|
||||||
|
`ifdef SIM_NOISE
|
||||||
|
assign effective_hash = row_hash ^ noise_mask_lanes_flat[lane*`HASH_BITS +: `HASH_BITS];
|
||||||
|
`else
|
||||||
|
assign effective_hash = row_hash;
|
||||||
|
`endif
|
||||||
|
|
||||||
|
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
|
||||||
@@ -14,17 +14,20 @@ NUM_ROWS ?= 512
|
|||||||
HASH_BITS ?= 512
|
HASH_BITS ?= 512
|
||||||
LANES ?= 16
|
LANES ?= 16
|
||||||
|
|
||||||
EXTRA_ARGS += -DNUM_ROWS=$(NUM_ROWS) -DHASH_BITS=$(HASH_BITS) -DLANES=$(LANES)
|
EXTRA_ARGS += +define+NUM_ROWS=$(NUM_ROWS) +define+HASH_BITS=$(HASH_BITS) +define+LANES=$(LANES)
|
||||||
|
|
||||||
# cocotb passes PLUSARGS/EXTRA_ARGS differently across simulators. Keep
|
# cocotb passes PLUSARGS/EXTRA_ARGS differently across simulators. Keep
|
||||||
# SystemVerilog parameters explicit through COMPILE_ARGS for Verilator.
|
# SystemVerilog parameters explicit through COMPILE_ARGS for Verilator.
|
||||||
COMPILE_ARGS += -Wall -Wno-fatal
|
COMPILE_ARGS += -Wall -Wno-fatal
|
||||||
|
COMPILE_ARGS += -I$(PWD)/../rtl
|
||||||
COMPILE_ARGS += +define+SIM_DEBUG
|
COMPILE_ARGS += +define+SIM_DEBUG
|
||||||
COMPILE_ARGS += $(EXTRA_DEFINES)
|
COMPILE_ARGS += $(EXTRA_DEFINES)
|
||||||
|
|
||||||
VERILOG_SOURCES += $(PWD)/../rtl/popcount.sv
|
VERILOG_SOURCES += $(PWD)/../rtl/popcount.sv
|
||||||
VERILOG_SOURCES += $(PWD)/../rtl/argmax_update.sv
|
VERILOG_SOURCES += $(PWD)/../rtl/argmax_update.sv
|
||||||
|
|
||||||
VERILOG_SOURCES += $(PWD)/../rtl/cam_core.sv
|
VERILOG_SOURCES += $(PWD)/../rtl/cam_core.sv
|
||||||
|
VERILOG_SOURCES += $(PWD)/../rtl/match_engine.sv
|
||||||
VERILOG_SOURCES += $(PWD)/../rtl/cam_top.sv
|
VERILOG_SOURCES += $(PWD)/../rtl/cam_top.sv
|
||||||
|
|
||||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
include $(shell uv run cocotb-config --makefiles)/Makefile.sim
|
||||||
|
|||||||
Reference in New Issue
Block a user