逻辑综合

一、综合综述

综合的过程是将行为描述的电路、 RTL 级的电路转换到门级的过程。

三个阶段:转换(translation)、映射(mapping) 与优化(optimization)。

  1. 转换:将 HDL 的描述转换成一个与工艺独立(technology-independent)的 RTL 级网表(网表中 RTL 模块通过连线互联);
  2. 映射:根据具体指定的工艺库, 将 RTL 级网表映射到工艺库上, 成为一个门级网表;
  3. 优化:根据设计者施加的诸如延时、 面积方面的约束条件,对门级网表进行优化。

1.1 DC

使用 DC 做综合也包含转换、 优化和映射三个阶段。

image

转换是使用 gtech.db库中的 RTL 级单元来组成一个中间网表;

优化与映射是综合工具对已有的中间网表进行分析,去掉其中的冗余单元,并对不满足限制条件(如 constraints.tcl)的路径进行优化,然后将优化之后的电路映射到由制造商提供的工艺库上(如 core_slow.db)。

二、Verilog 语言结构到门级的映射

2.1 if语句的综合

如果在使用 if 语句时, 没有指出条件判断的所有可能情况,就会在电路中引入锁存器(Latch)。

由于锁存器和触发器两种时序单元共存的电路会增大测试的难度,因此,在综合的时候尽量只选用一种时序单元, 为了不在电路中引入锁存器, 应该使用完备的 if…else if…else 的语句结构。

但是只有组合逻辑会出现这个问题。

2.2 case语句的综合

同样的,组合逻辑中,case语句未覆盖所有情况也会引入Latch。有下面几种方法:

  1. 在case语句的最后加入default;
  2. case语句之前给被赋值信号赋初值;
  3. 如果没写的情况不可能出现,可以加入指令//synopsys full_case。
always @(Toggle) begin
    case(Toggle) //synopsys full_case
        2'b00: ;
        2'b01: ;
 	endcase
end

如果case项是互斥的,可以加入指令//synopsys parallel_case进行并行检查,

always @(Toggle) begin
    case(Toggle) //synopsys parallel_case
        3'bxx1: ;
        3'bx1x: ;
        3'b1xx: ;
        default: ;
 	endcase
end

2.3 循环语句的综合

verilog有四种循环语句:for、while、repeat和forever。只有for可以综合,综合方法是把for循环展开。

always @(Address) begin
	for(J = 3; J >= 0; J = J - 1)
		if(Address == J) Line[J] = 1;
		else             Line[J] = 0;
end

//展开后等价于
if(Address == 3) Line[3] = 1; else Line[3] = 0;
if(Address == 2) Line[2] = 1; else Line[2] = 0;
if(Address == 1) Line[1] = 1; else Line[1] = 0;
if(Address == 0) Line[0] = 1; else Line[0] = 0;

2.4 算术电路的综合

遇到“+”、“-”和“*”等算术运算符和“>”、“<”、“>=”和“<=”等逻辑运算符时,DC会在DesignWare 中选取合适的逻辑电路来实现该运算符 。

DesignWare 分为 DesignWare Basic 与 DesignWare Foundation。DesignWare Basic 提供基本的电路,DesignWare Foundation 提供性能较高的电路结构。

三、使用Design Compiler进行综合

大致分为以下4个部分:

  1. 预综合过程(Pre-synthesis Processes);
  2. 施加设计约束(Constrainting the Design);
  3. 设计综合(Synthesizing the Design);
  4. 后综合过程(Post-synthesis Process)。

3.1 预综合过程

预综合过程是指在综合过程之前的一些为综合做准备的步骤, 包括 Design Compiler 的启动、 设置各种库文件、 创建启动脚本文件、 读入设计文件、 DC 中的设计对象、 各种模块的划分以及 Verilog 的编码等等。

3.1.1 DC启动

  1. dc_shell-t命令行方式

该方式是以 TCL(Tool Command Language) 为基础的,在该脚本语言上扩展了实现 Design Compiler 的命令。

  1. dc_shell -gui图形界面方式

使用图形界面, 如菜单、 对话框等来实现 Design Compiler 的功能,并提供图形方式的显示电路。工艺库(target_library)

command.log用于记录用户在使用 Design Compiler 时所执行的命令以及设置的参数;

filenames.log 用于记录 design compiler 访问过的目录,包括库、源文件等,filenames.log 文件在退出 design compiler 时会被自动删除。

