(3)如何判断设计的好坏

一、脚本整体作用

这份脚本用于使用 Synopsys Design Compiler 对顶层设计 my_top 进行逻辑综合。

整体流程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
设置设计名和运行目录

设置标准单元库和综合库

读取 RTL

展开顶层设计

链接设计和库

综合前检查

写出 precompile 文件

创建时钟约束

执行 compile_ultra 综合

写出综合后文件

修正命名并输出 mapped 网表

综合后检查

输出设计、面积、功耗、时钟、时序、QoR 报告

二、初始化设置

原脚本:

1
2
3
4
5
6
7
8
9
10
11
#------------------------------
#set initials
set DESIGN_NAME my_top
set TAG ${DESIGN_NAME}_syn_basicrun
set CORE_NUM 16

set_host_options -max_cores $CORE_NUM
define_design_lib WORK -path ./WORK

set RESULTS_DIR ./results/${TAG}
if {![file exists $RESULTS_DIR]} {file mkdir $RESULTS_DIR} ;

1. 设置顶层设计名

1
set DESIGN_NAME my_top

表示当前要综合的顶层模块名是:

1
my_top

这个名字需要和 RTL 文件里的顶层模块名保持一致。

例如 RTL 中应该有:

1
2
3
module my_top (...);
...
endmodule

2. 设置运行标签

1
set TAG ${DESIGN_NAME}_syn_basicrun

TAG 用来区分不同综合实验的输出目录。

这里最终结果目录类似:

1
./results/my_top_syn_basicrun

以后如果要区分不同实验,可以改成:

1
2
3
set TAG ${DESIGN_NAME}_syn_timing_opt
set TAG ${DESIGN_NAME}_syn_area_opt
set TAG ${DESIGN_NAME}_syn_lowpower

3. 设置 CPU 核数

1
2
set CORE_NUM 16
set_host_options -max_cores $CORE_NUM

表示 DC 最多使用 16 个 CPU 核心进行综合。

这样可以提高综合速度。


4. 定义 WORK 设计库

1
define_design_lib WORK -path ./WORK

WORK 是 DC 用来保存中间设计数据的工作库。

可以理解为:

1
WORK = DC 保存 analyze / elaborate 中间结果的地方

5. 创建结果目录

1
2
set RESULTS_DIR ./results/${TAG}
if {![file exists $RESULTS_DIR]} {file mkdir $RESULTS_DIR} ;

作用是:

  1. 设置结果目录路径;
  2. 如果目录不存在,就自动创建。

最终各种 .rpt.v.ddc 文件都会输出到这个目录。


三、库文件路径设置

原脚本:

1
2
3
4
5
6
7
#-----------------------------
#set library path

set_app_var search_path "$search_path ../../library/std/NLDM"
set_app_var target_library "svt_ssg_0p72v_m40c.db"
set_app_var synthetic_library "standard.sldb dw_foundation.sldb"
set_app_var link_path "* $target_library $synthetic_library";

1. 设置搜索路径

1
set_app_var search_path "$search_path ../../library/std/NLDM"

search_path 用来告诉 DC 去哪里找文件。

这里把下面这个目录加入搜索路径:

1
../../library/std/NLDM

这个目录通常用于存放 .db 标准单元库文件。


2. 设置目标标准单元库

1
set_app_var target_library "svt_ssg_0p72v_m40c.db"

target_library 是综合最终映射到的真实标准单元库。

例如 RTL 中写:

1
assign y = a & b;

综合后可能变成:

1
2
3
4
5
AND2_X1 U1 (
.A(a),
.B(b),
.Y(y)
);

这里的 AND2_X1 就来自 target_library


3. 设置综合库

1
set_app_var synthetic_library "standard.sldb dw_foundation.sldb"

synthetic_library 是 DC 用于优化高级运算结构的库。

例如:

1
2
assign sum = a + b;
assign product = a * b;

DC 可能会先把它识别成:

  • 加法器
  • 乘法器
  • 比较器
  • 移位器

然后借助 standard.sldbdw_foundation.sldb 做优化。

其中:

作用
standard.sldb DC 基础综合库
dw_foundation.sldb DesignWare 基础库,包含加法器、乘法器、比较器等高级组件

4. 设置链接路径

1
set_app_var link_path "* $target_library $synthetic_library";

link_path 用于告诉 DC 在链接设计时去哪里找模块和库单元。

其中:

1
*

表示当前 DC 内存中已经读入的设计。

所以这句话可以理解为:

1
link 时,既要查找当前读入的 RTL 设计,也要查找 target_library 和 synthetic_library。

四、读取、展开和链接 RTL

原脚本:

