网络课程《数字集成电路静态时序分析基础》的笔记
地址:https://www.iccollege.cn/portal/courseDetail/193.mooc
TCL 的应用
Synopsys Tcl
例如,统计时钟数量,人数显然不合理,可以用脚本语言统计,但是可以更加简单,直接用 Synopsys Tcl 的拓展命令更加便捷
参考资料
TCL 在 EDA 工具中的拓展与应用
通过对 Design Object 的分析,了解和学习 DC 获取电路并进行解析的方法
常见指令
get_ports
语法格式:get_ports portsName
指令功能:返回 design 中对应的 port object
如何查看 deign 当中有没有一个叫做 CLK 的 port?
get_ports CLK
{CLK}
- 如何查看 deign 当中有没有一个 port 叫做 SPI?
get—_ports SPI
No object Found!
- 查看 design 当中所有的 port(*可以统配任何字符)
get_port *
{A B C D CLK OUT[0] OUT[1]}
- 假设 port 名字交{CLKA CLKB OUTA OUT B INA INB},如何得到所有 C 开头的 port?
get_ports C*
{CLKA CLKB}
get_cells
- 语法格式:get_cells cellsName 指令功能:返回 design 中对应的 cell 的 instance name object
- 查看是否有一个叫 U4 的 cell
get_cells U4
{U4}
- 查看所有 cell
get_cells *
{U1 U2 U3 U4}
- 查看以 3 结尾的 cells
get_cells *3
{U3}
get_nets
- 语法格式 :get_nets netsName 指令功能:返回 design 中 net 的 object
- 查看 INV 开头的 net
get_nets INV*
{INV0 INV1}
- 查看所有 net
get_nets *
{A B C D CLK BUS0 BUS1 INV0 INV1 OUT[0 OUT[1]]}
- 查看有多少个 net
llength [get_object_name [get_nets *]]
11
sizeof_collection [get_nets *]
11
get_pins
语法格式:get_pin pinsName
指令功能:返回 design 中 pin 的 object
查看叫 Z 的 pin
get_pins */Z
{INV0/Z INV1/Z}
- 查看 Q 开头的 pin
get_pins */Q*
{ENCODER/Q0 ENCODER/Q1 REGFILE/Q[1] REGFILE/Q[0]}
数据类型
数据类型:”object(对象)“及其“属性”
说明:
- object 使 tcl 的一个重要拓展常见对象有四种 cell、net、port、pin 每种 object 有他的属性任何一个属性都可以用 get_attribute 得到 list_attribute -class *可以得到 object 的属性部分属性可以用 set_attribute 来设置
Cell object
- 属性 ref_name:用来保存器 map 到 reference cell 名称
get_attribute[get_cell -h U3] ref_name
{INV}
Pin object
- 属性 owner_net:用来保存与之相连的 net 的名称
get_attribute [get_pins U2/A] owner_net
{BUS0}
Port object
- 属性 direction:用来保存 port 方向
get_attribute [get_ports A] direction
{in}
get_attribute [get_ports OUT[1]] direction
{out}
Net object
- 属性 full_name:用来保存 net 的名称
get_attribute [gets_nets INV0]
{INV0}
get_object_name [get_nets INV0]
{INV0}
get_attribute INV0 full_name
Error:No attribute found
理解属性以后,就可以完成更多的任务:
- get_* -f:-f 这个 option 可以用来过滤属性,以得到我们想要的 object 得到所有方向是 input 的 port
get_ports * -f "direction==in"
{A B C D CLK}
- 得到所有方向是 output 的 pin
get_pins * -f "direction==out"
{U1/Q0 U1/Q1 U2/Z U3/Z REGFILE/Q[0] REGFIEL/Q[1]}
- 得到所有 ref_name 是 INV 的 cell
get_cells * -f "ref_name==INV"
{U2 U3}
- 如何的得到电路中所有的 inverter,那么应该输入什么样的脚本?
1. 直接使用 Synopsys TCL 指令
get_buffers -inverter
2. 人工拓展 TCL 指令
get_inverters
使用 TCL 语言控制设计 EDA 工具
讲述一个简单的、入门级的 Synopsys DesignComplier 自动化方案,供初学者参考,感兴趣的同学可以对该方案进行优化升级
特点
- 全自动化普适性与可重用性,修改参数即可应用到不同设计中
自动化电路综合平台只需要用户将待综合的设计与库文件放入一个文件加,修改与带综合设计对象有关的环境变量参数,在命令窗唤醒 DC 的指令,即自动化地完成综合过程,并得到综合后的网表文件和所需报告
运行流程:
- 运行 run.csh 脚本,启动 DC
#!/bin/csh -f
# 清除之前的文档
rm -rf *.log *svf alib* reports log work
# 新建文件夹
mkdir reports work
# 启动 DC 并运行 top.tcl
dc_shell-xg-t -32bit -f ./top.tcl
- 建立 reports 与 work 两个文件夹。reports 文件夹存放报告,work 存放文档和脚本启动顶层脚本 top.tcltop.tcl 按先后顺序启动子脚本,最总生成 script.tclDC 读取 script.tcl 中的约束,最总完成综合,并将所有报告写入 reports 文件夹中
top.tcl 脚本运行机制:
- set_library.tcl:生成设定库文件中的 search path 的约束 read_design.tcl:生成读入设计文件的约束 create_clock.tcl:生成时钟源相关的约束 set_rst.tcl:生成复位端口的约束 set_io.tcl:生成输入输出端口的约束 set_cons.tcl:生成保存门级网表、各种 reports 文件的约束
注意:
- 以上所有约束都自动生成,无需人为干预库文件、代码、时钟、复位、输入输出等均根据代码自动进行匹配,并生成相应的约束最终所有约束都被写入到 script.tcl 中,供 DC 读取,完成最终的逻辑综合过程
代码读入约束生成
工作流程:
- 设计文件通常使用 verilog 文件,所以拓展名通常为 v,所以先将变量 extension 设为 v 调用 filelist.tcl 脚本,将所有拓展名为 v 的文件的文件路径输出到一个名为 v_list 的文档打开 v_list 文档,根据文件的内容读入设计文件的指令输出道道 script.tcl 脚本
set extension v
source[file join $::script_path test/filelist.tcl]
#调用 filelist.tcl 脚本
set des[open[file join $::script_path test/work/v—list]r]
set design [gets $des] #打开 vlist 文档
for{}{$design!=""}{set design [gets $des]}{
puts $script [format "read_file -format verilog %s"$deslgn]
#输出读入设计文件指令
}
puts $scnpt[format "current_design %s" $top]
#输出设置顶层设计指令
代码 filelist 生成模块 filelist.tcl
功能:便利目标文件下所有文件,并将拓展名(.v)符合要求的文件完成路径输出到指定的文档,最终形成 DC 读取 verilog 代码的约束,写入 script.tcl 中
工作流程:
- 将工作路径切换到指定的工作路径判断当前目录下的文件拓展名是否与设置的变量 extension 一直,如果一致,就将该文件路径输出到指定的文件如果有文件夹,则递归调用本程序,直至结束
proc FindFile{myDirresult}{
if([catch {cd $WDir} err]}{
puts $result $err
return}
foreach myfile [glob-nocomplam *]{
cd $myDir #切换到对应路径
if{[string equal $myfile ""]}{
return} #如果是空文件夹就返回
set fullfile [file join $myDir $myfile]
if{[file isdirectory $myfile]}{
FindFile $fullfile $result #如果有下一级路径则递归调用本函数
}elseif{[string equal [file extension $fullfile] [format ".%s" $::extension]]){#判断扩展名是否与要求一致
puts $result $fullfile}}}
时钟约束生成子模块
功能和流程:
- 首先调用 parameter.tcl 脚本,读取其中用户对时钟源指定的参数,如时钟周期 等;调用 find_clk.tcl 脚本,该脚本会将搜索顶层设计中的所有的 clk 端口,并将所有搜索结果输出到一个名为 clk_list 的文档;打开 clk_list 档,将对时钟端口施加约束的指令输出到 script.tcl 脚本。
source [file join $::script_path test/findclk.tcl]
#调用 find_clk.tcl 脚本
set a [open [file join $::script_path test/work/clk_list] r]
#打开 v_list 文档
set b [gets $a]
set result [open[file join $::script_path test/work/script.tcl]
#DC 时钟约束
for {} {$b!=""}{set b [gets $a]}{
puts $result [format "create_clock -name "clock" -period %u -waveform {0 %d}{ %s }" $::clk_source[expr $::clk_source/2]$b]
#将生成时钟源的指令输出到 scnpt.tcl 脚本
puts $result [format "set_dont_touch_network [get_ports%s]"$b]
#对时钟网络设置 don't touch
puts $result [format "set_drive 0 [get_ports%s]"$b]
#设置时钟端口驱动为无穷大
puts $result [format "set_ideal_network [get_ports%s]"$b]
#设置时钟端为理想网线
}
close $result
匹配时钟端口子模块
功能:搜索代码中所有的时钟端口,将结果输出到 work 文件夹下的 clk_list 文档
工作流程
- 打开 v-list 文档,在其中找到顶层设计的路径,并打开设计文件;利正则表达式匹配其中的 clk 端口,并将匹配到的时钟端口的端口名输出到 work 文件夹下的 clk_list 文档
for {} {[eof $designfile]==0}{set fdesign [gets $designfile]}{
if{[regexp{input.*} $fdesign a]}{
#利用正则表达式匹配到声明输入端口那一行
if{[regexp {[^,( ]*clk[^,;]*}$a rport]}{
#利用正则表达式在那一行匹配后缀为 clk 的端口
puts $fport $rport
#将匹配到的端囗名输出到 clk_list 文档
}
}
}
- 其余脚本工作机制类似。最终,所有的约束都被写入了 script.tcl 中。script.tcl 脚本完全由自动化电路综合平台生成,并非人工编写;在自动化电路综合平台运行后,由顶层脚本调用各子模块脚本生成该脚本。生成该脚本后,由顶层脚本调用该脚本,由此实现对设计的综合。子模块脚本生成该脚本。生成该脚本后,由顶层脚本调用该脚本,由此实现对设计的综合。