第六章 dc - shell综合脚本(2)

2019-08-31 10:45

这个简明的脚本创建了时钟网络的四个主枝干并且设置了与时钟相关的默认的输入输出延时,它还定义了线宽和操作环境,创建了默认的负载和驱动约束,并设置了时钟的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

这些依次的命令与find(-hierarchy cell, “*”)相当。前三个命令将在while语句块中用到的变量初始化(其中第一个是整型的,第二个是字符串,第三个是列表)。While语句块附加了cell列表(那些在层次级上被wild_string指出的)到单元的列表中,然后它更新wild_string来考虑下一级层次并使计数器加一。如果While语句块没有使计数器加一,则While语句块会导致无限循环。 当while循环结束后,cell_list变量包含层次设计中的每个单元的列表,计数器变量等于10,变量wild_string等于“*/*/*/*/* /*/*/*/*/*/*/*/*”。 注意此脚本假定在当前层次设计中没有超过10级的子设计。由于在层次设计的每一级上必须有单元,当超过层次深度后,此脚本可通过改条件表达式 为一值为假的变量列表来改善。 wild_string = “*” cell_list = {}

new_cell_list = find(cell, wild_string) while (new_cell_list) {

cell_list = cell_list + new_cell_list wild_string = wild_string + “/”

new_cell_list = find(cell, wild_string) }

list cell_list

这个例子非常重要,为什么用这些依次的命令代替一个简单的层次的find命令呢?如果你只想要层次设计中的所有单元的列表,你将不会这样,但你想控制搜索顺序,搜索层次设计中所有的引用,或当你跨越设计层时有条件地执行命令,则while命令被证明是及其有用的。与filter命令的表达式相似,while命令的表达式可以是混和的表达式。 6-3-4 break和continue命令

break和continue命令只能用在while和foreach命令的语句块中。break命令立即退出最里面的循环结构,continue跳到最里面的循环结构的结尾而并不退出循环,并且启动下一个循环的重复操作。 注意break命令使改写以上的例子为没有表达式成为可能: wild_string = “*” cell_list = {}

new_cell_list = find(cell, wild_string) while (true) {

if (new_cell_list == {}) { break }

cell_list = cell_list + new_cell_list wild_string = wild_string + “/”

new_cell_list = find(cell, wild_string) }

list cell_list

重新考虑将set_output_delay约束加至所有的输出上的foreach例子,如果所选择的输出不需要约束会怎么样?没有必要的设计约束可能对设计质量产生负面的影响,所以改写此脚本以解决这个问题是十分有用的。假定一个命令为trivial的布尔属性已经加到不应该受约束的所有输出上(在VHDL/HDL源代码可用嵌套的脚本实现)。以下的脚本约束了所有的non_trivial的输出:

foreach (output_object, all_outputs()) {

if (get_attribute(-quiet output_object,trivial)) { continue }

set_output_delay 15 –clock “CLK” output_object }

第四节 在dc_shell使用unix命令

dc_shell的许多方面都是仿照UNIX的shell,在前面讨论的构造和UNIX命令之间存在着许多相似之处(如alias,foreach,if).甚至变量的构造对UNIX用户来说都是熟悉的。但是dc_shell存在更多类UNIX的特征。这一节简要地介绍输出重定向,历史记载,命令替换和shell命令。 6-4-1 输出重定向

如果你在运行一个编译一晚上的设计的脚本,你可能不要到处跑去看警告和错误信息,这些信息在你的脚本运行的时候反馈到命令窗口。Dc_shell允许将标准的输出重定向到一个文件中去,用UNIX的常规符号>创建一文件,用>>附加在一文件后。比如说,命令:

check_design >>error.log

将check_design返回的所有信息附加到名为error.log的文件后。这是及其有用的,因为重要的可能被丢失的run-time信息能被存档以供以后查阅。 6-4-2 历史记载和命令替换

在dc_shell命令行中键入“!!”则再执行最后一次执行的命令。UNIX命令替换dc_shell中的函数。!-n命令执行从最后一行数的第n条命令。!n在当前design compiler节中再次执行第n条命令。!text再次执行以text开头的最后的命令,!?text再次执行在命令字符串中的任意位置包含text的最后的命令。历史记载命令在命令窗口中打印寻呼前面执行过的命令的有序的列表。这对于决定你想要再次执行一个命令的所在行数有用(用!n),而且在结合输出重定向之后,history命令可被用来建立dc_shell脚本。history命令的句法为: history [n] [-r] [-h]

