1. 时钟为什么建模?
背景:
默认情况下,即使一个时钟要驱动很多寄存器,DC也不会在时钟连线上加clock buffer。Clock buffer 或时钟树,一般由后端工具完成。为了准确的描述时钟树,使综合结果与版图的结果匹配,需要为时钟树建模。
Set_clock_uncertainty、set_clock_latency 、set_clock_transtion
理想的时钟网络latency、skew、transition默认是零。时钟网络还是理想的,但是原来的零值,由这些命令中指定的值替代。
Set_clock_uncertainty ——模拟skew和jitte之和
set_clock_latency —— 模拟 时钟源延迟或连线延迟
set_clock_transtion —— 模式转换时间
2 说明两点
Set_clock_uncertainty —setup 0.5 给时钟赋予建立时间
Set_clock_transition —setup 给时钟赋予上升转换时间。
两个都有setup选项,但是不是一回事。
set_clock_latency –source :时钟源延迟,指时钟信号从其实际时钟原地到设计中时钟定义点的传输时间(P94会体会到)。
set_clock_latency : 时钟信号从其定义的点到寄存器时钟引脚的传输时间。
(1) Set_input_delay,和set_output_delay
是通过设置外部电路的延迟,来用时钟周期相减,计算留给内部要综合电路的做大延迟。
注意:1)设置的数值是外部的数值,
2)最大延迟是,内部要综合电路的最大延迟
3)只作用于同步电路,内部和外部时钟一致,而不适用于异步打拍的电路。
(2) 建立时间预算
背景:如果不知道外部输入延迟和外部输出的建立要求,则需要通过建立时间预算time budget,为输入/输出口设置约束。
一般假设:输入和输出的内部电路仅仅用了时钟的40%(即ts=tt=40%),还有20%富裕量包括tclkq+tsetp。
注:
1)因此需知道,通过time budget如何设置值?
设置值为60%Tperiod,也就是留给内部的Tn+Tsetup 只有40%。
2)如果模块划分,以寄存器输出进行划分,时间预算将变得简单。
但是实际中很少完全这样划分。
Set_input_delay –max clktoq–clockCLKall_in_ex_clk
Set_output_delay –max [expr 10 - $clk_to_q] –clock CLOCK [all_outputs]
设置环境约束
目的:上面的set_input_delay是提供了约束,但要计算路径的延迟,才能知道和约束是否满足。
背景:为了保证输入/输出路径(除时钟外)延时约束的精确性,还需提供环境属性。
1) 输出端,电容负载
为了精确计算输出电路的时间,DC需要知道,输出单元驱动的总负载电容。
默认情况下,DC外部电容负载为0.
DC中用set_load: 说明输入或输出上外部电容负载。
Load_of: 说明电容负载值为工艺库中某一单元引脚的负载。
2) 输入端,转换时间
为了精确计算输出电路的时间,DC需要知道,输入端口的转换时间transition。
Set_driving_cell 说明输入端口是由一个真实的外部单元驱动。
通过驱动,计算输入转换时间:
默认情况下,DC假设输入端口上外部型号转换时间为0. Set_driving_cell命令在输入端口上加上一个驱动单元,DC将计算输入信号的实际转换时间。
3) 负载预算(load budget)
背景:
模块划分时,设计者不知道输入端口的外部驱动单元或输出端口的负载,需要通过负载预算,设置环境约束。
负载预算规则:
保守起见,假设输入端口由驱动能力弱的单元驱动
限制每一个输入端口的输入电容(负载)
估算输出端口的驱动模块数目。
规则2,可以通过加限制性的设计规则做到,工艺库中设计规则分别是
”max_capacitance, max_transition, max_fanout”
注:
set_load不仅可,用于设置输出负载,也可用于设置输入负载
max_capacitance ,限制每一个输入端口的输入电容(负载)
门延迟和连线延迟
门延迟采用非线性延迟模型。由输入转换时间和输出负载,查查门的延迟及输出转换时间,输出转换时间,又做下一级的输入转换时间。
连线延迟:由线负载模型估算。
- 线负载模型
根据扇出数fanout,估算连线长度,库中提供连线单位长度的电阻值R、电容值C和面积。根据这些值,DC计算连线的延迟。T=RC?
延迟如何算?
根据RC来计算延迟时间。
Set_wire_load_model和set_wire_load_mode区别:
Set_wire_load_model:连线的线负载模型
set_wire_load_mode:连线穿越不同层次边界时,选择的模式(enclosed或top)
多时钟同步设计的时钟约束
1) 虚拟时钟
背景:所有的时钟信号来自同一个时钟源,经过不同的分频电路产生。但在我们要综合的电路中,只有一个时钟端CLKC;但其它的时钟如CLKA、CLAB,用作外部电路,在要综合的电路中没有时钟端口,虽然是同步时钟,但是因为频率不同,主要用作输入/输出端口作约束,可能出现一个端口多个约束的情况(输出端口会出现)。这样将执行最严格的约束。
目的:
在多时钟同步设计中,要综合的电路只有CLKC端口,同步时钟CLKA、CLKB、CLKD
用在外部输入或外部输出,因此在综合的电路中不驱动任何寄存器,主要说明相对于时钟I/O端口的约束,因频率不同,DC根据这些约束执行最严格的约束。
方法:
虚拟时钟不驱动,要综合的寄存器,所以没有源端口,因为没有对应的时钟端口,必须给它取个名字。
Create_clock -period 20 -name CLKA 虚拟时钟
Create_clock -period 20 [get_ports CLKC]
Set_input_delay 5.5 -clock CLKA -max [get_ports IN1]
a) 为什么出现一个端口多个约束呢?
因为频率不同,画出时序图可知,会出现发射沿 到采样沿,出现2个不同的时间。
b) 输入/输出约束差异
Set_input_delay 、和set_output_delay是通过设置外部电路约束的值,来约束要综合电路的。
输入:
一个输入端口一般只有一个输入,不会出现多驱动;所以set_input_delay只有一个设置值。
输出:
一个输入会带多个负载,两个负载是不同频率的同步时钟时,就会出现set_out_delay有两个设置值。
异步时钟约束
对穿越异步路径的任何路径,必须禁止对这些路径作约束。不要浪费DC的时间,试图使异步路径满足时序要求。
Set_false_path –from [get ports CLKA] -to [get ports CLKC]
时序路径的终点:不是输出端口或寄存器的数据输入端口么?为什么这里是两个CLK.
复杂时序约束
1) 多时钟周期约束
Hold分析时间:
重点:默认的hold分析时间在setup分析时间的前一个周期。但是在多时钟周期中,没有意思,这样会增加电路的复杂度;因此我们需要对保持时间做调整,在0ns时做hold检查。
原因:因为是时序电路,在后级寄存器把数据采到寄存器时,前及寄存器的输出也可能会变化。
Create_clock -period 10 [get_ports CLK]
Set_multicycle_path –setup 6 –to [get_pins C_reg[*]/D]
Set_multicycle_path –hold 5 –to [get_pins C_reg[*]/D] 必不可以少
这里用-hod 5 代替了默认的-hod 0
-hold 5:表示在0ns做检查
-hold 0:表示在建立时间的前一个周期做hold检查
2) 门控时钟约束
门控电路分两种:基于锁存器的和不基于锁存器的门控时钟单元。
3) 多路传输电路(时钟上带mux)
内部时钟连接到mux输出,如果不告诉DC要用哪个时钟,DC会自己选择一个,可能会出现DC选择不同的时钟做建立和保持分析。
Create _clock ext_clk –period 10
Create _clock test_clk –period 10
Set_dont_touch_network [get_clocks ext_clk]
Set_dont_touch_network [get_clocks test_clk]
Set_disable_timing CLOCK_GEN/U1 -from a –to y
如何选择呢通过mux的时钟呢?
Set_false_path命令不起作用:因为从mux引脚a和b到mux输出y是一条理想的时钟路径,不受约束。
方法1) Set_disable_timing,使库单元的时间弧无效(相当于断开)
方法2)使用模式分析特征(case analysis feature)对电路进行约束.
Set_case_analysis 0[get_pins U1/sel]
或
Set_case_analysis 0 [get_ports sel]
Set_case_analysis 会增加DC时间,但是使用简单。
4) 分频电路
时钟信号可以通过任何组合逻辑,但终止于寄存器。DC并不知道寄存器的输出是时钟信号还是非时钟信号。
Create_clock -period 50 [get_ports ext_clk]
Create_clock -name –int_clk –per 100 [get_pins CLOCK_GEN/U2/Q]
或Create_generate_clock -name –int_clk –source [get_pins CLOCK_GEN/U2/CP] –divide_by 2 [get_pins CLOCK_GEN/U2/Q] (推荐使用)
Set_clock_latency –source 1.5 [get_clock int_clk] (注:这里的-source指的是从实际时钟输入,即输入port口ext_clk ,而不是int_clk.
Set_clock_latency 0.5 [get_clock int_clk]
- 设计规则
Set_max_capacitance输入端口的最大电容设置
注意:set_load 用于设置输入或输出口的外部负载。
输入端口的最大内部负载 = 输入驱动的Set_max_capacitance —set_load(输入端口)。
Set_load和set_max_fanout的差别?
散出负载和散出数目的差别?
输入口和输出口约束的差别?
Set_max_fanout 使用的是扇出负载,表示一个扇出负载值,而不是扇出数目。
a) 扇出数目的作用:
线负载模型根据连线的扇出数目,估算连线的电阻和电容,而计算连线的延迟。
扇出数目:单元的输出引脚与其它单元的输入引脚之间连接的数目。
b) 扇出负载的作用:
扇出负载值是附加在输入端口。表示单元输入引脚相对负载的数目,并不是一个真正的电容负载,无量纲。
Set_max_fanout 1.0 [all_input]
也可以在输出端口上指定扇出负载值。
例:一个内部单元驱动几个其它内部单元且同时驱动一个输出端口。Set_load命令指定那个输出端口的实际电容负载。DC综合时遵从驱动单元的最大电容设计原则,但该命令没有为驱动单元的扇出提供约束,在输出端口使用set_fanout_load(?不是set_max_fanout?)命令时,可以为输出端口建立额外的预期扇出负载模型,DC综合也会使内部驱动单元的最大扇出遵从设计规则。
一、 静态时序分析:
起点:
输入端口
寄存器的CLK脚
终点:
输出端口
时序器件除时钟外的所有输入引脚(包括rst、clr)
1) 路径分组:
根据控制它们终点时钟进行分组;不被时钟控制的路径被分为default路径组。
2)路径的延迟与起点的边沿有关。
DC步骤:
1) 设计分路径组
2) 每条路径计算2次延迟,一次起点为上升沿,一次起点为下降沿;
3) 在每个路径组里找出关键路径
4) 显示每个路径组的时间报告
二、 优化
1) 结构级的优化
结构级的优化:用共用子表达式来减少逻辑,在电路中加入中间变量和逻辑结构。
a) 设计结构的选择
b) 数据通路的优化
c) 共享共同的子表达式
d) 资源共享(少用算术运算符)算术运算资源共享的默认策略是约束驱动的。
最好在代码编写阶段注意,少用运算,多用mux。
结构优化命令:Set_structure true
2) 逻辑级的优化
e) 结构优化
结构级的优化:用共用子表达式来减少逻辑,在电路中加入中间变量和逻辑结构。
共用子表达式:结构级指算术电路的共用子表达式,逻辑级指门电路的,
f) 展平优化
指把组合逻辑减少为2级,变为乘积之和,即先与后或的电路。做速度优化,电路面积会很大。
Set_flatten ture –effort low |medium |high
3) 门级优化
门级优化会做组合功能和时序功能的映射。
包含4个步骤
延迟优化;
设计规则修整;
以时序为代价的设计规则修整;
面积优化
映射过程中,DC会检查电路是否满足设计规则的约束,如有违反之处,DC会插入一些buffer和修改电路的驱动能力进行设计规则的修整。
三、 优化策略
综合优化,会有很多违反设计约束和设计规则的地方,需要分析结果,采取适当的措施解决。
对大的问题,修改代码和约束,再编辑修改
对于小的问题,时序违反在时钟周期的10%~25%或更小,采用以下方式
1) 使用compile_ultra命令
为算术运算选择适当的宏单元;选择最好的数据通路;映射宽扇入以减少逻辑级数;逻辑复制;在关键路径自动取消层次划分
Set compile_ultra_ungroup_dw true 所有的层次会被取消。
2) 边界优化
传递常数和没连接的引脚
3) Behavior retiming(BRT)技术对门级网表优化
两个命令:
a) optimize_register 适用于包含寄存器 寄存器之间的冗余前移
b) pipeline_design 适用于纯组合逻辑 组合逻辑中插入寄存器改善时序
4) 适用compile –scan –inc命令
5) 适用自定义路径组合关键范围:即在综合脚本中进行路径分组
DC默认行为是为关键路径做优化,当不能找到更好的优化解决时,综合停止,DC不会对次关键路径做优化。
默认情况下,所有路径属于同样的时钟组。
Group_path –name INPUT –from [all_inputs]
Group_path –name OUTPUT –from [all_outputs]
Group_path –name COMNO –from [all_inputs] –to [all_outputs]
三个自定义的路径组,加上原有的路径组(寄存器到寄存器的路径组),共4个路径组。
问题:静态时序分析中指出路径组划分是,终点被控制的时钟来划分,不被时钟控制的被划分为默认路径组和这里的不是矛盾么?
四、 网表的生成格式和处理
完成综合和时序分析后,需要把设计和约束以某种格式存储好,作为后端工具的输入。
把设计存档时,需要去掉assign指令,该指令会使非synopsys的工具产生问题;此外要保证网表中没有特别字符。写出网表中的“\”,不同的工具会有不一样的理解。
多端口连线,即一条连线连接多个端口,会在网表中产生assign指令。如果设计中有多端口连线,应该在编辑过程中将它们去掉,使用如下命令:
Set_fix_multple_port_net –all -buffer_constants [get_design *]
Compile -incr
特别字符指字母、数字、下划线以外的任何字符,chang_names将设计中的特别字符取消。
1)模块之间输入和输出寄存问题
在ASIC芯片内部模块之间可以采用组合逻辑输入和输出,因为芯片内部的时延迟比较小(在不影响性能的情况下,采用寄存器锁存输入和输出会更好);对不同的ASIC芯片之间的输入和输出必行采用寄存器,因为芯片之间的板间时延往往比较大,如果不采用寄存器会大大增加后端实现的难度。
2)芯片的可测性设计
两种:串行扫描技术和内建自测BIST(build in self-test)
2) 同步时钟的FIFO
FIFO的结构:分为数据存储区及逻辑控制。
实现的两种方式:数据移动型(采用寄存器阵列实现的)和读写指针移动型(memroy)
基于存储器结构的:
当fifo为满时,fifo需要反馈回上游节点,通知上游节点停止发数据,在这个通讯过程中,上游节点可能还在发数据,这就需要预留几个数据存储单元。
寄存器阵列:ASIC中常用这种实现
特点:可以自由配置FIFO的宽度和深度
大的寄存器阵列将影响后端实现布局布线,所以采用寄存器阵列实现的,不宜实现深度很深的FIFO。
设计思想:
数据在相邻的cell之间移动达到先进先出的目的。首先实现FIFO中一个最基本的单元cell逻辑,根据深度和宽度,将最基本的单元cell进行编号,并串联起来组成所需要的规格。
当读操作时:fifo的第一个cell输出数据,并且后面的数据将依次向前移动一个cell;当写操作时,数据被写入fifo中空cell中编号最小的一个。读写操作可以同时进行,只需要一个周期完成读写操作。
基本单元cell的逻辑行为:
Cell控制逻辑需完成以下操作:
1) 根据读写控制信号及相邻cell的空满信号改变自身的空满信号。
2) 根据读写控制信号及相邻cell的空满信号控制cell中寄存器阵列中数据的读出和写入。
当同时对FIFO进行读写操作时,不改变当前cell的空满状态。
说明:先进先出原则
1) 因为读操作,从编号最小的cell中出,最左端要输入0;如果next_cell为空,左边的cell均为空。
2)写操作,写入编号最小的一个cell,如果last_cell为满,右边的cell均为满。
3)!next_cell_full &&cell_full 表示cell是编号最大的非空cell;Last_cell_full &&!cell _ full 表示cell是编号最小的空cell。
DC - 天涯 - yxwyangxinwei的博客
异步FIFO:
组成:基于memory和读写控制
空满标志的产生:
1)当读写地址相同的时,表示空或满。为区分,加一个标志bit位。当读写地址完全相同时,表示FIFO空;当低bit相同而最高bit不同时,表示FIFO满。
问题:异步fifo,不能采用寄存器阵列结构的么?
编码风格:思考
为什么要将时序和组合分开:感觉可以合并在一起的逻辑。
1) 是写的复杂?
2) 便于用case?而不用if_else? 条件复杂?
3) 便于组合逻辑。不能用太多的时序电路?
个人观点:
定义一些变量,这样代码清晰,否则条件判断上逻辑复杂,代码可读性差
BFM:
1)基于任务级的BFM:一般用于任务级的测试
2)基于状态机的BFM :适合系统级的,有多个总线
代码综合:
If、if-else、case比较
1) if结构
多种if是有优先级结构的,最后一个if的优先级最高。
原因:多重if中最后的条件优先级最高,因为是顺序执行的,同时满足条件时,前面的会被覆盖。
lf_elseif_else :还是认为有优先级
没有优先级结构,各个选择路径延迟相同,但是要多用与门(书上的说法)。从下面实际综合结构看,if—elseif_else 也是有优先级的,if的优先级最高,也没有多消耗与门,跟自己的想法一致。(可能是综合工具和工艺库不同)
Case:
Case 没有优先级,各个路径的延迟相同。这也许就是为什么
always @(*)
begin
z=0;
if(sel[0]) z=a;
if(sel[1]) z=b;
if(sel[2]) z=c;
if(sel[3]) z=d; //优先级最高
end
always @(*)
begin
z=0;
if(sel[0]) z=a; //优先级最高
else if(sel[1]) z=b;
else if(sel[2]) z=c;
else if(sel[3]) z=d;
end
always @(*)
begin
case(sel)
4’b0001 : z=a;
4’b0010 : z=b;
4’b0100 : z=c;
4’b1000 : z=d;
default : z=0;
endcase
end
上面三种方式综合后门电路如图:
If—if结构
DC - 天涯 - yxwyangxinwei的博客
If_else结构
DC - 天涯 - yxwyangxinwei的博客
书上说的的if_else结构如下,这种mux不是最终的门级结构,
Case结构
DC - 天涯 - yxwyangxinwei的博客