1
2
3
4
5
6
7
8
#-----------------------------
#elaborate and analyze
analyze -f sverilog -vcs "./sources/${DESIGN_NAME}.sv"
elaborate ${DESIGN_NAME}
current_design ${DESIGN_NAME}
if {[link]==0} {
echo "\[USR-INFO\] Link Error!"
}

1. analyze

1
analyze -f sverilog -vcs "./sources/${DESIGN_NAME}.sv"

作用是读取并分析 RTL 文件。

因为:

1
set DESIGN_NAME my_top

所以实际读取的是:

1
./sources/my_top.sv

参数说明:

参数 作用
analyze 读入 HDL 源码
-f sverilog 指定文件格式为 SystemVerilog
-vcs 使用更接近 VCS 的语法兼容方式解析
"./sources/${DESIGN_NAME}.sv" RTL 文件路径

2. elaborate

1
elaborate ${DESIGN_NAME}

作用是展开顶层设计。

例如 RTL 中:

1
2
3
4
module my_top (...);
sub_module u1 (...);
sub_module u2 (...);
endmodule

elaborate my_top 之后,DC 会建立完整层次结构:

1
2
3
my_top
├── u1
└── u2

简单理解:

1
2
analyze   = 读代码
elaborate = 展开设计结构

3. current_design

1
current_design ${DESIGN_NAME}

指定当前正在操作的设计是:

1
my_top

后面的命令,例如:

1
2
3
4
link
check_design
compile_ultra
report_timing

都会默认作用在当前设计上。


1
2
3
if {[link]==0} {
echo "\[USR-INFO\] Link Error!"
}

link 的作用是检查并连接设计中的所有引用。

它会检查:

  • 子模块是否能找到
  • 库单元是否能找到
  • DesignWare 模块是否能找到
  • 顶层和子模块连接是否能解析
  • link_path 设置是否完整

如果找不到某个模块,可能会报:

1
Unable to resolve reference

这通常说明:

  • 子模块文件没有读入;
  • search_path 设置不对;
  • link_path 缺少库;
  • 模块名写错。

五、综合前检查和保存中间文件

原脚本:

1
2
3
4
5
6
#----------------------------
#pre compile
check_design -nosplit > ${RESULTS_DIR}/check_design.precompile.rpt

write_file -hierarchy -format ddc -output ${RESULTS_DIR}/${DESIGN_NAME}.precompile.ddc
write_file -hierarchy -format verilog -output ${RESULTS_DIR}/${DESIGN_NAME}.precompile.v

1. 综合前 check_design

1
check_design -nosplit > ${RESULTS_DIR}/check_design.precompile.rpt

作用是检查综合前的设计结构是否健康。

主要检查:

  • 是否有未连接端口;
  • 是否有未驱动信号;
  • 是否有多驱动信号;
  • 是否有组合环路;
  • 是否有 unresolved reference;
  • 是否有不合理的层次结构;
  • 是否有不完整的设计单元。

-nosplit 表示报告长行不拆开,方便查看和 grep 搜索。

输出文件:

1
check_design.precompile.rpt

表示综合前设计检查报告。


2. 输出 precompile 文件

1
2
write_file -hierarchy -format ddc -output ${RESULTS_DIR}/${DESIGN_NAME}.precompile.ddc
write_file -hierarchy -format verilog -output ${RESULTS_DIR}/${DESIGN_NAME}.precompile.v

这两条命令用于保存综合前状态。

文件 作用
.precompile.ddc DC 内部格式文件
.precompile.v 综合前展开后的 Verilog 文件

注意:

1
precompile.v 还不是最终门级网表。

它只是 RTL 被 DC 展开后的中间结果。


六、添加时钟约束

原脚本:

1
2
3
4
5
6
7
#-----------------------------
#add constraint
create_clock -period 1.0 [get_ports clk]
create_clock -period 1.2 [get_ports clk1]
create_clock -period 1.2 [get_ports clk2]
create_clock -period 1.2 [get_ports clk3]
create_clock -period 1.2 [get_ports clk4]

1. 创建主时钟

1
create_clock -period 1.0 [get_ports clk]

表示给端口 clk 创建一个周期为 1.0 ns 的时钟。

换算频率:

1
1 / 1.0 ns = 1 GHz

2. 创建其他时钟

1
2
3
4
create_clock -period 1.2 [get_ports clk1]
create_clock -period 1.2 [get_ports clk2]
create_clock -period 1.2 [get_ports clk3]
create_clock -period 1.2 [get_ports clk4]

表示 clk1clk2clk3clk4 的周期都是 1.2 ns。

换算频率约为:

1
1 / 1.2 ns ≈ 833.33 MHz