3.1.2 库文件设置

  1. 工艺库(target_library):综合后电路网表要最终映射到的库,由 Foundary 提供的,一般是.db 的格式。包含了各个门级单元的行为、 引脚、 面积以及时序信息;
  2. 链接库(link_library):设置模块或者单元电路的引用,对于所有 DC 可能用到的库,都需要在 link_library 中指定。在 link_library 的设置中必须包含’*’, 表示 DC 在引用实例化模块或者单元电路时首先搜索已经调进 DC memory 的模块和单元电路。同时需要设置 search_path,因为 link_library 默认是在运行 DC 的目录下寻找相关引用;
  3. 符号库 (symbol_library):定义了单元电路显示的 Schematic 的库,后缀是.sdb,用于图形界面看电路;
  4. 综合库(synthetic_library):在2.4中提到,使用 DesignWare Foundation 才需要在 synthetic_library 中设置,同时在 link_library 中链接;

3.1.3 启动文件设置

image

DC启动时按从上到下的顺序读取三个路径下的启动文件(.synopsys_dc.setup),后面的启动文件会覆盖前面的启动文件:

  1. $SYNOPSYS/admin/setup 目录下, DC 安装的标准初始化文件;
  2. 当前用户的$HOME 目录下,一般用于设置一些用户本人使用的变量以及一些个性化设置;
  3. DC 启动的目录下,一般用于与所在设计相关的设置。

3.1.4 读入设计文件

对于 TCL 工作模式,读取不同的文件格式需要使用不同的命令。

read_db file.db     //TCL 工作模式读取 DB 格式
read_verilog file.v //TCL 工作模式读取 verilog 格式
read_vhdl file.vhd  //TCL 工作模式读取 VHDL 格式

3.1.5 设计对象

image-20251028154052157

注意:DC 识别 Clock 不是通过 HDL 的书面表达, 而是要通过设计者施加一定的约束来区分的,

create_clock ... [get_ports CLK]

如果Port、Net、Pin都叫CLK,比如上面这个图,怎么知道把哪个CLK设置为时钟呢?

其实上面的代码已经给出答案了[get_ports CLK],即把port的CLK设置为时钟。

这个代码是搜索对象,下图是tcl和dcsh各自的搜索对象的语法,

image

3.1.6 设计划分

原则一:不要让一个组合电路穿越过多的模块:即一个完整的组合逻辑就写在一个module里。

原则二:寄存模块的输出:每个模块的输出在输出前先过一个寄存器,但是可能存在粘滞逻辑的问题:

image

上面的ABC三模块的输出都经过了寄存器,是正确的。但是在顶层中,A和B的输出经过了一个组合逻辑后,输入给C module,这就叫粘滞逻辑,可以通过把这个组合逻辑放到C的组合逻辑中解决。

原则三:根据综合时间长短控制模块大小:就是把很大的组合逻辑用寄存器隔开,形成多个小的组合逻辑,提升综合效率;

原则四:将同步逻辑部分与其他部分分离。

3.2 施加设计约束

  1. 时序和面积约束;
  2. 电路的环境属性;
  3. 时序和负载在不同模块之间的分配以及时序分析。

3.2.1 时序与面积

3.2.1.1 定义面积约束

定义面积约束通过 set_max_area 命令完成,

current_design PRGRM_CNT_TOP
set_max_area 100

给 PRGRM_CNT_TOP 的设计施加了一个最大面积 100 单位的约束,100的单位有Foundary决定,一般是:

  1. 二输入与非门的大小;
  2. 晶体管的数目;
  3. 实际的面积(平方微米等等)。

3.2.1.2 同步设计的时序特点和目标

同步时序电路的特点:电路中的信号从一个受时钟控制的寄存器触发, 到达另一个受时钟控制的寄存器。

目标:约束电路中所有的时序路径。

时序路径可以分为三类:输入到寄存器的路径、寄存器到寄存器之间的路径以及寄存器到输出的路径。

3.2.1.3 定义时钟

时序电路以及组合电路的优化都是以时钟为基准来计算路径延迟。

定义时钟必须定义时钟源(Clock source), 时钟源可以是端口也可以是管脚;另外还必须定义时钟的周期,

create_clock -period 10 [get_ports Clk]
set_dont_touch_network [get_clocks Clk]
  1. 把端口Clk设置为周期为10ns的时钟;
  2. 把时钟网络设置为dont touch,即不优化时钟。

占空比(Duty Cycle)、 时钟偏差(Clock Skew)和时钟名字(Clock Name)是可选配置项。

3.2.1.4 约束输入路径

输入延时是指被综合模块外的寄存器触发的信号在到达被综合模块之前经过的延时。

set_input_delay -max 4 -clock Clk [get_ports A]

被综合模块的端口 A 的最大输入延时为 4ns,为了满足时序单元建立时间(setup time)的要求。如果用-min,则是针对保持时间的约束使用的。

3.2.1.5 约束输出路径

set_output_delay -max 5.4 -clock Clk [get_ports B]

被综合模块的输出端口 B 的最大输出延时为 5.4ns

