1、设计导入 很多公司都有专门做逻辑综合的工程师。综合工程师需要把综合后的Netlist和Constraint(sdc时序约束文件)发给数字后端工程师。随后我们作为数字后端工程师就可以开始干活了。
时钟约束sdc主要内容如下: 1)timing相关基本单位设置 2)max_fanout,max_transition设定 3)设置模块端口port的驱动(时钟和data 分开设,因为时钟会更快) 4)设置output的load 5)创建时钟,定义好时钟周期(频率=1.0/T,其中T为时钟周期) 6)时序例外,比如set_multicycle_path,set_false_path等 7)模块接口的input delay和output 约束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 set sdc_version 1 .7 # 设置基本单位 set_units -time ns -resistance kOhm -capacitance pF -voltage V -current mA # fanout和transition约束(这个我们在PR flow中也会设置) set_max_fanout 32 [current_design] set_max_transition 0 .4 [current_design] set_driving_cell -lib_cell CKBD4BWP40P140 -pin Z -from_pin I -input_transition_rise 0 .15 -input_transition_fall 0 .15 [get_ports CLKIN] # 模块port的驱动指定 set_driving_cell -lib_cell BUFFD4BWP40P140 -pin Z -from_pin I -input_transition_rise 0 .3 -input_transition_fall 0 .3 [remove_from_collection [all_inputs] [get_ports CLKIN]] set_load -pin_load 0 .02 [all_outputs] # 最核心的定义,创建时钟,并指定时钟周期 set clock_period 1 .0 create_clock [get_ports CLKIN] -period $clock_period # 创建虚拟时钟,为了后面给io port端口约束input 和output delay create_clock -name VCLK -period $clock_period # 多周期路径设定 set_multicycle_path 2 -setup -from [get_ports DFTSE] set_multicycle_path 1 -hold -end -from [get_ports DFTSE] set_multicycle_path 2 -setup -from [get_ports DFTRSTDISABLE] set_multicycle_path 1 -hold -end -from [get_ports DFTRSTDISABLE] set_multicycle_path 2 -setup -from [get_ports DFTRAMHOLD] set_multicycle_path 1 -hold -end -from [get_ports DFTRAMHOLD] # ---------------------------------------------------------------------- # Define cycle percentage expressions # ---------------------------------------------------------------------- # Temporary variables used during constraint generation e.g . $cycle20, $cycle60 # reduce the i incr value to 1 to create a complete $cycle00 .. $cycle99 range for {set i 0 } {$i < 100 } {incr i 5 } { set cycle[format "%#02d" $i ] [expr 0 .01 * ${i} * ${clock_period}] } # ---------------------------------------------------------------------- # DFT ports # ---------------------------------------------------------------------- # input delay和output delay设定 set_input_delay -clock VCLK $cycle20 [get_ports DFTSE] set_input_delay -clock VCLK $cycle60 [get_ports DFTRSTDISABLE] set_input_delay -clock VCLK $cycle20 [get_ports DFTRAMHOLD]
注释代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 set sdc_version 1 .7 # 设置基本单位 ## 军师深度批注:这是定义整个芯片世界的“物理法则”。 ## 指定了时间=纳秒(ns),电容=皮法(pF)。这意味着下面代码里出现的所有数字 1 .0 、0 .4 ,都是以纳秒为单位。 set_units -time ns -resistance kOhm -capacitance pF -voltage V -current mA # fanout和transition约束(这个我们在PR flow中也会设置) ## 军师深度批注:【最大扇出 (Max Fanout)】—— 规定一个逻辑门最多只能连接 32 个下级门。 ## 就像一个老师最多只能同时对 32 个学生喊话,带的人太多,信号就会严重衰减。 set_max_fanout 32 [current_design] ## 军师深度批注:【最大转换时间 (Max Transition)】—— 规定信号从 0 变 1 的翻转时间不能超过 0 .4ns 。 ## 这就好比汽车换挡,离合器“半联动”的状态不能持续太久,否则齿轮(晶体管)会剧烈发热甚至烧毁。 set_max_transition 0 .4 [current_design] ## 军师深度批注:【驱动单元 (Driving Cell)】—— 告诉后端工具,外界是用多大的“发动机”把信号推进芯片的。 ## 这里给时钟引脚 CLKIN 强行绑定了台积电库里的专用时钟缓冲器 (CKBD4BWP40P140),上升/下降极其凌厉 (0 .15ns )。 set_driving_cell -lib_cell CKBD4BWP40P140 -pin Z -from_pin I -input_transition_rise 0 .15 -input_transition_fall 0 .15 [get_ports CLKIN] # 模块port的驱动指定 ## 军师深度批注:把除了 CLKIN 之外的所有普通输入引脚,挂上普通的缓冲器 (BUFFD4BWP40P140),速度稍慢一点 (0 .3ns )。 set_driving_cell -lib_cell BUFFD4BWP40P140 -pin Z -from_pin I -input_transition_rise 0 .3 -input_transition_fall 0 .3 [remove_from_collection [all_inputs] [get_ports CLKIN]] ## 军师深度批注:【负载电容 (Load)】—— 告诉工具芯片输出脚外面接的“大门”有多重 (0 .02pF )。 ## 如果不设这个,工具会以为外面是零阻力的真空环境,算出来的速度全是虚假的,流片回来一接外设直接死机。 set_load -pin_load 0 .02 [all_outputs] # 最核心的定义,创建时钟,并指定时钟周期 ## 军师深度批注:🔥 高能预警!1 .0ns 的周期意味着这颗芯片的频率是 1 GHz! ## 在数字后端里,这是一个极具挑战性的性能靶心,你后面的时序收敛将会是一场恶战。 set clock_period 1 .0 create_clock [get_ports CLKIN] -period $clock_period # 创建虚拟时钟,为了后面给io port端口约束input 和output delay ## 军师深度批注:【虚拟时钟 (Virtual Clock)】—— 凭空捏造一个“影子时钟”。 ## 因为我们要约束外部信号什么时候到达,必须得有一个绝对的“世界标准时间”作为参考系。 create_clock -name VCLK -period $clock_period # 多周期路径设定 ## 军师深度批注:【多周期路径 (Multicycle Path)】—— 给测试信号 (DFT) 发特权通行证。 ## 它们不需要跑 1 GHz 那么快。-setup 2 告诉工具:建立时间放宽到第 2 个周期再查(给 2 .0ns 的宽裕时间)。 set_multicycle_path 2 -setup -from [get_ports DFTSE] ## 军师深度批注:【极其老道的保命写法规】 -hold 1 强行把保持时间检查点拉回第 1 个周期! ## 如果不加这句,Hold 检查也会跟着推迟,导致后端工具疯狂瞎插 Buffer(缓冲器),直接把你的芯片面积撑爆! set_multicycle_path 1 -hold -end -from [get_ports DFTSE] set_multicycle_path 2 -setup -from [get_ports DFTRSTDISABLE] set_multicycle_path 1 -hold -end -from [get_ports DFTRSTDISABLE] set_multicycle_path 2 -setup -from [get_ports DFTRAMHOLD] set_multicycle_path 1 -hold -end -from [get_ports DFTRAMHOLD] # ---------------------------------------------------------------------- # Define cycle percentage expressions # ---------------------------------------------------------------------- # Temporary variables used during constraint generation e.g . $cycle20, $cycle60 # reduce the i incr value to 1 to create a complete $cycle00 .. $cycle99 range ## 军师深度批注:【TCL 动态脚本艺术】—— 这是一个自动生成百分比变量的 for 循环。 ## 它会根据上面的 1 .0ns 周期,自动算出 $cycle20 就是 0 .2ns 。 ## 为什么这么写?如果以后老板说降频到 500 MHz,你只需要把上面的 clock_period 改成 2 .0 。下面的延迟参数会自动跟着按比例放大!这就是顶级架构师的自动化思维。 for {set i 0 } {$i < 100 } {incr i 5 } { set cycle[format "%#02d" $i ] [expr 0 .01 * ${i} * ${clock_period}] } # ---------------------------------------------------------------------- # DFT ports # ---------------------------------------------------------------------- # input delay和output delay设定 ## 军师深度批注:【输入延迟 (Input Delay)】—— 明确告诉工具,DFTSE 这个信号,会在影子时钟 VCLK 敲响之后的 0 .2ns ($cycle20) 准时到达芯片大门口。 set_input_delay -clock VCLK $cycle20 [get_ports DFTSE] set_input_delay -clock VCLK $cycle60 [get_ports DFTRSTDISABLE] set_input_delay -clock VCLK $cycle20 [get_ports DFTRAMHOLD]
综合后的netlist如下。top module名字叫cortexa7core,module中的各个信号即为我们这个模块的所有io端口。
Netlist本质是一个电路图,只不过以netlist的形式呈现出来,作为后端布局布线的输入设计文件。所以netlist代表的是逻辑连接关系。下图的Netlist和Schematic(电路原理图)是等价的。
而我们后端要做的是基于这个逻辑连接实现实际的物理金属连接。所以数字后端实现也叫物理实现或物理设计(Physical Implementation /Physical Design)。
这里可以把这个netlist理解成盖房子前要有的设计图纸,而后端实现要做的工作就是基于设计的图纸把房子给盖出来。
有了netlist和constraint,我们就可以做设计导入了。
设计导入的脚本非常简单,就下面几句话。核心命令就是init_design。
这个脚本中读取了一个innovus支持的globals文件,它的内容包含以下几大部分。
而这个globals文件中又包含了一个mmmc的文件,这个文件内容的准备包含6大步骤,具体如下图所示。
以上信息配置完成后,我们就可以source我们scripts目录下的01_innovus_import_design.tcl 。
当然,我们新手可以打开01_innovus_import_design.tcl ,一步步执行里面的脚本命令。
设计导入完成后, 效果图如下图所示。
设计导入后我们最好检查下导入的设计是否代码上的设计问题,比如是否有multi-driver问题,io port悬空等问题。
使用的命令如下:
执行后的结果如下图所示:
这里举一三个常见的警告。
1)没有tie cell的警告 比如下面这个报告有instance的某些pin要连接到tie cell上(接0或接1信号),却没有找到tie cell。而且设计中有多个这样的信号,所以对应的是TieLo的net,但是工具没有看到有对应的TieLo cell。
之所以有这个警告,是因为在设计导入我们还没让工具加tie cell,这步是在后续的place阶段完成的。所以这个警告是正常的。
2)High Fanout Net和cell有Dont use 属性的警告 在设计导入阶段,不论是clock或者是data,都是允许存在高扇出的net。为什么呢?
因为此时clock一定是高扇出net,因为RTL代码中一定是一个clock port直接接到所有的sink上。一个设计中的sink是寄存器的CLK pin和memory的CLK pin,所以一般都有好几万的sink。时钟信号的high fanout处理就是后续时钟树综合要解决的问题。
data上如果有高扇出的net,也是没有问题的。因为在PR flow中除了CTS阶段外,其他任何阶段涉及到时序的优化都会帮我们解决data path上的高扇出net问题。
对于下图中报告的macro有dont use属性是正常的。这是因为macro相当于是第三方IP,供我们调用的,我们是无法更改它内部的东西,工具更无法针对它做任何的优化。如果能优化那才会出事,就无法保证第三方IP的功能。
3) output port floating(悬空问题) 由于实际项目中经常也会出现一些设计实际用不到的一些port。这是因为前端在做代码集成时是根据当前的spec需求,拿着原来的RTL进行集成的,所以难免会出现当前设计中有些port是用不到的情况。这就像我们买来一部手机,里面有些功能对我们来说可能一辈子都用不到。
2、查看设计 设计导入成功后,我们可以通过查看设计来了解当前设计的规模,设计中各个子功能模块以及memory的数量。
上图中的Terms是指设计中的io port端口,Nets是这些io port对应的net。