3. 多时钟设计注意点

脚本中只是创建了多个时钟,但还没有说明时钟之间的关系。

如果这些时钟是完全异步的,应该加:

1
2
3
4
5
6
set_clock_groups -asynchronous \
-group [get_clocks clk] \
-group [get_clocks clk1] \
-group [get_clocks clk2] \
-group [get_clocks clk3] \
-group [get_clocks clk4]

否则 DC 可能会默认它们之间存在时序关系,分析一些不该分析的跨时钟路径。

如果 clk1clk4 是由 clk 分频或倍频得到的,则不能简单设为异步,应该使用:

1
create_generated_clock

七、执行综合

原脚本:

1
2
3
#-----------------------------
#compile
compile_ultra

compile_ultra 的作用

1
compile_ultra

compile_ultra 是 DC 中常用的高强度综合优化命令。

它会根据当前约束进行综合,主要包括:

  • 将 RTL 映射成标准单元;
  • 优化组合逻辑;
  • 优化寄存器附近路径;
  • 尽量满足时序;
  • 尽量减少面积;
  • 调用 DesignWare 优化高级运算;
  • 可能进行层次打散和跨层次优化。

简单理解:

1
compile_ultra = 逻辑综合 + 优化 + 映射标准单元

八、综合后输出文件

原脚本:

1
2
3
4
5
6
7
#-----------------------------
#post compile
write_file -format verilog -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.postcompile.v
write_file -format ddc -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.postcompile.ddc
change_names -rules verilog -hierarchy
write_file -format verilog -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.mapped.v
write_file -format ddc -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.mapped.ddc

1. 输出 postcompile 文件

1
2
write_file -format verilog -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.postcompile.v
write_file -format ddc -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.postcompile.ddc

这时设计已经经过 compile_ultra 综合。

输出文件:

文件 说明
.postcompile.v 综合后的 Verilog 文件
.postcompile.ddc 综合后的 DC 内部格式文件

2. 修正规范命名

1
change_names -rules verilog -hierarchy

综合后的网表中可能出现反斜杠、特殊字符等名称。

例如:

1
\abc[0]

这类名字虽然 DC 能识别,但有些后端工具或仿真工具处理起来不方便。

change_names 的作用是:

1
把设计中的名字转换成更标准的 Verilog 命名格式。

3. 输出 mapped 文件

1
2
write_file -format verilog -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.mapped.v
write_file -format ddc -hierarchy -output ${RESULTS_DIR}/${DESIGN_NAME}.mapped.ddc

输出最终门级网表和 DDC 文件。

其中:

1
mapped.v

通常就是交给后端 APR 工具使用的门级网表。


九、综合后设计检查

原脚本:

1
check_design -nosplit > ${RESULTS_DIR}/check_design.mapped.rpt

这次 check_design 是在综合后执行的。

它主要检查综合后的 mapped netlist 是否健康,例如:

  • 标准单元实例是否完整;
  • 有没有未连接网络;
  • 有没有多驱动网络;
  • 端口连接是否合理;
  • change_names 后名字是否合法;
  • 最终网表是否适合后端读入。

综合前后两次 check_design 区别

阶段 文件 检查对象 重点
综合前 check_design.precompile.rpt RTL 展开后的设计 RTL 结构有没有问题
综合后 check_design.mapped.rpt mapped 门级网表 最终网表有没有问题

一句话记忆:

1
第一次检查 RTL,第二次检查网表。

十、设计相关报告

原脚本:

1
2
3
4
5
6
7
8
#-----------------------------
#report
#help report*

#design
report_design -nosplit > ${RESULTS_DIR}/design.rpt
report_hierarchy -full -noleaf -nosplit > ${RESULTS_DIR}/hier.rpt
report_resources -hierarchy > ${RESULTS_DIR}/resources.rpt

1. report_design

1
report_design -nosplit > ${RESULTS_DIR}/design.rpt

作用是报告当前设计的基本信息。

通常包括:

  • 当前设计名;
  • 设计属性;
  • 是否被综合;
  • 使用的库;
  • 设计状态信息。

输出文件:

1
design.rpt

2. report_hierarchy

1
report_hierarchy -full -noleaf -nosplit > ${RESULTS_DIR}/hier.rpt

作用是报告设计层次结构。

参数说明:

参数 作用
-full 输出完整层次信息
-noleaf 不显示 leaf cell,只显示模块层次
-nosplit 长行不拆分

输出文件:

1
hier.rpt

通过这个报告可以看到:

1
2
3
4
my_top
├── sub_module_0
├── sub_module_1
└── sub_module_2

如果综合后层次被 ungroup 打散,也可以在这个报告中观察到。


