具体介绍使用Synopsys的Design Compiler进行综合的过程,整个过程大致可以分为以下几个部分:
其中预综合过程包含以下内容:
dc_shell [-f script]
启动后,使用DCSH命令,DCSH 是基于Synopsys自身语言的命令行接口。(也就是说这种启动方式只能使用Synopsys TCL)
dc_shell -t [-f script]
该命令则可以使用标准TCL语言。(自动化程度更高)
design_analyzer
、design_vision
两个都是启动图形化界面。
design_analyzer
对应的是dc_shell
的命令行方式, 所以不能在 design_analyzer 里运行 tcl 命令。 另外需要注意的是: design_analyzer
的工作模式不是用于编辑电路图的, 它只能用于显示 HDL 语言描述电路的电路图。
design_vision
是与 tcl 对应的图形方式。
使用design_vision
启动如下:
此时打开的图形化界面如下:
这里,先使用 dc_shell
,再使用gui_start
也可以达到相同的效果。
Synopsys产品很类似,他们都有启动文件.synopsys_dc.setup
,就是 DC 在启动的时候首先读入的文件,用于初始化工具,其中PT需要单独的启动文件 .synopsys_pt.setup
。该文件是一个隐藏文件,需要使用ls -a
来查看。
DC在启动的时候, 会自动按顺序在以下三个目录下搜索该文件(如下图所示),对 DC 的工作环境进行初始化:
按照上述三个启动文件的顺序,后面读取的 setup 文件可以覆盖前面文件中的设置。 该文件主要包括库的设置、 工作路径的设置以及一些常用命令别名的设置等等。由于 dcshell 的启动脚本和 tcl 的脚本语法不一致, 所以如果只有一种方式的启动脚本,那么运行另一种方式的时候会报错。 因此, DC的启动脚本有一种兼容两种方式的格式。
启动文件示例:
文件的第一段设置工艺库和链接库, 第二段设置符号库和搜索路径, 第三段设置 DC 命令的别名。
DC读入设计文件有两种方式,一是read
指令,二是analyze
和elaborate
的组合。
具体示例如下:
read -format verilog[db, vhdl ...] file // DCSH mode
read_db file.db // Tcl mode
read_verilog file.v // Tcl mode
read_vhdl file.vhd // Tcl mode
DC可以读取设计流程中任何一种数据格式,如行为级描述、RTL级描述、门级网表等,但是不同的数据格式使的DC综合的起点不同,也就是说,即使实现相同的功能,也可能会产生不同的结果。
read
命令其实是一步完成analyze&elaborate的工作,read
都是读入设计文件,如果执行进行综合,更推荐使用组合命令,两者的一些区别如下:语法格式:
analyze [-library library_name] [-format verilog | vhdl | sverilog] file_list
elaborate design_name [-library library_name] [-parameters param_list]
示例:
dc_shell-t>analyze -f verilog [list ctrl_0723.v、datapath_0723.v、ram16s.v、ram16x1s.v、regfile.v、xram16.v、xr16.v、memctrl.v、vga.v、xsoc.v]
当读取完所有要综合的模块之后,需要使用link
命令将读取到DC存储区的模块或者示例连接起来。
link
前还需要使用current_design
指定顶层模块为当前设计,DC默认将最后读入的一个模块作为顶层模块。link
后还需要使用uniquify
进行实例唯一化。
对于被多次实例化的同一子设计,由于其例化后的工作环境各不相同,因此,需要用uniquify 命令为每个实例在内存中创建一份副本,以便区分开每个实例。DC可以根据不同的应用环境进行合适的优化。
指令示例如下:
dc_shell-t> current_design topModuleName # 设置顶层设计为当前设计
dc_shell-t> link # 链接
dc_shell-t> uniquify # 实例唯一化
Design Compiler 是一个约束驱动的综合工具,它的结果是和设计着施加的约束条件密切相关的。约束条件主要包括时序约束和面积约束两部分。
DC综合是一个迭代的过程,会对RTL代码进行修改,指导满足时序约束为止,如下图:
前面介绍了DC的设计对象,各种约束的施加其实就是对设计对象设置了相应的属性。设计对象的属性按照cell、clock、design、library cell、 net、 pin、 port、 read-only、 reference等进行划分,通常用到较多的attribute 包括:area、 dont _touch、 load 、rise_drive、fall_drive, max_rise_drive、max_fall_drive、 rise_delay 、fall_delay、 plus_uncertinty、minus_uncertainty, propagated_clock, pin_direction. Port_direction。
查看特定设计对象的特定属性时,可以使命令get_attributes
,比如,查看时钟端口 CIK 的上升沿驱动能力:
dc_ shell-t> get_attribute [get ports CLK] rise_drive
3.283230
再比如查看工艺库smic18ss 中单元 NAND2BIHIDIX的面积:
dc_shell-t> get_attribute [get_lib_cells smicI8_ss/NAND2B1HD1X] area
7.564000
面积是主要的成本因素,电路面积要尽可能小,速度要尽可能快,但速度越快面积就要大。
面积约束指令示例:
dc_shell-t> current_design PRGRM_CNT_TOP
dc_shell-t> set_max_area 100
上面的例子给PRGRM_CNT_TOP
的设计施加了一个最大面积100单位的约束。100的具体单位是有Foundary规定的,定义这个单位有三种可能的标准:
对于时序优先的设计,通常设置其最大面积为0,意指在时序收敛的前提下尽可能的优化面积。命令为:
dc_shell-t>set_max_area 0.0
逻辑综合的过程中,除了面积之外,要达到的目标是约束电路中的所有时序路径,从而实现对工作频率的约束。
设计中的时序路径可以划分为以下四种:
对于图中的路径X,是一个寄存器到寄存器的路径,对于该组合路径而言,其最大裕量是一个时钟周期,因此定义时钟周期就可以实现对该路径的约束。
在电路综合的过程中,所有的时序电路和组合电路的优化都要以时钟为基准来计算路径延迟,因此,一般都要在综合的时候指定时钟,将其作为估计路径延时的基准。
对时钟进行定义的具体内容如下:
时钟定义语法格式:
create_clcok [-name clock_name] [source_objects] [-period period_value] [-waveform edge_list]
# name:为创建的时间指定一个名称,如果省略该项,时钟名称为source_objects中第一个对象的名称,如果后续 source_objects省略,则该项必须指定,这种情况下创建的是虛拟时钟,用于约束组合逻辑的相对延时条件;
# source_objects:用于创建时钟的引脚或端口名称;
# -period:创建时钟的周期,单位由工艺库决定,一般为 ns;
# -waveform:指定时钟上升沿和下降沿的时刻,从而决定时钟信号的占空比;如果略去该项,默认时钟占空比为50%,上升沿的时刻为0。
时钟定义示例1:
dc_shell-t> create_clock -period 10 [get_ports Clk]
dc_shell-t> set_dont_touch_network [get_clocks Clk]
create_clock
定义了一个时钟,set_dont_touch_network
给时钟定义了一个dont_touch属性,即综合的时候不对Clk信号行优化。
如果不加这句,DC会根据Clk的负载自动对他产生Buffer,而在实际的电路设计中,时钟树(Clock Tree)的综合有自己特别的方法,它需要考虑到实际布线后的物理信息,所以 DC不需要在这里对它进行处理,就算处理了也不会符合要求。
DC综合是一个理想情况,单元的实际位置并没有固定下来,没有办法实现一个实际的时钟网络。DC得到的时钟是很不准确的,在布局布线的时候还要把这个不准确的时钟网络删除,然后重新做一个正确的网络,因此没必要在该阶段进行时钟综合。
时钟定义示例2 :
比如在输入端口 CLK创建一个周期为10ns,名称为clk的时钟,命令为:
dc_shell-t> create_clock -name clk -period 10 [get_ports CLK]
该时钟的占空比为 50%,若要时钟占空比为 40%,命令可改为:
dc_shell-t> create_clock -name clk -period 10 -waveform [0 4] [get_ports CLK]
create_clock
命令创建的时钟是理想时钟,没有延时。可以通过指定latench,uncertainty
等约束条件来模拟真实时钟,相应的命令为:set_clock_latency
,set_ clock_uncertainty
。
set_clock_latency
命令用于定义时钟网络的延迟,包括source_latency
和network_latency
。
source_latency
是从时钟源到时钟定义位置的延迟,network_latency
是时钟定义位置到触发器时钟输入端的延迟。
语法格式:
set_clock_latency [-source] delay object_list
# -source:指定latency为source_latency,若没有该选项,则为network latency.
# delay:时钟延时的值。
# object_list::指定latency所在的时钟、端口、引脚的对象列表。
示例:
dc_shell-t> set_clock_latency -source 3 [get clocks CLK]
dc_shell-t> set_clock_latency 3 [get clocks CLK]
Latency指定了时钟的延时,后端版图设计的结果可能会引起时钟网络的时序在一定范围内变化,因此可以使uncertainty来为 DC 的综合与优化提供一定的时间裕度。uncertainty分为 plus uncertainty(保持时间检查时用)和 min uncertainty(建立时问检查时用)。设置uncertainty的命令及其格式为:
set_clock_uncertainty [-setup] uncertainty
# -setup:指定仅用于建立时间检查的uncertainty,默认情记下 uncertaing同时用于建立时间和保持时间检查。
# uncertainty:时钟不确定性的值。
实际中在一些复杂设计上可能会用到分频或倍频时钟,DC 不能为这些时钟自动创建时钟对象,这就要用到 create_generated_clock
命令。其语法格式为:
create_generated clock [-name clock_name] -source master_pin [-divide_by divide_factor | -multiply_by multiply_factor] source_objects
# -name:指定生成时钟的名称。
# -source:指定主时钟。
# -divide:指定分频系数。
# -multiply:指定倍频系数。
# source_objects:指定生成时钟所在的端口或引脚列表。
比如,当时钟信号DIVIDE是主时钟SYSCLK的2分频,其命令为:
dc_shell-t>create_generated_clock -name DIVIDE -source SYSCLK divide_by 2 [get_pins U4/Q]
前面介绍的时钟定义需要手工为其设置各种条件,而对于布图后的时钟信号只需指定其为传播时钟,则DC会将时钟树上的延时属性自动加载到所指定的设计对象上,其命令为 set_propagated_clock
。
由于时钟的负载很大,时钟的翻转时间往往也很大,这与实际是不符的,因此需要为时钟信号指定一个固定的翻转时间,命令为set_clock_transtion
。
综合前面几条命令,现要设计创建一个时钟,周期 10ns, network_latency为 1ns, source_latency为3ns,时钟翻转时间为 0.3ns,建立时间检查的不确定性为0.5ns,完整的脚本命令为:
create_clock -period 10 [get_ports CLK]
set_clock_latency 1 [get_clocks CLK]
set_clock_latency -source 3 [get_clocks CLK]
set_clock_uncertainty -setup 0.5 [get_clocks CLK]
set_clock_transition 0.3 [get_clocks CLK]
set_dont_touch_network [get_clocks CLK]
注意:当内核逻辑加上 PAD 后,时钟应定义在“时钟PAD”的输出上(假定为D,同时为其设置dont_touch 属性,并将输出线(假定为pad_clk_o。)设为ideal_network
。具体脚本命令为:
set T 10
create_clock -period $T -waveform [list 0 $T/2] -name clk [get pins PAD INS/CLK PAD/D]
……
set_dont touch network [get_clocks CLK]
set_ideal_network [get_nets PAD_INS/pad_clk_o]
如下图,通过定义时钟,实现了对路径X的约束,但是路径N和路径S的还没有被约束,这个时候就要定义IO相对clock的时序。
对于输入端口,定义输入延迟。
输入延时指的是被综合模块外的寄存器触发的信号在到达被综合模块之前经过的延时,在图中就是外围触发器的clk-q的延时加上M电路延时。
(制定好输入延时之后,就可以确定出路径N的延时范围,只要其延时在这个范围内,信号就能正确传递。)
语法格式:
set_input_delay delay_value [clock clock_name] [-max] [-min] port_pin_list 。
# delay_value:设定的输入延时的大小,单位由工艺库决定,一般为ns。
# -clock:输入延时所参考关联的时钟;
# -max:最大延时(建立时间)
# -min:最小延时(保持时间)
# port_pin_list:当前设计中设定输入延时的输入端口或内部引脚的列表。
示例1:
dc_shell-t> set_input_delay -max 4 -clock Clk [get_ports A]
[get_ports A]
: 将输入延时施加到A端口上max 4
:端口最大延时(最大延时用于建立时间,最小延时用于保持时间)clock Clk
:延时值的基准时钟(即针对哪个时钟的延时)(电路中有多个时钟域,每个时钟域都有对应的输入和输出引脚,所以要指定时钟)假设待综合电路如上图所示,需要施加的时序约束如下:
create_clock -period 20 [get_ports CLK]
set_dont_touch_network [get_clocks CLK]
set_input_delay -max 7.4 -clcok Clk [get_ports A]
因为外部电路模块中给定的延时说明了worst,所以要将输入延时设为max
。
对于输入端口,定义输出延迟
信号在被综合模块的触发器U3里触发,被外围的一个触发器接收。对外围电路而言,它有一个T电路延时和外围触发器的建立时间。当确定了他们的延时之后,被综合模块内部的输出路径延时范围也就确定下来了。
set_output_delay delay_value [-clock clock_name] [-max] [-min] port_pin_list
# delay_value: 设定的输出延时的大小,单位由工艺库快定,一般为ns。
# -clock:输出延时所参考关联的时钟。
# -max:指定最长路径的输出延时。
# -min:指定最短路径的输出延时。
# port_pin_list:当前设计中设定输出延时的输出端口或内部引脚的列表。
示例:
dc_shell-t> set_output_delay -max 5.4 -clock Clk [get_ports B]
输入延迟和输出延迟的概念好像是一样的,只是针对的但当前电路而言有了输入和输出之分。两者都是时钟周期减去输入或输出延时得到当前待综合模块的输入或输出路径的时序约束。
对于纯组合逻辑,一般使用set_max_delay
和set_min_dealy
进行约束,也可以使虚拟时钟。
set_max_delay 用于在当前设计中指定从任意起点到任意终点的最大延时。
语法格式为:
set_max_delay delay_value [-from from_list] [-through through_list] [-to to_list] [-group_path group_name]
# delay_valve:指定最大延时的值,单位由工艺库决定,一般为 ns.
# -from:延时约束的起点列表;
# -through:延时路径经过的节点列表。
# -to:延时约束的终点列表.
# -group_path:建立一个时序关键路径的组,用于重点优化。
group_path
选项对编译时间有较大影响,而且该组优化的优先级高,可能会导致其他的时序违例。因此该选项(或单独使用 group_ path命令)通常作为综合优化的最后手段使用。
比如设定从UO的CP端经单元U1和U2的Z端到达U3的A端的最大延时为5.0ns,则命令为:
set_max_delay 5.0 -from [get_pins U0/CP] -through [list UI/Z U2/Z] -to [get_pins U3/A]
set_min_delay
用于在当前设计中指定路径的最小延时,与set_max_delay
相对,该命令与set_fix_hold
命令配合使用修正电路的保持时间,如果发生min_delay 违规,在不增大 max_delay 的情况下综合工具会自动添加合适的延时单元来修复违规。语法格式为:
set_min_delay delay_value [-from from_list] [-through through_list] [-to to_list]
# delay_value:指定最小延时的值,单位由工艺库决定,一般为ns。
# -from:延时约束的起点列表。
# -through:延时路径经过的节点列表。
# -to:延时约束的终点列表。
比如设定从UO的Cp端经单元 U1和U2 的Z端到达 U3 的A端的最小延时为 3.0ns,则命令为:
set_min_delay 3.0 -from [get_pins U0/CP] -through [list UI/Z U2/Z] -to [get_pins U3/A]
由于每条路径都有timing_constraints,所以才能进行时序分析,但在某些情况下,有些路径的时序分析没有意义,要想忽略这些路径的分析,就要设定时序例外。
除了前面讲的 set_max_delay
和 set_min_delay
指定的时序例外之外,另有两类时序例外:伪路径和多周期路径,分别有set_false_path
和set_multicycle_path
命令来指定。
伪路径也称为虚假路径,指时序分析时不需要关心的路径。DC不能自动识别伪路径,故需要显示指定。set_false_path
命令用于去掉特定路径上时序约束,
对异步逻辑和逻辑上的虚假路径非常有用。语法格式为:
set_false_path [-from from_list] [-through through_list] [-to to_list]
# -from:伪路径的起点列表。
# -through:伪路径经过的节点列表。
# -to:伪路径的终点列表。
比如设定ff1的CP端经单元U1 和U2 的Z端到达ff2的D端的路径为伪路径,则命令为:
dc_ shell-t>set_false_path -from [get_pins ffI/CP] -through [list U1/Z U2/Z] -to [get_pins ff2/D]
如果设计中有多个时钟,那么由一个时钟域 到另一个时钟域之间的路径为伪路径,需要一一标示,可以重复调用 set_false_path 命令,也可以采用如下的脚本命令:
foreach_in_collection clk1 [all_clocks] {
foreach_in_collection clk2 [remove_from_collection [all_clocks] [get_clocks $clk1]] {
set_false_path -from [get_clocks $clk1] -to [get_clocks $clk2]
}
}
多周期路径指两级相邻寄存器之间的组合逻辑延时较大,不能在1个时钟周期完成。因此需要设定为多周期路径,由set_multicycle_path
命令完成。语法格式为:
set_multicycle_path path_multiplier [-setup] [-hold] [-from form_list] [-through through_list] [-to to_list]
# path_multiplier:指定路径的时钟周期数。
# -setup:指定该路径针对建立时间检查;
# -hold:指定该路径针对保持时间检查;
# -from:多周期路径的起点列表;
# -through:多周期路径经过的节点列表;
# -to:多周期路径的终点列表。
示例:
上图为多周期路径示意图,比如在上图所示的设计中,时钟周期为10ns,而其中一级加法器的延时近60ns,那么约束方法为:
dc_shell-t>create_clock -period 10 [get clocks clk]
de shell-t>set_multicycle_path 6 -setup -to [get_pins c_reg[*]/D]
设计规则约束指为保证最终电路可以正常工作,而由工艺库定义的必须遵守的规则,也称隐含约束。一般用于限制在电容、翻转时间、扇出等因素影响,下一个单元可以和多少个其他单元相连,这些规则是必须遵守的,且比其他规则具有更高的优先级。设计规则约束由 set_max_transition
、set_max_fanout
和set_max_ capacitance
组成。(工艺库本身制定了,但是可以根据需求,人为指定,更加严苛或者宽松。)
约束design中的信号、端口、net最大transition不能超过这个值,当然是越小越严苛了,net的transition time取决于net的负载(fanout),负载越大,transition time越大。
翻转时间是指引脚或端口的电平翻转所需要的时间。工艺库中一般都会给出该值,如果要为特定的端口、设计或时钟组指定特定的翻转时间,可以采用 set_max_transition
命令,其语法格式为:
dc_shell-t> set_max_transition transition_value object list
# transition_value: 设定的最大翻转时间。
# object_list :设定其翻转时间为 transition_value 的对象列表.。
示例:
dc_shell-t> set_max_transition 1.0 [all_designs]
# 本例中设定所有设计的最大翻转时间为1.0ns
对design,net,output port进行操作,设定的不是具体的电容值。扇出负载值是用来表示单元输入引脚相对负载的数目,它并不表示真正的电容负载,而是个无量纲的数字。
扇出负载是指互连线可以驱动的扇出数目,这与容性负载不同。扇出负载没有量纲,在计算时 DC 把一个驱动引脚所连接的所有输入引脚的扇出负载相加,得出该驱动引脚的扇出负载值,并把该值与设定的max_ fan_out
相此较。工艺库中设定了扇出负载的默认值,通过set_max_fanout
可以进行修改。如果两者不同,综合时会以数值较小,即更严格的值为准。
语法格式:
dc_shell-t> set_max_fanout fanout_value object_list
# fanout_value:设定的max_fanout的属性值。
# object_list:设定的 max_fanout 属性为 fanout_value的端口或设计的对象列表。
示例:
dc_shell-t> set_max_fanout 8 [get designs mem_ctrl]
# 设mem_ctrl 的max_fanout为8,则该设计中所有的互连线都被约束。
补充:load vs. fanout_load vs. fanout
max_capacitance属性由命令set_max_capacitance
完成。该命令与set_max_transition
是相互独立的。
语法格式:
dc_shell-t> set_max_capacitance capacitance_value object_list
# capacitance_value:设定的 max_capacitance属性值。
# object_list :设定的 max_capacitance 属性为 capacitance_value 的端口或设计对象列表。
示例:
dc_shell-t> set LOAD_OF_A [load_of_smic13_ss/NAND2HD2X/A]
dc_shell-t> set_max_capacitance [expr $LOAD_OF_A*10] [all designs]
本例设定所有设计的max_capacitance
为 smic13_ss/NAND2HDD2X/A 电容的10倍,即0.0838869,该设计中所有的互连线都被约束。该例中的值可在 DC-Tcl 命令行中直接得到。
sh date # 显示时间
remove_design -designs # 移除DC中原有的设计
################################
# set library #
################################
set search_path [lsit ********]
set target_library {tt.db}
set link_library {* tt.db}
set symbol_library {tt.sdb}
################################
# void warning Info #
################################
# 屏蔽掉一些无意义的warning信息
suppress_message VER-130
suppress_message VER-129
suppress_message VER-318
suppress_message ELAB-311
suppress_message VER-936
################################
# read design #
################################
read_file -format verilog ~/example1.v
#analyze -format verilog ~/example1.v
#elaborate EXAMPLE1
current_design EXAMPLE1 # 指定顶层模块,否则会默认把最后一个读入的module设为top
uniquify
check_design
################################
# define IO port name #
################################
set clk [get_ports clk] # 设置变量的clk的值是[get_ports clk],在下面的代码中若出现$clk字样,则表示该变量的值,即用[get_ports clk]代替$clk
set rst_n [get_ports rst_n]
set general_inputs [list a b c]
set outputs [get_ports o]
################################
# set constraints #
################################
# 1 set constraints for clock signals
create_clock -n clock $clk -period 20 -waveform {0 10}
set_dont_touch_network [get_clocks clock]
set_drive 0 $clk # 设置时钟端口的驱动为无穷大
set_ideal_network [get_ports clk] # 设置时钟端口为理想网络 这两条设置保证了逻辑综合阶段的时钟是非常理想的(时钟网络不参与综合)
# 2 set constraints for reset signals
set_dont_touch_network $rst_n
set_drive 0 $rst_n
set_ideal_network [get_ports rst_n] # 复位信号同样这样设置,因为复位信号的重要性仅次于时钟信号
# 3 set input delay
set_input_delay -clock clock 8 $general_inputs
# 4 set output delay
set_output_delay -clock clock 8 $outputs
# 5 set design rule constraints
set_max_fanout 4 $general_inputs
set_max_transition 0.5 [get_designs "EXAMPLE1"]
# 6 set area constraint
set_max_area 0 # 在满足时序的条件下,尽可能减小面积
除了时序的DRC等约束外,电路还有一些其他因素影响电路的延时,如下:
所以这一部分的约束如下:
工作条件包括温度、电压和工艺参数。晶圆厂提供的单元库中单元延时是在一个标准条件下得到的,比如温度为25℃,工作电压为1.8V,工艺参数为1.0。
一旦工作条件发生了改变,电路的时序特性也必将受到影响。以上三者对时序的影响如下:
晶圆厂在建库的时候,已经考虑到了参数变化的影响,所以在工艺库中提供了几种工作条件模型:最好情况、典型情况、最差情况。
在逻辑综合的时候,一般只考虑最差情况(延时最大,用于建立时间检查)和最好情况(延时最小,用于保持时间检查)。
由于在逻辑综合阶段以最大化建立时间为目标,所以工作条件通常设为最坏情況。对应命令为:set_operating_conditions
dc_shell-t> set_operating_ conditions WORST
若同时指定最好情况和最坏情况,对修正保持时间违例比较有用,但自前一般不推荐使用。
dc_shell-t> set_operating_ conditions -max WORST -min BEST
为了准确估计模块输出的时序,除了需要知道输出延时外,还需要知道所接电路的负载情况。如果输出负载过大,会加大电路的transition time,影响时序特性。DC默认的输出负载为0,即相当于不接负载,这样综合出来的电路时序显然过于乐观,不能反应实际工作情况。
使用set_load
指令来设定输入负载值,负载值可以是一个具体的值,也可以是工艺库中现有单元的load值。语法格式如下:
dc_shell-t> set_load value objects
# value:设定的容性负载值(非负实数);
# objects:当前设计中设定容性负载的对象列表,包括端口、互连线等。
dc_shell-t> set_load load_of lib/cell/pin
示例:
# 1. 固定值
dc_shell-t> set_load 3 [all_outptus] # 设置所有输出端口的容性负载为 3pf
# 2. 单元load值
# 2.1
dc_shell-t> set_load [load_of my_lib/NAND2HD2X/A] [get_potrs OUT1]
# 2.2 采用 smic13_ss库中NAND2HD2X 的引脚A上的电容的10 倍表示所有输出端口的负载
dc_shell-t> set LOAD_OF_A [load_of my_lib/NAND2HD2X/A]
dc_shell-t> set_load [expr $LOAD_OF_A*10] [all outputs]
为了精确计算输入电路的时序,DC需要知道 input port 的 transition 时间。默认情况下DC假定外部信号的transition time 为 0 ,使用set_driving_cell
允许用户可以自行定一个实际的外部驱动cell,可以让DC能够计算一个实际的(non-zero)transition time。
在DC中,驱动强度用电阻值表示,阻值越小表示驱动能力越大,默认情况下DC认为输入端口的驱动电阻阻值为0,即驱动强度无限大。但0值通常用于时钟和复位等扇出很大的端口。对其他端口,为避免这种不切实际的驱动强度,可以采用set_drive
和set_driving_cell
两条命令来设置输入端口的驱动强度。
set_drive
命令通过直接指定驱动电阻值对输入端口或双向端口设置fall_drive或rise_drive 属性。语法格式为:
set_drive resistance [-rise] [-fall] port_list
# resistance:非负的驱动电阻值,该值越小表示驱动强度越大;
# -rise/-fall :指定是rise_drive属性还是fall_drive属性,如果都不指定,则rise_drive=fall_drive=resistance。
# port_list:驱动强度设置为resistance 的输入端口或双向端口列表。
示例:
dc_shell-t> set_drive 0 [list clk rst_n] # 时钟和复位端口的驱动强度设为无穷大。
set_drive
命令可以和drive_of
命令结合使用,比如采用 smicl3_ ss
库中单元IVHID1X
的引脚Z的驱动能力表示clk
和rst_n
的驱动能力,其命令为:
dc_shell-t> set_drive [expr [drive_of smic13_ss/IVHD1X/Z] [list clk rst]
若用 smic13_ss库中单元 INVHD1X 的引脚Z的驱动强度的 8倍表示 clk 的驱动强度,则命令为:
dc_shell-t> set_drive [expr [drive_of smic3_ss/INVHDIX/Z]*8] [get_ports clk]
set_driving_cell
命令对输入端口或双向端口的驱动电阻进行建模,将端口的驱动强度设定为驱动单元(只有一个输出)或驱动单元特定引脚的驱动强度,同时也把驱动单元的设计规则约束应用于待指定驱动强度的端口。语法格式为:
set_driving_cell [-lib_cell lib_cell_name] [-library lib] [-pin pin_name] [-no_design rule] port_list
# -lib_cell:用于驱动设计输入端口的库单元名称。
# -library:lib_cell 所在库的名称,若当前仅读入唯一的目标库且驱动单元就在该库中,则该选项可省略。
# -pin:用于驱动设计输入端口的单元引脚名称,若单元只有一个输出,该项可略去;若有多个输出,但不指定,则DC采用第一个找到的引脚。
# -no_design_rule:该选项要求 DC 忽咯驱动单元引脚上的设计规则。
# port_list:设置驱动强度的输入端口或双向端口列表。
示例1:
dc_shell-t> set_driving_cell -lib_cell and2a0 \[get_ports IN1]
示例2:
用smic13I0_02_line_ss库中单元 PLBI8N 的驱动强度表示所有输入端口的驱动强度,其命令为:
dc_shell-t> set_driving_cell -library smic13I0_02_line_ss -lib_cell PLBI8N [all_inputs]
如果设计中包含PAD模块,那么在指定时钟、复位等高扇出端口的驱动能力时,应使set_ideal_network
命令,且其强度应施加在 PAD 单元的输出线上。比如,时钟端口经PAD单元RAD_INS送入,PAD_INS的输出引脚连接到互连线PAD_CLK_O上,则其命令设置为:
dc_shell-t> set_ideal_network -no_ propagate [get_nets PAD_INS/PAD_CLK_O]
set_drive
命令只对线性延时模型是准确的,而对非线性延时模型不适用,set_driving_cell
命令对各种延迟模型都适用,故对时钟、复位外的其他端口设置驱动强度时建议使用 set_driving_cell 命令。
在DC综合的过程中,连线延时是通过设置连线负载模型(wire load model)确定的,连线负载模型基于连线的扇出,估计它的电阻电容等寄生参数,它是也是由Foundry提供的。Foundry根据其他用这个工艺流片的芯片的连线延时进行统计,从而得到这个值。
连线延时的计算是根据连线的扇出,通过查找表计算长度,然后计算电阻和电容。若扇出值超出表中的值(假设为7),那么DC就要根据扇出和长度的斜率(Slope)推算出此时的连线长度。
在每一种工作条件下都会有很多种负载模型,各种负载模型对应不同大小的模块的连线,如上图的模型近似认为是160K门大小的模块适用的。模块越小,它的单位长度的电阻及电容值也越小,负载模型对应的参数也越小。
具体语法格式:
set_wire_load_model -name model_name [-library lib]
# -name:线负载模型的名称
# -library:包含所指定线负载模型的库名称,若当前读入的目标库唯一则该选项可省略。
前以小节的线负载模型考虑的都是同一模块内部的连线,对于连接不同模块之间的连线,其线负载模型需要通过设定连线负载模式(wireload model mode)来指定。
连线负载模式包括围绕(enclosed)、顶层(top)、分段(segmented)三种。设定指令为:set_wire_load_mode
如下图所示,一根连线连接了B2和B1两个模块,这两个模块都位于TOP下的SUB这个子模块中。
在定义完环境属性之后,我们可以使用下面的几个命令检查约束是否施加成功。
check_timing
:检查设计是否有路径没有加入约束check_design
:检查设计中是否有悬空管脚或者输出短接的情况write_script
:将施加的约束和属性写出到一个文件中,可以检查这个文件看看是否正确。(该文件很重要,后续的设计的流程都要以该部分内容为时序基准)在完成设计约束、DRC、环境约束之后,就可以进行编译,然后得到逻辑综合的结果和输出文件。
(在编译之前还需要进行一些优化策略的选择,后续在了解这一部分)
compile
命令进行设计或模块的编译,将HDL代码映射到指定的目标库。其选项可用于设计的映射优化,语法格式为:
compile [-map_effort medium|high]
[-area_effort none|low|medium|high]
[-incremental_mapping]
[-ungroup_all]
[-auto_ungroup area|delay]
[-no_design_rule | -only_design_rule | -only_hold_time]
# -map_effort:综合映射的努力程度,有medium和high两个选项,缺省默认为medium项,缺省为值与 map_ctfort 的值相同。
# -area_effort:综合器面积优化的努力程度,有1ow,medium,high三个选项,缺省默认为medium;
# -incremental_mapping:称为增量编译,指示综合器在前一次综合结果的基础上进一步优化,只用在门级,通常用于改善时序和修正 DRC违规。增量编译时,DC 会进行各种映射优化以改善时序。若只对设计修正DRC,可以加上
# -only_desien_rule 选项;
# -ungroup_all:对设计中除了具有dont_touch属性的设计外全去除层次。
# -auto_ungroup:对设计中的层次结构根据需要自动去除层次。
比如,在初次编译时采用 medium 的映射努力,增量编译时采用high的映射努力,相应命令为:
#1st compile
compile -map_effort medium
#2nd compile
current_design xsoc
compile -incremental -map_effort high
编译时,DC提供了compie_ultra
命令,包括许多高级的综合优化算法,可以使关键路径的分析和优化在最短时间内完成。
以具体脚本为例,介绍输出的具体内容,如下所示:
################################
# complie_design #
################################
compile -map_effort medium
################################
# write *.db and *.v #
################################
write -f db -hier -output ~/EXAMPLE1.db # 保存整个工程
write -f verilog -hier -output ~/EXAMPLE1netlist.v # 逻辑综合后的网表,用于布局布线和后仿真
write_sdf -version 2.1 ~/EXAMPLE1.sdf # sdf反标文件,标注了使用的标准单元的延时值,后仿真也需要文件
################################
# generate reports #
################################
report_area> EXAMPLE!.area_rpt # 面积报告,包括时序电路面积、组合逻辑电路面积、总面积
report_timing> EXAMPLE1.timing_rpt # 时序报告,查看建立时间和保持时间是否满足要求
report_constraint -all_violators> EXAMPLE1.constraint_rpt # 违例报告,逻辑综合过程中没有达到的约束
sh date # 显示时间
时序报告的内容主要包括:表头、数据发射路径、数据捕获路径、时序结果
电路模块设计规划(以利于更好的进行约束),Design Compiler综合优化的过程(三大优化阶段,结构级,逻辑级,门级),时序分析的具体过程等综合过程中的一些详细信息。
(更加具体的优化策略后续再看)
综合完毕该怎么看结果,时序违反该如何解决?这就是后综合过程所要解决的问题。在综合之后,通过分析综合报告,可以得知此次的电路综合结果如何,根据不符合的要求,进行重新约束,甚至重新设计电路。在这个阶段特别值得一提的是综合预估,因为在写综合约束脚本的时候,需要确定约束条件,规格书一般不能够涉及到如此细节的部分,所以需要根据实际电路进行综合预估,这个步骤是在代码编写完之后,与验证同时进行的,目的在于大致估计电路是否符合要求,此时的预综合过程与正式的综合过程是一样的,但要求会宽松许多,时序违反的要求大概为 10%-15%,也就是说电路即使有10%-15%的电路不满足时序也没有关系。
芯动力 —— 硬件加速设计方法
EDA12–DC脚本命令(一)