第4章 Verilog RTL可综合性基础与可验证设计

问题背景

在数字前端流程中,RTL 是仿真验证与逻辑综合的共同输入。验证工程师如果只关心“仿真能过”,而忽略“可综合”这一硬约束,最终代码可能无法映射到真实芯片。本章以可综合性为主线,讲解可综合 RTL 的核心子集、仿真与综合的语义差异,以及可验证设计(DFV)对代码结构的要求。

核心概念

  • 可综合(Synthesizable):RTL 代码能够被综合工具完整映射为标准单元库中的组合逻辑、触发器和存储器。
  • 不可综合(Non-synthesizable):只用于仿真建模的语言构造,如 initial、#delay、fork/join、force/release 等。
  • 可验证设计(DFV):在 RTL 中预留可观测信号、断言、覆盖率点和调试接口,确保设计能被高效验证。

可综合是仿真正确性的物理下限,可验证是工程交付效率的保障。二者共同约束 RTL 编码风格。

可综合RTL设计验证链路 RTL编码 可综合子集 Lint检查 可综合性审查 行为仿真 DFV设计 逻辑综合 网表映射 门级验证 时序收敛

原理机制

仿真器和综合工具对同一段 RTL 的解释路径不同。

  • 仿真语义:基于事件队列推进时间,reg 是变量容器,initial、forever、#delay 都能被完整执行。
  • 综合语义:只处理可综合子集,把 always/assign 等结构映射到逻辑门;initial、#delay 等没有硬件对应,直接忽略或报错。
  • 推断规则:电平敏感列表推断组合逻辑,时钟沿敏感列表推断触发器;阻塞/非阻塞赋值影响仿真与综合匹配。

流程步骤:可综合RTL的验证链路

  1. RTL编码:使用 assign、always、实例化和参数化设计,遵守可综合子集。
  2. 静态检查:用 lint、CDC、可综合性检查工具在仿真前拦截不可综合语法。
  3. 行为仿真:验证 RTL 功能,同时插入断言与覆盖率点(DFV)。
  4. 逻辑综合:映射门级网表,检查面积、时序、功耗和约束是否满足。
  5. 门级验证:综合后仿真与 STA,确保门级行为与 RTL 一致。
DFV提醒:验证工程师应在RTL阶段加入关键信号观测点、断言和覆盖率点,不必担心这些结构干扰综合;通常可在综合时关闭或约束为非扫描对象。

案例说明:从“仿真能过”到“可综合”

一段“仿真正常但不可综合”的RTL风格:把时钟生成放进了RTL模块。

// 不可综合:把时钟与延迟写在RTL中
reg clk;
initial begin
  clk = 1'b0;
  forever #10 clk = ~clk;
end

always @(posedge clk) begin
  // 期望的时序逻辑
end

综合工具会报告 initial、forever、#delay 不被支持。修正思路:时钟属于仿真激励,应放入 testbench;RTL 只编写时钟域内的逻辑。

// testbench:生成时钟
initial clk = 1'b0;
always #10 clk = ~clk;

// RTL:可综合时序逻辑
always @(posedge clk or negedge rst_n) begin
  if (!rst_n)
    q <= 1'b0;
  else
    q <= d;
end
工程习惯:testbench 可以使用任意仿真建模手段;RTL 必须遵守可综合子集。把时钟、复位、延迟建模放在 testbench,把可综合逻辑留给 RTL。

表格总结:可综合、不可综合与仿真专用结构

类别 典型结构 用途 能否综合
可综合RTL assign、always、reg、wire、parameter、generate、function/task(可综合子集) 描述实际硬件逻辑 是
不可综合 initial、forever、#delay、fork/join、force/release、defparam 仅仿真激励与行为建模 否
仿真专用 $display、$monitor、$finish、assertion、interface、DPI-C、UVM对象 验证环境、检查与覆盖率 否(验证代码不综合)

误区提醒

  • “仿真通过 = 可以综合”:错误。initial、#10 可以仿真通过,但综合器直接报错。
  • “reg 就是寄存器”:错误。组合逻辑 always 块中的 reg 只是变量建模,综合后是 wire 网络。
  • “可综合 = 时序收敛”:错误。逻辑可综合只是第一步,时序约束与门级验证缺失仍会导致芯片失败。
  • “验证代码也要可综合”:错误。testbench、UVM、断言是仿真与形式验证代码,不需要综合。

实践清单

  1. 编码前:列出项目可综合子集约束并同步到全组。
  2. 编码中:组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值。
  3. 编码中:禁止在可综合模块中出现 initial、#delay、fork/join、force。
  4. 验证前:用 lint 做可综合性扫描。
  5. DFV:在RTL中增加关键信号观测点、断言与覆盖率点。
  6. 仿真:RTL行为仿真通过后,及时做综合后仿真,确认门级行为一致。
  7. 评审:每次代码评审把“可综合性”和“可验证性”作为必查项。