
数字IC后端实现这活儿说到底是跟工具死磕的过程。Cadence Innovus作为业界主流的后端实现平台从导入网表到最终GDSII输出每个阶段都有大量命令需要掌握。我做了十多年后端实现带过不少新人发现一个普遍问题很多人跑完flow就完了问他某个阶段用了什么命令、为什么用这个命令答不上来。这就像开车只会踩油门不知道刹车和离合是干嘛的。这篇内容我把自己在Innovus各阶段常用的命令做一个系统梳理从设计导入、Floorplan、Powerplan、Placement、CTS到Routing和Signoff每个阶段挑出真正高频、真正影响结果的命令来讲。不光列命令还会说清楚每个命令背后的意图、关键参数怎么设、什么场景下用哪个选项。适合刚入行的后端工程师建立命令体系也适合有经验的工程师查漏补缺。1. 设计导入与初始化阶段的命令选择1.1 网表与LEF导入init_design的完整参数链Innovus启动后的第一件事就是导入设计。很多人习惯用init_design一把梭但这个命令的参数其实很讲究。最基本的用法是init_design -netlist ./netlist/top.v \ -lef ./lef/tech.lef \ -lef ./lef/cells.lef \ -mmmc ./mmmc/view_definition.tcl这里每个参数都有讲究。-netlist指定结构网表注意Innovus读的是门级网表不是RTL。-lef可以多次指定先读tech LEF再读cell LEF顺序不能反因为cell LEF依赖tech LEF中定义的层信息。-mmmc指向多模式多端角配置文件这个文件里定义了RC corner、PVT corner和mode的组合关系。我见过有新人把LEF顺序搞反了结果工具报layer not defined的错误排查半天。还有个常见问题是网表里包含了物理单元比如FILLER、DECAP这些不应该在初始网表里出现应该在后续阶段由工具自动插入。如果网表里已经有了用-deleteInst选项或者在导入后用remove_inst清掉。导入完成后第一件事是检查设计状态checkDesign -all check_design.rpt summaryReport -noHtml -outfile summary.rptcheckDesign会检查网表完整性、LEF与网表的匹配性、时序约束的合理性等。summaryReport给出设计的规模统计——instance数量、net数量、面积、利用率等。这两个报告一定要看很多后续问题的根源就在导入阶段。1.2 MMMC配置view_definition的写法与常见错误MMMC配置是后端实现的基石。一个典型的view_definition.tcl长这样create_rc_corner -name rc_max -T 125 -qx_tech_file ./qrc/max.tch create_rc_corner -name rc_min -T -40 -qx_tech_file ./qrc/min.tch create_delay_corner -name dc_max -rc_corner rc_max create_delay_corner -name dc_min -rc_corner rc_min create_constraint_mode -name func -sdc_files {./sdc/func.sdc} create_analysis_view -name av_max -delay_corner dc_max -constraint_mode func create_analysis_view -name av_min -delay_corner dc_min -constraint_mode func set_analysis_view -setup {av_max} -hold {av_min}这里的关键是set_analysis_view它告诉工具在setup分析时用哪个viewhold分析时用哪个view。很多新人在这里犯错——setup和hold用了同一个delay corner结果时序分析完全不对。setup要用最慢的cornermax RC、高温hold要用最快的cornermin RC、低温这是基本常识。还有个坑是constraint mode的SDC文件。如果SDC里有多条clock定义要确认每条clock都被正确约束。我习惯在导入后跑一遍report_clocks和report_timing确认时钟定义和时序路径都符合预期。1.3 电源意图文件UPF的加载时机如果设计有低功耗需求UPF文件的加载时机很关键。必须在init_design之后、floorplan之前加载load_upf ./upf/top.upf加载后立即检查report_power_domain check_upf -allreport_power_domain列出所有电源域及其状态check_upf检查UPF文件的语法和逻辑正确性。我遇到过UPF里电源域嵌套关系写错的情况导致后续Powerplan阶段PG连接完全乱套。所以这一步的检查不能省。2. Floorplan阶段的命令与实操逻辑2.1 初始化FloorplanfloorPlan命令的参数计算Floorplan是决定芯片物理形状和模块摆放的关键步骤。最常用的命令是floorPlan -site core_site \ -r 1.0 0.7 5.0 5.0 5.0 5.0 \ -coreMarginsBy io-r参数指定宽高比aspect ratio和利用率utilization后面四个数字是core到IO边界的margin。宽高比1.0表示正方形0.7表示高度是宽度的0.7倍。利用率是指标准单元面积占core面积的比例一般设在0.6到0.75之间。为什么利用率不能太高超过0.8之后Placement阶段会非常拥挤Routing阶段容易出现DRC违例。但也不能太低否则面积浪费成本上去了。我的经验是如果设计以组合逻辑为主利用率可以到0.75如果寄存器多、时钟树复杂降到0.65左右更稳妥。-coreMarginsBy io表示margin从IO边界算起。如果设计没有IO ring可以用-coreMarginsBy die。执行完floorPlan后用reportFPlan查看结果reportFPlan -summary这个报告会给出core面积、利用率、宽高比等关键数据确认是否符合预期。2.2 模块摆放与区域约束createRegion与placeInstance对于层次化设计需要给每个模块划定区域createRegion -name region_cpu -box {100 100 500 400} placeInstance cpu_core -region region_cpucreateRegion定义一个矩形区域placeInstance把模块实例放进去。这里有个技巧区域之间要留够通道channel给布线。通道宽度取决于模块间的连接密度一般留20到50微米。我通常用reportNetConnectivity查看模块间的net数量连接多的模块之间通道留宽一些。还有个命令createGuide用于给模块指定相对位置关系但不强制固定createGuide -name guide_cpu -box {100 100 500 400} -type softsoft guide允许工具在优化时调整模块位置hard guide则完全固定。初期用soft后期timing紧张时改成hard。2.3 引脚摆放editPin的批量操作技巧IO引脚和模块引脚的摆放直接影响布线难度。editPin是最常用的命令editPin -pin {data_in[*]} -side Left -layer M4 -spreadType center -spacing 2.0-pin支持通配符data_in[*]会匹配所有data_in的bit。-side指定边-layer指定引脚所在的金属层-spreadType控制分布方式center/edge/even-spacing是引脚间距。批量摆放时我习惯先用reportPin查看当前引脚状态然后按总线分组摆放。比如数据总线放左边地址总线放上边控制信号放下边。这样布线时走线方向一致减少交叉。有个容易忽略的点引脚所在的金属层要和Powerplan的PG网格协调。如果引脚在M4而M4被PG stripe占用引脚就放不上去。所以引脚摆放要在Powerplan之前做或者预留PG通道。3. Powerplan阶段的PG网格构建命令3.1 全局PG网格addRing与addStripe的配合Powerplan的核心是构建电源地网格。第一步是加ringaddRing -nets {VDD VSS} \ -type core_rings \ -layer {top M5 bottom M5 left M6 right M6} \ -width 3.0 -spacing 1.5 \ -offset 2.0-nets指定电源地网络名-type core_rings表示core周围的ring。-layer指定每边用的金属层一般用较厚的顶层金属。-width是ring宽度-spacing是VDD和VSS之间的间距-offset是ring到core边界的距离。ring的宽度怎么定要看设计的功耗。粗略估算每100微米ring宽度能承载约1mA电流具体取决于金属层和工艺。如果设计功耗500mAring宽度至少5微米。当然实际要用PDN分析工具验证IR drop。然后是stripeaddStripe -nets {VDD VSS} \ -layer M5 \ -direction vertical \ -width 2.0 -spacing 1.0 \ -set_to_set_distance 30.0 \ -start_from left-direction指定stripe方向-set_to_set_distance是相邻VDD-VSS组的间距。这个间距决定了PG网格的密度。间距越小IR drop越好但布线资源被占用越多。一般M5/M6层做垂直stripeM7/M8层做水平stripe形成网格。3.2 模块PG连接sroute与connectCoreToRing全局网格建好后要把标准单元的PG引脚连到网格上sroute -connect {corePin blockPin padPin} \ -layerChangeRange {M1 M6} \ -corePinMaxViaWidth 0.5sroute是自动PG布线命令。-connect指定要连接的对象类型-layerChangeRange指定允许的层切换范围。-corePinMaxViaWidth限制via的最大宽度避免via太大影响布线。对于macro模块还需要单独连接sroute -connect {blockPin} -selectedInst {macro1 macro2}我踩过的一个坑sroute之后没有检查PG连接完整性结果Placement阶段发现有些标准单元的PG引脚悬空。所以sroute之后一定要跑verifyConnectivity -type special -error 1000 -report pg_connect.rpt这个命令检查PG连接的完整性报告悬空或短路的net。3.3 PG网格验证verifyPowerVia与IR drop预分析PG网格建完后验证步骤不能省verifyPowerVia -error 100 -report pg_via.rpt checkPGConnectivity -report pg_conn.rptverifyPowerVia检查PG via的完整性checkPGConnectivity检查PG网络的连通性。这两个报告如果有error必须修掉才能进入下一步。IR drop预分析可以用analyzePowerGrid -method static -report ir_drop.rpt静态IR drop分析给出电压降的分布。一般要求IR drop不超过电源电压的5%。如果超标需要加宽stripe或减小间距。4. Placement阶段的命令与优化策略4.1 标准单元摆放place_opt的核心选项Placement阶段的核心命令是place_opt -effort high -congestion -timing_driven-effort控制优化力度high会花更多时间但结果更好。-congestion开启拥塞优化-timing_driven开启时序驱动。对于时序紧张的设计还可以加-power_driven做功耗优化。place_opt之前先设置好优化目标setPlaceMode -congEffort high -timingDriven true -clkGateAware true-clkGateAware让工具考虑时钟门控单元的摆放这对低功耗设计很重要。place_opt跑完后检查结果reportCongestion -hotSpot -overflow 0.1 checkPlace -report place_check.rptreportCongestion报告拥塞热点checkPlace检查摆放合法性有没有重叠、有没有超出core区域。4.2 扫描链重排序scanReorder的时机如果设计有扫描链Placement之后要做扫描链重排序scanReorder -scanChain all -effort high这个命令重新排列扫描链中的寄存器顺序减少扫描链的走线长度。为什么要做因为原始扫描链顺序是逻辑连接决定的物理上可能绕很远。重排序后扫描链的wirelength能减少30%以上。但scanReorder有个风险可能改变寄存器的时钟域关系。所以重排序后要重新检查时序report_timing -from [all_registers] -to [all_registers] -max_paths 1004.3 布局后的时序与拥塞分析Placement完成后要做全面的时序和拥塞分析report_timing -max_paths 1000 -nworst 10 timing_place.rpt reportCongestion -overflow 0.05 cong_place.rpt时序报告要看WNSworst negative slack和TNStotal negative slack。Placement阶段WNS一般还有余量因为CTS和Routing还会优化。但如果WNS已经很大比如超过-500ps说明约束太紧或Floorplan有问题要回头调整。拥塞报告看overflow的分布。如果某个区域overflow严重可能是模块摆放不合理或者PG stripe太密。我通常用gui_showCongestion在GUI里看拥塞热图直观很多。5. CTS阶段的时钟树综合命令5.1 时钟树约束create_clock与set_clock_tree_optionsCTS之前要确认时钟定义正确create_clock -name clk -period 2.0 -waveform {0 1.0} [get_ports clk] set_clock_uncertainty -setup 0.15 [get_clocks clk] set_clock_transition -max 0.1 [get_clocks clk]-period是时钟周期-waveform定义上升沿和下降沿时刻。set_clock_uncertainty设置时钟不确定性jitterskewset_clock_transition设置时钟转换时间。然后设置时钟树综合选项set_clock_tree_options -target_skew 0.05 \ -max_transition 0.15 \ -max_capacitance 0.2 \ -buffer_list {CLKBUF_X2 CLKBUF_X4 CLKBUF_X8}-target_skew是目标skew一般设时钟周期的5%左右。-buffer_list指定可用于时钟树的buffer类型要选驱动能力适中的太小驱动不够太大功耗高。5.2 CTS执行ccopt_design的流程Innovus的CTS用ccopt_designccopt_design -cts这个命令会自动构建时钟树。执行过程中会插入buffer、调整skew、优化insertion delay。跑完后检查report_clock_tree -summary cts_summary.rpt report_clock_timing -type skew cts_skew.rptreport_clock_tree给出时钟树的整体统计——buffer数量、级数、skew等。report_clock_timing给出每个时钟的skew详情。一般要求skew在target的±20%以内。5.3 时钟树后的时序修复ccopt_design -postCTSCTS完成后时序会发生变化时钟树延迟改变了寄存器时钟到达时间需要做post-CTS优化ccopt_design -postCTS这个阶段会修复setup和hold违例。注意post-CTS阶段hold修复要谨慎因为此时时钟树已经固定修hold只能靠插buffer可能影响setup。我通常先修setup再修hold最后再检查setup有没有被影响。6. Routing阶段的命令与DRC收敛6.1 全局布线routeDesign的选项Routing分全局布线和详细布线两步routeDesign -globalDetail这个命令同时跑全局和详细布线。如果设计很大可以分开跑routeDesign -global routeDesign -detail全局布线决定走线的大致路径详细布线确定具体的track和via。routeDesign的常用选项setRouteMode -earlyGlobalMaxRouteLayer M6 \ -earlyGlobalMinRouteLayer M2 \ -routeWithViaInPin true-earlyGlobalMaxRouteLayer限制全局布线的最高层-routeWithViaInPin允许在pin内打via这对高密度设计很有用。6.2 布线后的DRC修复verifyGeometry与editDelete布线完成后检查DRCverifyGeometry -report drc.rpt如果有DRC违例可以用editDelete删除违例的wire然后重新绕线editDelete -type Special -net {VDD VSS}但更常用的方法是让工具自动修复routeDesign -detail -fix_drc或者用optDesign -postRoute -drv修复DRC和时序。6.3 时序驱动的ECOecoRoute的使用如果Routing后还有时序违例需要做ECOecoRoute -fix_drc -fix_timingecoRoute只重新绕线受影响的net不重跑整个布线速度快很多。ECO之前要先用optDesign做时序优化optDesign -postRoute -setup -hold这个命令会插入buffer、调整size、重新绕线来修复时序。注意postRoute阶段的hold修复要特别小心因为此时绕线资源紧张插buffer可能导致新的DRC。7. Signoff阶段的验证命令7.1 时序签核report_timing的详细分析Signoff阶段要出详细的时序报告report_timing -max_paths 10000 -nworst 100 -path_type full_clock_expanded timing_signoff.rpt-path_type full_clock_expanded展开完整的时钟路径包括时钟树上的buffer。这个报告用于确认setup和hold都满足约束。还要检查时序例外report_timing -exceptions exceptions.rpt确认false path、multicycle path都正确应用了。7.2 物理验证verifyConnectivity与verifyGeometry物理验证包括连接性检查和几何检查verifyConnectivity -type all -error 1000 conn.rpt verifyGeometry -error 1000 geom.rptverifyConnectivity检查所有net的连接完整性verifyGeometry检查DRC。这两个报告必须clean才能tapeout。7.3 输出GDSIIstreamOut的注意事项最后输出GDSIIstreamOut ./gds/top.gds -mapFile ./gds/gds.map -libName top -structureName top -mode ALL-mapFile指定层映射文件-mode ALL输出所有层次。输出后要用GDS viewer检查一遍确认没有缺失的层或错误的图形。我习惯在streamOut之前跑一遍checkDesign -all确保设计状态干净。还有个小技巧streamOut之后对比一下GDS的文件大小如果比预期小很多可能是某些层没输出。8. 各阶段命令的实战避坑经验8.1 命令执行顺序的依赖关系Innovus的命令有严格的执行顺序搞错了会报错或者结果不对。比如init_design必须在所有命令之前floorPlan必须在place_opt之前addRing和addStripe必须在sroute之前ccopt_design必须在routeDesign之前我见过有人在place_opt之后才加PG stripe结果工具报cannot add stripe after placement的错误。所以flow的顺序不能乱。8.2 常见报错与快速定位方法几个高频报错和解决方法报错信息原因解决方法layer not definedLEF顺序错误先读tech LEF再读cell LEFcannot find instance网表与LEF不匹配检查网表单元名和LEF是否一致PG pin floatingsroute未覆盖重新跑sroute或手动连接setup violation约束太紧或优化不够检查SDC增加optDesign effortDRC violation绕线资源不足调整Floorplan或增加绕线层8.3 命令日志与报告的管理习惯最后分享一个习惯每个阶段结束后保存命令日志和报告。Innovus支持setLogFile ./logs/place_opt.log setReportFile ./reports/place_opt.rpt这样出问题时可以回溯。我通常按阶段建目录01_init、02_floorplan、03_powerplan、04_place、05_cts、06_route、07_signoff。每个目录里放对应的命令脚本、日志和报告。项目交接时一目了然。还有个技巧用source命令把每个阶段的命令写成独立脚本主脚本按顺序source。这样修改某个阶段不用动整个flowsource ./scripts/01_init.tcl source ./scripts/02_floorplan.tcl source ./scripts/03_powerplan.tcl这种模块化的写法在项目迭代时特别方便改哪个阶段就改哪个脚本不会互相影响。