|
| 1 | +utl::set_metrics_stage "floorplan__{}" |
| 2 | +source $::env(SCRIPTS_DIR)/load.tcl |
| 3 | +load_design 1_synth.v 1_synth.sdc |
| 4 | + |
| 5 | +# Floorplan |
| 6 | + |
| 7 | +proc report_unused_masters { } { |
| 8 | + set db [ord::get_db] |
| 9 | + set libs [$db getLibs] |
| 10 | + set masters "" |
| 11 | + foreach lib $libs { |
| 12 | + foreach master [$lib getMasters] { |
| 13 | + # filter out non-block masters, or you can remove this conditional to detect any unused master |
| 14 | + if { [$master getType] == "BLOCK" } { |
| 15 | + lappend masters $master |
| 16 | + } |
| 17 | + } |
| 18 | + } |
| 19 | + |
| 20 | + set block [ord::get_db_block] |
| 21 | + set insts [$block getInsts] |
| 22 | + |
| 23 | + foreach inst $insts { |
| 24 | + set inst_master [$inst getMaster] |
| 25 | + set masters [lsearch -all -not -inline $masters $inst_master] |
| 26 | + } |
| 27 | + |
| 28 | + foreach master $masters { |
| 29 | + puts "Master [$master getName] is loaded but not used in the design" |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +report_unused_masters |
| 34 | + |
| 35 | +#Run check_setup |
| 36 | +puts "\n==========================================================================" |
| 37 | +puts "Floorplan check_setup" |
| 38 | +puts "--------------------------------------------------------------------------" |
| 39 | +check_setup |
| 40 | + |
| 41 | +set num_instances [llength [get_cells -hier *]] |
| 42 | +puts "number instances in verilog is $num_instances" |
| 43 | + |
| 44 | +set additional_args "" |
| 45 | +append_env_var additional_args ADDITIONAL_SITES -additional_sites 1 |
| 46 | + |
| 47 | +# Check which floorplan initialization method is specified (mutually exclusive) |
| 48 | +set use_floorplan_def [env_var_exists_and_non_empty FLOORPLAN_DEF] |
| 49 | +set use_footprint [env_var_exists_and_non_empty FOOTPRINT] |
| 50 | +set use_die_and_core_area \ |
| 51 | + [expr { [env_var_exists_and_non_empty DIE_AREA] && [env_var_exists_and_non_empty CORE_AREA] }] |
| 52 | +set use_core_utilization [env_var_exists_and_non_empty CORE_UTILIZATION] |
| 53 | + |
| 54 | +# Enforce mutual exclusion - exactly one method must be specified |
| 55 | +set methods_defined \ |
| 56 | + [expr { $use_floorplan_def + $use_footprint + $use_die_and_core_area + $use_core_utilization }] |
| 57 | +if { $methods_defined > 1 } { |
| 58 | + puts "Error: Floorplan initialization methods are mutually exclusive, pick one." |
| 59 | + exit 1 |
| 60 | +} |
| 61 | + |
| 62 | +# Method 1: Use existing DEF file with floorplan data |
| 63 | +if { $use_floorplan_def } { |
| 64 | + log_cmd read_def -floorplan_initialize $env(FLOORPLAN_DEF) |
| 65 | + # Method 2: Use ICeWall footprint file (platform-specific extension) |
| 66 | +} elseif { $use_footprint } { |
| 67 | + ICeWall load_footprint $env(FOOTPRINT) |
| 68 | + |
| 69 | + initialize_floorplan \ |
| 70 | + -die_area [ICeWall get_die_area] \ |
| 71 | + -core_area [ICeWall get_core_area] \ |
| 72 | + -site $::env(PLACE_SITE) |
| 73 | + |
| 74 | + ICeWall init_footprint $env(SIG_MAP_FILE) |
| 75 | + # Method 3: Use explicit die and core area coordinates |
| 76 | +} elseif { $use_die_and_core_area } { |
| 77 | + initialize_floorplan -die_area $::env(DIE_AREA) \ |
| 78 | + -core_area $::env(CORE_AREA) \ |
| 79 | + -site $::env(PLACE_SITE) \ |
| 80 | + {*}$additional_args |
| 81 | + # Method 4: Calculate core area from utilization, aspect ratio, and margins |
| 82 | +} elseif { $use_core_utilization } { |
| 83 | + initialize_floorplan -utilization $::env(CORE_UTILIZATION) \ |
| 84 | + -aspect_ratio $::env(CORE_ASPECT_RATIO) \ |
| 85 | + -core_space $::env(CORE_MARGIN) \ |
| 86 | + -site $::env(PLACE_SITE) \ |
| 87 | + {*}$additional_args |
| 88 | +} else { |
| 89 | + puts "Error: No floorplan initialization method specified" |
| 90 | + exit 1 |
| 91 | +} |
| 92 | + |
| 93 | +# Create routing tracks: MAKE_TRACKS script, platform make_tracks.tcl, or make_tracks command |
| 94 | +if { [env_var_exists_and_non_empty MAKE_TRACKS] } { |
| 95 | + log_cmd source $::env(MAKE_TRACKS) |
| 96 | +} elseif { [file exists $::env(PLATFORM_DIR)/make_tracks.tcl] } { |
| 97 | + log_cmd source $::env(PLATFORM_DIR)/make_tracks.tcl |
| 98 | +} else { |
| 99 | + make_tracks |
| 100 | +} |
| 101 | + |
| 102 | +# Configure global routing: FASTROUTE_TCL script or |
| 103 | +# set_global_routing_layer_adjustment/set_routing_layers |
| 104 | +if { [env_var_exists_and_non_empty FASTROUTE_TCL] } { |
| 105 | + log_cmd source $::env(FASTROUTE_TCL) |
| 106 | +} else { |
| 107 | + log_cmd \ |
| 108 | + set_global_routing_layer_adjustment \ |
| 109 | + $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) $::env(ROUTING_LAYER_ADJUSTMENT) |
| 110 | + log_cmd set_routing_layers -signal $::env(MIN_ROUTING_LAYER)-$::env(MAX_ROUTING_LAYER) |
| 111 | +} |
| 112 | + |
| 113 | +source_env_var_if_exists FOOTPRINT_TCL |
| 114 | + |
| 115 | +if { ![env_var_equal SKIP_REPAIR_TIE_FANOUT 1] } { |
| 116 | + # This needs to come before any call to remove_buffers. You could have one |
| 117 | + # tie driving multiple buffers that drive multiple outputs. |
| 118 | + # Repair tie lo fanout |
| 119 | + puts "Repair tie lo fanout..." |
| 120 | + set tielo_cell_name [lindex $::env(TIELO_CELL_AND_PORT) 0] |
| 121 | + set tielo_lib_name [get_name [get_property [lindex [get_lib_cell $tielo_cell_name] 0] library]] |
| 122 | + set tielo_pin $tielo_lib_name/$tielo_cell_name/[lindex $::env(TIELO_CELL_AND_PORT) 1] |
| 123 | + repair_tie_fanout -separation $::env(TIE_SEPARATION) $tielo_pin |
| 124 | + |
| 125 | + # Repair tie hi fanout |
| 126 | + puts "Repair tie hi fanout..." |
| 127 | + set tiehi_cell_name [lindex $::env(TIEHI_CELL_AND_PORT) 0] |
| 128 | + set tiehi_lib_name [get_name [get_property [lindex [get_lib_cell $tiehi_cell_name] 0] library]] |
| 129 | + set tiehi_pin $tiehi_lib_name/$tiehi_cell_name/[lindex $::env(TIEHI_CELL_AND_PORT) 1] |
| 130 | + repair_tie_fanout -separation $::env(TIE_SEPARATION) $tiehi_pin |
| 131 | +} |
| 132 | + |
| 133 | +if { [env_var_exists_and_non_empty SWAP_ARITH_OPERATORS] } { |
| 134 | + estimate_parasitics -placement |
| 135 | + replace_arith_modules |
| 136 | +} |
| 137 | + |
| 138 | +if { [env_var_equals REMOVE_ABC_BUFFERS 1] } { |
| 139 | + # remove buffers inserted by yosys/abc |
| 140 | + remove_buffers |
| 141 | +} else { |
| 142 | + # Skip clone & split |
| 143 | + set ::env(SETUP_MOVE_SEQUENCE) "unbuffer,sizeup,swap,buffer,vt_swap" |
| 144 | + set ::env(SKIP_LAST_GASP) 1 |
| 145 | + repair_timing_helper -setup |
| 146 | +} |
| 147 | + |
| 148 | +puts "Default units for flow" |
| 149 | +report_units |
| 150 | +report_units_metric |
| 151 | +report_metrics 2 "floorplan final" false false |
| 152 | + |
| 153 | +source_env_var_if_exists POST_FLOORPLAN_TCL |
| 154 | +source_env_var_if_exists IO_CONSTRAINTS |
| 155 | + |
| 156 | +write_db $::env(RESULTS_DIR)/2_1_floorplan.odb |
| 157 | +write_sdc -no_timestamp $::env(RESULTS_DIR)/2_1_floorplan.sdc |
| 158 | + |
| 159 | + |
| 160 | +# Macro placement |
| 161 | +source $::env(SCRIPTS_DIR)/macro_place_util.tcl |
| 162 | + |
| 163 | +write_db $::env(RESULTS_DIR)/2_2_floorplan_macro.odb |
| 164 | +write_macro_placement $::env(RESULTS_DIR)/2_2_floorplan_macro.tcl |
| 165 | + |
| 166 | + |
| 167 | +# Tapcell insertion |
| 168 | +if { [env_var_exists_and_non_empty TAPCELL_TCL] } { |
| 169 | + source $::env(TAPCELL_TCL) |
| 170 | +} else { |
| 171 | + cut_rows |
| 172 | +} |
| 173 | + |
| 174 | +write_db $::env(RESULTS_DIR)/2_3_floorplan_tapcell.odb |
| 175 | + |
| 176 | +# PDN |
| 177 | +source $::env(PDN_TCL) |
| 178 | +pdngen |
| 179 | + |
| 180 | +source_env_var_if_exists POST_PDN_TCL |
| 181 | + |
| 182 | +# Check all supply nets |
| 183 | +set block [ord::get_db_block] |
| 184 | +foreach net [$block getNets] { |
| 185 | + set type [$net getSigType] |
| 186 | + if { $type == "POWER" || $type == "GROUND" } { |
| 187 | + # Temporarily disable due to CI issues |
| 188 | + # puts "Check supply: [$net getName]" |
| 189 | + # check_power_grid -net [$net getName] |
| 190 | + } |
| 191 | +} |
| 192 | + |
| 193 | +write_db $::env(RESULTS_DIR)/2_4_floorplan_pdn.odb |
| 194 | + |
| 195 | +# Global placement skipping IOs |
| 196 | +if { [env_var_exists_and_non_empty FLOORPLAN_DEF] } { |
| 197 | + puts "FLOORPLAN_DEF is set. Skipping global placement without IOs" |
| 198 | +} elseif { [all_pins_placed] } { |
| 199 | + puts "All pins are placed. Skipping global placement without IOs" |
| 200 | +} else { |
| 201 | + log_cmd global_placement -skip_io -density [place_density_with_lb_addon] \ |
| 202 | + -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ |
| 203 | + -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ |
| 204 | + {*}[env_var_or_empty GLOBAL_PLACEMENT_ARGS] |
| 205 | +} |
| 206 | + |
| 207 | +write_db $::env(RESULTS_DIR)/3_1_place_gp_skip_io.odb |
| 208 | + |
| 209 | +# IO placement |
| 210 | +if { |
| 211 | + ![env_var_exists_and_non_empty FLOORPLAN_DEF] && |
| 212 | + ![env_var_exists_and_non_empty FOOTPRINT] && |
| 213 | + ![env_var_exists_and_non_empty FOOTPRINT_TCL] |
| 214 | +} { |
| 215 | + # load_design 3_1_place_gp_skip_io.odb 2_floorplan.sdc |
| 216 | + log_cmd place_pins \ |
| 217 | + -hor_layers $::env(IO_PLACER_H) \ |
| 218 | + -ver_layers $::env(IO_PLACER_V) \ |
| 219 | + {*}[env_var_or_empty PLACE_PINS_ARGS] |
| 220 | + write_db $::env(RESULTS_DIR)/3_2_place_iop.odb |
| 221 | + write_pin_placement $::env(RESULTS_DIR)/3_2_place_iop.tcl |
| 222 | +} else { |
| 223 | + log_cmd exec cp $::env(RESULTS_DIR)/3_1_place_gp_skip_io.odb $::env(RESULTS_DIR)/3_2_place_iop.odb |
| 224 | +} |
| 225 | + |
| 226 | +# Global placement |
| 227 | +utl::set_metrics_stage "globalplace__{}" |
| 228 | +set_dont_use $::env(DONT_USE_CELLS) |
| 229 | + |
| 230 | +if { $::env(GPL_TIMING_DRIVEN) } { |
| 231 | + remove_buffers |
| 232 | +} |
| 233 | + |
| 234 | +# Do not buffer chip-level designs |
| 235 | +# by default, IO ports will be buffered |
| 236 | +# to not buffer IO ports, set environment variable |
| 237 | +# DONT_BUFFER_PORT = 1 |
| 238 | +if { ![env_var_exists_and_non_empty FOOTPRINT] } { |
| 239 | + if { ![env_var_equals DONT_BUFFER_PORTS 1] } { |
| 240 | + puts "Perform port buffering..." |
| 241 | + buffer_ports |
| 242 | + } |
| 243 | +} |
| 244 | + |
| 245 | +set global_placement_args {} |
| 246 | + |
| 247 | +# Parameters for routability mode in global placement |
| 248 | +append_env_var global_placement_args GPL_ROUTABILITY_DRIVEN -routability_driven 0 |
| 249 | + |
| 250 | +# Parameters for timing driven mode in global placement |
| 251 | +if { $::env(GPL_TIMING_DRIVEN) } { |
| 252 | + lappend global_placement_args {-timing_driven} |
| 253 | + if { [info exists ::env(GPL_KEEP_OVERFLOW)] } { |
| 254 | + lappend global_placement_args -keep_resize_below_overflow $::env(GPL_KEEP_OVERFLOW) |
| 255 | + } |
| 256 | +} |
| 257 | + |
| 258 | +proc do_placement { global_placement_args } { |
| 259 | + set all_args [concat [list -density [place_density_with_lb_addon] \ |
| 260 | + -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ |
| 261 | + -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT)] \ |
| 262 | + $global_placement_args] |
| 263 | + |
| 264 | + lappend all_args {*}[env_var_or_empty GLOBAL_PLACEMENT_ARGS] |
| 265 | + |
| 266 | + log_cmd global_placement {*}$all_args |
| 267 | +} |
| 268 | + |
| 269 | +set result [catch { do_placement $global_placement_args } errMsg] |
| 270 | +if { $result != 0 } { |
| 271 | + write_db $::env(RESULTS_DIR)/3_3_place_gp-failed.odb |
| 272 | + error $errMsg |
| 273 | +} |
| 274 | + |
| 275 | +estimate_parasitics -placement |
| 276 | + |
| 277 | +if { [env_var_equals CLUSTER_FLOPS 1] } { |
| 278 | + cluster_flops |
| 279 | + estimate_parasitics -placement |
| 280 | +} |
| 281 | + |
| 282 | +report_metrics 3 "global place" false false |
| 283 | + |
| 284 | +write_db $::env(RESULTS_DIR)/3_3_place_gp.odb |
| 285 | + |
| 286 | +# Resizing |
| 287 | +utl::set_metrics_stage "placeopt__{}" |
| 288 | +estimate_parasitics -placement |
| 289 | + |
| 290 | +set instance_count_before [sta::network_leaf_instance_count] |
| 291 | +set pin_count_before [sta::network_leaf_pin_count] |
| 292 | + |
| 293 | +set_dont_use $::env(DONT_USE_CELLS) |
| 294 | + |
| 295 | +if { [env_var_exists_and_non_empty EARLY_SIZING_CAP_RATIO] } { |
| 296 | + log_cmd set_opt_config -set_early_sizing_cap_ratio $env(EARLY_SIZING_CAP_RATIO) |
| 297 | +} |
| 298 | + |
| 299 | +if { [env_var_exists_and_non_empty SWAP_ARITH_OPERATORS] } { |
| 300 | + replace_arith_modules |
| 301 | +} |
| 302 | + |
| 303 | +repair_design_helper |
| 304 | + |
| 305 | +# hold violations are not repaired until after CTS |
| 306 | + |
| 307 | +# post report |
| 308 | + |
| 309 | +puts "Floating nets: " |
| 310 | +report_floating_nets |
| 311 | + |
| 312 | +report_metrics 3 "resizer" true false |
| 313 | + |
| 314 | +puts "Instance count before $instance_count_before, after [sta::network_leaf_instance_count]" |
| 315 | +puts "Pin count before $pin_count_before, after [sta::network_leaf_pin_count]" |
| 316 | + |
| 317 | +write_db $::env(RESULTS_DIR)/3_4_place_resized.odb |
| 318 | + |
| 319 | +# Detailed placement |
| 320 | +utl::set_metrics_stage "detailedplace__{}" |
| 321 | + |
| 322 | +source $::env(PLATFORM_DIR)/setRC.tcl |
| 323 | + |
| 324 | +proc do_dpl { } { |
| 325 | + # Only for use with hybrid rows |
| 326 | + if { [env_var_equals BALANCE_ROWS 1] } { |
| 327 | + balance_row_usage |
| 328 | + } |
| 329 | + |
| 330 | + set_placement_padding -global \ |
| 331 | + -left $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) \ |
| 332 | + -right $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) |
| 333 | + detailed_placement |
| 334 | + |
| 335 | + if { [env_var_equals ENABLE_DPO 1] } { |
| 336 | + if { [env_var_exists_and_non_empty DPO_MAX_DISPLACEMENT] } { |
| 337 | + improve_placement -max_displacement $::env(DPO_MAX_DISPLACEMENT) |
| 338 | + } else { |
| 339 | + improve_placement |
| 340 | + } |
| 341 | + } |
| 342 | + optimize_mirroring |
| 343 | + |
| 344 | + utl::info FLW 12 "Placement violations [check_placement -verbose]." |
| 345 | + |
| 346 | + estimate_parasitics -placement |
| 347 | +} |
| 348 | + |
| 349 | +set result [catch { do_dpl } errMsg] |
| 350 | +if { $result != 0 } { |
| 351 | + write_db $::env(RESULTS_DIR)/3_5_place_dp-failed.odb |
| 352 | + error $errMsg |
| 353 | +} |
| 354 | + |
| 355 | +report_metrics 3 "detailed place" true false |
| 356 | + |
| 357 | +write_db $::env(RESULTS_DIR)/3_5_place_dp.odb |
| 358 | + |
| 359 | +# Repair timing after placement |
| 360 | +utl::set_metrics_stage "place_repair_timing__{}" |
| 361 | + |
| 362 | +set_placement_padding -global \ |
| 363 | + -left $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) \ |
| 364 | + -right $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) |
| 365 | + |
| 366 | +puts "Repair setup and hold violations" |
| 367 | +estimate_parasitics -placement |
| 368 | +log_cmd repair_timing -repair_tns $::env(TNS_END_PERCENT) |
| 369 | + |
| 370 | +# Legalize placement after timing repair |
| 371 | +detailed_placement |
| 372 | + |
| 373 | +puts "Estimate parasitics" |
| 374 | +estimate_parasitics -placement |
| 375 | +report_metrics 3 "place repair timing" true false |
| 376 | + |
| 377 | +write_db $::env(RESULTS_DIR)/3_6_place_repair_timing.odb |
0 commit comments