3. report_resources

1
report_resources -hierarchy > ${RESULTS_DIR}/resources.rpt

作用是报告综合中使用的资源。

常见资源包括:

  • 加法器;
  • 乘法器;
  • 比较器;
  • MUX;
  • DesignWare 组件;
  • 寄存器;
  • 存储结构。

输出文件:

1
resources.rpt

这个报告可以帮助你判断:

1
RTL 中的加法、乘法、比较等结构有没有被 DC 正确识别。

十一、面积报告

原脚本:

1
2
#area
report_area -hier -nosplit > ${RESULTS_DIR}/area.rpt

report_area

1
report_area -hier -nosplit > ${RESULTS_DIR}/area.rpt

作用是输出面积报告。

参数说明:

参数 作用
-hier 按层次显示面积
-nosplit 长行不拆分

输出文件:

1
area.rpt

面积报告通常会包含:

  • combinational area;
  • noncombinational area;
  • buffer / inverter area;
  • total cell area;
  • 各模块层次面积占比。

通过 area.rpt 可以判断哪个模块面积最大,后续可以针对性优化。


十二、功耗报告

原脚本:

1
2
3
4
5
#power
reset_switching_activity
report_power -hier -nosplit > ${RESULTS_DIR}/power.default.rpt
set_switching_activity -toggle_rate 0.25 [remove_from_collection [all_inputs ] [get_ports clk*]]
report_power -hier -nosplit > ${RESULTS_DIR}/power.0p25intoggle.rpt

1. 清除已有 switching activity

1
reset_switching_activity

作用是清除之前设置过的翻转活动信息。

例如清除通过以下方式导入或设置的活动信息:

1
2
3
set_switching_activity
read_vcd
read_saif

2. 输出默认功耗报告

1
report_power -hier -nosplit > ${RESULTS_DIR}/power.default.rpt

作用是在默认 switching activity 条件下输出功耗报告。

输出文件:

1
power.default.rpt

这份报告可以理解为:

1
没有额外指定输入翻转率时,工具默认估算出来的功耗。

3. 设置非时钟输入翻转率

1
set_switching_activity -toggle_rate 0.25  [remove_from_collection [all_inputs ] [get_ports clk*]]

这句表示:

给所有非时钟输入端口设置 toggle rate = 0.25。

拆开理解:

1
[all_inputs]

表示所有输入端口。

1
[get_ports clk*]

表示所有名字以 clk 开头的端口。

1
[remove_from_collection [all_inputs] [get_ports clk*]]

表示:

1
所有输入端口 - 时钟端口

也就是给数据输入、控制输入设置翻转率,而不设置时钟端口。


4. 输出 0.25 输入翻转率下的功耗报告

1
report_power -hier -nosplit > ${RESULTS_DIR}/power.0p25intoggle.rpt

输出文件:

1
power.0p25intoggle.rpt

这份报告表示:

1
假设非时钟输入 toggle_rate = 0.25 时的功耗估计。

5. 两份功耗报告的区别

报告 条件 用途
power.default.rpt 默认活动率 看工具默认估算功耗
power.0p25intoggle.rpt 非时钟输入 toggle rate = 0.25 看输入翻转对功耗的影响

一般来说,设置输入翻转后,dynamic power 可能会变大。


十三、Design Compiler 对象查询说明

原脚本注释:

1
2
3
4
5
6
#design compiler objects
#help get*: get_pins, get_cells, get_ports ... input name, but output collection
#get_cells my*
#get_ports rst*
#get_pins */CDN
#help *collection*

1. DC 中常见对象

DC 中很多命令的操作对象都是 collection。

常见对象包括:

命令 获取对象
get_ports 获取端口
get_pins 获取 pin
get_cells 获取 cell 或 instance
get_nets 获取 net
get_clocks 获取 clock
get_designs 获取 design

2. 示例

1
get_cells my*

获取名字以 my 开头的 cell 或 instance。

1
get_ports rst*

获取名字以 rst 开头的端口。

1
get_pins */CDN

获取所有层次下名为 CDN 的 pin。


3. collection 是什么

collection 可以理解为 DC 中的一组对象集合。

例如:

1
[get_ports clk*]

返回的不是普通字符串,而是一个端口对象集合。

所以很多 DC 命令中会看到:

1
2
3
remove_from_collection
add_to_collection
foreach_in_collection

十四、时钟报告

原脚本:

1
2
3
#clock
report_clock -attributes -nosplit > ${RESULTS_DIR}/clock.rpt
report_clock_gating -nosplit > ${RESULTS_DIR}/clock_gating.rpt

1. report_clock

