相关阅读
Synopsys
https://blog.csdn.net/weixin_45791458/category_12812219.html?spm=1001.2014.3001.5482
目录
为什么使用对象集合?
创建/删除/访问对象集合
显示对象集合中的对象名/数量
向对象集合中添加/移除对象
比较对象集合中的内容
从对象集合中提取单个对象
遍历对象集合
通过迭代向对象集合中添加对象
通过迭代从对象集合中移除对象
对于Synopsys的EDA工具(如Design Compiler、PrimeTime、IC Compiler)等,对象集合(Collections)是一个基本的概念,许多命令在执行操作时,都需要接收或返回由一个或多个对象组成的集合,本文就将介绍对象集合。
关于Synopsys中设计对象的更多介绍,可以参考下面的博客。
Synopsys:设计对象
https://blog.csdn.net/weixin_45791458/article/details/147015140?ops_request_misc=elastic_search_misc&request_id=58b392c0b3d9d3c7a1ec3fef31c13605&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~ElasticSearch~search_v2-1-147015140-null-null.541^v3^pc_search_result_blog8&utm_term=%E8%AE%BE%E8%AE%A1%E5%AF%B9%E8%B1%A1&spm=1018.2226.3001.4450
为什么使用对象集合?
Tcl语言提供了列表(List),它本质上是按照特定格式组织起来的字符串,虽然可以使用列表来引用对象,但这种方式存在以下缺点:
1、列表的内存使用效率较低
每个对象名都以完整字符串的形式存储,对于多个层次对象,其层次路径会被重复、冗余地存储。
2、列表的运行效率较低
必须通过字符串比较,在设计数据库中搜索每个列表元素所对应的对象。对于层次对象名,在搜索过程中还需要进行额外处理,以逐级识别各个层次,最终定位到叶级对象。
3、列表无法明确区分对象类型
列表中的元素本身并不包含对象类型信息。例如,CLK究竟表示一个端口,还是一个同名的线网?
4、列表无法提供额外的对象信息
除了对象名之外,列表元素本身不提供任何有关对象的信息。例如,无法仅通过一个时钟名列表获取其中各个时钟的周期,也无法仅通过一个单元名列表获取其中各个单元的面积。
为了解决这些问题,基于Tcl语言的Synopsys的EDA工具提供了对象集合,作为引用对象的一种方式,对象集合是一种二进制数据结构,用于引用由一个或多个对象组成的集合。其中,每个对象的引用都直接指向相应的内部数据结构,因此即使需要处理数千个对象,对象集合仍然具有很高的运行效率和内存使用效率。
对象集合中的大部分对象都具有object_class属性,用于指明该对象所属的类型。对象集合既可以只包含一种类型的对象,即同构对象集合(Homogeneous Collection),也可以包含多种不同类型的对象,即异构对象集合(Heterogeneous Collection)。
每种对象都提供了额外的属性,可以利用这些属性获取该设对象的更多信息。例如,时钟对象具有period属性用于表示时钟周期;单元对象具有area属性用于表示单元面积。这些属性值可以直接从EDA工具的内部数据结构中获取,也可以由EDA工具在查询时动态计算得到,因此属性查询同样具有较高的执行效率。
创建/删除/访问对象集合
通常,可以使用get_*和all_*类命令创建对象集合。例如,要创建一个包含所有名字以o开头、并且由FD2库单元例化得到的单元集合,可以使用以下命令:
dcnxt_shell> get_cells o* -filter "ref_name == FD2"
{o_reg1 o_reg2 o_reg3 o_reg4}
尽管回显的返回值看起来像一个列表,但实际上并不是(为了方便用户查看,返回对象集合的命令自动调用了query_objects命令显示对象名列表)。对象集合通过一个集合句柄(Collection Handle)进行引用,本质上是一个字符串值(类似指针),EDA工具会将这个字符串与对象集合的内部数据结构关联起来。
大多数接受对象作为参数的命令都支持并推荐使用对象而不是列表作为参数,如下博客所示。
SDC命令详解:使用集合(Collection)而不是字符串(String)/列表(List)作为命令参数
https://chenzhang.blog.csdn.net/article/details/147144571
对象集合可以是临时的,也可以在整个EDA工具会话期间持续存在。如果将一个嵌套的对象集合命令用作另一个命令的参数,那么由嵌套命令创建的对象集合只会在该命令的作用范围内存在。例如,可以使用以下命令为单元i1和i2设置size_only属性,:
dcnxt_shell> set_size_only [get_cells "i1 i2"] true
1
如果希望对象集合在当前EDA工具会话中持续存在,可以将其赋值给一个变量,随后可以使用这个变量作为其他命令的参数值,如下所示:
dcnxt_shell> set my_pins [get_pins o*/CP]
{o_reg1/CP o_reg2/CP}
dcnxt_shell> get_cells -of_objects $my_pins
{o_reg1 o_reg2}
只要变量仍然引用对应的集合句柄,该对象集合就会持续存在,如果使用unset命令删除了变量定义(或将其他值赋给变量),与该变量关联的对象集合也会删除。需要注意的是,对于Synopsys的EDA工具,如果把一个关联了对象集合的变量赋值给另一个变量,会创建一份新的副本,而不是共享同一个对象集合(就像在Python中的列表赋值那样),这与Tcl列表一致。关于Python中的赋值(引用)的更多信息,可以参考下面的博客。
Python:赋值的本质其实是引用
https://blog.csdn.net/weixin_45791458/article/details/142834055?ops_request_misc=elastic_search_misc&request_id=6fe5940fa597db72747b52dd4239db52&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~ElasticSearch~search_v2-2-142834055-null-null.541^v3^pc_search_result_blog8&utm_term=Python%20%E8%B5%8B%E5%80%BC&spm=1018.2226.3001.4450
在部分EDA工具(如Design Compiler和IC Compiler)中,如果用户使用current_design命令切换了当前设计,则相对原当前设计得到的对象集合会暂时失效(部分EDA工具不会失效,如IC Compiler II),少部分类型的对象集合(如时序路径timing_path)会永久失效,如下所示:
dcnxt_shell> current_design top
Current design is 'top'.
{top}
dcnxt_shell> set a [get_cells bot1]
{bot1}
dcnxt_shell> set b [get_timing_paths]
{path1}
dcnxt_shell> query_objects $a
{bot1}
dcnxt_shell> query_objects $b
{path1}
dcnxt_shell> current_design bot
Current design is 'bot'.
{bot}
dcnxt_shell> query_objects $a
Error: No such collection '_sel24' (SEL-001)
dcnxt_shell> query_objects $b
Error: No such collection '_sel156' (SEL-001)
dcnxt_shell> current_design top
Current design is 'top'.
{top}
dcnxt_shell> query_objects $a
{bot1}
dcnxt_shell> query_objects $b
Error: No such collection '_sel156' (SEL-001)
对象集合相关命令通常提供一些选项,以便更加精细地控制对象的获取方式。例如,get_pins命令提供了-leaf选项,用于跨层次边界搜索并只考虑叶单元上的引脚,关于get_pins命令的更多信息可以参考下面的博客。
SDC命令详解:使用get_pins命令进行查询
https://blog.csdn.net/weixin_45791458/article/details/147985165?ops_request_misc=elastic_search_misc&request_id=e9013962c789231b0d8d3dcb8bfb1d3c&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~ElasticSearch~search_v2-1-147985165-null-null.541^v3^pc_search_result_blog8&utm_term=get_pins&spm=1018.2226.3001.4450
显示对象集合中的对象名/数量
所有返回对象集合的命令,在交互式命令提示符下返回对象集合时,都会隐式地显示对象集合中的对象名。不过,为了获得更灵活的显示方式,可以显式使用query_objects命令显示对象集合中的对象名。
query_objects命令生成的输出与交互式环境下回显的返回值类似,查询结果会被格式化为Tcl列表的形式,以便用户直接查看结果。例如,可以使用以下命令显示所有名称以字符串in开头的端口:
dcnxt_shell> set a [get_ports in*]
{in0 in1 in2}
dcnxt_shell> query_objects $a # 必须添加$前缀
{in0 in1 in2}
用户甚至可以使用query_objects命令直接访问数据库,如下所示:
dcnxt_shell> query_objects -class port in*
{in0 in1 in2}
要控制显示的列表中的最大对象名数量,可以使用query_objects命令的-truncate选项或设置collection_result_display_limit变量,默认为100。
如果只需要获取对象集合中的对象数量,而不是显示对象名称,可以使用sizeof_collection命令,如下所示:
dcnxt_shell> sizeof_collection $all_cells
23856
如果需要生成更加详细的对象集合报告,包括自定义格式的报告,可以使用report_collection命令。
向对象集合中添加/移除对象
向对象集合中添加对象有两种方式,每种方式适用于不同的用途(与之前谈到的赋值类似,这里的添加也会创建副本):
1、向已有对象集合中添加对象
可以使用append_to_collection命令向已有的对象集合中添加对象。使用时,需要指定关联了对象集合的变量名(需要注意的是,这里不能添加$前缀,这是与其他大多数对象集合操作命令的区别),然后指定要添加的对象集合,如下所示:
dcnxt_shell> query_objects $a
{cell1}
dcnxt_shell> append_to_collection a [get_ports *]
{cell1 in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1]}
由于新对象是在数据结构层面直接复制到已有的对象集合中,因此该操作的执行速度非常快。
2、将多个对象集合合并为一个对象集合
可以使用add_to_collection命令将两个对象集合合并,并将合并后的结果作为一个新的对象集合返回,如下所示:
dcnxt_shell> query_objects $clock_sources
{clk}
dcnxt_shell> query_objects $reset_sources
{rst_n}
dcnxt_shell> set possible_sources \\
[add_to_collection $clock_sources $reset_sources]
{clk rst_n}
需要注意的是,只有在需要将多个对象集合合并为一个对象集合时,才应使用add_to_collection命令,如果只是向已有对象集合中添加新对象,则应使用append_to_collection命令,add_to_collection命令在运行过程中会创建和销毁临时对象集合。
3、使用Tcl列表保存多个对象集合(对象集合列表)
可以创建Tcl列表,使其包含多个对象集合。但不建议这么做,因为Tcl列表可能会受到原对象集合的影响,如下所示:
dcnxt_shell> set a [get_ports *]
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0] out_sum[7] out_sum[6] out_sum[5] out_sum[4] out_sum[3] out_sum[2] out_sum[1] out_sum[0]}
dcnxt_shell> set b [get_cells *]
{u_adder}
dcnxt_shell> set c "$a $b"
_sel179 _sel180
dcnxt_shell> query_objects [lindex $c 0]
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0] out_sum[7] out_sum[6] out_sum[5] out_sum[4] out_sum[3] out_sum[2] out_sum[1] out_sum[0]}
dcnxt_shell> query_objects [lindex $c 1]
{u_adder}
dcnxt_shell> unset a
dcnxt_shell> unset b
dcnxt_shell> query_objects [lindex $c 0]
Error: No such collection '_sel179' (SEL-001)
dcnxt_shell> query_objects [lindex $c 1]
{u_adder}
可以使用remove_from_collection命令从对象集合中移除对象。remove_from_collection命令会创建一个新的对象集合,其中包含原始对象集合中除指定移除对象之外的所有对象,remove_from_collection命令在运行过程中会创建和销毁临时对象集合。如果移除操作后集合中不再包含任何元素,则该命令返回一个空字符串。需要注意的是,原始对象集合不会被修改。例如,可以使用以下命令创建一个包含除CLOCK之外所有输入端口的对象集合:
dcnxt_shell> set data_ports [remove_from_collection [all_inputs] {CLOCK}]
{in1 in2}
可以指定一个对象名列表或一个对象集合,作为需要移除的对象。需要注意,待移除对象的类型必须与原始对象集合中的对象类型一致。例如,不能从一个单元对象集合中移除一个端口对象集合。如果对象集合曾经处于异构对象集合状态,那么不能指定一个对象名列表作为需要移除的对象,如下所示:
dcnxt_shell> set a [get_ports in_*]
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
dcnxt_shell> remove_from_collection $a in_b
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0]}
dcnxt_shell> remove_from_collection $a in_a
{in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
dcnxt_shell> set a [append_to_collection a [get_nets in_*]]
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0] in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
dcnxt_shell> remove_from_collection $a in_a
Warning: Nothing implicitly matched 'in_a' (SEL-003)
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0] in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
dcnxt_shell> remove_from_collection $a in_b
Warning: Nothing implicitly matched 'in_b' (SEL-003)
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0] in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
dcnxt_shell> set a [remove_from_collection $a [get_nets in_*]]
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
dcnxt_shell> remove_from_collection $a in_a
Warning: Nothing implicitly matched 'in_a' (SEL-003)
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
dcnxt_shell> remove_from_collection $a in_b
Warning: Nothing implicitly matched 'in_b' (SEL-003)
{in_a[7] in_a[6] in_a[5] in_a[4] in_a[3] in_a[2] in_a[1] in_a[0] in_b[7] in_b[6] in_b[5] in_b[4] in_b[3] in_b[2] in_b[1] in_b[0]}
比较对象集合中的内容
可以使用compare_collections命令比较两个对象集合的内容。如果两个对象集合包含完全相同的一组对象,并且任何一个对象集合中都不存在无法匹配的对象,那么compare_collections命令返回0;否则返回非零值,如下所示:
dcnxt_shell> compare_collections [get_cells *] [get_cells *]
0
默认情况下,两个对象集合中对象的排列顺序不会影响比较结果。如果希望比较结果与对象的排列顺序有关,可以在比较时使用-order_dependent选项。要判断一个对象集合是否为空,可以使用Tcl语言中的字符串比较操作,将其与空字符串进行比较,如下所示:
dcnxt_shell> if {$my_cells eq {}} { # …集合为空… }
dcnxt_shell> if {$my_cells ne {}} { # …集合不为空… }
要判断一个待查找对象集合中的所有对象是否都存在于另一个被搜索对象集合中,可以使用remove_from_collection命令后再与空字符串进行比较,如下所示:
dcnxt_shell> if {[remove_from_collection $needle $haystack] eq {}} {
# $needle 中的所有对象都存在于 $haystack 中
}
要确定两个对象集合是否存在共同对象,以及这些共同对象具体是什么,可以使用remove_from_collection -intersect命令,如果两个对象集合不存在任何共同对象,该命令将返回一个空对象集合,如下所示:
dcnxt_shell> remove_from_collection -intersect $fanin_pins $fanout_pins
从对象集合中提取单个对象
对象集合是有序的,其中的对象按照从0到n-1的索引进行编号,其中n为对象集合中的对象数量。可以使用index_collection命令,根据索引提取对象集合中的对象(与之前谈到的赋值类似,这里的提取也会创建副本)。
1、提取单个对象
指定一个索引值,即可提取单个对象,这相当于Tcl语言中的lindex命令,如下所示:
dcnxt_shell> index_collection $my_ports 3
{A[12]}
2、提取指定范围的对象
指定一个范围的起始索引和结束索引,即可提取该范围内的对象,这相当于Tcl语言中的lrange命令,如下所示:
dcnxt_shell> index_collection $my_ports 3 5
{A[12] A[11] A[10]}
与相应的Tcl命令一样,index_collection命令也可以使用end或end-value的形式指定索引,如下所示:
dcnxt_shell> index_collection $my_ports end
{test_se}
dcnxt_shell> index_collection $my_ports end-2 end
{test_si6 test_si7 test_se}
需要注意的是,虽然get_*和all_*类命令可能没有在文档中明确说明其返回的对象集合中对象的排列顺序,但这些命令会以确定性的顺序创建对象集合。换句话说,多次执行相同的命令会创建相同的 对象集合。
遍历对象集合
可以使用foreach_in_collection命令遍历对象集合中的每个元素。foreach_in_collection命令可以嵌套在其他控制结构中,包括另一个foreach_in_collection命令。在每次迭代过程中,迭代变量都会被赋值为一个恰好包含一个对象的对象集合(不能使用Tcl语言中的的foreach命令遍历对象集合),如下所示:
dcnxt_shell> foreach_in_collection this_cell [get_cells *] {
…
}
通过迭代向对象集合中添加对象
如果需要在循环过程中不断向对象集合中添加对象,应使用append_to_collection命令,直接对该对象集合进行原地添加,如下所示:
# 从空对象集合开始,用于累积符合条件的对象
set qualifying_cells {}
# 遍历对象集合,并根据条件
# 添加符合要求的对象
foreach_in_collection this_cell $all_cells {
if {…some criteria…} {
append_to_collection qualifying_cells $this_cell
}
}
不要使用add_to_collection命令在循环中逐个添加对象,因为这种方式会在循环过程中不断创建和销毁临时对象集合,从而产生显著的性能开销。
通过迭代从对象集合中移除对象
如果需要在循环过程中从对象集合中移除对象,应先使用append_to_collection命令构建一个包含所有待移除对象的对象集合,然后在循环结束后统一移除这些对象,如下所示:
# 从空对象集合开始,用于累积待移除对象
set cells_to_remove {}
# 遍历对象集合,并根据条件
# 收集所有需要移除的对象
foreach_in_collection this_cell $all_cells {
if {…some criteria…} {
append_to_collection cells_to_remove $this_cell
}
}
# 循环结束后,从完整集合中统一移除这些对象
set all_cells [remove_from_collection $all_cells $cells_to_remove]
不要使用remove_from_collection命令在循环中逐个移除对象,因为这种方式会在循环过程中不断创建和销毁临时对象集合,从而产生显著的性能开销。