可选参数n列出最后的n条命令,参数-r指定按年月顺序排的且是反向的命令,参数-h指明命令的索引号码不会被和命令一起列出。命令:

history –h > script.file

实际上构建了自动操作从前面执行过的命令中创建命令脚本的任务。 6-4-3 shell 命令

虽然dc_shell脚本编程语言功能强大,它永远不如UNIX灵活。要在dc_shell中访问UNIX,Design Compiler提供了pwd,cd,ls,get_unix_varible,set_unix_varible命令:

·pwd:列出Design Compiler的工作目录

·cd directory:改变Design Compiler的工作目录到指定目录 ·ls directory:列出指定目录的文件 ·get_unix_varible(varible):返回UNIX环境变量varible的值 ·set_unix_varible(varible,value):设置UNIX环境变量varible的值为value ·sh command:调用UNIX来执行command(从bourne shell)

在这些命令中sh command是最不熟悉的但是功能最强大。Sh命令是UNIX命令被执行。,为了从UNIX文件中执行命令,get_unix_varible命令、set_unix_varible命令以及include命令和输出重定向配合使用,shell命令提供从dc_shell输出信息到UNIX的机制,在一个UNIX编程语言中操作而返回到dc_shell。总之,这五个dc_shell命令使dc_shell脚本变成可完全扩展的。 虽然此引用手册的重点是写dc_shell脚本而不是扩展dc_shell脚本,考虑一段样本代码段: dc_shell脚本:

home = get_unix_varible(“HOME”) temp = home + “/temp”

set_unix_varible(“TEMP_DIR”,temp) sh mkdir $TEMP_DIR

