静态时序分析(STA)是通过工具对同步电路中所有存在的时序路径进行分析,检查是否存在时序违例。是标准的timing sign-off(时序签字)的工具。
PT和综合的过程和命令都是十分相似的;
!!与综合过程中对时序检查的区别:PT使用的是更加精准的时序模型,并且使用PT做STA会扫描所有的corner,而综合一般只做一两个corner
静态时序分析具有以下功能
补充知识:PVT:Process、Voltage、tempreture
常用的工具
时序单元的相关约束
时序路径:
时序路径(timing path)指设计中数据信号传播过程中所经过的逻辑路径。每一条时序路径都存在与之对应的一个始发点和一个终止点。
始发点:组合逻辑输入端、时序单元输入端;
终止点:组合逻辑输出端、时序单元输入端;
这样就有4种时序路径的组合:
1、输入端到触发器;
2、触发器到触发器;
3、触发器到输出端;
4、出入端到输出端;(需要虚拟时钟??)
PT的输入输出文件:
输入文件(【】表示非必须):
输出文件:
set_propagated_clock [all_clocks]设计成propagate后是一个实际的延时(实际的线网延时),这步是必不可少的。(没设置的话clock默认是理想的具有无穷大的驱动能力,时序就不准确)
时钟的创建,需要知道在哪一个端口创建时钟,以及时钟的频率,相位等。还要知道时钟之间的相互关系
设置内部transition约束,输入输出的延时控制,输入输出的驱动能力/负载;
设置时钟的不确定性。设置的值可以比DC时的小,因为skew和latency已经确定了。主要是预防jitter以及预留一些余量;
设置约束文件——OCV(on chip variation)
早期的工艺没有OCV,直接BC_WC(Bset_coner,Worst_coner)分别检查hol/setup时序;进入深压微米后,芯片内部不同位置的PVT情况不同,更差情况是同一条时序路径上launch path和capture path的PVT不同
假设date path(Launch path)处在WC,clock path(capture path)处在BC,有少量的偏差。通过引入OCV用derate来模拟实际的这种情况,并保留一定的余量,按一定的系数放大或者缩小,来模拟OCV的情况。比如Launtch的正常的延时是A,系数是0.95,则现在的延时是0.95A,Capture path正常的延时是B,系数是1.03则现在的延时是1.03B
设置约束文件——AOCV(更高级的OCV,之前是对整个芯片使用统一的derate,不是特别可靠)
两种启动PT方式
PT打开时会自动运行当前目录下的.synopsys_pt.setup文件。一些统一的参数配置等可以写在这个文件里。
脚本分步骤运行以及source一次性运行
pt_shell -f top_pt.tcl -output_log_file top_pt.log
可以用history查看之前使用过的命令或者上下箭头
一般由专门研究工艺的CAD team设计一个合理的timing sign-off标准。对不同的PVT分别设置什么derate。过分悲观会增大面积,过分乐观可能导致实际芯片时序有问题。
针对不同的Library会分别启动PT逐个把所有corner都处理一遍,并保存对应的session。一个PT处理一个corner,多运行几次PT。
每次PT设置不同的derate。只有每次PT的timing都通过了整个timing才能算通过。
用pt_shell -multi_senario可以同时导入所有的session。并用fix_eco_drc以及fix_eco_timing修复timing,并给出timing ECO文件。
后端会根据ECO文件进行进一步修复
迭代直到时序收敛
## file :top_pt_ff.tcl
set SCRIPT_FILE script
set CORNER saed90nm_max_hth
###############################################################
###### 设置STA环境 ######
###############################################################
source -echo ./$SCRIPT_FILE/set_env.tcl
source -echo ./$SCRIPT_FILE/file_create.tcl
###############################################################
###### 指定STA库文件 ######
###############################################################
set search_path [list \
./ \
../ \
/home/XXX/fab/synopsys90nm_lib/stdcel/db/ss1p08v125c \
]
#set target_library [list ${CORNER}.db]
set link_library [list "*" ${
CORNER}.db]
set_app_var report_default_significant_digits 4
###############################################################
###### 读取Netlist ######
###############################################################
puts "### read design started"
read_verilog $NETLIST
current_design $WORKING_DESIGN
link_design -verbose
puts "### read design done"
set_operating_conditions -analysis_type on_chip_var -library [get_libs ${CORNER}*]
###############################################################
###### 读取SPEF ######
###############################################################
############# read spef ################
set parasitics_log_file $REPORT_PATH/parasitics_command.log
set_app_var si_enable_analysis true
set_app_var si_filter_per_aggr_noise_peak_ratio 0.01
set_app_var si_xtalk_delay_analysis_mode all_path_edges
if ($EXIST_SPEF) {
read_parasitic -keep_capacitive_coupling $SPEF_FILE -verbose
complete_net_parasitics
report_annotated_parasitics -check -constant_arcs -list_not_annotated -max_nets 100000
}
###############################################################
###### 设置约束文件 ######
###############################################################
source -echo ./${
SCRIPT_FILE}/read_constraints.tcl
update_timing -full
set_timing_derate -early [expr 1 - 0.05]
set_timing_derate -late [expr 1 + 0.03]
# write sdf
write_sdf -context verilog -significant 4 $OUT_PATH/${
WORKING_DESIGN}.sdf.setuphold_recrem -version 3.0 -include {
SETUPHOLD RECREM}
write_sdf -context verilog -significant 4 $OUT_PATH/${
WORKING_DESIGN}.sdf -version 3.0
######################### save session ###################
if {
$SAVE_SESSION == 1} {
save_session $DATA_OUT/$CORNER/session
set f [open "restore_session_${CORNER}.csh" w]
puts $f "\
#!/bin/csh
pt_shell -sgq normal:1c:4m -x \"restore_session $OUT_PATH/session\"
"
close $f
exec chmod +x "restore_session_${CORNER}.csh"
}
###############################################
###############################################################
###### 输出报告 ######
###############################################################
source -echo ./${
SCRIPT_FILE}/report.tcl
# get fanout number
#sizeof_collection [get_pins -leaf -of [get_nets x_stdblk_rtl/inst_sif/ADDR1[1] ] -filter "direction==in" ]
set_env.tcl:
### file :set_env.tcl
set WORKING_DESIGN plus_pipe
set SOURCE_FILE source_file
set NETLIST ./${
SOURCE_FILE}/${
WORKING_DESIGN}.v
set SPEF_FILE ./${
SOURCE_FILE}/${
WORKING_DESIGN}.spef
set file_version cp_test
set RPT_DIR RPT
set OUT_DIR OUT
### 设置的控制变量
set SAVE_SESSION 1
set REPORT_GEN 1
set EXIST_SPEF 0
set RPT_OUT [format "%s%s" $RPT_DIR/ $file_version]
set DATA_OUT [format "%s%s" $OUT_DIR/ $file_version]
set REPORT_PATH [format "%s%s" $RPT_OUT/ $CORNER]
set OUT_PATH [format "%s%s" $DATA_OUT/ $CORNER]
file_create.tcl :创建目录结构
### file : file_create.tcl
if {
[file exist $RPT_DIR]} {
echo "File $RPT_DIR already exist"
} else {
exec mkdir $RPT_DIR
echo "Creating $RPT_DIR !!!"
}
if {
[file exist $RPT_DIR/$file_version]} {
echo "File $file_version already exist"
#exec rm $RPT_DIR/$file_version -r
#exec mkdir $RPT_DIR/$file_version
#echo "Re-create $file_version files"
} else {
exec mkdir $RPT_DIR/$file_version
echo "Creating $file_version in $RPT_DIR !!!"
}
if {
[file exist $RPT_DIR/$file_version/$CORNER]} {
echo "File $file_version/$CORNER already exist"
exec rm $RPT_DIR/$file_version/$CORNER -r
exec mkdir $RPT_DIR/$file_version/$CORNER
echo "Re-create $file_version files"
} else {
exec mkdir $RPT_DIR/$file_version/$CORNER
echo "Creating $file_version/$CORNER in $RPT_DIR !!!"
}
if {
[file exist $OUT_DIR]} {
echo "File $OUT_DIR already exist"
} else {
exec mkdir $OUT_DIR
echo "Creating $OUT_DIR !!!"
}
if {
[file exist $OUT_DIR/$file_version]} {
echo "File $file_version already exist"
# exec rm $OUT_DIR/$file_version -r
# exec mkdir $OUT_DIR/$file_version
# echo "Re-create $file_version files"
} else {
exec mkdir $OUT_DIR/$file_version
echo "Creating $file_version in $OUT_DIR !!!"
}
if {
[file exist $OUT_DIR/$file_version/$CORNER]} {
echo "File $file_version/$CORNER already exist"
exec rm $OUT_DIR/$file_version/$CORNER -r
exec mkdir $OUT_DIR/$file_version/$CORNER
echo "Re-create $file_version files"
} else {
exec mkdir $OUT_DIR/$file_version/$CORNER
echo "Creating $file_version/$CORNER in $OUT_DIR !!!"
}
执行以上内容得到新的目录结构
OUT:存放输出文件
RPT:存放报告
read_constrains.tcl:
set timing_disable_clock_gating_checks true
set timing_enable_multiple_clocks_per_reg true
set enable_recovery_removal_arcs true
set timing_report_unconstrained_paths 1
create_clock -name CLK_IN -p 10 [get_ports CLK_IN] -waveform {
0 5}
set_max_transition 1.0 [current_design]
set_max_transition -clock_path 0.90 [all_clocks]
set_clock_transition 0.9 [all_clocks]
set_input_transition 0.89 [all_inputs]
set_driving_cell -lib_cell NBUFFX2 -pin Z -no_design_rule [all_inputs]
set_load [load_of ${lib_slow}/NBUFFX2/INP] [all_outputs]
#set_load 0.02 [all_outputs]
#set_load 0.006484 [all_outputs]
set_input_delay 3 -clock CLK_IN [all_inputs]
set_input_delay -max 5 -clock CLK_IN {
PLUS_A PLUS_B}
set_input_delay -min 2 -clock CLK_IN {
PLUS_A PLUS_B}
set_output_delay 1 -clock CLK_IN {
COUT SUM_OUT}
#set_multicycle_path -setup 2 -from A -to B
#set_multicycle_path -hold 1 -from A -to B
# false path
set_false_path -from [get_ports RST]
report.tcl
puts "### reporting started"
if {
$REPORT_GEN == 1} {
update_timing -full
redirect -tee -compress -file $REPORT_PATH/all_clock.rpt.gz {
report_clock -skew}
#check multiple clocks pe$REPORT_PATH
redirect -tee -compress -file $REPORT_PATH/check_timing_multiclock.rpt.gz {
check_timing -over {
data_check_multiple_clock}}
#check no clocks
redirect -tee -compress -file $REPORT_PATH/check_timing_no_clock.rpt.gz {
check_timing -over {
no_clock} -verbose}
#check ideal clocks
redirect -tee -compress -file $REPORT_PATH/check_timing_ideal_clocks.rpt.gz {
check_timing -over {
ideal_clocks} -verbose}
#check input delay
redirect -tee -compress -file $REPORT_PATH/check_timing_input_delay.rpt.gz {
check_timing -over {
no_input_delay partial_input_delay} -verbose}
#check no driving cell
redirect -tee -compress -file $REPORT_PATH/check_timing_no_driving_cell.rpt.gz {
check_timing -over {
no_driving_cell} -verbose}
#check loops
redirect -tee -compress -file $REPORT_PATH/check_timing_loops.rpt.gz {
check_timing -over {
loops} -verbose}
#check unconstrained endpoints (clock-domain crossing may be included).
redirect -tee -compress -file $REPORT_PATH/check_timing_unconstrained_endpoints.rpt.gz {
check_timing -over {
unconstrained_endpoints} -verbose}
#check disbled timing arcs
redirect -tee -compress -file $REPORT_PATH/disable_timing.rpt.gz {
report_disable_timing -nosplit}
#constraints violations
redirect -tee -compress -file $REPORT_PATH/violators_short_all.rpt.gz {
report_constraint -all_violators -nosplit}
#setup timing
redirect -tee -compress -file $REPORT_PATH/violators_short_setup.rpt.gz {
report_constraint -all_violators -max_delay -nosplit -recovery}
#hold timing
redirect -tee -compress -file $REPORT_PATH/violators_short_hold.rpt.gz {
report_constraint -all_violators -min_delay -nosplit -removal}
#report_timing
alias report_timing_summary report_timing -path summary -nosplit -slack_lesser_than 0.0 -max_paths 1000
redirect -tee -compress -file $REPORT_PATH/violators_summary_setup.rpt.gz {
report_timing_summary -delay max}
redirect -tee -compress -file $REPORT_PATH/violators_summary_hold.rpt.gz {
report_timing_summary -delay min}
#transition
redirect -tee -compress -file $REPORT_PATH/violators_short_trans.rpt.gz {
report_constraint -all_violators -max_transition -min_transition -nosplit}
#qor
puts "##### reporting qor #####"
redirect -tee -compress -file $REPORT_PATH/qor.rpt.gz {
report_qor}
}