mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
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
This commit is contained in:
@@ -65,6 +65,10 @@ cam-test-full:
|
|||||||
cam-test-top:
|
cam-test-top:
|
||||||
just remote "make -C hw/sim clean && make -C hw/sim 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
|
# Run Python reference model tests
|
||||||
cam-test-py:
|
cam-test-py:
|
||||||
make -C hw/sim test-model
|
make -C hw/sim test-model
|
||||||
|
|||||||
@@ -24,9 +24,11 @@ module cam_core_banked (
|
|||||||
|
|
||||||
assign wr_ready = 1'b1;
|
assign wr_ready = 1'b1;
|
||||||
|
|
||||||
|
`ifndef SYNTHESIS
|
||||||
initial begin
|
initial begin
|
||||||
if (`NUM_ROWS % `LANES != 0) $fatal(1, "NUM_ROWS must be divisible by LANES");
|
if (`NUM_ROWS % `LANES != 0) $fatal(1, "NUM_ROWS must be divisible by LANES");
|
||||||
end
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
if (wr_valid) begin
|
if (wr_valid) begin
|
||||||
@@ -44,9 +46,11 @@ module cam_core_banked (
|
|||||||
rd_valid_o <= rd_valid_i;
|
rd_valid_o <= rd_valid_i;
|
||||||
rd_lane_valid_o <= rd_valid_i ? {`LANES{1'b1}} : '0;
|
rd_lane_valid_o <= rd_valid_i ? {`LANES{1'b1}} : '0;
|
||||||
|
|
||||||
|
`ifndef SYNTHESIS
|
||||||
if (rd_valid_i && ((rd_base_row_i % `LANES) != 0)) begin
|
if (rd_valid_i && ((rd_base_row_i % `LANES) != 0)) begin
|
||||||
$fatal(1, "rd_base_row_i must be LANES-aligned");
|
$fatal(1, "rd_base_row_i must be LANES-aligned");
|
||||||
end
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
for (int lane = 0; lane < `LANES; lane++) begin
|
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];
|
rd_row_ids_o[lane*`ROW_BITS +: `ROW_BITS] <= rd_base_row_i + lane[(`ROW_BITS)-1:0];
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ module cam_read_noise #(
|
|||||||
logic [127:0] random_num [0:`LANES-1];
|
logic [127:0] random_num [0:`LANES-1];
|
||||||
logic [(`HASH_BITS)-1:0] mask [0:`LANES-1];
|
logic [(`HASH_BITS)-1:0] mask [0:`LANES-1];
|
||||||
|
|
||||||
|
`ifndef SYNTHESIS
|
||||||
initial begin
|
initial begin
|
||||||
if (READ_NOISE_SEED == 64'd0) $fatal(1, "READ_NOISE_SEED must be nonzero");
|
if (READ_NOISE_SEED == 64'd0) $fatal(1, "READ_NOISE_SEED must be nonzero");
|
||||||
end
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
generate
|
generate
|
||||||
for (genvar lane = 0; lane < `LANES; lane++) begin : gen_lane_noise
|
for (genvar lane = 0; lane < `LANES; lane++) begin : gen_lane_noise
|
||||||
|
|||||||
@@ -44,9 +44,11 @@ module cam_write_noise #(
|
|||||||
.mask_o (flip_mask)
|
.mask_o (flip_mask)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
`ifndef SYNTHESIS
|
||||||
initial begin
|
initial begin
|
||||||
if (WRITE_NOISE_SEED == 64'd0) $fatal(1, "WRITE_NOISE_SEED must be nonzero");
|
if (WRITE_NOISE_SEED == 64'd0) $fatal(1, "WRITE_NOISE_SEED must be nonzero");
|
||||||
end
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
always_ff @(posedge clk or negedge rst_n) begin
|
always_ff @(posedge clk or negedge rst_n) begin
|
||||||
if (!rst_n) begin
|
if (!rst_n) begin
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ module noise_mask_grouped #(
|
|||||||
localparam int SAMPLE_RANGE = 1 << SAMPLE_BITS;
|
localparam int SAMPLE_RANGE = 1 << SAMPLE_BITS;
|
||||||
localparam int THRESHOLD = (NOISE_RATE_NUM * SAMPLE_RANGE) / NOISE_RATE_DEN;
|
localparam int THRESHOLD = (NOISE_RATE_NUM * SAMPLE_RANGE) / NOISE_RATE_DEN;
|
||||||
|
|
||||||
|
`ifndef SYNTHESIS
|
||||||
initial begin
|
initial begin
|
||||||
if (NOISE_BITS <= 0) $fatal(1, "NOISE_BITS must be > 0");
|
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");
|
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_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");
|
if (NOISE_RATE_NUM < 0 || NOISE_RATE_NUM > NOISE_RATE_DEN) $fatal(1, "NOISE_RATE_NUM out of range");
|
||||||
end
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
mask_o = '0;
|
mask_o = '0;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ module random128 (
|
|||||||
next_z = w;
|
next_z = w;
|
||||||
next_w = w ^ (w >> 19) ^ t ^ (t >> 8);
|
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
|
end
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|||||||
76
hw/syn/Makefile
Normal file
76
hw/syn/Makefile
Normal file
@@ -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)
|
||||||
38
hw/syn/synth_cam_top_flat.ys
Normal file
38
hw/syn/synth_cam_top_flat.ys
Normal file
@@ -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
|
||||||
40
hw/syn/synth_cam_top_hier.ys
Normal file
40
hw/syn/synth_cam_top_hier.ys
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user