diff --git a/configuration/checkers.tcl b/configuration/checkers.tcl
index bc5802aa..2ae70df7 100755
--- a/configuration/checkers.tcl
+++ b/configuration/checkers.tcl
@@ -29,6 +29,7 @@ set ::env(QUIT_ON_SETUP_VIOLATIONS) 1
# Routing
set ::env(QUIT_ON_TR_DRC) 1
+set ::env(QUIT_ON_LONG_WIRE) 0
# Magic
# This is disabled by default for now until we are 100% sure we want to make this
diff --git a/configuration/routing.tcl b/configuration/routing.tcl
index 564c2b8a..cca0ace4 100755
--- a/configuration/routing.tcl
+++ b/configuration/routing.tcl
@@ -18,10 +18,11 @@ if { ![info exists ::env(ROUTING_CORES)] } {
set ::env(ROUTING_CORES) 2
}
+set ::env(DIODE_PADDING) 2
+
set ::env(GLOBAL_ROUTER) fastroute
set ::env(DETAILED_ROUTER) tritonroute
-set ::env(GLB_OPTIMIZE_MIRRORING) 1
set ::env(GRT_ADJUSTMENT) 0.3
set ::env(GRT_ALLOW_CONGESTION) 0
@@ -30,17 +31,14 @@ set ::env(GRT_ANT_ITERS) 3
set ::env(GRT_ESTIMATE_PARASITICS) 1
set ::env(GRT_MACRO_EXTENSION) 0
-set ::env(DIODE_PADDING) 2
-
-# GRT_MAX_DIODE_INS_ITERS is set to 1 because of the bulk testing we're running (as it will speed-up the runtime for big designs).
-# However, the user is advised to set it up to 5 or more, in case of running a specific design.
-# It is capable to detect any divergence, so, you'll probably end up with the lowest # of Antenna violations possible.
-# Check the configuration/README.md for more.
+# Increasing this value is very recommended for larger designs.
set ::env(GRT_MAX_DIODE_INS_ITERS) 1
+# Maximum number of DRT Optimization iterations. Any number above 64 is ignored.
set ::env(DRT_OPT_ITERS) 64
# GLB Resizer
+set ::env(GLB_OPTIMIZE_MIRRORING) 1
set ::env(GLB_RESIZER_TIMING_OPTIMIZATIONS) 1
set ::env(GLB_RESIZER_MAX_WIRE_LENGTH) 0
set ::env(GLB_RESIZER_MAX_SLEW_MARGIN) 10
@@ -49,4 +47,4 @@ set ::env(GLB_RESIZER_HOLD_SLACK_MARGIN) 0.05
set ::env(GLB_RESIZER_SETUP_SLACK_MARGIN) 0.025
set ::env(GLB_RESIZER_HOLD_MAX_BUFFER_PERCENT) 50
set ::env(GLB_RESIZER_SETUP_MAX_BUFFER_PERCENT) 50
-set ::env(GLB_RESIZER_ALLOW_SETUP_VIOS) 0
+set ::env(GLB_RESIZER_ALLOW_SETUP_VIOS) 0
\ No newline at end of file
diff --git a/docs/source/for_developers/pdk_structure.md b/docs/source/for_developers/pdk_structure.md
index f4dccc10..6241a79d 100644
--- a/docs/source/for_developers/pdk_structure.md
+++ b/docs/source/for_developers/pdk_structure.md
@@ -67,7 +67,7 @@ This section defines the neccessary variables for PDK configuration file. Note t
| `RCX_RULES_MIN` | OpenRCX rules at the minimum corner. (Optional) |
| `RCX_RULES` | OpenRCX rules at the nominal corner. |
| `RCX_RULES_MAX` | OpenRCX rules at the maximum corner. (Optional) |
-
+| `WIRE_LENGTH_THRESHOLD` | A value in microns above which wire lengths generate warnings, and, if `QUIT_ON_LONG_WIRE` is set, the flow will error out. If a PDK does not set this value, the value is considered to be infinite. (Optional) |
## SCL-specific variables
diff --git a/docs/source/reference/configuration.md b/docs/source/reference/configuration.md
index 9b312e8b..8496cc84 100644
--- a/docs/source/reference/configuration.md
+++ b/docs/source/reference/configuration.md
@@ -218,7 +218,7 @@ These variables worked initially, but they were too sky130 specific and will be
| `GRT_OVERFLOW_ITERS` | The maximum number of iterations waiting for the overflow to reach the desired value.
(Default: `50`) |
| `GRT_ANT_ITERS` | The maximum number of iterations for global router repair_antenna. This option is only available in `DIODE_INSERTION_STRATEGY` = `3`.
(Default: `3`) |
| `GRT_ESTIMATE_PARASITICS` | Specifies whether or not to run STA after global routing using OpenROAD's estimate_parasitics -global_routing and generates reports under `logs/routing`. 1 = Enabled, 0 = Disabled.
(Default: `1`) |
-| `GRT_MAX_DIODE_INS_ITERS` | Controls the maximum number of iterations at which re-running Fastroute for diode insertion stops. Each iteration ARC detects the violations and FastRoute fixes them by inserting diodes, then producing the new DEF. The number of antenna violations is compared with the previous iteration and if they are equal or the number is greater the iterations stop and the DEF from the previous iteration is used in the rest of the flow. If the current antenna violations reach zero, the current def will be used and the iterations will not continue. This option is only available in DIODE_INSERTION_STRATEGY = `3`.
(Default: `1`) |
+| `GRT_MAX_DIODE_INS_ITERS` | Controls the maximum number of iterations at which re-running Fastroute for diode insertion stops. Each iteration ARC detects the violations and FastRoute fixes them by inserting diodes, then producing the new DEF. The number of antenna violations is compared with the previous iteration and if they are equal or the number is greater the iterations stop and the DEF from the previous iteration is used in the rest of the flow. If the current antenna violations reach zero, the current def will be used and the iterations will not continue. This option is only available in DIODE_INSERTION_STRATEGY = `3` and `6`.
(Default: `1`) |
| `GRT_OBS` | Specifies custom obstruction to be added prior to global routing. Comma separated list of layer and coordinates: `layer llx lly urx ury`, where `ll` and `ur` stand for "lower left" and "upper right" respectively.
(Example: `li1 0 100 1000 300, met5 0 0 1000 500`)
(Default: unset) |
| `GRT_ADJUSTMENT` | Reduction in the routing capacity of the edges between the cells in the global routing graph. Values range from 0 to 1.
1 = most reduction, 0 = least reduction
(Default: `0.3`)|
| `GRT_MACRO_EXTENSION` | Sets the number of GCells added to the blockages boundaries from macros. A GCell is typically defined in terms of Mx routing tracks. The default GCell size is 15 M3 pitches.
(Default: `0`) |
@@ -312,6 +312,7 @@ These variables worked initially, but they were too sky130 specific and will be
| `CHECK_UNMAPPED_CELLS` | Checks if there are unmapped cells after synthesis and aborts if any was found. 1 = Enabled, 0 = Disabled
(Default: `1`)|
| `CHECK_ASSIGN_STATEMENTS` | Checks for assign statement in the generated gate level netlist and aborts of any was found.1 = Enabled, 0 = Disabled
(Default: `0`)|
| `QUIT_ON_TR_DRC` | Checks for DRC violations after routing and exits the flow if any was found. 1 = Enabled, 0 = Disabled
(Default: `1`)|
+| `QUIT_ON_LONG_WIRE` | Exits the flow if any wire length exceeds the threshold set in the PDK. 1 = Enabled, 0 = Disabled
(Default: `0`)|
| `QUIT_ON_MAGIC_DRC` | Checks for DRC violations after magic DRC is executed and exits the flow if any was found. 1 = Enabled, 0 = Disabled
(Default: `1`)|
| `QUIT_ON_ILLEGAL_OVERLAPS` | Checks for illegal overlaps during magic extraction. In some cases, these imply existing undetected shorts in the design. It also exits the flow if any was found. 1 = Enabled, 0 = Disabled
(Default: `1`)|
| `QUIT_ON_LVS_ERROR` | Checks for LVS errors after netgen LVS is executed and exits the flow if any was found. 1 = Enabled, 0 = Disabled
(Default: `1`)|
diff --git a/flow.tcl b/flow.tcl
index 275dd3d9..5ecd9bbb 100755
--- a/flow.tcl
+++ b/flow.tcl
@@ -162,7 +162,7 @@ proc run_klayout_step {args} {
proc run_post_run_hooks {} {
if { [file exists $::env(DESIGN_DIR)/hooks/post_run.py]} {
puts_info "Running post run hook"
- set result [exec $::env(OPENROAD_BIN) -exit -python $::env(DESIGN_DIR)/hooks/post_run.py]
+ set result [exec $::env(OPENROAD_BIN) -exit -no_init -python $::env(DESIGN_DIR)/hooks/post_run.py]
puts_info "$result"
} else {
puts_info "hooks/post_run.py not found, skipping"
@@ -392,7 +392,7 @@ if {[catch {exec cat $::env(OPENLANE_ROOT)/install/installed_version} ::env(OPEN
}
}
-if { ! [info exists ::env(OPENLANE_LOCAL_INSTALL)] || ! $::env(OPENLANE_LOCAL_INSTALL)} {
+if { [file isdirectory $::env(OPENLANE_ROOT)/.git] } {
if {![catch {exec git --git-dir $::env(OPENLANE_ROOT)/.git rev-parse HEAD} ::env(OPENLANE_MOUNTED_SCRIPTS_VERSION)]} {
if { $::env(OPENLANE_VERSION) == $::env(OPENLANE_MOUNTED_SCRIPTS_VERSION)} {
unset ::env(OPENLANE_MOUNTED_SCRIPTS_VERSION)
diff --git a/scripts/odbpy/wire_lengths.py b/scripts/odbpy/wire_lengths.py
new file mode 100644
index 00000000..ea0feb2e
--- /dev/null
+++ b/scripts/odbpy/wire_lengths.py
@@ -0,0 +1,98 @@
+# Copyright ©2022 Efabless Corporation
+#
+# This file is part of the DFFRAM Memory Compiler.
+# See https://github.com/Cloud-V/DFFRAM for further info.
+#
+# 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.
+import os
+import click
+from decimal import Decimal
+
+from reader import click_odb, OdbReader
+
+
+def to_si(microns: Decimal) -> str:
+ units = ["μm", "mm", "m"]
+ unit = 0
+ value = microns
+ while value >= 1000 and unit < len(units):
+ value /= 1000
+ unit += 1
+ return f"{value}{units[unit]}"
+
+
+@click.command()
+@click.option(
+ "-h",
+ "--human-readable",
+ default=False,
+ is_flag=True,
+ help="Print with SI units instead of database units.",
+)
+@click.option(
+ "-t",
+ "--threshold",
+ default=Decimal("Infinity"),
+ type=Decimal,
+ help="Threshold above which to print the wire (Default: ∞)",
+)
+@click.option(
+ "-F",
+ "--fail",
+ default=False,
+ is_flag=True,
+ help="Exit with a non-zero code if any wire surpasses the threshold.",
+)
+@click.option(
+ "-R",
+ "--report-out",
+ default=None,
+ help="Output to print CSV file to. (Default: input + .wire_lengths.csv)",
+)
+@click_odb
+def main(report_out, threshold, fail, human_readable, input_db, reader: OdbReader):
+ db = reader.db
+ if report_out is None:
+ report_out = f"{input_db}.wire_length.csv"
+
+ block = db.getChip().getBlock()
+ dbunits = block.getDefUnits()
+ nets = list(filter(lambda net: net.getWire() is not None, block.getNets()))
+ nets.sort(key=lambda net: net.getWire().getLength(), reverse=True)
+
+ above_threshold = []
+ with open(report_out, "w") as f:
+ print("net,length_um", file=f)
+ for net in nets:
+ length = net.getWire().getLength()
+ length_microns = Decimal(length) / Decimal(dbunits)
+ if length_microns >= threshold:
+ above_threshold.append((net, length_microns))
+ length_printable: str = str(length_microns)
+ if human_readable:
+ length_printable = str(to_si(length_microns))
+ print(f"{net.getName()},{length_printable}", file=f)
+
+ for (net, length_microns) in above_threshold:
+ print(
+ f"Net {net.getName()} is above the length threshold ({length_microns}/{threshold} μm)."
+ )
+
+ if len(above_threshold) == 0:
+ print(f"No wire length surpasses the threshold ({threshold} μm).")
+ elif fail:
+ exit(os.EX_DATAERR)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/tcl_commands/all.tcl b/scripts/tcl_commands/all.tcl
index 45088166..f0028aa0 100755
--- a/scripts/tcl_commands/all.tcl
+++ b/scripts/tcl_commands/all.tcl
@@ -120,7 +120,7 @@ proc prep_lefs {args} {
if { [info exists ::env(METAL_LAYER_NAMES)] } {
set ::env(TECH_METAL_LAYERS) $::env(METAL_LAYER_NAMES)
} else {
- try_catch $::env(OPENROAD_BIN) -exit -python\
+ try_catch $::env(OPENROAD_BIN) -exit -no_init -python\
$::env(SCRIPTS_DIR)/odbpy/lefutil.py get_metal_layers\
-o $::env(TMP_DIR)/layers.list\
$arg_values(-tech_lef)
diff --git a/scripts/tcl_commands/eco.tcl b/scripts/tcl_commands/eco.tcl
index 726daa14..c5a1ceb5 100755
--- a/scripts/tcl_commands/eco.tcl
+++ b/scripts/tcl_commands/eco.tcl
@@ -64,7 +64,7 @@ proc eco_gen_buffer {args} {
puts_info "\[ECO: $::env(ECO_ITER)\] Generating buffer insertion script..."
- try_catch $::env(OPENROAD_BIN) -exit -python $::env(SCRIPTS_DIR)/odbpy/eco.py \
+ try_catch $::env(OPENROAD_BIN) -exit -no_init -python $::env(SCRIPTS_DIR)/odbpy/eco.py \
insert_buffer \
-o $::env(routing_tmpfiles)/eco_fix.tcl \
-s $::env(ECO_SKIP_PIN) \
diff --git a/scripts/tcl_commands/floorplan.tcl b/scripts/tcl_commands/floorplan.tcl
index 9dc26a57..7f336bfa 100755
--- a/scripts/tcl_commands/floorplan.tcl
+++ b/scripts/tcl_commands/floorplan.tcl
@@ -19,7 +19,7 @@ proc extract_core_dims {args} {
set out_tmp $::env(TMP_DIR)/dimensions.txt
- try_catch $::env(OPENROAD_BIN) -exit -python $::env(SCRIPTS_DIR)/odbpy/defutil.py extract_core_dims\
+ try_catch $::env(OPENROAD_BIN) -exit -no_init -python $::env(SCRIPTS_DIR)/odbpy/defutil.py extract_core_dims\
--output-data $out_tmp\
--input-lef $::env(MERGED_LEF)\
$::env(CURRENT_DEF)
@@ -77,7 +77,7 @@ proc init_floorplan {args} {
set intermediate [index_file $::env(floorplan_tmpfiles)/minimized_pdn.txt]
- try_catch $::env(OPENROAD_BIN) -exit -python $::env(SCRIPTS_DIR)/odbpy/snap_to_grid.py\
+ try_catch $::env(OPENROAD_BIN) -exit -no_init -python $::env(SCRIPTS_DIR)/odbpy/snap_to_grid.py\
--output $intermediate\
--input-lef $::env(MERGED_LEF)\
[expr {$core_width/8.0}] [expr {$core_height/8.0}] [expr {$core_width/4.0}] [expr {$core_height/4.0}]
diff --git a/scripts/tcl_commands/klayout.tcl b/scripts/tcl_commands/klayout.tcl
index 3938d9a2..7dad9cc7 100755
--- a/scripts/tcl_commands/klayout.tcl
+++ b/scripts/tcl_commands/klayout.tcl
@@ -153,7 +153,7 @@ proc run_klayout_gds_xor {args} {
$arg_values(-layout1) $arg_values(-layout2) $::env(DESIGN_NAME) \
$arg_values(-output_gds) \
|& tee $::env(TERMINAL_OUTPUT) $log
- try_catch $::env(OPENROAD_BIN) -exit -python $::env(SCRIPTS_DIR)/parse_klayout_xor_log.py \
+ try_catch python3 $::env(SCRIPTS_DIR)/parse_klayout_xor_log.py \
-l [index_file $::env(signoff_logs)/xor.log] \
-o [index_file $::env(signoff_reports)/xor.rpt]
scrot_klayout -layout $arg_values(-output_gds) -log $::env(signoff_logs)/screenshot.klayout.xor.log
diff --git a/scripts/tcl_commands/lvs.tcl b/scripts/tcl_commands/lvs.tcl
index 40c4cb26..5b178829 100755
--- a/scripts/tcl_commands/lvs.tcl
+++ b/scripts/tcl_commands/lvs.tcl
@@ -93,7 +93,7 @@ proc write_powered_verilog {args} {
set_if_unset arg_values(-powered_netlist) ""
}
- try_catch $::env(OPENROAD_BIN) -exit -python $::env(SCRIPTS_DIR)/odbpy/power_utils.py write_powered_def\
+ try_catch $::env(OPENROAD_BIN) -exit -no_init -python $::env(SCRIPTS_DIR)/odbpy/power_utils.py write_powered_def\
--output $arg_values(-output_def) \
--input-lef $arg_values(-lef) \
--power-port $arg_values(-power) \
diff --git a/scripts/tcl_commands/routing.tcl b/scripts/tcl_commands/routing.tcl
index da17c454..d82f4801 100755
--- a/scripts/tcl_commands/routing.tcl
+++ b/scripts/tcl_commands/routing.tcl
@@ -140,7 +140,7 @@ proc detailed_routing_tritonroute {args} {
unset ::env(_tmp_drt_file_prefix)
unset ::env(_tmp_drt_rpt_prefix)
- try_catch $::env(OPENROAD_BIN) -exit -python $::env(SCRIPTS_DIR)/drc_rosetta.py tr to_klayout \
+ try_catch python3 $::env(SCRIPTS_DIR)/drc_rosetta.py tr to_klayout \
-o $::env(routing_reports)/drt.klayout.xml \
--design-name $::env(DESIGN_NAME) \
$::env(routing_reports)/drt.drc
@@ -309,6 +309,30 @@ proc add_route_obs {args} {
}
}
+proc check_wire_lengths {args} {
+ increment_index
+ TIMER::timer_start
+ set log [index_file $::env(routing_logs)/wire_lengths.log]
+ puts_info "Checking Wire Lengths (log: [relpath . $log])..."
+
+ set arg_list [list]
+ lappend arg_list --report-out [index_file $::env(routing_reports)/wire_lengths.csv]
+ if { [info exists ::env(WIRE_LENGTH_THRESHOLD)] } {
+ lappend arg_list --threshold $::env(WIRE_LENGTH_THRESHOLD)
+ }
+ if { $::env(QUIT_ON_LONG_WIRE) } {
+ lappend arg_list --fail
+ }
+
+ manipulate_layout $::env(SCRIPTS_DIR)/odbpy/wire_lengths.py\
+ -indexed_log $log\
+ {*}$arg_list
+
+ TIMER::timer_stop
+
+ exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "wire lengths - openlane"
+}
+
proc run_spef_extraction {args} {
set options {
{-save required}
@@ -408,12 +432,16 @@ proc run_routing {args} {
ins_fill_cells
}
- # detailed routing
+ # Detailed Routing
detailed_routing
+ # Print Wire Lengths + Check Thresholds
+ check_wire_lengths
+
+ # Screenshot (If Applicable)
scrot_klayout -layout $::env(CURRENT_DEF) -log $::env(routing_logs)/screenshot.log
- ## Calculate Runtime To Routing
+ # Calculate Runtime
set ::env(timer_routed) [clock seconds]
}
diff --git a/scripts/utils/utils.tcl b/scripts/utils/utils.tcl
index 5f9e19e2..683b79fe 100755
--- a/scripts/utils/utils.tcl
+++ b/scripts/utils/utils.tcl
@@ -424,7 +424,7 @@ proc manipulate_layout {args} {
set_if_unset arg_values(-output) $arg_values(-input)
set_if_unset arg_values(-output_def) /dev/null
- try_catch $::env(OPENROAD_BIN) -exit -python \
+ try_catch $::env(OPENROAD_BIN) -exit -no_init -python\
{*}$args \
--input-lef $::env(MERGED_LEF) \
--output-def $arg_values(-output_def) \
diff --git a/tests/1007/interactive.tcl b/tests/1007/interactive.tcl
index b7a1d8a5..70cdf659 100644
--- a/tests/1007/interactive.tcl
+++ b/tests/1007/interactive.tcl
@@ -18,6 +18,6 @@ insert_buffer\
exec cp $::env(CURRENT_ODB) $::env(DESIGN_DIR)/out.odb
-try_catch $::env(OPENROAD_BIN) -exit -python $::env(DESIGN_DIR)/hooks/post_run.py
+try_catch $::env(OPENROAD_BIN) -exit -no_init -python $::env(DESIGN_DIR)/hooks/post_run.py
puts_info "Done."
diff --git a/tests/1413/interactive.tcl b/tests/1413/interactive.tcl
index e1e8cb70..6e14b4a5 100644
--- a/tests/1413/interactive.tcl
+++ b/tests/1413/interactive.tcl
@@ -19,6 +19,6 @@ remove_nets -rx {^in$} -input $save_odb
set ::env(CURRENT_ODB) $save_odb
-try_catch $::env(OPENROAD_BIN) -exit -python $::env(DESIGN_DIR)/hooks/post_run.py
+try_catch $::env(OPENROAD_BIN) -exit -no_init -python $::env(DESIGN_DIR)/hooks/post_run.py
puts_info "Done."
\ No newline at end of file
diff --git a/tests/892/hooks/post_run.py b/tests/892/hooks/post_run.py
index 782464b6..f851f9b8 100644
--- a/tests/892/hooks/post_run.py
+++ b/tests/892/hooks/post_run.py
@@ -2,7 +2,7 @@
# export MERGED_LEF=/openlane/designs/def_test/runs/RUN_2022.01.23_17.23.46/tmp/merged.lef
# export HOOK_OUTPUT_PATH=/openlane/designs/def_test/runs/RUN_2022.01.23_17.23.46/results/final
# export DESIGN_DIR=/openlane/designs/def_test
-# openroad -exit -python designs/def_test/hooks/post_run.py
+# openroad -exit -no_init -python designs/def_test/hooks/post_run.py
import odb