第六章 dc_shell综合脚本
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第六章dc_shell命令解释程序
第一节设计目标
6-1-1背景介绍
dc_shell 是Synopsys Design Compiler的shell(命令解释程序),与unix的shell 类似。
Unix的C shell 和Bourne-shell作为命令解释程序,在用户和unix 核之间实现了功能极强的接口程序。
相同地,Dc_shell最为Synopsys Design Compiler的功能极强的命令解释程序。
象unix shell 提供程序设计语言在unix 文件系统中操作一样,dc_shell 提供script(脚本)语言在Design Compiler 的设计中操作,且仿造unix shell 的相同的结构。
用dc_shell 脚本综合设计有许多优点:首先,脚本执行速度比象design analyzer 交互式的界面快得多,脚本也用来证明综合设计的过程。
更重要的是,脚本提供一个重复编译的机制,这不仅对设计的再利用重要,而且对于当要求一项函数改变时,再次产生设计文件的所要求的时间最小化也很重要。
所有的这些优点源于使用脚本自动走完综合流程。
但是,dc_shell 脚本能够做的远不只这些,它能扩展Design Analyzer和Design Compiler的功能。
一些Design compiler命令的顺序由脚本得出。
大多数经验丰富的Synopsys的用户将脚本和Design analyzer结合使用来分析和优化设计。
6-1-2 目标程序类型的审阅
dc_shell脚本生成设计目标程序和编译属性来引导综合流程。
当编写dc_shell脚本时,考虑正在运行的目标程序/信息的类型是很重要的。
这一节从“Design Compiler Family Reference Manual”的章节中总结了“design compiler”的概念。
6-1-2-1 实例、网络、端口
原理图由三个基础的构件组成:实例、网点、端口。
实例是代表逻辑子程序或层次的符号,网络是代表在实例之间有电气连续性的导线,端口是用来代表层次连续性的线路终结器。
这些都是标准的术语。
使设计者感到新颖的是reference 的概念。
6-1-2-2 单元、引用、设计
如果一实例代表一逻辑子程序,则它能代表什么类型的子程序呢?一实例能代表一库元件或一设计。
用许多术语描述设计是必须的因为一设计可能包含同一库元件(或子设计)的多重实例。
举例说,一典型设计包含与非门,设计中的每一门实例都被赋予唯一的单元名用来在非唯一的实例中彼此区分。
同样的,一设计可能包含多个加法器,与与非门不同,加法器一般来说不是库元件,加法器是一个可逐步分解成库元件和网络且相互连接后执行加法器功能的完全设计。
与库元件相同,每一子设计的实例都被赋予唯一的单元名。
库元件是无形的设计子程序且在设计中常被做为节点单元引用。
设计是逻辑块,它们可作为独立的设计或作为更大设计的子设计。
作为其它设计中连接上下关系的子模块,设计中每一个唯一的实例被作为一个分层次的单元引用。
在一个单独设计的上下关系中,每一个实例具有唯一的单元名,这些单元引用库元件或设计。
设计者可以对每个单元单独地进行优化,也可以通过布置属性或约束(在以下定义)对每个库元件或设计进行优化。
但是,属性被直接加至库元件或设计中,这可能影响包含引用这些库元件或设计的每一个设计。
图6.1 单元、引用、设计之间的关系
假设你想要影响一个单独设计中的每一个与非门的优化而没有影响其它设计中的与非门则将会如何呢?引用的概念使这成为可能,设计中的每一个单元不仅是库元件中或设计中唯一命名的实例,而且是引用库元件或设计的一系列单元中的一员。
参考以下图6.2的设计:
图6.2脉动计数器:count_16
这个分层次设计的顶层是一个16位的计数器,顶层设计由与非门、或非门、8位计数器组成。
在这层次设计的关系
中,有6个单元、3个引用、2个设计。
这些单元是u1、u2、u3、u4、u5、u6,引用是一个三输入与非门、一个三输入或非门和一个count8的设计。
设计包含count6和count8的设计。
第二节收集和控制信息
一些dc_shell的构件是用来收集和控制信息。
变量和属性是特殊方法、指定设计信息的主要知识宝库。
别名提供创建自定义的命令或改变一个命令的行为的技巧。
如find、filter、list命令对提取变量或设计目标程序中的信息有相当大的作用。
6-2-1 变量:储存信息
变量在dc_shell的章节中用来存储信息。
一些变量被事先定义了,它们对于desing compiler 有特殊的意义。
比如search_path这一变量,告诉design compiler 到哪里去找Unix文件系统下的用户的设计文件及库。
事先定义的变量分为11组。
组是组织变量履行相似功能的便捷方法。
比如说,系统组的变量包含design compiler 用来和Unix交互的信息。
由于变量可被任意分配给哪个组,所以可用group_variable命令创建或改变组。
表6.1列出11个事先定义好的组以及组包含的变量举例。
的单词一个值时,变量则自动产生了。
选择一个没有保存过的名字代表呢想要保存的值,然后使它与值相等,创建变量的句法与改变变量值的句法相同,给variable_name=value。
6-2-1-1变量介绍
所有的dc_shell变量都是全局的dc_shell变量。
变量不和设计数据库一起保存,一旦一段dc_shell结束了,所有在这段赋值的变量都不存在了。
所有的变量都是全局变量,没有局部变量(对当前脚本或当前设计使关系独立的)。
变量是严格分类的,也就是说,当一个变量创建后,它将保存某一类型的值。
变量能保存字符串、数字(整型或浮点型)、设计目标程序或列表。
设计目标程序包括设计、库、端口、总线、管脚、单元、引用、网络、时钟、根目录(也称为DB文件)。
列表是一组字符串、数字,设计目标程序可能在列表中被混淆。
一旦变量被创建后用来保存某一类型的值时,它只能被赋予那种类型的值。
如果两个脚本用相同的变量名来引用不同类型的信息,那么两个脚本是不相容的。
在这种情况下脚本是不相容的,而且在相同的dc_shell端不能共存。
当脚本赋予一个已存在的变量一个错误类型的值,将会报错且脚本会退出。
然而这种情况是容易避免和改正的。
首先,选择有代表性的要保存的值的类型以及要保存的值的含义来创建变量。
比如说,如果你想要保存当前驻留在内存中的设计列表时,你会键入:active_design_list=find(design,”*”),这命令搜寻所有驻留在内存中的设计并保存列表到active_design_list变量中(此例中的find命令将在以后做详细解释)。
其次,若你想用存储错误类型的变量,则删除此变量,然后保存需要的类型。
Remove_variable variable_name;variable_name=value.变量能维持设计具有唯一的性能。
如果在变量中存储的设计从内存中被删除了,那么也将从变量中被删除。
无论变量维持一设计还是包括设计的列表,这都是正确的。
以下的例子帮助阐明这种特性的原因。
启动dc_shell(或从design analyzer的命令窗口启动),读入设计,键入以上命令来初始化active_design_list变量。
List新变量查看它的内容,即list active_design_list。
active_design_list变量保存内存中所有变量的列表。
要从内存中删除一个设计,利用你刚才创建的变量来删除内存中所有的设计,即remove_design active_design_list。
发出以下的命令来验证当一个设计从内存中删除时,它们将从所有的变量中删除:
find design“*”
list active_design_list
为什么会发生这种情况?当设计从内存中删除时design compiler 删除了所有的引用,这保证未来的命令对不存在的设计目标程序不产生操作(一项实践操作可能对当前的dc_shell产生致命的牵连)。
6-2-1-2 事先定义的变量
这节描述一些重要的事先定义的变量。
1、dc_shell_status
每次dc_shell命令执行时,一个值返回到命令窗口(在命令提示之前立即返回)。
对于大多数命令来说,这值是整型的。
如果命令成功地完成了,则返回1,否则返回0。
返回值不只返回到命令窗口,它也赋予变量dc_shell_status。
这使调节后来命令的执行结果与前面命令执行结果一致成为可能。
这种特性的流程控制含意详细地描述如下。
不是所有地命令都返回一个整型值,举例说,find命令返回一个值地列表。
为了适应象这样的命令,dc_shell_status变量没有严格分类。
这种特性非常功能非常强大,但它要求设计者在利用dc_shell_status写脚本时清楚要返回dc_shell_status变量的类型。
2、current_design
大多数命令、约束、属性不像变量,它们没有全局的含义。
大多数命令对current_design是指定环境的。
基本说来,设计是可独立编译的单元,current_design变量告诉design compiler编译哪个设计。
象compile命令,大多数命令在current_design变量的环境中操作。
这对于design compiler的初学者来说是容易混淆的地方因为所有设计都彼此独立存在。
从技术上来说,一个设计可能包含另一个设计的引用,但它不会全部包含那个设计。
对于高层设计来说,引用的设计是独立存在的。
考虑前面介绍过的16位的计数器。
发出命令current_design count8,则接下来的所有的命令应用于8位的计数器而不是16位的计数器。
8位计数器可能在几个可能包含或不包含16位计数器的设计中被用到,在这种情况下,16位计数器是32位计数器的子设计吗?它能作为一个32位设计的实例,但它一直都作为一个16位的计数器而独立存在的(除非设计取消组)。
有两个原因希望指定设计的引用和独立设计之间存在差异。
首先,它促进了设计的重复利用;其次,它提供了有细密纹理的优化的机制。
在大型设计中,一些子模块可能对时间有严格的要求而另一些子模块可能对面积有严格的要求,通过定义每一子模块为一个设计,那么子设计能够单独地优化从而满足它们单独的设计目标。
3、current_instance和current_reference
设计者通常希望在current_design层次中进入一实例从而应用约束条件或观察层次路径的时序。
current_instance 命令允许设计者在不改变current_design的情况下改变特定实例命令的层次重点。
考虑图6-2中16位计数器。
在Design Compiler和Design Analyzer的以前版本中,进入U1即改变current_design 至count_8,对于16位计数器设计中U1这一实例8位计数器的时间信息和属性是不可见的(除非对count_8设计用characterize命令)。
Design Analyzer和Design Compiler使在不改变current_design的情况下改变层次重点。
考虑以下的命令顺序:
current_design count_16
current_instance U1
set_don't_touch U15
current_instance
这段代码将don't_touch加至16位计数器设计中的层次实例U1/U15中,它不影响16位计数器或8位计数器设计中的U6。
用set_don't_touch U1/U15命令将产生同样的效果。
在开发脚本时使用current_instance命令没有严格的必要。
在使用Design Analyzer观看实例时current_instance 命令的实际值使能够进入和操作实例。
如果你想用Design Analyzer交互式地开发脚本,current_instance命令会在你的许多脚本中起作用。
current_instance以与unix中的cd命令横穿文件层次相似的方式横跨设计的各层次,考虑以下的命令:
1 current_instance U1
2 current_instance .
3 list current_instance
4 current_instance
5 current_instance U6/U15
6 current_instance ..
7 current_design current_reference
这些命令说明了current_instance命令的句法的灵活性。
命令1将设计的重点转到U1,命令2列出current_instance (没有改变)。
与current_design相似,current_instance既是变量又是命令。
命令3完成与命令2相似的功能,即列出current_instance变量的值,命令4式current_instance复位,将设计重点转回到current_design,命令5将current_instance设置到比current_design低两级的实例中来,命令6将current_design移到高一层次的设计,命令7介绍current_design变量。
这变量一直包含current_design的引用。
命令7将current_design改变到通过current_instance引用的设计中来。
如果你进入到16位计数器的U6并想在所有的8位计数器的实例中将don't_touch属性应用到U15中来,你可能要使用以下顺序的命令:
current_design current_reference
set_don't_touch U15
current_design count_16
如果你打算在dc_shell中规则地使用current_instance命令,你可能要改变dc_shell的命令提示符来反射current_instance的值。
这能用shell_prompt= “dc_shell$CI>”命令实现。
6-2-1-3 初始化变量
由于变量是严格分类的,大多数在使用之前应该被初始化成想要的类型。
考虑以下的赋值:
new_var=my_design
假设new_var是以前不存在的新变量,那么new_var是什么类型的呢?它
依据my_design的类型。
如果my_design是一变量,则new_var采用my_design变量的类型和值。
如果my_design既不是一变量又不是一目标程序,new_var将是包含“my_design”的一字符串。
一般说来,在赋予一目标程序类型一个值之前没有必要初始化它们,但初始化别的变量是个好主意。
表6-2说明各
6-2-2 属性:储存目标程序的信息
属性在dc_shell段中提供另一种储存信息的机制。
与变量相似,一些属性是事先定义的并对design compiler具有特殊的意义。
属性储存特别的设计目标程序的信息。
考虑事先定义好的don't_touch属性,这属性能够加至单元、引用、设计或网络。
大多数synopsys用户熟悉don't_touch属性。
它表示“不要对此目标程序编译和优化”。
Design compiler识别几种不同类型的属性。
举例说,有事先定义的和用户定义的属性。
在事先定义的属性中,它们都是提供信息的,“read only”性不能被改变,标准属性能被用户设置。
一些事先定义的属性显示出“目标方向的继承性”。
这些事先定义的属性在Synopsys的attributes手册中列出。
表在Design Compiler Family Reference Manual中的第三章,给属性和操作者提供了很好的参考。
要寻求在线帮助,用help attributes命令,可列出每一个属性及它的含义。
Design Compiler Family Reference Manual中的第五章有事先定义属性的介绍,这对于Synopsys Design Compiler 的高级用户来说是必须遵循的阅读材料。
6-2-2-1检索属性
get_attributes命令返回指定目标程序上的特定属性的值,如果属性存在,get_attributes的句法为:
get_attributes object_list attribut_name[-quiet]
如果对于任意目标程序的指定属性不存在,则会发出错误并且dc_shell_status变量包含空格,{ }。
如果属性为一个或多个目标程序而存在,则属性列表的值将返回到dc_shell_status变量中。
属性既容易设置也容易获得。
许多命令如set_don't_touch命令被特定定义来设置一目标程序的属性。
为了设计被
current_design变量识别命令set_don't_touch current_design设置don't_touch属性为真。
除了所有的特殊属性的命令之外,大多数属性可用set_attribute命令设置,set_attribute的句法为:
set_attribute object_list attribute_name \attribute_value [-type data_type] [-quiet] 有效的data_type有浮点型、整型、字符串、布尔型。
不能用set_attribute命令代替set_don't_touch命令给当前设计加don't_touch属性(注意,don't_touch是不能被设置成假值的特殊的属性。
要解除目标程序的don't_touch属性,则要用remove_attribute命令)。
Set_attribute命令用来定义新属性。
假设一个工程技术队中的每一员给一项工程提供设计,这些工程师们都用高层次设计模式并产生了三种设计形式:行为级(软件模型)、RTL级(寄存器传输级描述)、结构级(可综合门级设计)。
在此高层次设计模式中,设计者将行为级设计当作不可综合的,结构设计是完全的,RTL级设计是可综合的。
设计者想将这些设计结合到一块芯片上分析,但他们想要一个在每一级抽象上很快识别设计的途径。
Design compiler使这变得容易。
设计者可以简单地将字符串型的属性叫“abstraction”加到每一个设计中。
假设在RTL级chip_A被编码用来做综合。
工程师执行以下命令对chip_A操作:
read –format vhdk chip_A.vhd
set_attribute chip_A abstraction “RTL”–type striong –quiet
write –hierarchy
这些命令为设计者创建Design Compiler的数据库文件(DB文件)以供使用。
如果另一个工程师对chip_B操作,且chip_B和chip_A交互,则设计者发出以下的命令:
read –format vhdk WHOLE.vhd
link
get_attribute chip_A abstraction –quiet
第一个命令读入引用chip_A和chip_B的WHOLE设计,第二个命令为chip_A和chip_B在DB文件里连接,第三个命令返回RTL值。
工程师知道他的合作伙伴的芯片准备做综合但还没有做综合。
在第五章开发了用户自定义的属性,此外的例子也很有用,不要局限于使用手册中提到的例子。
用户自定义的属性使定制dc_shell脚本语言来满足设计者独特的需求成为可能。
6-2-3 别名:自定义Design Compiler命令
与unix的c-shell相似,dc_shell允许用户为自己喜爱的命令或命令次序取新的别名。
发出以下命令创建别名: alias [alias_name [expandion]]
注意alias命令后所有的参数都是可选择的。
只键入alias会列出存在的所有别名,键入带有无扩展名的别名的alias 命令则会列出别名的当前扩展名。
重定义已存在的别名可更改别名。
考虑以下的例子:
alias readv “read –format vhdl”
alias an “anlyze –f vhdl”
alias anw “an –w WORK”
alias initialize_ports “set_drive 1 all_inputs(); \
set_load 1 all_outputs()”
alias report_slack “report_timing –to all_outputs() + \
all_inputs(-data_pins) –path end”
如果你使用VHDL Compiler或厌恶敲字,你会喜欢第一个命令。
它允许你替换read –format vhdl file_name命令成readv file_name命令。
第二个命令为新的analyze命令创建简写别名。
注意用第二个命令创建的别名在anw alias的定义中用到。
这别名分解vhdl文件到work库中(必须用define_design_lib命令定义work库)。
第四个命令是通常使用别名的例子,它创建在端口加更多的实际的默认drive和load属性的命令。
最后一个命令为设计分析创建别名:report_slack输出timing slack到每一个寄存器和端口。
要删除别名,用unalias alias_name 命令
6-2-4 find 和filter:搜寻信息
在介绍设计目标程序和它们的属性之后,约束和生成综合是紧要的。
但是,这方面的能力是使一个一般目的的综合工具切实可行的基础。
幸运的是很少对优化过程细致操作。
Synopsys用很少的用户交互即可产生很高质量的不同类型的电路。
即使再次保证这些,大多数设计者希望在综合过程中手工地控制一些步骤。
这为部分设计层次自定义综合过程的能力保证关键的设计模块能被完全的优化以满足特定的要求。
对高级综合群体来说有好主意,即用象find和filter命令只操作设计目标和属性相对容易:
Find [-hierarchy] object_type name_list
Find命令是dc_shell的函数的举例之一,它返回给dc_shell_status变量一个列表。
Find命令对拥有指定名字的特殊类型的目标程序的定位很有用。
有效的目标程序的类型有:设计、端口、引用、单元、时钟、网络、管脚、文件以及库。
为什么这些有效?由于目标设计程序是严格分类的,find命令能被用来保证对指定目标程序操作的命令的有序。
考虑前面讨论过的16位计数器。
如果发出set_don't_touch count8命令,则don't_touch属性将加在count8设计中。
在dc_shell中有一个隐含的搜索顺序。
当一个命令对不同类型的目程序操作时,数据库按以下顺序搜索与指定名字相匹配的目标程序:design,cell,net,reference,library element。
Find命令可明确地用来控制搜索地目标程序的类型,而不顾隐含的搜索顺序。
如果以下的命令:
Find reference count8
Set_don't_touch dc_shell_status
依次执行,则don't_touch属性将加在当前设计中的count8引用中。
它不影响在其它设计中的count8引用。
当Find命令和通配符“*”搭配使用时会更有用。
考虑以下的命令:
find cell “*”
find reference “co*8”
第一个命令返回当前设计中所有单元的列表,第二个命令返回以“co”开始并以“8”结尾的所有引用。
作为一个dc_shell的函数,find命令可嵌套在其它的dc_shell命令中。
为了在当前设计中将don't_touch加至所有的单元中,执行命令:set_don't_touch find(cell, “*”)。
要在基于current_design根下的完全层次设计中加don't_touch到所有单元,执行命令:
set_don't_touch find(-hierarchy cell, “*”)
注意园括号用来隔开调用函数嵌套命令的参数。
同时注意逗号用来在函数调用中分隔参数。
当函数嵌套在其它的命令和函数中,嵌套的函数在包含函数之前执行。
考虑以上的命令,首先,函数调用执行了,find函数返回当前设计层次的所有单元列表。
嵌套函数将它的结果返回到set_don't_touch命令中(代替dc_shell_status变量)。
set_don't_touch命令将一个don't_touch属性加至返回到find命令的list中的所有元素中。
假设你想要将当前设计中已映射到工艺库中的单元加至don't_touch属性,这是一个必须的命令举例。
工程师想要在设计中搜寻具有多数相同而不是一个名字的目标程序,filter命令满足这要求:
filter object_list “filter_expression”
filter_expression参数表明object_list的要返回的子集(或舍弃的)。
filter_expression的句法为:
“@attributes_name relational_operator attribute_value”
将don't_touch加至设计中的已映射到工艺库中的所有单元中,发出命令:
set_don't_touch filter( find(cell, “*”), “@is_mapped == true”)
当执行这命令时,find函数返回设计中所有单元列表到filter函数,filter函数随后返回具有is_mappe识别在属性设置成真的单元列表到set_don't_touch命令中。
注意@符号用来作为名字的属性以识别在filter_expression中的第一个参数。
相关的操作符(==)和attribute_value参数决定object_list的什么样的子集将被返回到filter命令中。
合法的操作符有:==(相等),!=(不等),>(大于),>=(大等于),<(小于),以及<=(小等于)。
注意操作符==和赋值等号=之间的差异,等号=用来赋值,不是相等操作符。
你想要多次使用混和的filter_expression,举例说,将don't_touch加至设计中除了引用低驱动的非门和缓冲器之外的所有单元(以致非门和缓冲器可被调整大小),用以下逻辑操作符使这成为可能:
set_don't_touch filter(find(cell, “*”), \
“@ref_name != inv && @ref_name != buf”
design compiler 识别&&(逻辑与)和||(逻辑或)两个逻辑操作符。
第三节控制流命令
dc_shell_status变量的介绍提到有条件地依次执行命令的能力,这能力依靠前面的命令的结果。
以下的流程控制命令允许这种或更多的能力:
·if
·foreach
·while
·break
·continue
这些命令在以下的章节中被描述。
6-3-1 if命令
最简单的流程控制结构是if语句。
它的句法为:
if (expression) {
then –statement –block
} else if (expression) {
else-if-statement-block
}else
else-statement-block
}
else if结构可能没有或有更多,else结构是任意的。
在if…else中if分支依次被求值直到一个值为真。
当一个值为真时,在{}中的语句块将被执行。
然后,执行将顺着树继续下去。
只有一个语句块被执行。
如果没有条件表达式的值为真,而一个else语句块存在,则将执行else语句块。
考虑以下的例子:
readv new_block.vhd
if (dc_shell_status != {}) {
compile
write
quit
}else {
quit}
}
这脚本段使用在前面创建的readv别名来读入VHDL文件,if分支紧跟read命令,read命令返回成功读入的设计到dc_shell_status变量中。
If句法决定设计的列表是否不空。
如果new_block.vhd被成功地读入了,则then语句块将被执行,并且设计在退出之前被编译、写入DB文件。
如果设计没有被成功地读入,else语句块将被执行并且dc_shell退出。
在此例中,条件表达将一变量和空格比较。
条件表达式不一定要包含相关的操作符,它可包含简单的变量因为design compiler为非布尔型的变量类型定义了布尔型值。
整型和浮点型变量的值如0(或0.0)的值时则所求值为假。
用{}列出变量(空表),其所求值为假。
其它所求值为真。
这样,此例中的条件表达式可以改写为:
if (dc_shell_status)
6-3-2 foreach命令
if语句在dc_shell中只有一个流程控制结构可用,foreach语句是在unix相等物后之后的模块,它是另一种形式。
当你想单独地对列表中的元素操作而不是对列表整体地操作时,Foreach语句会很有用。
许多设计团队喜欢将默认的dc_shell脚本文件共享。
设计团队中的成员一般使用这default.scr文件来将默认的约束应用到他们总体设计中的一部分。
Set_operating_condition “WCCOM”
Set_wire_load “10k”
Clock_list ={clk1 clk2 clk3 clk4}
Set_attribute all_inputs() is_clock false \
-type boolean –quiet
Set_attribute clock_list trut –type boolean –quiet
Create_clodk –name “CLK”–period 20 \
-wavefoem {0,10} clock_list
set_input_delay 5 –clock “CLK” \
filter(all_inputs(), “@is_clock !=true”)
set_driving_cell –cell “FD1” \
filter(all_inputs(), “@is_clock !=true”)
set_drive 0 clock_list
set_output_delay 15 –clock “CLK” all_outputs()
group_path –name “CLK”–critical_range 2
group_path –default “CLK”–critical_range 2
set_load 1 all_outputs()
这个简明的脚本创建了时钟网络的四个主枝干并且设置了与时钟相关的默认的输入输出延时,它还定义了线宽和操作环境,创建了默认的负载和驱动约束,并设置了时钟的critical_range 为2ns和默认的组。
这好像是一流的脚本,它甚至定义了is_clock属性来保证时钟输入和函数输入不延时。
但是这脚本有一个缺点,如果此脚本运行在不包含所有的四个时钟输入时会发生什么情况呢?如果此脚本应用到一个不包含任何主时钟的设计中又会发生什么情况呢?脚本会产生错误并失去约束设计的作用。
幸运的是,foreach命令能够克服此脚本的局限性。
Set_operating_condition “WCCOM”
Set_wire_load “10k”
Clock_list ={}
Foreach (possible_clock, { clk1 clk2 clk3 clk4})
{
find(port, possible_clock)
if (dc_shell_status)
{
clock_list =clock_list +possible_clock
}
}
Set_attribute all_inputs() is_clock false \
-type boolean –quiet
if (clock_list)
{
Set_attribute clock_list true –type boolean –quiet
Create_clodk –name “CLK”–period 20 \
-wavefoem {0,10} clock_list
} else {
Create_clodk –name “CLK”–period 20 -wavefoem {0,10}
}
set_input_delay 5 –clock “CLK” \
filter(all_inputs(), “@is_clock !=true”)
set_driving_cell –cell “FD1” \
filter(all_inputs(), “@is_clock !=true”)
set_drive 0 clock_list
set_output_delay 15 –clock “CLK” all_outputs()
group_path –name “CLK”–critical_range 2
group_path –default “CLK”–critical_range 2
set_load 1 all_outputs()
这个改进的脚本没有假设所有时钟都存在每一个设计中。
相反地,它将clock_list初始化成空的并且使用foreach 循环来将存在在current_design中的时钟加至时钟列表中。
Foreach语句的第一个参数是变量名。
在此情况下,变量名是possible_clock,Foreach语句的第二个参数是列表。
在执行的过程中,Foreach语句分配列表中的每个元素的参数给变量参数,然后执行Foreach语句块。
注意默认脚本推迟时钟的产生直到if…else分支遵循foreach循环。
if…else分支保证即使在current_design中没有时钟也能产生一个虚拟时钟。
这是关键的因为后来的set_input_delay命令和set_output_delay命令依据虚拟时钟clk的存在。
Foreach循环的句法为:
Foreach (varible_name, list_expression) {
Loop-statement-block
}
其中, list_expression被明确地包括在内因为它在以上默认的默认的约束脚本中,但使用嵌套的函数调用来导出list_expression往往更方便。
Root_design = current_design
Echo “Hierarchical Reference Report” > ref.rpt
Design_list =root_design +find(-hierarchy design, “*”)
Foreach (subdesign,list)
{
echo ““ >>ref.rpt
current_design subdesign
report_reference >>ref.rpt
}
current_design root_design
这个简短的脚本使用层次的find命令来返回当前设计中所有子设计的列表。
它将current_design预先挂起导设计列表中并使用一个foreach循环来产生层次设计中的所有设计的引用报告。
这输出报告重定向到unix的ref.rpt文件中。
当循环结束后,current_design被复位为root_design。
6-3-3 while命令
dc_shell中最后一个有用的控制流程语句为while循环。
While循环的句法为:
while (expression) {
while-statement-block
}
while循环中最重要的部分是表达式,如果表达式的值从不为假那么while循环将不会结束,这可能会造成while语句的无限循环。
考虑以下的例子:
count = 0
wild_string = “*”
cell_list =()
while (count <10) {
cell_list = cell_list +find(cell,wild_string)
wild_string = wild_string + “/*”
count = count +1
}
list cell_list。