From 706d148a0b3d83ce6b6f83252b5b5ad3b847f45b Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Mon, 18 May 2026 14:30:52 +0800 Subject: [PATCH] feat(hw): add CAM top-level synthesis infrastructure and fix RTL synthesis compatibility - Add hw/syn/Makefile with hier/flat/full synth targets and artifact mirroring - Add synth_cam_top_hier.ys for hierarchy-preserving resource estimation on Xilinx 7-series - Add synth_cam_top_flat.ys for flattened Xilinx 7-series synthesis - Add cam-synth just target for convenient invocation - Guard runtime assertions (NUM_ROWS/LANES checks, noise seed checks, NOISE_BITS checks) behind SYNTHESIS guard in cam_core_banked, cam_read_noise, cam_write_noise, and noise_mask_grouped - Fix shadowed 'return' variable in random128 xorshift128 function --- .justfile | 4 ++ hw/rtl/core/cam_core_banked.sv | 4 ++ hw/rtl/noise/cam_read_noise.sv | 2 + hw/rtl/noise/cam_write_noise.sv | 2 + hw/rtl/noise/noise_mask_grouped.sv | 2 + hw/rtl/random/random128.sv | 2 +- hw/syn/Makefile | 76 ++++++++++++++++++++++++++++++ hw/syn/synth_cam_top_flat.ys | 38 +++++++++++++++ hw/syn/synth_cam_top_hier.ys | 40 ++++++++++++++++ 9 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 hw/syn/Makefile create mode 100644 hw/syn/synth_cam_top_flat.ys create mode 100644 hw/syn/synth_cam_top_hier.ys diff --git a/.justfile b/.justfile index 3b37c56..d1cde93 100644 --- a/.justfile +++ b/.justfile @@ -65,6 +65,10 @@ cam-test-full: cam-test-top: just remote "make -C hw/sim clean && make -C hw/sim test-top" +# Run full-scale CAM Yosys synthesis and resource reporting +cam-synth: + make -C hw/syn synth + # Run Python reference model tests cam-test-py: make -C hw/sim test-model diff --git a/hw/rtl/core/cam_core_banked.sv b/hw/rtl/core/cam_core_banked.sv index 077a1a6..9d1c7f6 100644 --- a/hw/rtl/core/cam_core_banked.sv +++ b/hw/rtl/core/cam_core_banked.sv @@ -24,9 +24,11 @@ module cam_core_banked ( assign wr_ready = 1'b1; + `ifndef SYNTHESIS initial begin if (`NUM_ROWS % `LANES != 0) $fatal(1, "NUM_ROWS must be divisible by LANES"); end + `endif always_ff @(posedge clk) begin if (wr_valid) begin @@ -44,9 +46,11 @@ module cam_core_banked ( rd_valid_o <= rd_valid_i; rd_lane_valid_o <= rd_valid_i ? {`LANES{1'b1}} : '0; + `ifndef SYNTHESIS if (rd_valid_i && ((rd_base_row_i % `LANES) != 0)) begin $fatal(1, "rd_base_row_i must be LANES-aligned"); end + `endif for (int lane = 0; lane < `LANES; lane++) begin rd_row_ids_o[lane*`ROW_BITS +: `ROW_BITS] <= rd_base_row_i + lane[(`ROW_BITS)-1:0]; diff --git a/hw/rtl/noise/cam_read_noise.sv b/hw/rtl/noise/cam_read_noise.sv index bf6da56..8eb9ac1 100644 --- a/hw/rtl/noise/cam_read_noise.sv +++ b/hw/rtl/noise/cam_read_noise.sv @@ -27,9 +27,11 @@ module cam_read_noise #( logic [127:0] random_num [0:`LANES-1]; logic [(`HASH_BITS)-1:0] mask [0:`LANES-1]; + `ifndef SYNTHESIS initial begin if (READ_NOISE_SEED == 64'd0) $fatal(1, "READ_NOISE_SEED must be nonzero"); end + `endif generate for (genvar lane = 0; lane < `LANES; lane++) begin : gen_lane_noise diff --git a/hw/rtl/noise/cam_write_noise.sv b/hw/rtl/noise/cam_write_noise.sv index e4e405e..7897539 100644 --- a/hw/rtl/noise/cam_write_noise.sv +++ b/hw/rtl/noise/cam_write_noise.sv @@ -44,9 +44,11 @@ module cam_write_noise #( .mask_o (flip_mask) ); + `ifndef SYNTHESIS initial begin if (WRITE_NOISE_SEED == 64'd0) $fatal(1, "WRITE_NOISE_SEED must be nonzero"); end + `endif always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin diff --git a/hw/rtl/noise/noise_mask_grouped.sv b/hw/rtl/noise/noise_mask_grouped.sv index efc246d..159fdb6 100644 --- a/hw/rtl/noise/noise_mask_grouped.sv +++ b/hw/rtl/noise/noise_mask_grouped.sv @@ -17,6 +17,7 @@ module noise_mask_grouped #( localparam int SAMPLE_RANGE = 1 << SAMPLE_BITS; localparam int THRESHOLD = (NOISE_RATE_NUM * SAMPLE_RANGE) / NOISE_RATE_DEN; + `ifndef SYNTHESIS initial begin if (NOISE_BITS <= 0) $fatal(1, "NOISE_BITS must be > 0"); if (HASH_BITS % NOISE_BITS != 0) $fatal(1, "HASH_BITS must be divisible by NOISE_BITS"); @@ -25,6 +26,7 @@ module noise_mask_grouped #( if (NOISE_RATE_DEN <= 0) $fatal(1, "NOISE_RATE_DEN must be > 0"); if (NOISE_RATE_NUM < 0 || NOISE_RATE_NUM > NOISE_RATE_DEN) $fatal(1, "NOISE_RATE_NUM out of range"); end + `endif always_comb begin mask_o = '0; diff --git a/hw/rtl/random/random128.sv b/hw/rtl/random/random128.sv index 12e02c9..637eb3f 100644 --- a/hw/rtl/random/random128.sv +++ b/hw/rtl/random/random128.sv @@ -42,7 +42,7 @@ module random128 ( next_z = w; next_w = w ^ (w >> 19) ^ t ^ (t >> 8); - return {next_x, next_y, next_z, next_w}; + xorshift128 = {next_x, next_y, next_z, next_w}; end endfunction diff --git a/hw/syn/Makefile b/hw/syn/Makefile new file mode 100644 index 0000000..3122f4e --- /dev/null +++ b/hw/syn/Makefile @@ -0,0 +1,76 @@ +#=============================================================================== +# CAM Top Synthesis Makefile +# Targets: synth, hier, flat, clean +# Usage: +# make -C hw/syn synth (defaults, output in build/) +# make -C hw/syn synth OUT_DIR=/some/path (mirror artifacts) +# make -C hw/syn synth NUM_ROWS=8192 (override parameter) +# make -C hw/syn hier (hierarchy-only pass) +# make -C hw/syn flat (flattened-synthesis pass) +# make -C hw/syn clean (remove build/) +#=============================================================================== + +# ── Configurable variables (defaults) ───────────────────────────────────────── +YOSYS ?= yosys +TOP ?= cam_top +NUM_ROWS ?= 4096 +HASH_BITS ?= 512 +LANES ?= 8 +OUT_DIR ?= build + +# ── TOP enforcement (only cam_top is supported) ─────────────────────────────── +ifneq ($(TOP),cam_top) +$(error error: only TOP=cam_top is supported) +endif + +# ── Internal build directory ────────────────────────────────────────────────── +BUILD_DIR := build + +# ── Fixed script and artifact names ─────────────────────────────────────────── +HIER_SCRIPT := synth_cam_top_hier.ys +FLAT_SCRIPT := synth_cam_top_flat.ys + +HIER_LOG := yosys_hier.log +FLAT_LOG := yosys_flat.log +HIER_JSON := cam_top_hier_resources.json +FLAT_JSON := cam_top_flat_resources.json +SYNTH_V := cam_top_synth.v + +ARTIFACTS := $(HIER_JSON) $(FLAT_JSON) $(SYNTH_V) $(HIER_LOG) $(FLAT_LOG) + +# ── Yosys command-line defines (always passed) ──────────────────────────────── +# cam_params.svh uses `ifndef guards, so -D on the Yosys CLI overrides defaults. +# Use -D NAME=value syntax (Yosys 0.62); do NOT use -define. +YOSYS_DEFINES := -D NUM_ROWS=$(NUM_ROWS) -D HASH_BITS=$(HASH_BITS) -D LANES=$(LANES) + +# ── Targets ─────────────────────────────────────────────────────────────────── +.PHONY: synth hier flat clean + +# ── Hierarchy resource reference pass ───────────────────────────────────────── +hier: + mkdir -p $(BUILD_DIR) + $(YOSYS) $(YOSYS_DEFINES) -l $(BUILD_DIR)/$(HIER_LOG) -s $(HIER_SCRIPT) + +# ── Flattened Xilinx synthesis pass ─────────────────────────────────────────── +flat: + mkdir -p $(BUILD_DIR) + $(YOSYS) $(YOSYS_DEFINES) -l $(BUILD_DIR)/$(FLAT_LOG) -s $(FLAT_SCRIPT) + +# ── Full synthesis: hier + flat, then mirror artifacts to OUT_DIR if different ─ +synth: hier flat + @if [ "$(abspath $(OUT_DIR))" != "$(abspath $(BUILD_DIR))" ]; then \ + set -e; \ + echo "Mirroring artifacts to $(OUT_DIR) ..."; \ + mkdir -p "$(OUT_DIR)"; \ + for f in $(ARTIFACTS); do \ + if [ ! -f "$(BUILD_DIR)/$$f" ]; then \ + echo "error: missing artifact $(BUILD_DIR)/$$f" >&2; \ + exit 1; \ + fi; \ + cp "$(BUILD_DIR)/$$f" "$(OUT_DIR)/$$f"; \ + done; \ + fi + +# ── Clean ───────────────────────────────────────────────────────────────────── +clean: + rm -rf $(BUILD_DIR) diff --git a/hw/syn/synth_cam_top_flat.ys b/hw/syn/synth_cam_top_flat.ys new file mode 100644 index 0000000..5cf1136 --- /dev/null +++ b/hw/syn/synth_cam_top_flat.ys @@ -0,0 +1,38 @@ +# synth_cam_top_flat.ys — Flattened CAM top synthesis for Xilinx Zynq-7020 / 7-series +# Run from hw/syn: yosys -s synth_cam_top_flat.ys + +# Set include directories before reading RTL +verilog_defaults -push +verilog_defaults -add -I../rtl +verilog_defaults -add -I../rtl/core +verilog_defaults -add -I../rtl/noise +verilog_defaults -add -I../rtl/random + +# Read RTL sources in canonical order +read_verilog -sv -D SYNTHESIS ../rtl/random/random128.sv +read_verilog -sv -D SYNTHESIS ../rtl/noise/noise_mask_grouped.sv +read_verilog -sv -D SYNTHESIS ../rtl/noise/cam_write_noise.sv +read_verilog -sv -D SYNTHESIS ../rtl/noise/cam_read_noise.sv +read_verilog -sv -D SYNTHESIS ../rtl/core/cam_core_banked.sv +read_verilog -sv -D SYNTHESIS ../rtl/core/popcount_pipeline.sv +read_verilog -sv -D SYNTHESIS ../rtl/core/match_engine_pipeline.sv +read_verilog -sv -D SYNTHESIS ../rtl/cam_noisy.sv +read_verilog -sv -D SYNTHESIS ../rtl/cam_top.sv + +# Restore verilog defaults +verilog_defaults -pop + +# Flattened Xilinx synthesis (includes proc, opt, fsm, memory, etc.) +synth_xilinx -family xc7 -top cam_top -flatten + +# Ensure build directory exists for output files +exec -- mkdir -p build + +# Write flattened Verilog netlist +write_verilog -attr2comment build/cam_top_synth.v + +# Resource statistics (JSON to file via tee, not mixed into logs) +tee -q -o build/cam_top_flat_resources.json stat -tech xilinx -json + +# Final checks +check -noinit diff --git a/hw/syn/synth_cam_top_hier.ys b/hw/syn/synth_cam_top_hier.ys new file mode 100644 index 0000000..bac2ccc --- /dev/null +++ b/hw/syn/synth_cam_top_hier.ys @@ -0,0 +1,40 @@ +# synth_cam_top_hier.ys — Hierarchy-preserving CAM top resource reference flow +# Run from hw/syn: yosys -s synth_cam_top_hier.ys + +# Set include directories before reading RTL +verilog_defaults -push +verilog_defaults -add -I../rtl +verilog_defaults -add -I../rtl/core +verilog_defaults -add -I../rtl/noise +verilog_defaults -add -I../rtl/random + +# Read RTL sources in canonical order +read_verilog -sv -D SYNTHESIS ../rtl/random/random128.sv +read_verilog -sv -D SYNTHESIS ../rtl/noise/noise_mask_grouped.sv +read_verilog -sv -D SYNTHESIS ../rtl/noise/cam_write_noise.sv +read_verilog -sv -D SYNTHESIS ../rtl/noise/cam_read_noise.sv +read_verilog -sv -D SYNTHESIS ../rtl/core/cam_core_banked.sv +read_verilog -sv -D SYNTHESIS ../rtl/core/popcount_pipeline.sv +read_verilog -sv -D SYNTHESIS ../rtl/core/match_engine_pipeline.sv +read_verilog -sv -D SYNTHESIS ../rtl/cam_noisy.sv +read_verilog -sv -D SYNTHESIS ../rtl/cam_top.sv + +# Restore verilog defaults +verilog_defaults -pop + +# Hierarchy check and elaboration +hierarchy -top cam_top -check + +# Process and optimize +proc +opt +memory -nomap + +# Ensure build directory exists for output files +exec -- mkdir -p build + +# Resource statistics (JSON to file via tee, not mixed into logs) +tee -q -o build/cam_top_hier_resources.json stat -tech xilinx -json + +# Final checks +check -noinit