文章目录
- 前言
- 一、综合综述
- 1、综合
- 2、综合的不同层次
- (1)逻辑级综合
- (2)RTL级综合
- (3)行为级综合
- 二、verilog语言结构到门级的映射
- 三、使用DC进行综合
- 1、定义
- 2、写时序约束
- 3、写环境约束
- (1)设置环境条件
- (2)设置连线负载模型
- (3)设置驱动强度
- (4)设置电容负载
- (5)设置设计规则约束(DRC)
- (6)面积约束
- (7)完整的环境约束
- 四、输出结果
- 五、简答
- 1、目标库和链接库的区别
前言
2023.6.25
2023.6.27 和之前学的芯动力mooc中很多内容相似,这篇整理的逻辑更好些
一、综合综述
1、综合
将RTL代码转换到基于工艺库的门级网表。一般分为如下三个步骤。
2、综合的不同层次
(1)逻辑级综合
设计被描述成布尔等式的形式,触发器、锁存器这样的基本单元采用元件例化(instantiate)的方式表达出来,下面是一个加法器的代码。
(2)RTL级综合
电路的数学运算和行为功能分别通过HDL语言特定的运算符和行为结构描述出来。电路在每个时钟边沿的行为都被确切的描述出来。
(3)行为级综合
电路的行为可以描述成一个时序程序(sequential program),没有明确规定电路的时钟周期,综合工具的任务就是根据指定的设计约束,找出哪些运算可以在哪个时钟周期内完成,需要在多个周期内用到的变量值需要通过寄存器寄存起来。
二、verilog语言结构到门级的映射
1、always
语句描述的组合逻辑电路,敏感列表要包含所有的输入变量。
2、if
或case
语句不完整会综合出锁存器,解决方法:在最开始的时候给变量赋初值或者把语句写完整(写default)。
3、如果设计者知道case语句不会有其他值,且不想综合出锁存器,可以使用一条综合指令:synopsys full_case
,这句话以注释的形式加在设计代码里面。
带来的问题:降低代码的可移植性,会让他依赖于综合工具;产生的网表和当初的verilog建模有区别,带来验证的复杂性。
4、casex
语句是有优先级的(如优先编码器),相当于if-else if-else,如果想要产生互斥的语句,也就是平行结构,可以加上synopsys parallel_case
。
5、常见的循环语句有4种:for
、forever
、while
、repeat
。循环语句综合时相当于展开循环体,把相同的电路结构重复多次,会造成综合后的面积和性能受到影响。
6、DesignWare
是集成在DC综合环境中的可重用电路的集合,DesignWare 分为 DesignWare Basic
与 DesignWare Foundation
,DesignWare Basic 提供基本的电路,DesignWare Foundation 提供性能较高的电路结构。针对同一种算术符,可以有不同的算法,根据添加的约束条件来选择。
在使用的时候,需要有license,同时在综合的时候要设置synthetic library
。
三、使用DC进行综合
lib格式
:用户可读,其中包含信息有工艺条件、单位、基本单元的引脚、方向、时序信息等。
db格式
:供DC软件读取的格式
1、定义
流程:准备设计文件、指定库文件、读入设计、定义设计环境、设置约束、编译(选择编译策略)、报告、存储数据
工艺库(technology library):目标库和链接库统称为工艺库,一般只要设置好这两个
set
: 自己自定义的一些变量,方便定义系统变量,相当于减少一些重复的代码,同时增加了代码的可读性,和tcl的语法是一样的。
set_app_var
:定义DC内部的系统变量、指定DC内部的连接等。主要指定有:search_path、synthetic_library、target_library、link_library、symbol_library 以及其他的一些命令开关等。
define_design_lib work -path $WORK_PATH
:DC内部命令格式,指定设计和库的工作路径。
printvar target_library
:启动DC后,可以通过该命令来查看库的名称。
dcprocheck xxx.tcl
:检查该文件的语法是否正确。
source
:是用来定义一些命名规则,去掉网表中的一些符号,防止后端工程师拿到的网表中带一些奇怪的符号从而引起不必要的错误。(没有用这个)
source -v -e ./../../../xxxxx/syn/work/hs_name_rules.tcl
在和物理库相关的时候需要使用拓扑模式来启动dc,选项为-topo
,同时可以把启动dc时的相关信息输出到log文件,指令为tee -i
,中间的|
为管道连接符,连接输入和输出
dc_shell -topo | tee -i start_report.log
2、写时序约束
模块如下所示:
设计约束规格书如下所示:
create_clock -period 3 [get_ports clk]
set_clock_latency -source -max 0.7 [get_clocks clk] //时钟延迟中的时钟源延迟的最大值为0.7ns
set_clock_latency -max 0.3 [get_clocks clk] //时钟网络延迟的最大值
set_clock_uncertainty -setup 0.15 [get_clocks clk] //0.15=0.03+0.03+0.04+0.05,两个时钟之间的最大延时偏差为0.06,再加上该时钟的时钟抖动0.04,同时加上留的裕量0.05
set_clock_transition 0.12 [get_clocks clk]
//输入延迟时间是相对于clock的相对时间,而这里给出的是绝对时间,所以要减去时钟延迟,1.4-0.7-0.3=0.4(每台明白)
set_input_delay -max 0.4 -clock clk [get_ports sel]
//3-2.2-0.2-0.15=0.45,这里只给出了内部的组合逻辑延时,如果要知道外部的输入延时的话,用一个时钟周期去-组合逻辑延时-Tsetup-uncertainty
set_input_delay -max 0.45 -clock clk [get_ports data*]
set_output_delay -max 0.5 -clock clk [get_ports out1] //0.42+0.08
set_output_delay -max 2.04 -clock clk [get_ports out2] //3-0.81-0.15=2.04
set_output_delay -max 0.4 -clock clk [get_ports out3]
3-0.15-输入延时-2.45=输出延时
输入延时+输出延时=0.4 只要满足这个要求即可,可以根据后端要求再进行调整
set_input_delay -max 0.1 -clock clk [get_ports Cin*]
set_output_delay -max 0.3 -clock clk [get_ports Cout]
3、写环境约束
(1)设置环境条件
一般不设置的话默认用库里面默认的norminal
set_operating_conditions -max $OPERA_CONDITION -max_library $LIB_NAME
(2)设置连线负载模型
在计算时序路径的延迟,需要知道门单元延迟
和连线的延迟
。
门单元的延迟采样非线性延迟模型,依据输入转换时间和输出负载的查找表得出,
同时查找出输出转换时间,作为下一级电路的输入转换时间。
连线的延迟通过线负载模型进行估算,根据连线的扇出来估算连线的寄生参数RC。
线负载模型(右侧)给出的是单位连线的电阻/电容/面积信息。
下面的计算超出了最大扇出长度,根据slope来外推计算。
set auto_wire_load_selection false //DC可以自动选择合适的连线负载模型,可以使用命令关掉
set_wire_load_model -name $WIRE_LOAD_MODEL -library $LIB_NAME
连线负载模型的模式:围绕(enclosed)、顶层(top)、分段(segmented)
enclosed模式
:使用的是包围该模块的连线负载模型。
top模式
:最悲观的情况,使用的是顶层的连线负载模型。
segmented模式
: 位于两个小模块中的部分采用这两个小模块对应的连线负载模型, 中间部分采用子模块的连线负载模型。也就是连线位于哪个模块就采样哪个模块的模型。
set_wire_load_mode enclosed/top/segmented
(3)设置驱动强度
默认情况下会认为输入转换时间为0,为了得到真实的延迟,我们需要给输入端加上驱动
set_drive 0/100 //0表示最大驱动强度,通常为时钟端口,其他数字的单位为电阻
set_driving_cell -lib_cell FD1 -pin Q [get_potrs IN1] //指定一个真实的外部单元来进行驱动,指定cell和cell的哪个引脚来进行驱动,不指定引脚的话也会有个默认引脚
set_input_transition 10 [get_ports IN1] //也可以直接指定某个输入端的转换时间
(4)设置电容负载
同理,默认情况下外部端口电容负载为0
set_load 5 [get_potrs IN1] //直接设置为某个具体的值
set_load load_of cell/lib/pin [get_ports out1] //设置为某个特定单元的引脚,一般为输入端口
set_load [expr [load_of my_lib/inv1a0/A]*3] out1 //相当于设置输出端同时连接3个反相器
和输入输出延迟一样,一般不知道每个模块输入端口的外部驱动单元和/或输出端口的外部输出负载,可以假设输入端口为驱动能力弱的单元驱动(即转换时间长),同时限制每一个输入端口的输入电容(负载),限制输出端口的驱动模块数目。
(5)设置设计规则约束(DRC)
一般设计规则约束的优先级最高,其中优先级依次为最大电容
、最大转换时间
、最大扇出
。
设置约束如下:
set DRIVE_PIN TECH_LIB/invla27/Y //设置某个单元的输出引脚为外部驱动单元
set MAX_CAP [get_attribute $DRIVE_PIN max_capacitance] //得到最大电容值
set CONSERVATIVE_ MAX_CAP [expr $MAX_CAP / 2.0] //除以一半,留点裕量
set_max_capacitance $CONSERVATIVE_MAX_CAP [get_ports IN1] //设置最大电容值
set_max_capacitance 3.0 $current_design //为整个设计添加最大电容约束
set_ max_transition $CONSERVATIVE_MAX_TRANS [get_ports IN1]
set_max_fanout 6 [get_ports IN1] //这里设置的是最大扇出负载,并不是扇出的绝对数目
get_attribute TECH_LIB/invla1/A fanout_load //0.6,用来查看load,根据上面可以得出6/0.6=10,u也就是可以驱动10个这样的单元
(6)面积约束
面积的衡量单位有三种:2输入与非门(2-input-NAND-gate)、晶体管数目(Transistors)、平方微米(Square microns),可以通过report_area
这个指令来判断面积的单位,输出为1第一种,输出为4第二种,输出为其他第三种。
不设置面积约束的情况下,DC也会对其进行面积优化,设置为0的话会进行最大限度的优化,直至不能再继续优化了。对于较小的设计,可以设置面积约束为0,但是对于较大的设计,这样会消耗很多的时间。
set_max_area 0
(7)完整的环境约束
set LIB_NAME slow //最差劲的情况
set WIRE_LOAD_MODEL tsmc090_w150
set DRIVE_CELL INVX1 //驱动单元选的是库中的反相器
set DRIVE_PIN Y
set OPERA_CONDITION slow
set ALL_IN_EXCEPT_CLK [remove_from_collection [all_inputs] [get_ports "$CLK_NAME"]] //从all_inputs这个对象集合中,移除掉CLK_NAME这些代表的端口
set MAX_LOAD [expr [load_of $LIB_NAME/INVX8/A]*10]
set_operating_conditions -max $OPERA_CONDITION -max_library $LIB_NAME
set auto_wire_load_selection false
set_wire_load_mode top
set_wire_load_model -name $WIRE_LOAD_MODEL -library $LIB_NAME
set_driving_cell -lib_cell ${DRIVE_CELL} -pin ${DRIVE_PIN} $ALL_IN_EXCEPT_CLK
set_load [expr $MAX_LOAD * 3] [all_outputs]
四、输出结果
综合之后把门级网表和约束交付给后端,进行布局布线和时钟树综合等流程。
如果时序违例大于时钟周期的25%
,需要重新修改RTL代码。
时序违例在10-25%
之间,可以进行优化,如利用指令compile_ultra
,在拓扑模式下进行编译,适合于高性能的电路优化。
//设置搜索路径和工艺库
set search_path "../lib/logic ../src" #设置搜索路径
set target_library " slow.db " #设置标准元件库
set link_library "* $target_library "
set symbol_library " smic18.sdb " #设置标准元件图标库
set access_internal_pins true
set report_path "./reports" #设置reports文件夹
set output_path "./outputs" #设置outputs文件夹
//读入设计文件
read_file -format verilog cic_filter.v #读取verilog设计文件
read_file -format verilog divider64.v
//指定当前设计
current_design cic_filter #指明主程序
link #工艺库链接
uniquify
set design_name [get_object_name [current_design]]
//设置环境约束,包括线负载模型
set_wire_load_model -name "smic18_wl10" #设置线负载模型
set_wire_load_mode top
//设置时钟约束
create_clock -period 156 -waveform {0 78} [get_ports clk] -name clk #设置时钟,周期156ns,脉宽0-78ns
create_generated_clock [get_pins div/clk_div] -source [get_ports clk] -divide_by 64 -name clk_div #分频64后的时钟
set_clock_latency 2.5 clk #延迟时间2.5ns
set_clock_transition 0.3 clk #翻转时间0.3ns
set_clock_uncertainty 1.5 -setup clk #建立时间1.5ns
set_clock_uncertainty 0.3 -hold clk #保持时间0.3ns
//设置环境约束
set_drive 0 [list clk rst_n] #设置输入驱动强度为0
set_driving_cell -lib_cell NAND2X1 in #设置驱动单元
set_input_delay 35 -clock [get_clocks clk] {in rst_n} #设置输入延时35ns
set_output_delay 35 -clock [get_clocks clk_div] [get_ports out] #设置输出延时35ns
set_load 2 [all_outputs] #设置输出负载为2pF
set_max_area 0
//输出综合前的时序信息和设计信息
check_design > $report_path/check_design_before_compile.rpt
check_timing > $report_path/check_timing_before_compile.rpt
//综合的指令compile
compile
compile -incremental_mapping -map_effort high
//把文件进行保存,DC是不会保存的
write_sdf -version 2.1 $output_path/${design_name}_post_dc.sdf #时序描述
write -f ddc -hier -output $output_path/${design_name}_post_dc.ddc
write -f verilog -hier -output $output_path/${design_name}_post_dc.v #网表
write_sdc $output_path/${design_name}_post_dc.sdc #约束
//报告时序、面积、功耗等相关信息
report_constraint -all_violators -verbose > $report_path/constraint.rpt
report_qor > $report_path/qor.rpt
report_power > $report_path/power.rpt
report_area > $report_path/area.rpt
report_cell > $report_path/cell.rpt
report_clock > $report_path/clk.rpt
report_hierarchy > $report_path/hierarchy.rpt
report_design > $report_path/design.rpt
report_reference > $report_path/reference.rpt
report_timing > $report_path/timing.rpt
//最后检测时序、设计信息
check_design > $report_path/check_design_post_compile.rpt
check_timing > $report_path/check_timing_post_compile.rpt
#start_gui
五、简答
1、目标库和链接库的区别
target library
是rtl代码映射到工艺库时stdcell所在的库,link library
是包括了target library,同时还包括了设计中用到的IP等宏模块,查找reference进行连接时所搜寻的库,是为了更好地理解design。
link库路径面前加*号表示开辟一块单独的内存空间给DC自己使用,然后先搜寻内存中已有的库,然后再搜寻变量link_library指定的其他库。DC搜寻的库为search_path指定的目录(比如说之前读入设计时读入了库a,库a存到内存里;这时DC在进行综合的时候,发现缺少某个东西,于是就先从库a里面找,找不到时就会从列表里面的变量路径中找)。
一般情况下,我们只用一个工艺库,需要引用目标工艺库,因此指定target_library
;此外我们还有可能用到synopsys公司的IP核,因此需要指定他的DW库。