all_bussed_nets =find(net, “*[* “] foreach(net_member,all_bussed_nets) {

list net_member >> temp + “nets“ }

sh “sed –f busses.sed \\

$TEMP_DIR/nets |uniq >$TEMP_DIR/bussed_nets” sh “awk –f nets.awk \\

$TEMP_DIR/bussed_nets > $TEMP_DIR/create_nets” include temp + “/create_nets” sh rm –R $TEMP_DIR

sed script, “busses.sed”: s/.* “\\(.*\\)\\[.*/\\1/ awk script, “nets.awk”: {

print“create_bus find(net,\\ ““$1”[*\\] “$1” –reverse_sort” }

总之,脚本将总线上的独立索引的网络分组成总线型的网络(它们不影响总线端口)。当一个指定的应用要求扩展dc_shell命令时 Sh命令十分有用。Sh命令实际上扩展了dc_shell的脚本的能力。 6-4-4 创建自定义的命令

脚本是将默认约束应用到你经常使用的设计中吗?如果是这样,为什么不创建一个命令来执行脚本?你已经知道怎样做了,就像使用alias命令一样。将此脚本输入到UNIX文件中去,取名为default.scr,然后在你的.synopsys_dc.setup文件加一行:

alias def_con “include defaut.scr”

那么无论何时你想要将默认的约束应用到你的设计中,只要键入命令def_con(假定defaut.scr脚本在搜索路径下)。 6-4-5 excute命令

dc_shell的excute命令执行带有指定参数的命令: excute [-s] command [argument ?]

其中-s(开关)指定通过执行的命令输出的字符串必须被返回来代替命令状态。当使用别名和sh命令时,excute命令给予设计者定义复杂新命令的能力。 考虑以下命令: alias rdv execute –s sh rdv.csh alias run execute dc_shell_status rdv my_design;run

第一个命令用来创建执行rdv.csh的UNIX命令解释程序的脚本的别名,并且通过此脚本返回字符串的输出。注意当rdv别名被执行时参数被传到rdv.csh脚本中。第二个命令创建执行dc_shell_status值的别名。第三个行说明了怎样使用这些别名,它将my_design参数传到UNIX的rdv.csh程序中,然后执行rdv.csh返回的字符串。 #!/bin/csh

# USAGE:rdv.csh

# return a command sequence to dc_shel what will : # analyze # elabrate

# and reeinquish the VHDL_Compiler license set design=$1

set file = “${design}.vhd”

echo “anayze –f vhdl $file;elaborate $design;remove_license VHDL_Compiler” unset design,file exit

这个csh程序使dc_shell的一系列命令格式化后用来在放弃VHDL_Compiler的许可证之前分析和加工指定设计。Excute命令传递任意参数给一个命令并返回这个命令产生的字符串到dc_shell,在那它被赋值给一个变量和被执行。 Excute命令可和sh命令一起使用来执行UNIX字符串,这些字符串在dc_shell中是无效的。以下的举例将显示UNIX的tr命令可被用来将字符串列表翻译成以上的情况:

/* set list1 to a list of lowercase string */ dc_shell> list1 ={aa bb cc dd ee ff gg}

{ “aa”, “bb”, “cc”, “dd”, “ee”, “ff”, “gg”} dc_shell> list2={} {}

/* convert the strings to upper case,and parse the result back into a string */

dc_shell> list2=excute( -s “sh echo list1 | tr a-z A-Z”) { “AA”, “BB”, “CC”, “DD”, “EE”, “FF”, “GG”}

UNIX命令解释程序给一些字符以指定含义,比如说“*”。这些字符可能会作为sh命令的参数出现,这要注意。有一种办法避免这种情况,就是用一个文件作为储存的中介。

dc_shell>echo list1 >tmp_file 1

dc_shell>list2=execute ( -s “sh cat tmp_file | tr a-z A-Z”)

{ “AA”, “BB”, “CC”, “DD”, “EE”, “FF”, “GG”}

第五节 编译大型的层次化设计

在介绍编写dc_shell脚本必需的全部结构后,下面的任务是创建阐释层次编译的dc_shell 脚本。目的为有效编译任意的设计层次高效地编写脚本文件。 6-5-1 一般脚本的编写

客户化定位性能的设计思想最能满足这个目标,为此脚本应密切遵循charactrize/write_script/compile的方法。这种方法认为许多设计太大不能作为整体编译,需要提供一种机理来编译树状的子设计,从而满足设计层次环境和时序的要求。这种方法基本的六个步骤如下:

1:把整个设计层次读进设计编译器。 2:在顶层设计应用层次设计约束。

3:对每一个设计用charactrize命令获得模块级的约束(从层次约束中)。在低层设计前描绘高层设计的特征。 4:用write_script命令给一个文件写衍生的约束。

5:编译每一个子设计满足包含在write_script文件中衍生的约束。在高层设计前编译低层设计,放置低层设计一个don't_touch属性以阻止低层设计被再次编译。 6:把子设计连一块产生层次时序报告。

这种方法必需改进,确保脚本可在广阔种类的设计产生高质量的结果。对任何依赖于衍生约束的方法,其缺点是衍生的约束可能与设计目标的目的不一致。为说明这种缺点的限制,许多设计者用时序预算替代衍生的约束,用来约束他们的设计。

一个时序预算是在设计模块的接口之间通过在个体模块之中分派可利用时间的方式,实现基本约束的逻辑。 简单的情况,所有的模块都登记输出(或输出)。合适的时间预算给登记的接口和非登记得接口(可利用的时间的剩余部分)分配寄存器延迟(时钟周期少于一个寄存器延迟)。此时,时序预算和衍生的约束可以很好一起工作。

在模块接口之间组合逻辑进行分割时,可利用的时间依据设计者分割的目的进行划分。由于未优化的设计不可能反映在设计的分割目标中,时序预算对衍生的约束是合适的。另外,优化成规范的设计接口,应使用时序预算替代衍生的约束。为支持时序预算 以及层次编译方法中衍生的约束提供一种机理,在write_script程序中加进revise_script的步骤。Write_script命令列出设计的约束,不管它们是否为衍生的约束。因此,在描述设计的特征后,增强的方法可寻找一个revise_script脚本的存在性。若revise_script存在,revise_script将会覆盖有关指定在revise_script文件的任何约束衍生的约束。

新的约束覆写任何前面加在设计中有冲突的约束。由于Revise_script文件只涉及预算而不是衍生的约束,它需要补充衍生约束。在write_script产生前,write_script文件反映衍生约束的统一性。为同原来的方法相比较,反映这种改进,这种开发的方法遵照characterize/revise_script/write_script/compile方法(或简写成CRWC)。为使CRWC编译方法尽可能有弹性,脚本的设置中有两个深层次的改进。许多设计组共享脚本文件以便建立缺省约束(如wire_load,operating_condintions)及为项目预先做好时序预算。

为支持这种脚本,在层次编译时,在write_script和revise_script文件中CRWC会用到一个default.scr文件。另外,由于不同的设计模块有不同的设计目标,在每一个模块编译前将会按照脚本的方式置入一个策略脚本(strategy script)。这个策略脚本的目的是允许在编译前及时产生set_flatten set_structure命令,但脚本的使用不限于这些命令。设计者想运行的任何命令在编译前必需包含在设计的策略脚本中。Strategy_script脚本中的命令位于revise_script中,strategy_script结构为组织结构的弹性而简单存在。

CRWC层次编译法是一个七个步骤的方法:

1:读进设计编译器整个设计体系,移开设计体系存储器中不相关部分的任何设计。 2:在顶层设计中应用体系设计约束。

3:对每个设计,使用characterize命令得出模块级约束(从层次约束中)。在低层设计前描述高层设计的特征。 4:revise_script覆盖应用时序预算的衍生的约束。 5:用write_script写出约束的结果文件。

6:在策略脚本对每一个编译设置结构化和展平的选项后,编译每一个子设计以便满足在default_script write_script revise_script 文件约束。在高层设计前编译低层设计,加上低层设计的don't_touch属性(阻止低层设计被再次编译)。 7:把子程序连结一起产生体系层次时序的报告。

随着这种脚本的开发,提出理解脚本的背景的材料是必要的。实现CRWC的方法是开始讨论设计树、修建树、搜寻树、宽度首先(breadth-first)搜寻、深度首先(depth-first)搜寻、描述设计体系层次特征的概念,接着编译设计体系层次会聚一起实现这种方法。这儿介绍的脚本是CRWC方法的最小实现,因而在应用前,用一节提出可能扩展这些脚本的方法。

6-5-2 设计树

设计层次可以看作一棵树。如以下的设计层次:

在计算机科学术语中,设计的top和foo是两个独立设计树的根(roots)。多数设计有子(children),通过设计树

贯穿一个层次抵达(孙grandchildren在设计树向下有两层次,依次类推)。上图中foo的子有C、4、A。 类似,不是根(root)设计的所有设计都有父母(parents)。设计3 的父母是C(其祖父是foo)。最后没有子的设计叫树的叶(leaves)。在foo中树的叶是3、4、1、2 。

这些计算机科学术语在描述设计的层次是有用的。借来讨论层次处理的技术,这同计算机科学是平行的。按照搜寻

设计树非常容易考虑搜寻设计层次。 6-5-2-1 修剪树(pruning trees)

假设你在运行Design Analyzer,且已装进top和foo设计。你已在综合这些设计,决定重新编译设计B以改进性能。你可能设置当前的设计为B(用命令current_design B),改变或增加约束来鉴别新的设计目标,发出compile命令。那个编译不需要慢,但在存储器中仍有许多不在B设计树下的设计。为其它用途的自由存储器对修剪树是一个推动。

如果有较少的集合理论用在分析设计树种,修剪树的概念是容易理解的。Top和foo树设计的集合为{top,A,B,1,2,foo,4,3,C}。在B树中设计的集合{B,A,1,2}.如果你打算搜寻其中之一的集合,以便找到B设计中的一个单元,你搜寻哪一个集合?当然,你应该搜寻较小的集合。

修剪树是减少操作判定空间的过程。除了考虑那些同操作相关的子树下的设计,删去其它的所有的目标。不需删去存储器中的目标以便在处理时修剪,但由此释放的存储有它有利的副作用。

使用dc_shell有有多种方式修剪存储的设计。最简单的程序是利用设计编译器的层次寻找能力。思考以一下prune.scr,它可以修剪不在树根current_design层次中的存储的目标。Prune.scr执行3个任务:1.它初始化一个in_tree属性给存储中所有的设计的false;2.它用一个层次寻找这种加在current_design的true属性,以及在current_design层次中所有的设计;3.它删去不在current_design树下存储的所有的设计。一旦树被修剪,脚本删去设计的in_tree属性,这种属性不再是必需的。如:

1 set_attribute find(design,”*”)\\

in_tree false –type boolean –quiet

2 set_attribute current_design\\

in_tree true –type boolean –quiet

3 set_attribute find(design,”*”)\\

in_tree true –type boolean –quiet

4 removable_designs =filter(find(design,”*”),\\

“@in_tree !=true”

5 if (removable_designs) {

6 remove_design removable_designs }

7 current_design current_reference 6-5-2-2 搜寻树 (searching trees)

前面介绍的find命令对于搜寻设计树有完美的用途。这个命令有强的限制不能单独作为处理设计树的搜寻用途。然而,find 命令可以在存储所有的设计中返回。对于其它的目标类型,find命令仅在current_design目标返回一个列表。在整个设计树,编写的脚本当然能找到目标的列表(仅对一些目标类型,层次切换可以进行)。

扩展层次的find的能力是执行有用的搜寻设计树所必需的吗?考虑到层次编译方法的需要。第一步在设计树的根目录下应用约束,接着通过整个设计树向下特征化,一直到约束衍生到叶的层次。这需要设计树从顶向下的贯串。一个有序的搜寻能力当然能简化这个过程。遗憾是,命令find(design,”*”)返回一个存储设计的列表没有明显的顺序(事实上,它们按顺序装进存储器)。一个编写的脚本能返回树中一个有序的设计列表吗?答案是肯定的。

以上top的树做过再次安排。这份新的top层次替代图形的格式更准确反映设计设计编译存储器设计的组织结构。原先的图包含许多名字的复本。事实上,对每一个多层设计的关系照应,它包含一个设计名。这种新图包含每个设计名的拷贝。

这图安排清楚表明每一个设计与其他设计地关系如父亲关系。举例,设计A有直接的和有父辈关系的(包含在同A有关系的每个设计中):top 和B。设计A也向下连结每一个子(包含在同A有关系的每个设计中):1和2。

这图也演示在每个设计子图(或子树)存在多少代或层次的设计。叶层或层次0设计位于图形的最低端。有层次0作为子设计的设计叫做层次1。这个设计仅包含层次1的设计为A。

当图形按照下面的规则贴上标签时,设计也按照它们的层次作上标志。规则:N层次设计不包含比N-1层更高的设计,至少包含N-1层次和任何更低层的设计。

如果你发现这个新提出的设计树的概念感到困惑,参照返回原始树。从叶层到根层的设计都贴上标志,按规则贴上的设计标志独立代表设计的层次。

只有当所有子设计贴上标志时,设计才算贴上标志。分辨设计的层次同增加一个子层一样简单。回头看原先的树或新图,注意到top设计含有层次1树,A和层次2树,B。由于top最高层次的子为层次2设计,top是3层的设计。

为什么这层标志重要呢?开发一个有序搜寻脚本的途径是在current_design树下给每一个设计定义一个level层属性,然后使用filter命令按顺序有选择返回设计。辨别每一个设计层次关键是有一个有序搜寻的算法。

下面的脚本在current_design层次中每个设计放置一个level层次属性。象多数脚本一样,它需要初始化: 1 find design \–hierarchy

2 unlabeled_designs =dc_shell_status+current_design 3 set_attribute unlabeled_designs\\

level –1 –type integer –quiet

4 current_level=0 5 design_name=\

行1-2 初始化变量unlabeled_designs,在current_design层次下给所有设计一个列表。current_design清晰含在列表中。行3在unlabeled_designs列表中对每一个设计创建整型的层次level属性,初始化这种属性的值为1。行4初始化一个计数变量:current_level=0。行5-6 初始化字符串变量design_name reference_name,它们需要从设计目标中提取名字。

7 while (unlabeled_designs !={ }) {

8 foreach(active_design,unlabeled_designs) {


第六章 dc - shell综合脚本(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:体操试题库

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: