RTL代码综合与网表分析实战 - 第1节
一、综合概述:什么是逻辑综合
大家好,我是老李。做数字IC设计十几年了,今天咱们聊聊综合这件事。
逻辑综合,说白了就是把你的RTL代码翻译成门级网表。你写的是always块、assign语句,综合工具把它变成与门、或门、触发器这些东西。嗯,就这么简单。
我记得刚入行那会儿,有个老工程师跟我说:「小李啊,你写的代码最终是要变成硅片的,不是让你在纸上画着玩的。」当时不太理解,后来做了几个项目才明白——综合就是连接你写的代码和实际芯片的那座桥。
核心定义:逻辑综合是将RTL(寄存器传输级)描述转换为门级网表的过程,同时满足时序、面积、功耗等约束条件。
综合在数字IC设计流程中的位置
整个数字IC设计流程,我习惯把它分成三个阶段:前端设计、综合实现、后端物理设计。综合正好卡在中间,承上启下。
你想想看,前端你写好了RTL代码,做了功能仿真,验证了逻辑正确性。但这时候的代码还是「软」的,没法直接拿去流片。综合就是把这个「软」的东西变「硬」的第一步。
典型设计流程中的综合位置
这张图是我自己画的,你看综合的位置,前面连着RTL和仿真,后面接着门级仿真和STA。综合做得好不好,直接决定了后端能不能顺利跑下去。
个人经验:我建议你在综合之前,先把RTL代码的仿真覆盖率做到95%以上。不然综合出来的网表出了问题,你都不知道是代码写错了还是综合工具没用好。
综合的输入与输出
综合的输入,说白了就三样东西:RTL代码、工艺库、约束文件。缺一不可。
输入一:RTL代码
就是你写的Verilog或VHDL。这里有个坑——不是所有能仿真的代码都能综合。我曾经见过一个同事,写了满屏的#10延时,仿真跑得欢,一综合就报错。嗯,综合工具只认可综合的语法。
输入二:工艺库
工艺库是foundry提供的,里面包含了标准单元的各种信息:
- 每个门的延迟参数
- 面积信息
- 功耗数据
- 驱动能力
说白了,工艺库就是综合工具的「零件手册」。没有它,工具不知道用什么元件来搭你的电路。
输入三:约束文件
约束文件告诉综合工具你的设计目标是什么。最常见的约束包括:
- 时钟频率(比如你要跑200MHz还是500MHz)
- 输入输出延迟
- 面积上限
- 功耗预算
注意:约束文件不是随便写写的。我曾经接手过一个项目,前工程师把时钟约束设得太松,综合出来的网表时序一塌糊涂,后端怎么修都修不回来。最后只能重新综合,浪费了两周时间。
综合的输出
综合完,你会得到这些东西:
| 输出文件 | 说明 | 后缀名举例 |
|---|---|---|
| 门级网表 | 由标准单元组成的电路连接描述 | .v, .vg |
| 时序报告 | 各路径的建立时间、保持时间检查结果 | .rpt |
| 面积报告 | 综合后的芯片面积统计 | .area.rpt |
| 功耗报告 | 动态功耗和静态功耗估算 | .power.rpt |
| SDC约束文件 | 综合后的时序约束,供后端使用 | .sdc |
这里我要多说一句:网表文件是综合最核心的输出。它长什么样呢?给你看个例子:
// 综合后的网表示例
module counter (clk, rst_n, en, count);
input clk, rst_n, en;
output [3:0] count;
wire n1, n2, n3;
wire [3:0] count_int;
DFFRQ_X1 count_reg_0_ (.D(n1), .CK(clk), .RN(rst_n), .Q(count[0]));
DFFRQ_X1 count_reg_1_ (.D(n2), .CK(clk), .RN(rst_n), .Q(count[1]));
DFFRQ_X1 count_reg_2_ (.D(n3), .CK(clk), .RN(rst_n), .Q(count[2]));
DFFRQ_X1 count_reg_3_ (.D(count_int[3]), .CK(clk), .RN(rst_n), .Q(count[3]));
// ... 组合逻辑部分省略
endmodule
你看,原来你写的always块,现在变成了具体的DFFRQ_X1触发器。X1表示驱动能力等级,这是工艺库里定义好的。
关键点:综合输出的网表是「工艺相关」的。同样的RTL代码,用不同的工艺库综合,出来的网表完全不一样。所以换工艺节点时,一定要重新综合。
综合的本质是什么
说了这么多,综合的本质其实就是一件事:映射。把行为级的描述映射到结构级的实现。
你写了一个加法器:
assign sum = a + b;
综合工具会去工艺库里找,看看有没有现成的加法器单元。如果有,直接例化。如果没有,就用全加器和半加器搭一个。这个过程,工具会自动完成。
但我得提醒你,工具不是万能的。你写的代码风格直接影响综合结果。比如:
- 组合逻辑写得太深,时序容易出问题
- if-else写得不完整,会综合出锁存器
- case语句没写default,也会出锁存器
避坑指南:我曾经因为一个case语句漏了default,综合出来一堆锁存器,面积大了30%。从那以后,我写case必带default,写if-else必带else。这个习惯救了我很多次。
好了,关于综合的概述就聊到这儿。记住一句话:综合是连接你写的代码和实际芯片的桥梁。桥搭得好不好,直接决定了你的芯片能不能跑起来。