预综合过程是指在综合过程之前的一些为综合作准备的步骤,包括Design Compiler的启动、设置各种库文件、创建启动脚本文件、读入设计文件、DC中的设计对象、各种模块的划分以及Verilog的编码等等。
目前,DC的启动方式有三种:
较为推荐第三种批处理的方式。图中的命令意思是:使用拓扑模式启动DC,启动的同时执行run.tcl脚本文件,并且把启动过程中显示在终端的信息记录到run.log中。| tee -i就是写进信息的管道命令,将dc_shell -topo -f run.tcl 执行后显示的信息(输出结果),流入到run.log文件中。这样子是为了在DC启动失败的时候,通过查看启动信息,进而排除错误。
在Design Compiler的运行过程中需要用到几种库文件,他们是工艺库、链接库、符号库以及综合库,下面对他们一一说明。
详细可见逻辑综合——工艺库
目标库是综合后电路网表要最终映射到的库,读入的HDL代码首先由synopsys自带的GTECH库转换成Design Compiler内部交换的格式,然后经过映射到工艺库和优化生成门级网表。目标库是由Foundary提供的,一般是.db的格式。这种格式是DC认识的一种内部文件格式,不能由文本方式打开。.db格式可以由文本格式的.lib转化过来,他们包含的信息是一致的。一个例子如下:
从图中可以看出,工艺库中包含了各个门级单元的行为、引脚、面积以及时序信息(有的目标库还有功耗方面的参数),DC在综合时就是根据target_library中给出的单元电路的延迟信息来计算路径的延迟。并根据各个单元延时、面积和驱动能力的不同选择合适的单元来优化电路。
在DC中,使用以下命令来设置目标库
dc_shell > set target_library my_tech.db
link_library设置模块或者单元电路的引用,对于所有DC可能用到的库,我们都需要在link_library中指定,其中也包括要用到的IP。
值得注意的一点是:在link_library的设置中必须包含’*’, 表示DC在引用实例化模块或者单元电路时首先搜索已经调进DC memory的模块和单元电路,如果在link library中不包含’*’,DC就不会使用DC memory中已有的模块,因此,会出现无法匹配的模块或单元电路的警告信息(unresolved design reference)。
另外,设置link_library的时候要注意设置search_path
图中设置了link_library,但是DC在link的时候却报错,找不到TOP中引用的DECODE模块,这说明link_library默认是在运行DC的目录下寻找相关引用。要使上例的DECODE能被找到,需要设置search_path。
symbol_library是定义了单元电路显示的Schematic的库。用户如果想启动design_vision来查看、分析电路时需要设置symbol_library。符号库的后缀是.sdb,如果没有设置,DC会用默认的符号库取代。
设置符号库的命令是
dc_shell > set symbol_library my.sdb
在初始化DC的时候,不需要设置标准的DesignWare库standard.sldb用于实现Verilog描述的运算符,对于扩展的DesignWare,需要在synthetic_library中设置,同时需要在link_library中设置相应的库以使得在链接的时候DC可以搜索到相应运算符的实现。
启动文件顾名思义,就是DC在启动的时候首先读入的文件,DC在启动的时候,会自动在三个目录下搜索该文件,对DC的工作环境进行初始化:
其中后面的setup 文件可以覆盖前面文件中的设置。该文件主要包括库的设置、工作路径的设置以及一些常用命令别名的设置等等。
由于dcshell的启动脚本和tcl的脚本语法不一致,所以如果只有一种方式的启动脚本,那么运行另一种方式的时候会报错。因此,DC的启动脚本有一种兼容两种方式的格式。下面是这种脚本的举例——
它区别与其他启动脚本的特征是第一行有一个”#”,说明它是dcshell的一个子集,同时兼容两种方式。文件的第一段设置工艺库和链接库,第二段设置符号库和搜索路径,第三段设置DC命令的别名,这一点与Shell相似。
Design Compiler支持多种硬件描述的格式,.db、.v、.vhd、等等,对于dcsh工作模式来说,读取不同的文件格式只需要带上不同的参数,对于TCL的工作模式来说,读取不同的文件格式需要使用不同的命令。
read –format verilog[db、vhdl etc.] file //dcsh的工作模式
read_db file.db //TCL工作模式读取DB格式
read_verilog file.v //TCL工作模式读取verilog格式
Design Compiler可以读取设计流程中任何一种数据格式,如行为级的描述、RTL级的描述、门级网表等等,不过由于不同的数据格式使得Design Compiler综合的起点不同,即使实现相同的功能,也可能会产生不同的结果。
读取源程序的另外一种方式是配合使用analyze命令和elaborate命令:
当读取完所要综合的模块之后,需要使用link命令将读到Design Compiler存储区中的模块或实体连接起来,如果在使用link命令之后,出现unresolved design reference的警告信息,需要重新读取该模块,或者在.synopsys_dc.setup文件中添加link_library,告诉DC到库中去找这些模块,同时还要注意search_path中的路径是否指向该模块或单元电路所在的目录。
上图是一个Verilog描述的设计实例,里面包含了我们所要讨论的几种设计对象。这些对象也是今后DC命令的操作对象。Verilog描述的各个模块可以称之为设计(Design),里面包含时钟(Clock),他的输入输出称为端口(Port),模块中的互连线是线网(Net),内部引用的元件称为引用(Reference),引用的实例称为单元(Cell),引用单元的内部端口是管脚(Pin)。
其中值得注意的是DC识别Clock不是通过HDL的书面表达,而是要通过设计者施加一定的约束来区分的,具体内容后续会讨论。
把一个复杂的设计分割成几个相对简单的部分,称为设计划分(Design Partition)。这种方法,也可以称为“分而治之”(Divide and conquer)的方法,在平常的电路设计中这是一种普遍使用的方法,一般我们在编写HDL代码之前都需要对所要描述的系统作一个系统划分,根据功能或者其他的原则将一个系统层次化的分成若干个子模块,这些子模块下面再进一步细分。这是一种设计划分,模块(module)就是一个划分的单位。
在运用DC作综合的过程中,默认的情况下各个模块的层次关系是保留着的,保留着的层次关系会对DC综合造成一定的影响,比如在优化的过程中,各个子模块的管脚必须保留,这势必影响到子模块边界的优化效果。下面我们将详细介绍在作设计划分的过程中要注意的几点原则,并根据每个原则举一个实例说明。
不要让一个组合电路穿越过多的模块
上图中的组合逻辑电路存在于寄存器A与寄存器C之间,它同时穿过了模块A、模块B以及模块C。前面提到了,如果直接将这样的划分交给DC综合,那么综合后的电路将仍旧保持上面的层次关系,即端口定义不会改变。这样的话,DC在作组合电路的优化的时候就会分别针对A、B、C三块电路进行,这样势必会影响到DC的优化能力,不必要的增加了这条路径的延时和面积。因此,可以考虑将三块分散的组合逻辑划分到一个模块中,如下图所示——
这张图说明了组合电路划分到一个模块之后的电路情况,这样DC就可以充分的施展它的的优化技巧,综合出比较满意的电路来。为什么说它只是一个较好的划分呢?因为它只是考虑到组合电路的最优划分而没有想到时序电路部分。我们进一步修改:
在这张图里,组合逻辑被划到了C模块中,它不仅能保证组合的最佳优化还能保证时序的最佳优化,因为里面的寄存器在优化的过程中可以吸收前面的组合逻辑,从而形成其他形式的时序元件,如由原先的D触发器变成JK触发器、T触发器、带时钟使能端的触发器等等。这样工艺库中的大量的时序单元都可以得到充分的利用了。
通过前面的讨论,可以知道:在编写代码或者综合的过程中,我们可以把模块尽量写成这样的逻辑结构:将所有的输出寄存起来。其实这样不但是最佳的优化结构,也可以简化时序约束(使得所有模块的输入延时相等)。
就算遵循了输出寄存的原则,我们还是可能犯下面的错
图中可以看到,一个与非门连接了A、B、C三个模块,同样的不难看出来,它也会影响到C的组合逻辑的优化。一般这种情况只会在自下而上的综合策略中才出现。可以通过把与非门吸收到C中的组合逻辑的方法消除粘滞逻辑(如下图),从而使得电路的顶层模块仅仅是将子模块拼接在一起,而没有独立的电路结构,这样的一个另一个好处是可以使得在自下而上的设计策略中不需要编译顶层模块。
综合时间主要受到硬件条件(主频、内存)的制约,对于早期的工作站而言,硬件水平不高,跑一个大型的设计可能会一次花上几天时间才会有结果,这样对调试和缩短工期是不利的,所以需要根据工作站的能力选择合适的模块大小。
这个例子的模块大小从500门到37万门不等,假设工作站的硬件条件限制最多只能跑30万门的设计,那么上面的这种划分就有一些弊病。首先,TEENY模块太小,不适合优化出最好的结果,可以考虑将它合并到其他模块中。其次,另一个组合模块逻辑太大,这势必使得综合的时间变得不能承受。因此,改进的划分可以如下图所示——
可以看到,虽然各个模块也是大小不一,但却可以取得较前面的划分更好的结果。值得注意的是——Design Compiler软件本身没有模块大小的限制,它完全根据工作站的环境决定,在具体作设计的时候,我们可以在硬件条件允许的条件下编译较大的模块,假如硬件条件的确有限,只能选择小的模块来综合了
将同步逻辑部分与其他部分分离
上图是一个芯片的顶层设计,可以看到它被分层了三个层次——最外边是芯片的Pad,Pad是综合工具中没有的,也不是工具能生成的,它由Foundry提供,并由设计者根据芯片外围的环境手工选择;中间一层被分成四个部分,其中最里面那个称为Core,也就是DC可以综合的全同步逻辑电路,另外的三个部分DC不能综合,需要其他的办法来解决:ASYNCH是异步时序部分,不属于DC的范畴;CLOCK GEN是时钟产生模块(可能用到PLL),尽管有一部分同步电路,但也不符合综合的条件;JTAG是边界扫描的产生电路,这一部分可以由Synopsys的另外一个工具BSD Compiler自动生成。
上面我们介绍了四个划分的原则,当然这些原则并不是我们在编写HDL代码的时候就必须遵守的,它只是说明什么样的设计划分对于DC来说是最理想的,能得到最优化的结果。事实上除了通过HDL中的模块体现划分,我们还可以运用DC的两个命令(Group及Ungroup)来调整设计划分。
比如在第一点中提到的例子
第一步是使用group命令,创建一个新的模块NEW_DES(设计名),单元名为U23,包含了U2和U3,这个命令很直观,很容易看懂。
第二步则是使用ungroup命令,将U23中的U2和U3的边界去掉,使之称为一个整体: