mirror of
https://github.com/The-OpenROAD-Project/OpenLane.git
synced 2026-05-29 00:23:55 +08:00
Add Wire Length Checker (#1463)
\+ Add PDK variable `WIRE_LENGTH_THRESHOLD` which wires with lengths >= said value are flagged \+ Add `QUIT_ON_LONG_WIRE` which fails the flow if any wires are flagged for length ~ Update all `$::env(OPENROAD_BIN) -exit -python` invocations to include `-no_init` to suppress message about rc file ~ Replace ill-fitting `$::env(OPENROAD_BIN) -exit -python` invocations with just `python3` ~ Replace local install check with a simple git directory check
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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. <br> (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`. <br> (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. <br> (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`. <br> (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`. <br> (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.<br> (Example: `li1 0 100 1000 300, met5 0 0 1000 500`) <br> (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. <br> 1 = most reduction, 0 = least reduction <br> (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. <br> (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 <br> (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 <br> (Default: `0`)|
|
||||
| `QUIT_ON_TR_DRC` | Checks for DRC violations after routing and exits the flow if any was found. 1 = Enabled, 0 = Disabled <br> (Default: `1`)|
|
||||
| `QUIT_ON_LONG_WIRE` | Exits the flow if any wire length exceeds the threshold set in the PDK. 1 = Enabled, 0 = Disabled <br> (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 <br> (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 <br> (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 <br> (Default: `1`)|
|
||||
|
||||
4
flow.tcl
4
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)
|
||||
|
||||
98
scripts/odbpy/wire_lengths.py
Normal file
98
scripts/odbpy/wire_lengths.py
Normal file
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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}]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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."
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user