`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