add design report and timing analysis report

This commit is contained in:
2026-06-30 02:49:40 +08:00
parent faf15ee113
commit b7eb59fb5b
2 changed files with 427 additions and 0 deletions

101
docs/timing_analysis.md Normal file
View File

@@ -0,0 +1,101 @@
# 50 MHz 时序收敛分析与修复方案
> 报告来源:`synth_timing.tcl`OOC 综合 `mlkem_top`,器件 `xc7a200tfbg676-1`
> `sysclk` 20 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。
**两个叠加的放大因素:**
1. **串联两次 Barrett 模乘**(t2 → t2·zeta)挤在一个组合周期。
2. **`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 上约 ~1012 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 拉成 45 级;
- 或对乘法做 **基-4/基-8 部分积 + 进位保存加法器(CSA)树**,减少 CARRY4 链深度。
改动大,仅在 3 级流水实测仍 > 20 ns 时再考虑。
## 四、建议路线(不用 DSP
1.`barrett_mul` 改成 3 级流水版(带 clk/valid),单独综合确认单级 < 20 ns。
2. 重构 `basecase_mul`:c0 路径两级 Barrett 级联(6 拍),c1 对齐;`poly_mul_sync` 节拍
按固定流水深度调整(CALC 等 N 拍再出 c0/c1)。
3. 全量 KAT 复测(`run_tb.sh top/enc/dec` + `hello`)确认功能不变 —— 流水加深会改变
`poly_mul`/`ntt`/`comp_decomp` 的拍数,各 FSM 的 done/valid 判定需同步更新。
4. 重综合看 WNS;若 comp_decomp 成新瓶颈,同法流水化。
5. 迭代直到 WNS ≥ 0 @ 20 ns。
> 注意:本项目所有时序验证目前靠 XSIM 功能仿真 + KAT,**没有跑过布局布线后时序**。
> 加流水属于改时序行为的大改,务必每步重跑全部 KAT,确保 ek/dk/ss/ct 仍逐字节正确。
## 五、复现命令
```bash
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 占用)
```