diff --git a/openlane/config/preprocessor.py b/openlane/config/preprocessor.py index 1051b7aba..7d9b121a1 100644 --- a/openlane/config/preprocessor.py +++ b/openlane/config/preprocessor.py @@ -180,7 +180,7 @@ def evaluate(expression: str, symbols: Mapping[str, Any]) -> Decimal: eval_stack.pop() eval_stack.pop() - result = Decimal(0.0) + result = Decimal("0") if token.value == "**": result = number1**number2 elif token.value == "*": diff --git a/openlane/scripts/openroad/common/dpl.tcl b/openlane/scripts/openroad/common/dpl.tcl index cf8158580..66dec0051 100644 --- a/openlane/scripts/openroad/common/dpl.tcl +++ b/openlane/scripts/openroad/common/dpl.tcl @@ -15,7 +15,7 @@ source $::env(SCRIPTS_DIR)/openroad/common/dpl_cell_pad.tcl remove_fillers -detailed_placement\ +log_cmd detailed_placement\ -max_displacement [subst { $::env(PL_MAX_DISPLACEMENT_X) $::env(PL_MAX_DISPLACEMENT_Y) }] if { [info exists ::env(PL_OPTIMIZE_MIRRORING)] && $::env(PL_OPTIMIZE_MIRRORING) } { diff --git a/openlane/scripts/openroad/common/grt.tcl b/openlane/scripts/openroad/common/grt.tcl index 12ba85f7a..96bc24427 100644 --- a/openlane/scripts/openroad/common/grt.tcl +++ b/openlane/scripts/openroad/common/grt.tcl @@ -26,7 +26,7 @@ lappend arg_list -verbose if { $::env(GRT_ALLOW_CONGESTION) == 1 } { lappend arg_list -allow_congestion } -puts $arg_list -global_route {*}$arg_list -write_guide $::env(STEP_DIR)/after_grt.guide \ No newline at end of file +log_cmd global_route {*}$arg_list + +write_guide $::env(STEP_DIR)/after_grt.guide diff --git a/openlane/scripts/openroad/common/io.tcl b/openlane/scripts/openroad/common/io.tcl index 486211086..5234bf8a6 100644 --- a/openlane/scripts/openroad/common/io.tcl +++ b/openlane/scripts/openroad/common/io.tcl @@ -474,3 +474,85 @@ if { [namespace exists utl] } { puts "%OL_METRIC $metric $value" } } + +proc exit_unless_gui {{status 0}} { + if { ![info exists ::env(_OPENROAD_GUI)] || !$::env(_OPENROAD_GUI) } { + exit $status + } +} + +proc find_unfixed_macros {} { + set macros [list] + + foreach inst [$::block getInsts] { + set inst_master [$inst getMaster] + + # BLOCK means MACRO cells + if { ![string match [$inst_master getType] "BLOCK"] } { + continue + } + + if { [$inst isFixed] } { + continue + } + + lappend macros $inst + } + return $macros +} + +proc append_if_exists_argument {list_arg glob_variable_name option} { + upvar $list_arg local_array + if [info exists ::env($glob_variable_name) ] { + lappend local_array $option $::env($glob_variable_name) + } +} + +proc append_if_flag {list_arg glob_variable_name flag} { + upvar $list_arg local_array + if { [info exists ::env($glob_variable_name)] && $::env($glob_variable_name) } { + lappend local_array $flag + } +} +proc append_if_not_flag {list_arg glob_variable_name flag} { + upvar $list_arg local_array + if { [info exists ::env($glob_variable_name)] && !$::env($glob_variable_name) } { + lappend local_array $flag + } +} + +# Code below adapted from OpenROAD Flow Scripts under the following license: +# +# BSD 3-Clause License +# +# Copyright (c) 2018-2023, The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +proc log_cmd {cmd args} { + puts "+ $cmd [join $args " "]" + $cmd {*}$args +} diff --git a/openlane/scripts/openroad/common/set_global_connections.tcl b/openlane/scripts/openroad/common/set_global_connections.tcl index 13a48b433..cf5dd7627 100644 --- a/openlane/scripts/openroad/common/set_global_connections.tcl +++ b/openlane/scripts/openroad/common/set_global_connections.tcl @@ -45,7 +45,7 @@ proc set_global_connections {} { if { $power_pin == "" || $ground_pin == "" } { puts "PDN_MACRO_CONNECTIONS missing power and ground pin names" - exit -1 + exit_unless_gui 1 } set matched 0 @@ -57,7 +57,7 @@ proc set_global_connections {} { } if { $matched != 1 } { puts "\[ERROR\] No match found for regular expression '$instance_name' defined in PDN_MACRO_CONNECTIONS." - exit 1 + exit_unless_gui 1 } add_global_connection \ diff --git a/openlane/scripts/openroad/common/set_power_nets.tcl b/openlane/scripts/openroad/common/set_power_nets.tcl index 951b5f749..b8b623a73 100644 --- a/openlane/scripts/openroad/common/set_power_nets.tcl +++ b/openlane/scripts/openroad/common/set_power_nets.tcl @@ -17,7 +17,7 @@ if { [info exists ::env(VDD_NETS)] || [info exists ::env(GND_NETS)] } { # current assumption: they cannot have a common ground if { ! [info exists ::env(VDD_NETS)] || ! [info exists ::env(GND_NETS)] } { puts stderr "\[ERROR\] VDD_NETS and GND_NETS must *both* either be defined or undefined" - exit -1 + exit_unless_gui 1 } set ::env(VDD_NET) [lindex $::env(VDD_NETS) 0] set ::env(GND_NET) [lindex $::env(GND_NETS) 0] diff --git a/openlane/scripts/openroad/cts.tcl b/openlane/scripts/openroad/cts.tcl index 81fcf05de..2a8147fcd 100755 --- a/openlane/scripts/openroad/cts.tcl +++ b/openlane/scripts/openroad/cts.tcl @@ -33,7 +33,7 @@ if { [info exists ::env(CTS_MAX_CAP)] } { if { [info exists ::env(CTS_MAX_SLEW)] } { lappend cts_characterization_args -max_slew [expr {$::env(CTS_MAX_SLEW) * 1e-9}]; # ns -> S } -configure_cts_characterization {*}$cts_characterization_args +log_cmd configure_cts_characterization {*}$cts_characterization_args puts "\[INFO\] Performing clock tree synthesis…" puts "\[INFO\] Looking for the following net(s): $::env(CLOCK_NET)" @@ -66,8 +66,7 @@ if { [info exists ::env(CTS_BALANCE_LEVELS)] && $::env(CTS_BALANCE_LEVELS) } { lappend arg_list -balance_levels } -puts "clock_tree_synthesis {*}$arg_list" -clock_tree_synthesis {*}$arg_list +log_cmd clock_tree_synthesis {*}$arg_list set_propagated_clock [all_clocks] diff --git a/openlane/scripts/openroad/cut_rows.tcl b/openlane/scripts/openroad/cut_rows.tcl index 076e37a6d..0167ee7c6 100644 --- a/openlane/scripts/openroad/cut_rows.tcl +++ b/openlane/scripts/openroad/cut_rows.tcl @@ -14,10 +14,27 @@ source $::env(SCRIPTS_DIR)/openroad/common/io.tcl read_current_odb -cut_rows\ - -endcap_master $::env(ENDCAP_CELL)\ - -halo_width_x $::env(FP_MACRO_HORIZONTAL_HALO)\ - -halo_width_y $::env(FP_MACRO_VERTICAL_HALO) +set arg_list [list] +lappend arg_list -endcap_master $::env(ENDCAP_CELL) +lappend arg_list -halo_width_x $::env(FP_MACRO_HORIZONTAL_HALO) +lappend arg_list -halo_width_y $::env(FP_MACRO_VERTICAL_HALO) +if { [info exists ::env(FP_PRUNE_THRESHOLD)] } { + lappend arg_list -row_min_width $::env(FP_PRUNE_THRESHOLD) +} +log_cmd cut_rows {*}$arg_list + +# # verify -row_min_width worked +# if { [info exists ::env(FP_PRUNE_THRESHOLD)] } { +# foreach row [$::block getRows] { +# set bbox [$row getBBox] +# set width [expr ([$bbox xMax] - [$bbox xMin])] +# set width_um [expr $width / $::dbu] +# if { $width < $::env(FP_PRUNE_THRESHOLD) } { +# exit -1 +# # odb::dbRow_destroy $row +# } +# } +# } write_views diff --git a/openlane/scripts/openroad/drt.tcl b/openlane/scripts/openroad/drt.tcl index 5e8d13397..7b912dd12 100755 --- a/openlane/scripts/openroad/drt.tcl +++ b/openlane/scripts/openroad/drt.tcl @@ -26,7 +26,7 @@ if { [info exists ::env(DRT_MAX_LAYER)] } { set max_layer $::env(DRT_MAX_LAYER) } -detailed_route\ +log_cmd detailed_route\ -bottom_routing_layer $min_layer\ -top_routing_layer $max_layer\ -output_drc $::env(STEP_DIR)/$::env(DESIGN_NAME).drc\ @@ -34,4 +34,4 @@ detailed_route\ -or_seed 42\ -verbose 1 -write_views \ No newline at end of file +write_views diff --git a/openlane/scripts/openroad/floorplan.tcl b/openlane/scripts/openroad/floorplan.tcl index f3e750f43..aa1c0e918 100755 --- a/openlane/scripts/openroad/floorplan.tcl +++ b/openlane/scripts/openroad/floorplan.tcl @@ -53,7 +53,7 @@ puts "\[INFO\] Using $::env(FP_SIZING) sizing for the floorplan." if {$::env(FP_SIZING) == "absolute"} { if { [llength $::env(DIE_AREA)] != 4 } { puts stderr "Invalid die area string '$::env(DIE_AREA)'." - exit -1 + exit_unless_gui 1 } if { ! [info exists ::env(CORE_AREA)] } { set die_ll_x [lindex $::env(DIE_AREA) 0] @@ -70,7 +70,7 @@ if {$::env(FP_SIZING) == "absolute"} { } else { if { [llength $::env(CORE_AREA)] != 4 } { puts stderr "Invalid core area string '$::env(CORE_AREA)'." - exit -1 + exit_unless_gui 1 } puts "\[INFO\] Using the set CORE_AREA; ignoring core margin parameters" } @@ -94,7 +94,7 @@ if { [info exists ::env(FP_OBSTRUCTIONS)] } { } } -initialize_floorplan {*}$arg_list +log_cmd initialize_floorplan {*}$arg_list insert_tiecells $::env(SYNTH_TIELO_CELL) -prefix "TIE_ZERO_" insert_tiecells $::env(SYNTH_TIEHI_CELL) -prefix "TIE_ONE_" diff --git a/openlane/scripts/openroad/gpl.tcl b/openlane/scripts/openroad/gpl.tcl index ad1015e6a..241d0d077 100755 --- a/openlane/scripts/openroad/gpl.tcl +++ b/openlane/scripts/openroad/gpl.tcl @@ -26,11 +26,11 @@ foreach inst $::insts { } if { !$placement_needed } { - puts stderr "\[WARNING\] All instances are FIXED/FIRM." - puts stderr "\[WARNING\] No need to perform global placement." - puts stderr "\[WARNING\] Skipping…" + puts "\[INFO\] All instances are FIXED/FIRM." + puts "\[INFO\] No need to perform global placement." + puts "\[INFO\] Skipping…" write_views - exit 0 + exit_unless_gui } set arg_list [list] @@ -56,8 +56,7 @@ if { $::env(PL_SKIP_INITIAL_PLACEMENT) } { lappend arg_list -skip_initial_place } - -if { [info exists ::env(__PL_SKIP_IO)] } { +if { [info exists ::env(__PL_SKIP_IO)] && $::env(__PL_SKIP_IO) == "1" } { lappend arg_list -skip_io } @@ -75,8 +74,7 @@ lappend arg_list -pad_right $cell_pad_side lappend arg_list -pad_left $cell_pad_side lappend arg_list -init_wirelength_coef $::env(PL_WIRE_LENGTH_COEF) -puts "+ global_placement $arg_list" -global_placement {*}$arg_list +log_cmd global_placement {*}$arg_list source $::env(SCRIPTS_DIR)/openroad/common/set_rc.tcl diff --git a/openlane/scripts/openroad/insert_buffer.tcl b/openlane/scripts/openroad/insert_buffer.tcl index e0e41b7b6..032d2118b 100644 --- a/openlane/scripts/openroad/insert_buffer.tcl +++ b/openlane/scripts/openroad/insert_buffer.tcl @@ -121,7 +121,7 @@ if { [info exists ::env(INSERT_BUFFER_COMMAND) ]} { read_current_odb set arg_list [split $::env(INSERT_BUFFER_COMMAND) " "] - insert_buffer {*}$arg_list + log_cmd insert_buffer {*}$arg_list write_views -} \ No newline at end of file +} diff --git a/openlane/scripts/openroad/ioplacer.tcl b/openlane/scripts/openroad/ioplacer.tcl index 6e0aa2ab1..6a8d45a88 100755 --- a/openlane/scripts/openroad/ioplacer.tcl +++ b/openlane/scripts/openroad/ioplacer.tcl @@ -55,8 +55,7 @@ if { $::env(FP_PPL_MODE) == "annealing" } { set HMETAL $::env(FP_IO_HLAYER) set VMETAL $::env(FP_IO_VLAYER) -puts "\[INFO\] place_pins args: $arg_list" -place_pins {*}$arg_list \ +log_cmd place_pins {*}$arg_list \ -random_seed 42 \ -hor_layers $HMETAL \ -ver_layers $VMETAL diff --git a/openlane/scripts/openroad/irdrop.tcl b/openlane/scripts/openroad/irdrop.tcl index f5545707f..60fbeec7c 100644 --- a/openlane/scripts/openroad/irdrop.tcl +++ b/openlane/scripts/openroad/irdrop.tcl @@ -27,7 +27,7 @@ if { [info exists ::env(VSRC_LOC_FILES)] } { lappend arg_list -net $net lappend arg_list -voltage_file $::env(STEP_DIR)/net-$net.csv lappend arg_list -vsrc $vsrc_file - analyze_power_grid {*}$arg_list + log_cmd analyze_power_grid {*}$arg_list } puts "%OL_END_REPORT" } else { @@ -38,14 +38,14 @@ if { [info exists ::env(VSRC_LOC_FILES)] } { lappend arg_list -net $net lappend arg_list -voltage_file $::env(STEP_DIR)/net-$net.csv set_pdnsim_net_voltage -net $net -voltage $::env(LIB_VOLTAGE) - analyze_power_grid {*}$arg_list + log_cmd analyze_power_grid {*}$arg_list } foreach net "$::env(GND_NETS)" { set arg_list [list] lappend arg_list -net $net lappend arg_list -voltage_file $::env(STEP_DIR)/net-$net.csv set_pdnsim_net_voltage -net $net -voltage 0 - analyze_power_grid {*}$arg_list + log_cmd analyze_power_grid {*}$arg_list } puts "%OL_END_REPORT" } diff --git a/openlane/scripts/openroad/pdn.tcl b/openlane/scripts/openroad/pdn.tcl index 59e8af625..900eeb9ec 100644 --- a/openlane/scripts/openroad/pdn.tcl +++ b/openlane/scripts/openroad/pdn.tcl @@ -23,28 +23,29 @@ read_pdn_cfg set arg_list [list] if { $::env(FP_PDN_SKIPTRIM) } { lappend arg_list -skip_trim - puts "adding -skip_trim to pdngen" } # run PDNGEN -if {[catch {pdngen {*}$arg_list} errmsg]} { +if {[catch {log_cmd pdngen {*}$arg_list} errmsg]} { puts stderr $errmsg - exit 1 -} + exit_unless_gui 1 +} else { + write_views + report_design_area_metrics -write_views -report_design_area_metrics + foreach {net} "$::env(VDD_NETS) $::env(GND_NETS)" { + set report_file $::env(STEP_DIR)/$net-grid-errors.rpt -foreach {net} "$::env(VDD_NETS) $::env(GND_NETS)" { - set report_file $::env(STEP_DIR)/$net-grid-errors.rpt + # For some reason, check_power_grid is… totally okay if no nodes are found + # at all. i.e. PDN generation has completely failed. + # This is a fallback file. + set f [open $report_file "w"] + puts $f "" + close $f - # For some reason, check_power_grid is… totally okay if no nodes are found - # at all. i.e. PDN generation has completely failed. - # This is a fallback file. - set f [open $report_file "w"] - puts $f "" - close $f + if { [catch {check_power_grid -net $net -error_file $report_file} err] } { + puts stderr "\[WARNING\] Grid check for $net failed: $err" + } - if { [catch {check_power_grid -net $net -error_file $report_file} err] } { - puts stderr "\[WARNING\] Grid check for $net failed: $err" } + } diff --git a/openlane/scripts/openroad/rcx.tcl b/openlane/scripts/openroad/rcx.tcl index 573506797..534119784 100644 --- a/openlane/scripts/openroad/rcx.tcl +++ b/openlane/scripts/openroad/rcx.tcl @@ -26,7 +26,7 @@ if { !$::env(RCX_MERGE_VIA_WIRE_RES) } { # RCX puts "Using RCX ruleset '$::env(RCX_RULESET)'…" define_process_corner -ext_model_index 0 CURRENT_CORNER -extract_parasitics $rcx_flags\ +log_cmd extract_parasitics $rcx_flags\ -ext_model_file $::env(RCX_RULESET)\ -lef_res write_views diff --git a/openlane/scripts/openroad/repair_design.tcl b/openlane/scripts/openroad/repair_design.tcl index ef457ae10..cbd5c6add 100644 --- a/openlane/scripts/openroad/repair_design.tcl +++ b/openlane/scripts/openroad/repair_design.tcl @@ -42,17 +42,25 @@ if { $::env(DESIGN_REPAIR_BUFFER_OUTPUT_PORTS) } { buffer_ports -outputs } +set arg_list [list] +lappend arg_list -verbose +lappend arg_list -max_wire_length $::env(DESIGN_REPAIR_MAX_WIRE_LENGTH) +lappend arg_list -slew_margin $::env(DESIGN_REPAIR_MAX_SLEW_PCT) +lappend arg_list -cap_margin $::env(DESIGN_REPAIR_MAX_CAP_PCT) +if { [info exists ::env(DESIGN_REPAIR_MAX_UTILIZATION)] } { + lappend arg_list -max_utilization $::env(DESIGN_REPAIR_MAX_UTILIZATION) +} +if { [info exists ::env(DESIGN_REPAIR_BUFFER_GAIN)] } { + lappend arg_list -buffer_gain $::env(DESIGN_REPAIR_BUFFER_GAIN) +} # Repair Design -repair_design -verbose \ - -max_wire_length $::env(DESIGN_REPAIR_MAX_WIRE_LENGTH) \ - -slew_margin $::env(DESIGN_REPAIR_MAX_SLEW_PCT) \ - -cap_margin $::env(DESIGN_REPAIR_MAX_CAP_PCT) +log_cmd repair_design {*}$arg_list if { $::env(DESIGN_REPAIR_TIE_FANOUT) } { # repair tie lo fanout - repair_tie_fanout -separation $::env(DESIGN_REPAIR_TIE_SEPARATION) $::env(SYNTH_TIELO_CELL) + repair_tie_fanout -verbose -separation $::env(DESIGN_REPAIR_TIE_SEPARATION) $::env(SYNTH_TIELO_CELL) # repair tie hi fanout - repair_tie_fanout -separation $::env(DESIGN_REPAIR_TIE_SEPARATION) $::env(SYNTH_TIEHI_CELL) + repair_tie_fanout -verbose -separation $::env(DESIGN_REPAIR_TIE_SEPARATION) $::env(SYNTH_TIEHI_CELL) } report_floating_nets -verbose diff --git a/openlane/scripts/openroad/repair_design_postgrt.tcl b/openlane/scripts/openroad/repair_design_postgrt.tcl index 54e9ec5fa..e0404305c 100644 --- a/openlane/scripts/openroad/repair_design_postgrt.tcl +++ b/openlane/scripts/openroad/repair_design_postgrt.tcl @@ -31,11 +31,19 @@ source $::env(SCRIPTS_DIR)/openroad/common/grt.tcl #} estimate_parasitics -global_routing -# Repair design -repair_design -verbose \ - -max_wire_length $::env(GRT_DESIGN_REPAIR_MAX_WIRE_LENGTH) \ - -slew_margin $::env(GRT_DESIGN_REPAIR_MAX_SLEW_PCT) \ - -cap_margin $::env(GRT_DESIGN_REPAIR_MAX_CAP_PCT) +# Repair Design +set arg_list [list] +lappend arg_list -verbose +lappend arg_list -max_wire_length $::env(GRT_DESIGN_REPAIR_MAX_WIRE_LENGTH) +lappend arg_list -slew_margin $::env(GRT_DESIGN_REPAIR_MAX_SLEW_PCT) +lappend arg_list -cap_margin $::env(GRT_DESIGN_REPAIR_MAX_CAP_PCT) +if { [info exists ::env(GRT_DESIGN_REPAIR_MAX_UTILIZATION)] } { + lappend arg_list -max_utilization $::env(GRT_DESIGN_REPAIR_MAX_UTILIZATION) +} +if { [info exists ::env(GRT_DESIGN_REPAIR_BUFFER_GAIN)] } { + lappend arg_list -buffer_gain $::env(GRT_DESIGN_REPAIR_BUFFER_GAIN) +} +log_cmd repair_design {*}$arg_list # Re-DPL and GRT source $::env(SCRIPTS_DIR)/openroad/common/dpl.tcl diff --git a/openlane/scripts/openroad/rsz_timing_postcts.tcl b/openlane/scripts/openroad/rsz_timing_postcts.tcl index be22825ea..a3c2dd4ec 100644 --- a/openlane/scripts/openroad/rsz_timing_postcts.tcl +++ b/openlane/scripts/openroad/rsz_timing_postcts.tcl @@ -1,4 +1,4 @@ -# Copyright 2020-2023 Efabless Corporation +# Copyright 2020-2024 Efabless Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -34,9 +34,11 @@ lappend setup_args -verbose lappend setup_args -setup lappend setup_args -setup_margin $::env(PL_RESIZER_SETUP_SLACK_MARGIN) lappend setup_args -max_buffer_percent $::env(PL_RESIZER_SETUP_MAX_BUFFER_PCT) -if { $::env(PL_RESIZER_GATE_CLONING) != 1 } { - lappend setup_args -skip_gate_cloning -} +append_if_not_flag setup_args PL_RESIZER_SETUP_BUFFERING -skip_buffering +append_if_not_flag setup_args PL_RESIZER_SETUP_BUFFER_REMOVAL -skip_buffer_removal +append_if_not_flag setup_args PL_RESIZER_SETUP_GATE_CLONING -skip_gate_cloning +append_if_exists_argument setup_args PL_RESIZER_SETUP_REPAIR_TNS_PCT -repair_tns +append_if_exists_argument setup_args PL_RESIZER_SETUP_MAX_UTIL_PCT -max_utilization set hold_args [list] lappend hold_args -verbose @@ -44,16 +46,16 @@ lappend hold_args -hold lappend hold_args -setup_margin $::env(PL_RESIZER_SETUP_SLACK_MARGIN) lappend hold_args -hold_margin $::env(PL_RESIZER_HOLD_SLACK_MARGIN) lappend hold_args -max_buffer_percent $::env(PL_RESIZER_HOLD_MAX_BUFFER_PCT) -if { $::env(PL_RESIZER_ALLOW_SETUP_VIOS) == 1 } { - lappend hold_args -allow_setup_violations -} +append_if_flag hold_args PL_RESIZER_ALLOW_SETUP_VIOS -allow_setup_violations +append_if_exists_argument hold_args PL_RESIZER_HOLD_REPAIR_TNS_PCT -repair_tns +append_if_exists_argument hold_args PL_RESIZER_HOLD_MAX_UTIL_PCT -max_utilization if { $::env(PL_RESIZER_FIX_HOLD_FIRST) == 1 } { - repair_timing {*}$hold_args - repair_timing {*}$setup_args + log_cmd repair_timing {*}$hold_args + log_cmd repair_timing {*}$setup_args } else { - repair_timing {*}$setup_args - repair_timing {*}$hold_args + log_cmd repair_timing {*}$setup_args + log_cmd repair_timing {*}$hold_args } # Legalize diff --git a/openlane/scripts/openroad/rsz_timing_postgrt.tcl b/openlane/scripts/openroad/rsz_timing_postgrt.tcl index 2ad629281..897163c0c 100644 --- a/openlane/scripts/openroad/rsz_timing_postgrt.tcl +++ b/openlane/scripts/openroad/rsz_timing_postgrt.tcl @@ -1,4 +1,4 @@ -# Copyright 2020-2023 Efabless Corporation +# Copyright 2020-2024 Efabless Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -37,9 +37,11 @@ lappend setup_args -verbose lappend setup_args -setup lappend setup_args -setup_margin $::env(GRT_RESIZER_SETUP_SLACK_MARGIN) lappend setup_args -max_buffer_percent $::env(GRT_RESIZER_SETUP_MAX_BUFFER_PCT) -if { $::env(GRT_RESIZER_GATE_CLONING) != 1 } { - lappend setup_args -skip_gate_cloning -} +append_if_not_flag setup_args GRT_RESIZER_SETUP_BUFFERING -skip_buffering +append_if_not_flag setup_args GRT_RESIZER_SETUP_BUFFER_REMOVAL -skip_buffer_removal +append_if_not_flag setup_args GRT_RESIZER_SETUP_GATE_CLONING -skip_gate_cloning +append_if_exists_argument setup_args GRT_RESIZER_SETUP_REPAIR_TNS_PCT -repair_tns +append_if_exists_argument setup_args GRT_RESIZER_SETUP_MAX_UTIL_PCT -max_utilization set hold_args [list] lappend hold_args -verbose @@ -47,16 +49,16 @@ lappend hold_args -hold lappend hold_args -setup_margin $::env(GRT_RESIZER_SETUP_SLACK_MARGIN) lappend hold_args -hold_margin $::env(GRT_RESIZER_HOLD_SLACK_MARGIN) lappend hold_args -max_buffer_percent $::env(GRT_RESIZER_HOLD_MAX_BUFFER_PCT) -if { $::env(GRT_RESIZER_ALLOW_SETUP_VIOS) == 1 } { - lappend hold_args -allow_setup_violations -} +append_if_flag hold_args GRT_RESIZER_ALLOW_SETUP_VIOS -allow_setup_violations +append_if_exists_argument hold_args GRT_RESIZER_HOLD_REPAIR_TNS_PCT -repair_tns +append_if_exists_argument hold_args GRT_RESIZER_HOLD_MAX_UTIL_PCT -max_utilization if { $::env(GRT_RESIZER_FIX_HOLD_FIRST) == 1 } { - repair_timing {*}$hold_args - repair_timing {*}$setup_args + log_cmd repair_timing {*}$hold_args + log_cmd repair_timing {*}$setup_args } else { - repair_timing {*}$setup_args - repair_timing {*}$hold_args + log_cmd repair_timing {*}$setup_args + log_cmd repair_timing {*}$hold_args } # Re-DPL and GRT diff --git a/openlane/scripts/openroad/sta/check_macro_instances.tcl b/openlane/scripts/openroad/sta/check_macro_instances.tcl index d6aa20448..057da8c29 100644 --- a/openlane/scripts/openroad/sta/check_macro_instances.tcl +++ b/openlane/scripts/openroad/sta/check_macro_instances.tcl @@ -49,5 +49,5 @@ foreach {instance_name macro_name} $::env(_check_macro_instances) { } if { $error_count != 0 } { - exit -1 + exit_unless_gui 1 } diff --git a/openlane/scripts/openroad/tapcell.tcl b/openlane/scripts/openroad/tapcell.tcl index 355e16355..8e921df99 100755 --- a/openlane/scripts/openroad/tapcell.tcl +++ b/openlane/scripts/openroad/tapcell.tcl @@ -14,7 +14,7 @@ source $::env(SCRIPTS_DIR)/openroad/common/io.tcl read_current_odb -tapcell\ +log_cmd tapcell\ -distance $::env(FP_TAPCELL_DIST)\ -tapcell_master "$::env(WELLTAP_CELL)"\ -endcap_master "$::env(ENDCAP_CELL)"\ diff --git a/openlane/scripts/openroad/ungpl.tcl b/openlane/scripts/openroad/ungpl.tcl new file mode 100644 index 000000000..a44c301d8 --- /dev/null +++ b/openlane/scripts/openroad/ungpl.tcl @@ -0,0 +1,23 @@ +# Copyright 2024 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +source $::env(SCRIPTS_DIR)/openroad/common/io.tcl +read_current_odb + +set ::insts [$::block getInsts] + +foreach inst $::insts { + $inst setPlacementStatus "NONE" +} + +write_views diff --git a/openlane/steps/openroad.py b/openlane/steps/openroad.py index 46dea650e..a24bf9ee8 100644 --- a/openlane/steps/openroad.py +++ b/openlane/steps/openroad.py @@ -341,7 +341,7 @@ def get_command(self) -> List[str]: metrics_path = os.path.join(self.step_dir, "or_metrics_out.json") return [ "openroad", - "-exit", + ("-gui" if os.getenv("_OPENROAD_GUI", "0") == "1" else "-exit"), "-no_splash", "-metrics", metrics_path, @@ -1105,7 +1105,7 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]: @Step.factory.register() class TapEndcapInsertion(OpenROADStep): """ - Places well TAP cells across a floorplan, as well as end-cap cells at the + Places welltap cells across a floorplan, as well as endcap cells at the edges of the floorplan. """ @@ -1116,7 +1116,7 @@ class TapEndcapInsertion(OpenROADStep): Variable( "FP_MACRO_HORIZONTAL_HALO", Decimal, - "Specify the horizontal halo size around macros while cutting rows.", + "Specify the horizontal halo size around macros.", default=10, units="µm", deprecated_names=["FP_TAP_HORIZONTAL_HALO"], @@ -1124,7 +1124,7 @@ class TapEndcapInsertion(OpenROADStep): Variable( "FP_MACRO_VERTICAL_HALO", Decimal, - "Specify the vertical halo size around macros while cutting rows.", + "Specify the vertical halo size around macros.", default=10, units="µm", deprecated_names=["FP_TAP_VERTICAL_HALO"], @@ -1135,6 +1135,22 @@ def get_script_path(self): return os.path.join(get_script_dir(), "openroad", "tapcell.tcl") +@Step.factory.register() +class UnplaceAll(OpenROADStep): + """ + Sets placement status of *all* instances to NONE. + + Useful in flows where a preliminary placement is needed as a pre-requisite + to something else but that placement must be discarded. + """ + + id = "OpenROAD.UnplaceAll" + name = "Unplace All" + + def get_script_path(self): + return os.path.join(get_script_dir(), "openroad", "ungpl.tcl") + + def get_psm_error_count(rpt: io.TextIOWrapper) -> int: sio = io.StringIO() @@ -1216,7 +1232,7 @@ class _GlobalPlacement(OpenROADStep): "The desired placement density of cells. If not specified, the value will be equal to (`FP_CORE_UTIL` + 5 * `GPL_CELL_PADDING` + 10).", units="%", deprecated_names=[ - ("PL_TARGET_DENSITY", lambda d: Decimal(d) * Decimal(100.0)) + ("PL_TARGET_DENSITY", lambda d: Decimal(d) * Decimal("100")) ], ), Variable( @@ -1315,7 +1331,7 @@ class GlobalPlacement(_GlobalPlacement): @Step.factory.register() class GlobalPlacementSkipIO(_GlobalPlacement): """ - Performs global placement without taking I/O into consideration. + Performs preliminary global placement as a basis for pin placement. This is useful for flows where the: * Cells are placed @@ -1334,6 +1350,11 @@ class GlobalPlacementSkipIO(_GlobalPlacement): default="matching", deprecated_names=[("FP_IO_MODE", _migrate_ppl_mode)], ), + Variable( + "FP_PIN_ORDER_CFG", + Optional[Path], + "Path to a custom pin configuration file.", + ), Variable( "FP_DEF_TEMPLATE", Optional[Path], @@ -1345,39 +1366,18 @@ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]: kwargs, env = self.extract_env(kwargs) if self.config["FP_DEF_TEMPLATE"] is not None: info( - f"I/O pins were loaded from {self.config['FP_DEF_TEMPLATE']}. Skipping the first global placement iteration…" + f"I/O pins were loaded from {self.config['FP_DEF_TEMPLATE']}. Returning state unaltered…" + ) + return {}, {} + if self.config["FP_PIN_ORDER_CFG"] is not None: + info( + f"I/O pins to be placed from {self.config['FP_PIN_ORDER_CFG']}. Returning state unaltered…" ) return {}, {} env["__PL_SKIP_IO"] = "1" return super().run(state_in, env=env, **kwargs) -@Step.factory.register() -class BasicMacroPlacement(OpenROADStep): - id = "OpenROAD.BasicMacroPlacement" - name = "Basic Macro Placement" - - config_vars = OpenROADStep.config_vars + [ - Variable( - "PL_MACRO_HALO", - str, - "Macro placement halo. Format: `{Horizontal} {Vertical}`.", - default="0 0", - units="µm", - ), - Variable( - "PL_MACRO_CHANNEL", - str, - "Channel widths between macros. Format: `{Horizontal} {Vertical}`.", - default="0 0", - units="µm", - ), - ] - - def get_script_path(self): - raise NotImplementedError() - - @Step.factory.register() class DetailedPlacement(OpenROADStep): """ @@ -1934,7 +1934,7 @@ class CutRows(OpenROADStep): Variable( "FP_MACRO_HORIZONTAL_HALO", Decimal, - "Specify the horizontal halo size around macros while cutting rows.", + "Specify the horizontal halo size around macros.", default=10, units="µm", deprecated_names=["FP_TAP_HORIZONTAL_HALO"], @@ -1942,11 +1942,18 @@ class CutRows(OpenROADStep): Variable( "FP_MACRO_VERTICAL_HALO", Decimal, - "Specify the vertical halo size around macros while cutting rows.", + "Specify the vertical halo size around macros.", default=10, units="µm", deprecated_names=["FP_TAP_VERTICAL_HALO"], ), + Variable( + "FP_PRUNE_THRESHOLD", + Optional[Decimal], + 'If specified, all rows smaller in width than this value will be removed. This helps avoid "islets" of cells that are hard to route and connect to PDNs.', + pdk=True, + units="µm", + ), ] def get_script_path(self): @@ -2330,10 +2337,47 @@ class ResizerTimingPostCTS(ResizerStep): default=False, ), Variable( - "PL_RESIZER_GATE_CLONING", + "PL_RESIZER_SETUP_GATE_CLONING", bool, "Enables gate cloning when attempting to fix setup violations", default=True, + deprecated_names=["PL_RESIZER_GATE_CLONING"], + ), + Variable( + "PL_RESIZER_SETUP_BUFFERING", + bool, + "Rebuffering and load splitting during setup fixing.", + default=True, + ), + Variable( + "PL_RESIZER_SETUP_BUFFER_REMOVAL", + bool, + "Buffer removal transform during setup fixing.", + default=True, + ), + Variable( + "PL_RESIZER_SETUP_REPAIR_TNS_PCT", + Optional[Decimal], + "Percentage of violating endpoints to repair during setup fixing.", + units="%", + ), + Variable( + "PL_RESIZER_SETUP_MAX_UTIL_PCT", + Optional[Decimal], + "Defines the percentage of core area used during setup fixing.", + units="%", + ), + Variable( + "PL_RESIZER_HOLD_REPAIR_TNS_PCT", + Optional[Decimal], + "Percentage of violating endpoints to repair during hold fixing.", + units="%", + ), + Variable( + "PL_RESIZER_HOLD_MAX_UTIL_PCT", + Optional[Decimal], + "Defines the percentage of core area used during hold fixing.", + units="%", ), Variable( "PL_RESIZER_FIX_HOLD_FIRST", @@ -2403,10 +2447,11 @@ class ResizerTimingPostGRT(ResizerStep): deprecated_names=["GLB_RESIZER_ALLOW_SETUP_VIOS"], ), Variable( - "GRT_RESIZER_GATE_CLONING", + "GRT_RESIZER_SETUP_GATE_CLONING", bool, "Enables gate cloning when attempting to fix setup violations", default=True, + deprecated_names=["GRT_RESIZER_GATE_CLONING"], ), Variable( "GRT_RESIZER_RUN_GRT", @@ -2414,6 +2459,42 @@ class ResizerTimingPostGRT(ResizerStep): "Gates running global routing after resizer steps. May be useful to disable for designs where global routing takes non-trivial time.", default=True, ), + Variable( + "GRT_RESIZER_SETUP_BUFFERING", + bool, + "Rebuffering and load splitting during setup fixing.", + default=True, + ), + Variable( + "GRT_RESIZER_SETUP_BUFFER_REMOVAL", + bool, + "Buffer removal transform during setup fixing.", + default=True, + ), + Variable( + "GRT_RESIZER_SETUP_REPAIR_TNS_PCT", + Optional[Decimal], + "Percentage of violating endpoints to repair during setup fixing.", + units="%", + ), + Variable( + "GRT_RESIZER_SETUP_MAX_UTIL_PCT", + Optional[Decimal], + "Defines the percentage of core area used during setup fixing.", + units="%", + ), + Variable( + "GRT_RESIZER_HOLD_REPAIR_TNS_PCT", + Optional[Decimal], + "Percentage of violating endpoints to repair during hold fixing.", + units="%", + ), + Variable( + "GRT_RESIZER_HOLD_MAX_UTIL_PCT", + Optional[Decimal], + "Defines the percentage of core area used during hold fixing.", + units="%", + ), Variable( "GRT_RESIZER_FIX_HOLD_FIRST", bool,