1
report_clock -attributes -nosplit > ${RESULTS_DIR}/clock.rpt

作用是报告当前设计中的时钟信息。

通常包括:

  • 时钟名称;
  • 时钟周期;
  • 时钟端口;
  • 波形;
  • 时钟属性;
  • 是否为 generated clock。

输出文件:

1
clock.rpt

这个报告可以检查:

1
create_clock 有没有生效。

2. report_clock_gating

1
report_clock_gating -nosplit > ${RESULTS_DIR}/clock_gating.rpt

作用是报告 clock gating 相关信息。

如果设计或综合中使用了 ICG / clock gating cell,可以通过它查看:

  • clock gating 结构;
  • clock gating cell;
  • enable 信号;
  • gating 检查信息。

输出文件:

1
clock_gating.rpt

如果没有启用 clock gating,这个报告可能比较少或为空。


十五、时序和约束报告

原脚本:

1
2
3
#timing
report_constraints -all_violators -nosplit > ${RESULTS_DIR}/all_violators.rpt
report_timing -max_paths 100 -input_pins -capacitance -net -transition_time -nosplit > ${RESULTS_DIR}/timing.rpt

1. report_constraints

1
report_constraints -all_violators -nosplit > ${RESULTS_DIR}/all_violators.rpt

作用是报告所有违反约束的路径或对象。

重点看:

  • setup violation;
  • hold violation;
  • max transition violation;
  • max capacitance violation;
  • max fanout violation;
  • design rule violation。

输出文件:

1
all_violators.rpt

这个报告可以快速判断:

1
综合后设计还有哪些约束没有满足。

2. report_timing

1
report_timing -max_paths 100 -input_pins -capacitance -net -transition_time -nosplit > ${RESULTS_DIR}/timing.rpt

作用是输出详细时序路径报告。

参数说明:

参数 作用
-max_paths 100 最多输出 100 条关键路径
-input_pins 显示 cell 输入 pin 信息
-capacitance 显示电容信息
-net 显示 net 延迟信息
-transition_time 显示转换时间
-nosplit 长行不拆分

输出文件:

1
timing.rpt

时序报告中重点看:

  • startpoint;
  • endpoint;
  • path group;
  • data arrival time;
  • data required time;
  • slack;
  • 哪些 cell / net 延迟最大。

3. slack 怎么看

时序报告中通常会看到:

1
slack (MET)      0.05

或者:

1
slack (VIOLATED) -0.03

含义:

slack 含义
正数 时序满足,还有余量
0 刚好满足,几乎没有余量
负数 时序违例,需要优化

十六、QoR 报告

原脚本:

1
2
#qor
report_qor > ${RESULTS_DIR}/qor.rpt

report_qor

1
report_qor > ${RESULTS_DIR}/qor.rpt

QoR 是 Quality of Results 的缩写。

report_qor 用来汇总设计综合质量。

通常包括:

  • WNS:Worst Negative Slack
  • TNS:Total Negative Slack
  • Number of violating paths
  • 面积信息
  • 设计规则违例
  • 时序状态
  • 层次和路径组概况

输出文件:

1
qor.rpt

这个报告适合用来快速判断综合结果好不好。


十七、最终会生成哪些文件

根据脚本,${RESULTS_DIR} 目录下会生成以下文件。


1. 中间设计文件

文件 作用
${DESIGN_NAME}.precompile.ddc 综合前 DC 内部格式
${DESIGN_NAME}.precompile.v 综合前展开后的 Verilog
${DESIGN_NAME}.postcompile.v 综合后 Verilog
${DESIGN_NAME}.postcompile.ddc 综合后 DDC
${DESIGN_NAME}.mapped.v 最终门级网表
${DESIGN_NAME}.mapped.ddc 最终 DDC 文件

2. 检查报告

文件 作用
check_design.precompile.rpt 综合前设计检查
check_design.mapped.rpt 综合后网表检查

3. 分析报告

文件 作用
design.rpt 设计基本信息
hier.rpt 设计层次结构
resources.rpt 资源推断情况
area.rpt 面积报告
power.default.rpt 默认功耗报告
power.0p25intoggle.rpt 设置输入翻转率后的功耗报告
clock.rpt 时钟报告
clock_gating.rpt 时钟门控报告
all_violators.rpt 所有约束违例
timing.rpt 详细时序路径
qor.rpt 综合质量汇总

十八、建议检查顺序

综合跑完后,建议按下面顺序检查结果。


1. 先看 log

1
2
3
4
grep -i "Error" dc.log
grep -i "Warning" dc.log
grep -i "unresolved" dc.log
grep -i "link" dc.log

重点确认没有严重错误。


2. 看综合前检查报告

