chore(enc): merge run_enc.sh into run_tb.sh; TB dumps hardware ct

run_tb.sh gains an 'enc' module that shares the 'top' KeyGen tcl compile
list (same RTL datapath) and swaps in tb_mlkem_enc_katK_xsim. Usage mirrors
'top': ./run_tb.sh enc [K] [CASE]; no args -> full sweep K=2/3/4 cases 0..2.
--list shows enc; per-case summary lines parse PASS (E7). run_enc.sh deleted.

tb_mlkem_enc_katK_xsim verify_e7 now dumps the hardware-produced ct (read
from ct_bram via the dbg_ct tap) on one line (byte 0 first), same format as
ml-kem-r's encaps_io example, so ss/ct can be eyeballed and diffed. On
mismatch it re-scans to print the first 8 differing byte positions.

Verified: ./run_tb.sh enc -> 9/9 PASS (E7) (ct==KAT.ct && ss==KAT.ss);
./run_tb.sh top 3 0 KeyGen unregressed.
This commit is contained in:
2026-06-29 12:32:29 +08:00
parent 7228bebb78
commit 4091fd0676
4 changed files with 92 additions and 54 deletions

View File

@@ -7,11 +7,16 @@
# ./run_tb.sh top 2 # only K=2 (ML-KEM-512), all its cases
# ./run_tb.sh top 2 3 # only K=2, only CASE=3
# ./run_tb.sh top 4 0 # only K=4 (ML-KEM-1024), CASE=0
# ./run_tb.sh enc # ML-KEM Encaps: all K, all cases (0..2)
# ./run_tb.sh enc 2 # Encaps K=2, all its cases
# ./run_tb.sh enc 4 1 # Encaps K=4, only CASE=1
# ./run_tb.sh --list
#
# For the 'top' module, K (2/3/4) and CASE select a single KAT run so you can
# iterate quickly instead of elaborating 3 snapshots and running all 11 cases.
# Other modules ignore the extra args and run their xsim_run.tcl verbatim.
# 'top' (KeyGen) and 'enc' (Encaps) share the same RTL datapath; both compile
# the xvlog lines from sync_rtl/top/TB/xsim_run.tcl. They differ only in the
# testbench: top -> tb_mlkem_kg_katK_xsim, enc -> tb_mlkem_enc_katK_xsim.
# For these two, K (2/3/4) and CASE select a single KAT run so you can iterate
# quickly. Other modules ignore the extra args and run their xsim_run.tcl verbatim.
#
# Prerequisites:
# Vivado 2019.2 at /opt/Xilinx/Vivado/2019.2/
@@ -29,6 +34,7 @@ if [ "$1" = "--list" ]; then
echo " $name"
fi
done
echo " enc (ML-KEM Encaps; shares the 'top' RTL/tcl, enc testbench)"
exit 0
fi
@@ -39,9 +45,15 @@ if [ -z "$1" ]; then
fi
MODULE="$1"
SEL_K="$2" # optional: 2/3/4 (top module only)
SEL_CASE="$3" # optional: KAT case index (top module only)
TB_DIR="$SCRIPT_DIR/sync_rtl/$MODULE/TB"
SEL_K="$2" # optional: 2/3/4 (top/enc modules only)
SEL_CASE="$3" # optional: KAT case index (top/enc modules only)
# 'enc' is not its own RTL dir; it reuses the 'top' KeyGen tcl compile list
# (same datapath) and swaps in the encaps testbench.
if [ "$MODULE" = "enc" ]; then
TB_DIR="$SCRIPT_DIR/sync_rtl/top/TB"
else
TB_DIR="$SCRIPT_DIR/sync_rtl/$MODULE/TB"
fi
TCL_FILE="$TB_DIR/xsim_run.tcl"
if [ ! -f "$TCL_FILE" ]; then
@@ -129,9 +141,61 @@ run_top_selected() {
return $fail
}
# ML-KEM Encaps runner. Compiles the 'top' tcl xvlog lines (KeyGen datapath =
# Encaps datapath) MINUS the KeyGen TB, plus the encaps TB, then elaborates the
# requested K and runs the requested CASE(s). Mirrors run_top_selected.
run_enc_selected() {
local tcl_file="$1" ksel="$2" csel="$3"
set +e
rm -rf xsim.dir .Xil
# Compile every xvlog line from the tcl EXCEPT the KeyGen TB (the encaps TB
# replaces it). The tcl already includes pipeline_reg + comp_decomp_sync.
while read -r cmd; do
[[ "$cmd" == *tb_mlkem_kg_katK* ]] && continue
eval "$cmd" || { echo "COMPILE FAILED: $cmd"; return 1; }
done < <(grep -E '^xvlog ' "$tcl_file")
echo " xvlog -sv --relax sync_rtl/top/TB/tb_mlkem_enc_katK_xsim.v"
xvlog -sv --relax sync_rtl/top/TB/tb_mlkem_enc_katK_xsim.v \
|| { echo "ENC TB COMPILE FAILED"; return 1; }
# K to run: requested one, or all of 2/3/4.
local ks; if [ -n "$ksel" ]; then ks="$ksel"; else ks="2 3 4"; fi
local fail=0
for k in $ks; do
echo " xelab tb_mlkem_enc_katK_xsim -generic_top KP=$k -s mlkem_enc_k$k --timescale 1ns/1ps"
xelab tb_mlkem_enc_katK_xsim -generic_top KP=$k -s mlkem_enc_k$k --timescale 1ns/1ps \
|| { echo "ELAB FAILED for K=$k"; fail=1; continue; }
# Encaps KAT cases per K: 0..2 (vectors enc_k{K}_c{0,1,2}_*).
local cases="0 1 2"
if [ -n "$csel" ]; then cases="$csel"; fi
for c in $cases; do
local log="/tmp/run_tb_enc_k${k}_c${c}.log"
echo " xsim mlkem_enc_k$k -R -testplusarg CASE=$c"
echo "========================================" | tee "$log"
xsim "mlkem_enc_k$k" -R -testplusarg "CASE=$c" 2>&1 | tee -a "$log"
echo "========================================" | tee -a "$log"
local pf nf
pf=$(grep -oE 'PASS \(E7\)|FAIL \(E7\)' "$log" | tail -1)
nf=$(grep -c 'cannot be opened' "$log")
echo " K=$k CASE=$c -> ${pf:-NORESULT} (file-not-found=$nf, log: $log)"
{ [ "$pf" = "PASS (E7)" ] && [ "$nf" -eq 0 ]; } || fail=1
done
done
return $fail
}
if [ "$MODULE" = "enc" ]; then
run_enc_selected "$TCL_FILE" "$SEL_K" "$SEL_CASE"
exit $?
fi
if [ "$MODULE" = "top" ] && [ -n "$SEL_K" ]; then
run_top_selected "$TCL_FILE" "$SEL_K" "$SEL_CASE"
exit $?
fi
execute_tcl "$TCL_FILE"
execute_tcl "$TCL_FILE"