From d45646342b79cefbc30775b5045e34c1f0d26ad6 Mon Sep 17 00:00:00 2001 From: FallenSigh Date: Wed, 15 Jul 2026 04:13:15 +0800 Subject: [PATCH] test: add board FFT validation and VCD capture --- doc/reports/system/.gitignore | 1 + doc/reports/system/REPORT_RERUN_CHECKLIST.md | 77 ++++++++++++++++-- doc/reports/system/evidence/README.md | 7 +- doc/reports/system/system_design_report.pdf | Bin 3176123 -> 3176117 bytes doc/reports/system/system_design_report.tex | 4 +- doc/reports/system/tools/run_report_tests.sh | 24 +++++- doc/reports/system/tools/run_soc_sim.tcl | 62 +++++++++++++- .../system/tools/update_report_metrics.py | 7 +- sdk/software/examples/fft/main.c | 27 +++++- sdk/software/examples/fft_dma/main.c | 12 ++- 10 files changed, 198 insertions(+), 23 deletions(-) diff --git a/doc/reports/system/.gitignore b/doc/reports/system/.gitignore index 0062456..afc54af 100644 --- a/doc/reports/system/.gitignore +++ b/doc/reports/system/.gitignore @@ -7,3 +7,4 @@ system_design_report.synctex.gz system_design_report.toc system_design_report.xdv tools/__pycache__/ +evidence/**/*.vcd diff --git a/doc/reports/system/REPORT_RERUN_CHECKLIST.md b/doc/reports/system/REPORT_RERUN_CHECKLIST.md index 72d0ac0..2c40503 100644 --- a/doc/reports/system/REPORT_RERUN_CHECKLIST.md +++ b/doc/reports/system/REPORT_RERUN_CHECKLIST.md @@ -42,10 +42,35 @@ cd doc/reports/system ./tools/run_report_tests.sh soc ``` -软件集合固定为 `asm`、`fft`、`fft_dma`、`mlkem_test` 和 `mlkem_hello`。`asm` -需要官方 ExtRAM 测试数据和专用 matmul 流程,因此 `soc` 只编译它,不用通用 -`tb_top` 仿真;其余四项编译后依次运行 SoC 仿真。每次构建都会覆盖 -`sdk/axi_ram.mif`,因此不要并行执行这些用例。构建日志位于 `evidence/build/`。 +需要保存 VCD 时使用可选开关。默认只记录 `tb_top` 的时钟、复位、UART 和提交 PC, +文件写入 `evidence/soc/<用例>.vcd`。记录内部模块时用 `VCD_SCOPE` 指定层次;长时间 +软件测试若递归记录整个 SoC,可能产生数 GB 文件: + +```bash +SAVE_VCD=1 \ +VCD_SCOPE='/tb_top/u_soc_top/u_fft_mlkem_axi_slave/u_mlkem_axi_slave/*' \ +./tools/run_report_tests.sh soc +``` + +启用 VCD 后 elaboration 使用 `debug_level=typical`,并从 0 ns 开始记录,因此包含 +上电复位和复位释放过程。只需要短窗口诊断时可额外设置 `SIM_RUN_TIME=20us`;该选项 +会在软件完成前退出,不能作为功能回归通过证据。VCD 属于大体积临时证据,默认被 +Git 忽略。 + +软件集合固定为 `asm`、`fft`、`fft_dma`、`mlkem_test` 和 `mlkem_hello`。默认 `soc` +会编译全部五项,但只对 `mlkem_test` 和 `mlkem_hello` 运行通用 `tb_top` 仿真。 +`asm` 需要官方 ExtRAM 数据和专用 matmul 流程;`fft` 和 `fft_dma` 包含耗时很长的 +软件 FFT 参考计算,因此默认只做编译检查。每次构建都会覆盖 `sdk/axi_ram.mif`,不要 +并行执行这些用例。构建日志位于 `evidence/build/`。 + +需要更新 FFT 当前提交的功能或性能证据时,再单独执行长仿真: + +```bash +./tools/run_report_tests.sh soc-fft +``` + +没有执行 `soc-fft` 且没有生成当前提交的板级日志时,报告中的 FFT 数值只能标记为 +历史基线,不能声明为当前提交的功能回归结果。 脚本会设置 `CCACHE_DISABLE=1`,避免 Vivado 2019.2 在编译 XSIM 自动生成的 C 文件时 因 ccache 目录不可写而只报告不透明的 `XSIM 43-3409`。 同时会将 `/lib64` 加入 XSIM 子进程库路径,避免旧版 Vivado clang 混用不匹配的 @@ -56,11 +81,51 @@ cd doc/reports/system | 日志 | 必须出现 | 不得出现 | |---|---|---| | `evidence/build/{asm,fft,fft_dma,mlkem_test,mlkem_hello}.log` | 编译、链接和 objcopy 成功 | `Error` | -| `evidence/soc/fft.log` | Hardware/Software FFT Time;更新后的程序应输出 `Max Abs Error` | 仿真超时、X/Z 扩散 | -| `evidence/soc/fft_dma.log` | Hardware/Software FFT Time、`Max Abs Error` | DMA 死锁、仿真超时 | | `evidence/soc/mlkem_test.log` | `MLKEM_RESULT=PASS`、`MLKEM_DONE` | 任一 `FAILS` 非 0 | | `evidence/soc/mlkem_hello.log` | `MLKEM_HELLO_RESULT=PASS`、`MLKEM_HELLO_DONE` | `RESULT=FAIL` | +若执行了可选的 `soc-fft`,再检查: + +| 日志 | 必须出现 | 不得出现 | +|---|---|---| +| `evidence/soc/fft.log` | Hardware/Software FFT Time;更新后的程序应输出 `Max Abs Error` | 仿真超时、X/Z 扩散 | +| `evidence/soc/fft_dma.log` | Hardware/Software FFT Time、`Max Abs Error` | DMA 死锁、仿真超时 | + +### FFT 板级验证(推荐) + +FFT 的软件浮点参考在 RTL 仿真中耗时很长,默认使用板级测试作为当前提交的功能与性能 +证据。使用同一提交生成的 bitstream,分别下载 `fft` 和 `fft_dma` 的程序镜像,在 +115200 baud 下保存完整 UART 输出: + +```text +doc/reports/system/evidence/board/fft.log +doc/reports/system/evidence/board/fft_dma.log +``` + +`fft.log` 必须出现: + +```text +FFT_MAX_ABS_ERROR_RE=<不大于8> +FFT_MAX_ABS_ERROR_IM=<不大于8> +FFT_ERROR_LIMIT=8 +FFT_RESULT=PASS +FFT_DONE +``` + +`fft_dma.log` 必须出现: + +```text +FFT_DMA_MAX_ABS_ERROR_RE=<不大于8> +FFT_DMA_MAX_ABS_ERROR_IM=<不大于8> +FFT_DMA_ERROR_LIMIT=8 +FFT_DMA_RESULT=PASS +FFT_DMA_DONE +``` + +两项日志还必须保留 Hardware/Software FFT Time 和 Speedup Ratio。每项至少冷启动运行 +3 次,确认结果和最大误差稳定;DMA 用例还要确认没有轮询死锁。板级日志存在时, +`update_report_metrics.py` 会优先于 XSIM 日志读取它们。 + ML-KEM 的正确计数是 3 个固定 KAT 向量、900 次执行,不是 360 个不同 KAT。若要在 报告中声称覆盖隐式拒绝,必须另外增加“篡改 ciphertext 后共享密钥不等且流程按规范 完成”的负向测试;当前脚本不提供该证据。 diff --git a/doc/reports/system/evidence/README.md b/doc/reports/system/evidence/README.md index 756b241..e02e416 100644 --- a/doc/reports/system/evidence/README.md +++ b/doc/reports/system/evidence/README.md @@ -5,8 +5,9 @@ Generated logs and Vivado reports used by `system_design_report.tex` live here: - `soc/`: UART output from SoC simulations - `build/`: software build logs for the five selected examples - `vivado/`: timing, utilization, CDC, DRC, route and power reports -- `board/`: official board evaluation output +- `board/`: official matmul evaluation plus FFT/FFT-DMA board UART logs Run `../tools/run_report_tests.sh refresh` after replacing evidence. Large generated -artifacts such as `.wdb`, `.jou`, `.str`, implementation checkpoints and bitstreams do -not belong in this directory. +artifacts such as `.vcd`, `.wdb`, `.jou`, `.str`, implementation checkpoints and +bitstreams do not belong in Git. SoC VCD files may be generated here temporarily with +`SAVE_VCD=1`; archive them separately when they are needed as report evidence. diff --git a/doc/reports/system/system_design_report.pdf b/doc/reports/system/system_design_report.pdf index f77b04027d5f0f23b2507bb65b94c085da705db0..fb8fb71912b29417df7262b94633a7f5257a24c8 100644 GIT binary patch delta 4663 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 delta 4657 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 lQ.vcd. +Set VCD_SCOPE to a Vivado hierarchy glob to limit waveform size. +Set SIM_RUN_TIME only for bounded waveform diagnostics; regressions use 'all'. + Board-only tests (matmul official 5000-group timing and reset behavior) are listed in REPORT_RERUN_CHECKLIST.md and are intentionally not automated here. EOF @@ -95,21 +100,31 @@ build() { run_soc_case() { local example="$1" + local vcd_path="$EVIDENCE_DIR/soc/$example.vcd" require_vivado build_example "$example" - (cd "$ROOT/fpga" && "$VIVADO_BIN" -mode batch \ + if [[ "${SAVE_VCD:-0}" != "0" ]]; then + echo "VCD output: $vcd_path (scope: ${VCD_SCOPE:-top-level control signals})" + fi + (cd "$ROOT/fpga" && SOC_VCD_PATH="$vcd_path" "$VIVADO_BIN" -mode batch \ -source "$SCRIPT_DIR/run_soc_sim.tcl") 2>&1 | tee "$EVIDENCE_DIR/soc/$example.log" } soc() { prepare build_example asm - run_soc_case fft - run_soc_case fft_dma + build_example fft + build_example fft_dma run_soc_case mlkem_test run_soc_case mlkem_hello } +soc_fft() { + prepare + run_soc_case fft + run_soc_case fft_dma +} + implement() { prepare require_vivado @@ -130,6 +145,7 @@ case "${1:-}" in lint) lint ;; build) build ;; soc) soc ;; + soc-fft) soc_fft ;; implement) implement ;; refresh) refresh ;; quick) lint; refresh ;; diff --git a/doc/reports/system/tools/run_soc_sim.tcl b/doc/reports/system/tools/run_soc_sim.tcl index 6b176f9..5561349 100644 --- a/doc/reports/system/tools/run_soc_sim.tcl +++ b/doc/reports/system/tools/run_soc_sim.tcl @@ -5,6 +5,17 @@ set script_dir [file dirname [file normalize [info script]]] set repo_root [file normalize [file join $script_dir ../../../..]] set xpr [file join $repo_root fpga project Loongson_Soc.xpr] +set save_vcd 0 +if {[info exists ::env(SAVE_VCD)]} { + set value [string tolower [string trim $::env(SAVE_VCD)]] + set save_vcd [expr {$value ni {"" "0" "false" "no" "off"}}] +} + +set sim_run_time "all" +if {[info exists ::env(SIM_RUN_TIME)] && $::env(SIM_RUN_TIME) ne ""} { + set sim_run_time $::env(SIM_RUN_TIME) +} + # xelab inherits this when compiling generated C files with the host gcc. set ::env(CCACHE_DISABLE) 1 @@ -31,11 +42,58 @@ set simset [get_filesets sim_1] set_property top tb_top $simset set_property incremental false $simset set_property xsim.elaborate.mt_level off $simset -set_property xsim.elaborate.debug_level off $simset +set_property xsim.elaborate.debug_level [expr {$save_vcd ? "typical" : "off"}] $simset set_property xsim.simulate.log_all_signals false $simset +if {$save_vcd} { + # launch_simulation normally runs 1000 ns before returning. Start at 0 ns + # so the VCD includes power-on reset and reset release. + set_property xsim.simulate.runtime 0ns $simset +} update_compile_order -fileset sim_1 launch_simulation -run all + +if {$save_vcd} { + if {![info exists ::env(SOC_VCD_PATH)] || $::env(SOC_VCD_PATH) eq ""} { + puts stderr "ERROR: SAVE_VCD requires SOC_VCD_PATH" + close_sim + close_project + exit 4 + } + + set vcd_path [file normalize $::env(SOC_VCD_PATH)] + set vcd_patterns [list \ + /tb_top/clk \ + /tb_top/reset \ + /tb_top/UART_TX \ + /tb_top/uart_wen \ + /tb_top/uart_data \ + /tb_top/debug_wb_pc] + if {[info exists ::env(VCD_SCOPE)] && $::env(VCD_SCOPE) ne ""} { + set vcd_patterns [list $::env(VCD_SCOPE)] + set vcd_objects [get_objects -quiet -r {*}$vcd_patterns] + } else { + # Keep the default trace small. Recursive collection is only enabled + # when the caller explicitly supplies VCD_SCOPE. + set vcd_objects [get_objects -quiet {*}$vcd_patterns] + } + if {[llength $vcd_objects] == 0} { + puts stderr "ERROR: VCD scope matched no simulation objects: $vcd_patterns" + close_sim + close_project + exit 5 + } + + file mkdir [file dirname $vcd_path] + puts "Recording VCD: $vcd_path (scope: $vcd_patterns)" + open_vcd $vcd_path + log_vcd $vcd_objects +} + +puts "Running simulation for: $sim_run_time" +run $sim_run_time +if {$save_vcd} { + close_vcd +} close_sim close_project exit 0 diff --git a/doc/reports/system/tools/update_report_metrics.py b/doc/reports/system/tools/update_report_metrics.py index a0a48bc..9e14c8f 100755 --- a/doc/reports/system/tools/update_report_metrics.py +++ b/doc/reports/system/tools/update_report_metrics.py @@ -144,6 +144,7 @@ def update_matmul(metrics: str, log: str) -> str: def main() -> None: metrics = METRICS.read_text(encoding="utf-8") vivado = REPORT_DIR / "evidence" / "vivado" + board = REPORT_DIR / "evidence" / "board" legacy = ROOT / "fpga" / "vivado_reports_nodsp" metrics = update_timing(metrics, read_first(vivado / "timing_summary_full.rpt", legacy / "timing_summary_full.rpt")) metrics = update_util(metrics, read_first(vivado / "utilization.rpt", legacy / "utilization.rpt")) @@ -153,10 +154,10 @@ def main() -> None: metrics = update_mlkem(metrics, read_first(soc / "mlkem_test.log", ROOT / "sdk/software/examples/mlkem_test/result.txt")) metrics = update_fft( metrics, - read_first(soc / "fft.log", ROOT / "sdk/software/examples/fft/result.txt"), - read_first(soc / "fft_dma.log", ROOT / "sdk/software/examples/fft_dma/result.txt"), + read_first(board / "fft.log", soc / "fft.log", ROOT / "sdk/software/examples/fft/result.txt"), + read_first(board / "fft_dma.log", soc / "fft_dma.log", ROOT / "sdk/software/examples/fft_dma/result.txt"), ) - metrics = update_matmul(metrics, read_first(REPORT_DIR / "evidence" / "board" / "matmul_official.log")) + metrics = update_matmul(metrics, read_first(board / "matmul_official.log")) try: revision = subprocess.check_output( diff --git a/sdk/software/examples/fft/main.c b/sdk/software/examples/fft/main.c index 39bf914..519aa88 100644 --- a/sdk/software/examples/fft/main.c +++ b/sdk/software/examples/fft/main.c @@ -15,6 +15,8 @@ unsigned long CORE_CLOCKS_PER_SEC = 33000000L; const float PI = 3.14159265358979323846; +#define FFT_MAX_ABS_ERROR_LIMIT 8 + // 读取定时器的当前Tick unsigned int get_timer_ticks() { return RegRead(CONFREG_TIMER_BASE); @@ -139,14 +141,35 @@ int main(int argc, char** argv) } printf("\n--- Verification (Only showing Bins with energy > 10) ---\n"); + int max_abs_err_re = 0; + int max_abs_err_im = 0; for (int i = 0; i < FFT_POINT_NUM; i++) { + int sw_re = (int)sw_in_re[i] / FFT_POINT_NUM; + int sw_im = (int)sw_in_im[i] / FFT_POINT_NUM; + int err_re = hw_out_re[i] - sw_re; + int err_im = hw_out_im[i] - sw_im; + + if (err_re < 0) err_re = -err_re; + if (err_im < 0) err_im = -err_im; + if (err_re > max_abs_err_re) max_abs_err_re = err_re; + if (err_im > max_abs_err_im) max_abs_err_im = err_im; + if (fabs(hw_out_re[i]) > 10 || fabs(hw_out_im[i]) > 10) { printf("Bin [%4d] Hz: HW(Re:%6d, Im:%6d) | SW(Re:%6d, Im:%6d)\n", i, hw_out_re[i], hw_out_im[i], - (int)sw_in_re[i] / FFT_POINT_NUM, (int)sw_in_im[i] / FFT_POINT_NUM); + sw_re, sw_im); } } - return 0; + int passed = max_abs_err_re <= FFT_MAX_ABS_ERROR_LIMIT && + max_abs_err_im <= FFT_MAX_ABS_ERROR_LIMIT; + printf("Max Abs Error : Re=%d, Im=%d\n", max_abs_err_re, max_abs_err_im); + printf("FFT_MAX_ABS_ERROR_RE=%d\n", max_abs_err_re); + printf("FFT_MAX_ABS_ERROR_IM=%d\n", max_abs_err_im); + printf("FFT_ERROR_LIMIT=%d\n", FFT_MAX_ABS_ERROR_LIMIT); + printf("FFT_RESULT=%s\n", passed ? "PASS" : "FAIL"); + printf("FFT_DONE\n"); + + return passed ? 0 : 1; } diff --git a/sdk/software/examples/fft_dma/main.c b/sdk/software/examples/fft_dma/main.c index dec934f..5d2fcb5 100644 --- a/sdk/software/examples/fft_dma/main.c +++ b/sdk/software/examples/fft_dma/main.c @@ -18,6 +18,8 @@ unsigned long CORE_CLOCKS_PER_SEC = 33000000L; const float PI = 3.14159265358979323846; +#define FFT_MAX_ABS_ERROR_LIMIT 8 + // 软件FFT实现 (基2 DIT-FFT 算法) void sw_fft(float re[], float im[], int n) { int i, j, k, l; @@ -185,5 +187,13 @@ int main(int argc, char** argv) } printf("Max Abs Error : Re=%d, Im=%d\n", max_abs_err_re, max_abs_err_im); - return 0; + int passed = max_abs_err_re <= FFT_MAX_ABS_ERROR_LIMIT && + max_abs_err_im <= FFT_MAX_ABS_ERROR_LIMIT; + printf("FFT_DMA_MAX_ABS_ERROR_RE=%d\n", max_abs_err_re); + printf("FFT_DMA_MAX_ABS_ERROR_IM=%d\n", max_abs_err_im); + printf("FFT_DMA_ERROR_LIMIT=%d\n", FFT_MAX_ABS_ERROR_LIMIT); + printf("FFT_DMA_RESULT=%s\n", passed ? "PASS" : "FAIL"); + printf("FFT_DMA_DONE\n"); + + return passed ? 0 : 1; }