1
less check_design.precompile.rpt

重点看:

  • unresolved reference;
  • multiple drivers;
  • undriven nets;
  • unconnected ports;
  • combinational loop。

3. 看综合后检查报告

1
less check_design.mapped.rpt

确认最终网表结构健康。


4. 看 QoR

1
less qor.rpt

快速查看整体质量,例如 WNS、TNS、面积、违例数量。


5. 看时序

1
2
less timing.rpt
less all_violators.rpt

重点看:

  • slack 是否为负;
  • 最差路径在哪里;
  • 哪个模块是关键路径来源;
  • 是 cell delay 大还是 net delay 大。

6. 看面积和功耗

1
2
3
less area.rpt
less power.default.rpt
less power.0p25intoggle.rpt

重点看:

  • 哪个模块面积最大;
  • 动态功耗和静态功耗占比;
  • 输入翻转率变化后功耗是否明显上升。

十九、这份脚本可以改进的地方

当前脚本已经能完成基础综合,但还可以补充一些约束和检查。


1. 补充时钟不确定性

1
set_clock_uncertainty 0.05 [all_clocks]

用于考虑时钟抖动、偏差等不确定因素。


2. 补充输入输出延迟

1
2
set_input_delay  0.2 -clock clk [remove_from_collection [all_inputs] [get_ports clk*]]
set_output_delay 0.2 -clock clk [all_outputs]

这样可以让 DC 考虑外部电路到芯片输入、芯片输出到外部电路的时序预算。


3. 说明多时钟关系

如果多个时钟异步:

1
2
3
4
5
6
set_clock_groups -asynchronous \
-group [get_clocks clk] \
-group [get_clocks clk1] \
-group [get_clocks clk2] \
-group [get_clocks clk3] \
-group [get_clocks clk4]

如果是分频时钟,需要使用:

1
create_generated_clock

4. 补充设计规则约束

1
2
3
set_max_transition 0.1 [current_design]
set_max_fanout 32 [current_design]
set_max_capacitance 0.05 [current_design]

这些可以帮助控制 transition、fanout 和 capacitance。


5. 补充 SDC 输出

1
write_sdc ${RESULTS_DIR}/${DESIGN_NAME}.sdc

输出综合约束文件,方便后端 APR 使用。


二十、一句话总结

这份脚本的作用是:

使用 Design Compiler 读取 my_top.sv,设置标准单元库和时钟约束,执行 compile_ultra 逻辑综合,输出最终门级网表 mapped.v,并生成设计、层次、面积、功耗、时钟、时序和 QoR 等报告。

最重要的几个输出文件是:

1
2
3
4
5
6
7
8
9
mapped.v
mapped.ddc
timing.rpt
area.rpt
power.default.rpt
power.0p25intoggle.rpt
qor.rpt
check_design.precompile.rpt
check_design.mapped.rpt

其中:

1
2
3
4
5
6
mapped.v       :后端 APR 主要输入
timing.rpt :看时序是否满足
area.rpt :看面积
power.rpt :看功耗
qor.rpt :看综合整体质量
check_design :看设计结构是否健康

二十一、查看一个设计的log

注意power报告仅仅可以作为相对参考:1)计算功耗通常使用ff的环境(而不是ss)2)计算功耗用的翻转因子最好来自真实场景,例如仿真环境的波形(后续介绍);3)在综合过程中主要关注低阈值cell的使用比例(后续介绍)

area.rpt 面积报告简要总结

该报告用于查看综合后设计的面积和资源使用情况。

设计规模

综合后设计包含:

  • 端口数:395
  • 网络数:10763
  • Cell 总数:10465
  • 组合逻辑 cell:9377
  • 时序逻辑 cell:1088
  • Buffer / Inverter:1818
  • Macro / Black Box:0

其中 Macro/Black Box = 0 说明设计中没有未展开的黑盒模块,网表完整性较好。

面积组成

主要面积如下:

类型 面积
Combinational area 2690.92
Buf/Inv area 244.92
Noncombinational area 872.20
Macro/Black Box area 0
Total cell area 3563.13

其中组合逻辑面积占比较大,说明设计主要面积来自组合逻辑。

Noncombinational area 主要对应寄存器、触发器等时序单元面积。

线网面积

报告中显示:

1
Net Interconnect area: undefined

说明当前综合阶段还没有真实物理布线信息,因此线网面积无法准确估算。真实连线面积需要后端布局布线后才能得到。

DesignWare / Synthetic 资源

报告中出现:

  • DW01_add:DesignWare 加法器,面积约 31.53
  • DW_mult_uns:DesignWare 无符号乘法器,面积约 905.98

