5.2 KiB
50 MHz 时序收敛分析与修复方案
报告来源:
synth_timing.tcl(OOC 综合mlkem_top,器件xc7a200tfbg676-1,sysclk20 ns / 50 MHz)。生成timing.rpt/timing_worst.rpt/util.rpt。
一、现状
| 指标 | 值 |
|---|---|
| WNS | -32.206 ns(目标 20 ns,实际关键路径 ~52 ns) |
| TNS | -37879 ns,失败端点 3132 / 44689 |
| Hold (WHS) | +0.134 ns ✅(无 hold 违例) |
| 关键路径 | u_pmul/mem_A_reg[239][2] → u_pmul/c0_reg_reg[0] |
| 路径延迟 | 52.055 ns(逻辑 21.9 ns / 布线 30.1 ns),70 逻辑级(CARRY4×26 + LUT×43 + MUXF×3) |
| 面积 | LUT 25.5%、FF 8.6%、BRAM ~5 片、DSP 0 / 740(完全没用) |
之前那份 timing.rpt(WNS -17.7 ns,关键路径在 comp_decomp 的组合除法器)已经过时——
717a992 用 Barrett 乘法替换了组合除法器,comp_decomp 不再是瓶颈。本次重新综合后,
瓶颈转移到 poly_mul 的 basecase 乘法器 u_pmul。
二、根因
basecase_mul(NTT 域 degree-1 乘法)单周期组合计算 c0/c1:
c0 = (a0·b0 + (a1·b1)·zeta) mod Q
c1 = (a0·b1 + a1·b0) mod Q
c0 这条路径串联了两级 Barrett 模乘:先 t2 = a1·b1 mod Q,再 t2_zeta = t2·zeta mod Q,
最后再做一次模加。每级 barrett_mul 含 12×12 乘 + ×K 乘 + ×Q 移位加 + 两次条件减,
而且全局带 (* use_dsp = "no" *) —— 所有乘法都摊成 LUT+CARRY4 阵列。两级串联 ⇒ 70 级、52 ns。
两个叠加的放大因素:
- 串联两次 Barrett 模乘(t2 → t2·zeta)挤在一个组合周期。
use_dsp="no"把每个乘法变成进位链,本可用的 740 个 DSP48 一个没用。
注:此前给乘法器加
use_dsp="no"多半是为了规避 XSIM 仿真问题;但综合时这逼着工具 用 LUT 搭乘法,正是当前 52 ns 关键路径的主因。
三、修复方案(约束:不允许使用 DSP,纯 LUT/CARRY4 流水化)
实测细节(timing_worst.rpt 逐级):一个
barrett_mul单独就要 ~24 ns (t2 = a1·b1 走到 ~28 ns,其中乘法本体 + ×K + ×Q 约简占大头),c0 又把 两个 Barrett 串联(t2 → t2·zeta)+ 模加 ⇒ 52 ns。 关键结论:单级 Barrett(~24 ns)本身就超 20 ns,所以光在两次乘法之间插一拍 (26 ns/级)不够,必须在barrett_mul内部也切流水。
推荐方案:三段式流水的 Barrett 模乘 + basecase 重构
把 a·b mod Q 拆成 3 个寄存级,每级 < ~12 ns:
级1: p = a * b (12×12 → 24b 乘法,纯 LUT/CARRY4) → 寄存 p
级2: qe = (p * K) >> 24 (24×13 乘法 + 移位) → 寄存 qe、p
级3: r = p - qe*Q; 两次条件减 Q → 寄存 product
- 单个乘法(12×12 或 24×13)在 LUT 上约 ~10–12 ns,加约简一拍单独走,各级都能压到 20 ns 内。
barrett_mul从纯组合改成 3 拍流水(加clk/valid端口或用上层节拍计数)。
basecase 的 c0 双乘串联(a1·b1 再 ·zeta)= 两个 3 级流水级联 = 6 拍;
c1 只有单乘 = 3 拍。让两条对齐到 6 拍输出。poly_mul_sync 现有
S_COMP_CALC → S_COMP_C0 → S_COMP_C1 节拍改为:CALC 阶段等待乘法流水排空(固定 N 拍),
再依次输出 c0/c1。吞吐:逐点乘本就 1 系数/多拍,加深流水只增加固定启动延迟(~6 拍/128 次
basecase = 几百拍),相对 KeyGen ~22.9k、Decaps ~50.8k 周期可忽略。
同源风险:comp_decomp 的 Barrett
comp_decomp_sync 也用同样的 Barrett 结构(compress 路径 dividend*5039>>24 + ×Q 约简),
单条也可能逼近 20 ns。修好 basecase 后若它冒头,同样按“Barrett 内部 3 级流水”处理。
其 5-phase 微序列(cd_valid 脉冲 + ph 等待)很容易吸收额外流水拍。
备选:更激进的乘法器结构(若 3 级仍不够)
- 12×12 乘法本身用 2 级流水(部分积分两半累加),把 Barrett 拉成 4–5 级;
- 或对乘法做 基-4/基-8 部分积 + 进位保存加法器(CSA)树,减少 CARRY4 链深度。 改动大,仅在 3 级流水实测仍 > 20 ns 时再考虑。
四、建议路线(不用 DSP)
- 把
barrett_mul改成 3 级流水版(带 clk/valid),单独综合确认单级 < 20 ns。 - 重构
basecase_mul:c0 路径两级 Barrett 级联(6 拍),c1 对齐;poly_mul_sync节拍 按固定流水深度调整(CALC 等 N 拍再出 c0/c1)。 - 全量 KAT 复测(
run_tb.sh top/enc/dec+hello)确认功能不变 —— 流水加深会改变poly_mul/ntt/comp_decomp的拍数,各 FSM 的 done/valid 判定需同步更新。 - 重综合看 WNS;若 comp_decomp 成新瓶颈,同法流水化。
- 迭代直到 WNS ≥ 0 @ 20 ns。
注意:本项目所有时序验证目前靠 XSIM 功能仿真 + KAT,没有跑过布局布线后时序。 加流水属于改时序行为的大改,务必每步重跑全部 KAT,确保 ek/dk/ss/ct 仍逐字节正确。
五、复现命令
source /opt/Xilinx/Vivado/2019.2/settings64.sh
export LD_PRELOAD=/usr/lib64/libtinfo.so.5
vivado -mode batch -source synth_timing.tcl # 器件在脚本里:xc7a200tfbg676-1
# 读 timing.rpt(摘要) / timing_worst.rpt(逐路径) / util.rpt(面积、DSP 占用)