3. Jasper CDC/RDC环境搭建

CDC/RDC 形式验证的成败,往往在环境搭建阶段就已经决定了一半。Jasper 工具本身并不复杂,真正容易出问题的是:文件列表是否完整、编译选项是否与设计意图一致、时钟复位约束是否准确描述了真实硬件行为。本节围绕一个可复现的最小工程,把目录结构、文件列表、编译选项、约束文件和命令流串成一条完整链路。

一、工程目录结构:让约束与设计分离

推荐采用“设计源文件只读、验证环境独立”的目录组织方式。设计文件通过文件列表引用,不复制进验证目录,避免设计与验证版本漂移。一个典型结构如下:

cdc_project/
├── rtl/                     # 设计源文件(只读引用)
│   ├── top.sv
│   ├── clk_gen.v
│   └── sync_ff.sv
├── filelist/
│   ├── design.f             # 设计文件列表
│   └── include.f            # 宏与 include 路径
├── constraints/
│   ├── clocks.sdc           # 时钟定义
│   ├── resets.sdc           # 复位定义
│   └── cdc_waiver.tcl       # 豁免与例外
├── scripts/
│   ├── compile.tcl          # 编译脚本
│   └── run_cdc.tcl          # 运行与报告脚本
└── reports/                 # 输出报告目录

把 clocks.sdc 与 resets.sdc 分开维护,是因为时钟约束决定 CDC 分析中“哪些域之间存在跨域”,而复位约束决定 RDC 分析中“哪些复位之间存在异步释放风险”,两者的检查目标和调试路径完全不同,混在一个文件里后期维护成本很高。

二、文件列表:顺序、宏与 include 路径

文件列表使用 -f 方式传入。需要注意三点:第一,包(package)文件必须排在引用它的模块之前;第二,宏定义与 include 路径建议单独放在 include.f 中,通过 -I 与 +define+ 传入;第三,避免使用通配符一次性抓取整个目录,否则新增的测试文件可能被误编译进设计。

# design.f
+incdir+../rtl/include
../rtl/pkg/cdc_pkg.sv
../rtl/top.sv
../rtl/clk_gen.v
../rtl/sync_ff.sv

# include.f
+define+SYNTHESIS
+define+CDC_CHECK

如果设计中存在 ifdef 分支,务必确认编译时使用的宏与综合时一致。CDC 检查的是实际综合出来的电路结构,若仿真宏与综合宏不同,可能出现“工具认为存在跨域、实际硬件不存在”的假阳性,或更危险的假阴性。

三、编译选项:把工具行为固定下来

Jasper 的编译阶段通过 analyze 与 elaborate 完成。建议把选项写入脚本,而不是每次手工输入。关键选项包括:

  • -sv:按 SystemVerilog 解析,避免把 SV 语法当 Verilog 处理。
  • -f filelist/design.f:传入设计文件列表。
  • -define / +define+:传入宏定义。
  • -top top:明确顶层模块,避免工具自动推断错误。
  • -allow_unsupported:仅在确认不影响 CDC 结构时使用,否则可能掩盖真实问题。
# compile.tcl
analyze -sv -f ../filelist/design.f -f ../filelist/include.f
elaborate -top top

编译完成后,先用 get_design_info 或 report_design 确认模块层次、端口数量和实例数是否符合预期。如果实例数明显偏少,通常是文件列表漏文件或宏导致模块被裁剪。

四、时钟与复位约束:CDC/RDC 的判据来源

时钟约束的核心是 create_clock,需要给出周期、名称和源对象。对于 CDC 分析,时钟之间的频率关系并不直接决定是否跨域,真正决定的是“是否来自同一个时钟源、是否存在确定的相位关系”。因此,除了周期,还要用 create_generated_clock 描述分频、倍频和门控时钟。

# clocks.sdc
create_clock -name clk_a -period 10 [get_ports clk_a]
create_clock -name clk_b -period 6.667 [get_ports clk_b]
create_generated_clock -name clk_div2 -source [get_ports clk_a] \
    -divide_by 2 [get_pins u_div/Q]