其中 DW_mult_uns 占 cell area 的 13.9%,说明乘法器是面积占比较大的模块。

总结

本设计综合后总 cell 面积约为 3563.13,其中组合逻辑面积占主要部分。设计中没有 black box,说明综合展开较完整。DesignWare 资源中乘法器面积较大,是后续面积优化时需要重点关注的部分。

power report 功耗报告简要总结

这两份报告分别是:

  • power.default.rpt:默认 switching activity 下的功耗估算
  • power.0p25intoggle.rpt:给非时钟输入设置 toggle_rate = 0.25 后的功耗估算

两份报告的工作电压都是:

1
Global Operating Voltage = 0.72V
  1. 单位说明

报告中需要特别注意单位:

1
2
Dynamic Power Units = 1mW
Leakage Power Units = 1nW

因此:

  • Switch Power 单位是 mW
  • Int Power 单位是 mW
  • Total Power 单位是 mW
  • Leak Power 单位是 nW

所以 Leak Power = 37.573 表示的是:

1
37.573 nW

不是 37.573 mW,漏电功耗实际非常小。

  1. 默认功耗报告

power.default.rpt 中:

类型 数值
Switch Power 0.314 mW
Int Power 2.918 mW
Leak Power 37.573 nW
Total Power 3.232 mW

其中 Int Power 占主要部分,说明标准单元内部动态功耗较大。

  1. 设置输入翻转率后的功耗报告

power.0p25intoggle.rpt 中:

类型 数值
Switch Power 0.393 mW
Int Power 3.140 mW
Leak Power 37.362 nW
Total Power 3.533 mW

这份报告是在给非时钟输入设置:

1
set_switching_activity -toggle_rate 0.25 [remove_from_collection [all_inputs] [get_ports clk*]]

之后得到的结果。

  1. 两份报告对比
报告 Switch Power Int Power Leak Power Total Power
default 0.314 mW 2.918 mW 37.573 nW 3.232 mW
input toggle = 0.25 0.393 mW 3.140 mW 37.362 nW 3.533 mW

可以看到,设置输入翻转率后:

1
Total Power: 3.232 mW → 3.533 mW

总功耗增加约:

1
3.533 - 3.232 = 0.301 mW

增长比例约为:

1
0.301 / 3.232 ≈ 9.3%
  1. 结论

设置输入翻转率后,Switch PowerInt Power 都有所增加,说明输入信号活动增强后,内部逻辑翻转也增加,从而导致动态功耗上升。

Leak Power 基本不变,因为漏电功耗主要和工艺角、电压、温度、cell 类型有关,和输入翻转率关系不大。

这两份 power report 可以用于比较不同 switching activity 下的功耗变化,但由于综合阶段没有真实后端寄生参数,也不一定有真实 VCD / SAIF 波形,因此只能作为相对参考。

DC 功耗报告字段总结

  1. 功耗类型区别
名称 中文理解 来源 是否和翻转有关
Switch Power 网络翻转功耗 net 线网电容充放电 有关
Int Power 单元内部功耗 标准单元内部节点翻转、短路电流、内部电容 有关
Leak Power 漏电功耗 / 静态功耗 晶体管关断时的漏电流 基本无关
Total Power 总功耗 三者相加 综合结果

  1. 各项含义

Switch Power

Switch Power 是线网翻转功耗,主要来自 net 上电容的充放电。

例如信号从 0 → 11 → 0 时,线网和负载电容会充放电,从而产生功耗。

主要影响因素:

  • 信号翻转率
  • 线电容
  • 负载电容
  • 电压
  • 频率

Int Power

Int Power 是标准单元内部功耗。

当 cell 输入变化时,cell 内部节点会翻转,同时可能产生短路电流,因此会消耗功耗。

例如:

  • DFF 内部锁存结构翻转
  • MUX 内部节点翻转
  • AND / OR / XOR 等逻辑门内部翻转

该项属于动态功耗的一部分。


Leak Power

Leak Power 是漏电功耗,也叫静态功耗。

即使电路不翻转,只要上电,也会存在漏电。

主要来源包括:

  • 亚阈值漏电
  • 栅漏电
  • 结漏电

主要影响因素:

  • 工艺角
  • 电压
  • 温度
  • 阈值电压类型
  • cell 数量和类型

注意:Leak Power 的单位通常是 nW,不是 mW


Total Power

Total Power 是总功耗,近似为:

1
2
Total Power = Switch Power + Int Power + Leak Power

Results & Analyze 结果分析笔记

  1. 本页主要内容