3.2.2 环境属性

外界的温度变化、电路的供电电压变化、输入输出的外围电路的驱动能力和负载大小以及电路内部的互连线延时。

3.2.2.1 设置输出负载

输出负载过大会加大电路的 transition time,影响时序特性;而如果不设置输出负载,那么 DC 默认输出负载为 0,这样综合出来的电路时序显然过于乐观。

设置输出负载是通过 DC 的 set_load 命令完成。

该命令有两种用法, 一种是直接给端口赋一个具体的值, 另外则结合另一个命令 load_of 指出它的负载相当于工艺库中的哪个单元的负载值,

set_load 5 [get_ports OUT1]
set_load [load_of my_lib/and2a0/A] [get_ports OUT1]
set_load [expr [load_of my_lib/inv1a0/A] * 3] [get_ports OUT1]
  1. 直接给端口OUT1赋5;
  2. 给端口OUT1赋 my_lib 中 and2a0 单元的 A 管脚的负载值;
  3. OUT1 相当于接了三个 inv1a0 单元的 A 管脚的负载值。

3.2.2.2 设置输入驱动

为了更加准确的估计模块输入的时序,同样需要知道输入端口所接单元的驱动能力。 在默认的情况下, DC 认为驱动输入的单元的驱动能力为无穷大,即 transition time 为 0。

设置输入驱动是通过 DC 的 set_driving_cell 命令完成。set_driving_cell 是指定使用库中的某一个单元来驱动输入端口。 该命令是在输入端口之前假想一个驱动单元, 然后按照该单元的输出电阻来计算 transition time,从而计算输入端口到门单元电路的延迟。

set_driving_cell -lib_cell and2a0 [get_ports IN1]

设置模块输入端口 IN1 的驱动单元是工艺库中的 and2a0。

3.2.2.3 设置工作条件

工作条件包括三方面:温度、 电压以及工艺。

单元的延时会随着温度上升增加; 随着电压上升减小; 随着工艺尺寸增大增大

工艺库中提供的工作条件一般分为三种: 最好情况(best case)、 典型情况(typical case)以及最差情况(worst case)。

最好情况用于保持时间(hold time)的时序分析,最差情况用于建立时间(setup time)的时序分析。

  1. 通过 report_lib 命令来列出在当前的工艺库里提供了哪几种工作条件;
  2. 通过 set_operating_conditions 指定需要用到的工作条件,
set_operating_conditions -max "slow_125_1.62"

“ ”中是工作条件的名字,-max表示分析建立时间。

3.2.2.4 设置连线负载模型

连线负载模型基于连线的扇出,估计它的电阻电容等寄生参数,由 Foundry 提供。

以下讨论模块内部的连线。

  1. 通过命令 report_lib 查询连线负载模型;
  2. 通过 DC 的 set_wire_load_model 命令设置连线负载模型;
set_wire_load_model -name 160KGATES

不过默认情况下DC会自动选择连线负载模型。

以下讨论模块外部的互连线。

如果是模块外部连线,就必须使用 set_wire_load_model 命令,此时有三个模式:围绕(enclosed)、顶层(top)以及分段(segmented)

围绕:用这两个module的最接近的顶层module的负载模型代替;

顶层:用最顶层module的负载模型代替;

分段:根据穿过的三段的模型相加得到。

3.2.3 时序分析

Design Time 是 DC 的一个内嵌的静态时序分析引擎,PrimeTime 是在 DesignTime 的基础上发展起来的独立的专业的时序工具,效率和应用范围更高。

静态时序分析的三个步骤:

  1. 将电路分解成不同的时序路径(timing paths);
  2. 计算每段路径的延时;
  3. 检查所有路径的延时,看是否能满足时序要求。

3.2.3.1 分解时序路径

DesignTime 对时序路径的分解是根据时序路径的起点和终点的位置来决定的。

数据路径:

  1. 输入到寄存器;
  2. 寄存器到寄存器;
  3. 寄存器到输出;
  4. 输入到输出。

时钟路径:

  • 时钟输入到寄存器;

3.2.4 DC Tcl 初步

3.2.4.1 执行 DC-Tcl 脚本

第一种:

dc_shell-t
source my.tcl

也可以结合起来

dc_shell-t -f my.tcl
dc_shell-t -f my.tcl > my.log
dc_shell-t -f my.tcl | tee my.log
  1. 打开dc_shell并执行my.tcl
  2. 打开dc_shell后,将执行结果记录在my.log里;
  3. 打开dc_shell后,将执行结果记录在my.log里并且打印出来。

声明

本文内容均参考自《DesignCompiler中文guide手册》。

posted @ 2025-10-27 16:15  Holybanban  阅读(5)  评论(0)    收藏  举报