复位约束需要区分同步复位与异步复位。RDC 关注的是异步复位释放时的亚稳态风险,因此必须用 create_reset 或等效约束标明复位类型、有效电平和复位源。若复位经过同步器释放,应在约束中体现同步级数,否则工具会把已同步的复位路径误判为异步跨域。

# resets.sdc
create_reset -name rst_n -sense low [get_ports rst_n]
create_reset -name rst_sync -sense low -sync [get_pins u_sync/Q]
约束文件中的对象名必须与 elaborate 后的层次名完全一致。建议先用 get_ports *、get_pins * 列出实际对象,再写约束,避免因名称拼写错误导致约束静默失效。

五、工具启动与基本命令流

Jasper 的典型启动方式是在工程目录下执行 jaspergold 或 jg,然后通过 -tcl 加载脚本。一个完整的 CDC 检查命令流如下:

# run_cdc.tcl
analyze -sv -f ../filelist/design.f -f ../filelist/include.f
elaborate -top top
read_sdc ../constraints/clocks.sdc
read_sdc ../constraints/resets.sdc
clock -rate -all
reset -all
check_cdc -all
report_cdc -summary -file ../reports/cdc_summary.rpt
report_cdc -detail -file ../reports/cdc_detail.rpt

命令流的关键顺序是:先 analyze 再 elaborate,先读约束再执行 clock / reset 检查,最后才跑 check_cdc。如果顺序颠倒,工具会在没有时钟定义的情况下分析,结果要么为空,要么全是未约束告警。

运行结束后,先看 cdc_summary.rpt 中的跨域总数、已同步数、未同步数和豁免数。若未同步数不为零,再打开 cdc_detail.rpt 定位具体路径。对于确认安全的路径,通过 cdc_waiver.tcl 添加豁免,并在豁免中写明原因和责任人,避免后续版本把真实问题一起豁免掉。

Jasper CDC/RDC 环境搭建与命令流 设计输入 rtl/*.sv filelist/design.f include.f(宏/路径) 约束输入 clocks.sdc resets.sdc cdc_waiver.tcl 编译阶段 analyze -sv -f ... elaborate -top top 确认层次/实例数 约束加载 read_sdc clocks.sdc read_sdc resets.sdc clock -rate -all CDC 检查 check_cdc -all 跨域/同步器识别 未同步路径告警 RDC 检查 reset -all 异步复位释放路径 同步级数校验 报告与判定 cdc_summary.rpt:跨域总数 / 已同步 / 未同步 / 豁免 cdc_detail.rpt:逐条路径定位 未同步数 > 0 → 定位并修复或填写豁免理由 命令顺序要点 1. analyze → elaborate 2. read_sdc → clock/reset 3. check_cdc → report

六、常见搭建问题与排查顺序

环境搭建阶段最常见的四类问题及排查顺序如下:

现象可能原因排查动作
elaborate 报顶层找不到文件列表漏文件或 -top 名称错误检查 design.f 与顶层模块名
跨域数为 0时钟约束未生效或对象名不匹配用 get_ports/get_pins 核对对象名
大量未同步告警同步器未被识别或约束缺失检查同步器结构是否符合工具识别模板
复位路径误报复位同步级数未在约束中体现补充 create_reset -sync 约束
不要用 -allow_unsupported 或大范围豁免来“消除”告警。CDC/RDC 的告警数量本身不是目标,目标是每一条跨域路径都有明确的同步机制或书面豁免理由。环境搭建阶段留下的模糊约束,会在后期版本迭代中变成难以定位的假阴性。

把上述目录、文件列表、编译选项、约束文件和命令流固化成脚本后,每次版本更新只需替换 rtl/ 与文件列表,其余流程可一键复现。这样 CDC/RDC 检查才能真正成为回归流程的一部分,而不是每次手工重搭的临时任务。