综合运行结束后,需要重点查看以下报告:

  • clock.rpt:查看时钟定义是否正确
  • clock_gating.rpt:查看是否生成 clock gating 结构
  • all_violators.rpt:查看所有时序/约束违例
  • timing.rpt:查看详细关键路径
  • qor.rpt:查看综合质量汇总

  1. clock.rpt:时钟信息

clock.rpt 中显示设计里有多个时钟:

时钟 周期 频率
clk 1.00 ns 1 GHz
clk1 0.80 ns 1.25 GHz
clk2 0.80 ns 1.25 GHz
clk3 0.80 ns 1.25 GHz
clk4 0.80 ns 1.25 GHz

说明综合脚本中的 create_clock 约束已经生效。


  1. clock_gating.rpt:时钟门控情况

clock_gating.rpt 中显示:

  • Clock gating elements:0
  • Gated registers:0
  • Ungated registers:1088
  • Total registers:1088

说明当前综合结果中没有识别或生成 clock gating 结构,所有 1088 个寄存器都是 ungated registers。

这意味着该设计暂时没有通过 clock gating 来降低动态功耗。


  1. all_violators.rpt:时序违例情况

all_violators.rpt 中显示存在 setup 违例,主要集中在:

  • clk1 path group
  • clk3 path group

其中 clk1 组中,部分 endpoint 例如:

1
2
3
u_my_calc_result1_ff_reg_45_/D
u_my_calc_result1_ff_reg_46_/D
u_my_calc_result1_ff_reg_43_/D

required path delay 约为:

1
0.77 ns

actual path delay 约为:

1
0.85 ns

slack 约为:

1
-0.09 ns

说明 clk1 时钟域中,数据路径延迟超过了要求时间,存在 setup violation。

clk3 组中,部分 endpoint 例如:

1
2
3
u_my_calc_result3_ff_reg_48_/D
u_my_calc_result3_ff_reg_53_/D
u_my_calc_result3_ff_reg_57_/D

required path delay 约为:

1
0.77 ns

actual path delay 约为:

1
0.87 ns

slack 约为:

1
-0.11 ns

说明 clk3 时钟域违例更严重一些。


  1. timing.rpt:局部时钟组结果

右下角 timing summary 中显示 clk path group:

  • Levels of Logic:5
  • Critical Path Length:0.25 ns
  • Critical Path Slack:0.74 ns
  • Critical Path Clock Period:1.00 ns
  • Total Negative Slack:0
  • No. of Violating Paths:0

说明 clk 时钟组本身时序是满足的,而且 slack 还有较大余量。

也就是说,当前主要问题不在 clk 域,而是在 clk1clk3 相关路径。


  1. qor.rpt:QoR 汇总

qor.rpt 用来快速查看综合结果质量。

图中显示 setup 方向有违例:

  • WNS 约为 -0.11 ns
  • TNS 约为 -7.01 ns
  • Number of Violating Paths:86

hold 方向没有违例:

  • Hold WNS:0.00
  • Hold TNS:0.00
  • Hold Violating Paths:0

说明当前设计主要是 setup timing 没过,hold timing 没问题。


  1. DRC 情况

右下角 Design Rules 显示:

  • Total Number of Nets:10763
  • Nets With Violations:0
  • Max Trans Violations:0
  • Max Cap Violations:0

说明当前没有明显的设计规则违例,例如 transition 和 capacitance 约束没有问题。


  1. 重点结论

本次综合结果的主要问题是 setup timing violation。

违例主要集中在:

  • clk1 时钟域的 result1_ff 路径
  • clk3 时钟域的 result3_ff 路径

这些路径很可能和 my_calc 模块中的乘法、乘加/乘减逻辑有关。

其中:

1
2
clk1 group slack ≈ -0.09 ns
clk3 group slack ≈ -0.11 ns

说明 clk3 组违例略严重。


  1. 后续优化方向

可以考虑以下优化方法:

  1. 放宽时钟周期,例如把 0.80 ns 放宽到更大;
  2. 对乘法器或乘加路径增加 pipeline;
  3. 优化 my_calcresult1result3 相关逻辑;
  4. 检查是否需要使用更快的标准单元;
  5. 检查是否约束过紧,例如 uncertainty、input/output delay 是否合理;
  6. 如果是多时钟路径,需要确认 clock group 或 generated clock 约束是否正确;
  7. 如果某些路径不需要单周期完成,可以考虑 multicycle path。

  1. 一句话总结

综合结果中,clk 时钟域满足时序且 DRC 无明显违例,但 clk1clk3 时钟域存在 setup violation,最差 slack 约为 -0.11 ns,问题主要集中在 my_calcresult1_ffresult3_ff 相关路径,需要进一步做时序优化。

ESC 关闭 | 导航 | Enter 打开
输入关键词开始搜索