Files
OpenLane/flow.tcl
Donn 96670268d9 Usability Tweaks (#759)
~ CI now uploads each run tarball individually
~ Updated READMEs
~ `save_views` now always executed
- Removed `run_power_pins_insertion_step`: `write_powered_verilog` now run right before LVS
2021-12-14 16:42:41 +02:00

363 lines
10 KiB
Tcl
Executable File

#!/usr/bin/tclsh
# Copyright 2020-2021 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.
set ::env(OPENLANE_ROOT) [file dirname [file normalize [info script]]]
if { [file exists $::env(OPENLANE_ROOT)/install/env.tcl ] } {
source $::env(OPENLANE_ROOT)/install/env.tcl
}
if { ! [info exists ::env(OPENROAD_BIN) ] } {
set ::env(OPENROAD_BIN) openroad
}
lappend ::auto_path "$::env(OPENLANE_ROOT)/scripts/"
package require openlane; # provides the utils as well
proc run_placement_step {args} {
if { ! [ info exists ::env(PLACEMENT_CURRENT_DEF) ] } {
set ::env(PLACEMENT_CURRENT_DEF) $::env(CURRENT_DEF)
} else {
set ::env(CURRENT_DEF) $::env(PLACEMENT_CURRENT_DEF)
}
run_placement
}
proc run_cts_step {args} {
if { ! [ info exists ::env(CTS_CURRENT_DEF) ] } {
set ::env(CTS_CURRENT_DEF) $::env(CURRENT_DEF)
} else {
set ::env(CURRENT_DEF) $::env(CTS_CURRENT_DEF)
}
run_cts
run_resizer_timing
}
proc run_routing_step {args} {
if { ! [ info exists ::env(ROUTING_CURRENT_DEF) ] } {
set ::env(ROUTING_CURRENT_DEF) $::env(CURRENT_DEF)
} else {
set ::env(CURRENT_DEF) $::env(ROUTING_CURRENT_DEF)
}
run_routing
}
proc run_diode_insertion_2_5_step {args} {
if { ! [ info exists ::env(DIODE_INSERTION_CURRENT_DEF) ] } {
set ::env(DIODE_INSERTION_CURRENT_DEF) $::env(CURRENT_DEF)
} else {
set ::env(CURRENT_DEF) $::env(DIODE_INSERTION_CURRENT_DEF)
}
if { ($::env(DIODE_INSERTION_STRATEGY) == 2) || ($::env(DIODE_INSERTION_STRATEGY) == 5) } {
run_antenna_check
heal_antenna_violators; # modifies the routed DEF
}
}
proc run_lvs_step {{ lvs_enabled 1 }} {
if { ! [ info exists ::env(LVS_CURRENT_DEF) ] } {
set ::env(LVS_CURRENT_DEF) $::env(CURRENT_DEF)
} else {
set ::env(CURRENT_DEF) $::env(LVS_CURRENT_DEF)
}
if { $lvs_enabled } {
run_magic_spice_export
run_lvs; # requires run_magic_spice_export
}
}
proc run_drc_step {{ drc_enabled 1 }} {
if { ! [ info exists ::env(DRC_CURRENT_DEF) ] } {
set ::env(DRC_CURRENT_DEF) $::env(CURRENT_DEF)
} else {
set ::env(CURRENT_DEF) $::env(DRC_CURRENT_DEF)
}
if { $drc_enabled } {
run_magic_drc
run_klayout_drc
}
}
proc run_antenna_check_step {{ antenna_check_enabled 1 }} {
if { ! [ info exists ::env(ANTENNA_CHECK_CURRENT_DEF) ] } {
set ::env(ANTENNA_CHECK_CURRENT_DEF) $::env(CURRENT_DEF)
} else {
set ::env(CURRENT_DEF) $::env(ANTENNA_CHECK_CURRENT_DEF)
}
if { $antenna_check_enabled } {
run_antenna_check
}
}
proc run_non_interactive_mode {args} {
set options {
{-design required}
{-from optional}
{-to optional}
{-save_path optional}
{-no_lvs optional}
{-no_drc optional}
{-no_antennacheck optional}
{-override_env optional}
}
set flags {-save}
parse_key_args "run_non_interactive_mode" args arg_values $options flags_map $flags -no_consume
prep {*}$args
# signal trap SIGINT save_state;
if { [info exists arg_values(-override_env)] } {
set env_overrides [split $arg_values(-override_env) ',']
foreach override $env_overrides {
set kva [split $override '=']
set key [lindex $kva 0]
set value [lindex $kva 1]
set ::env(${key}) $value
}
}
set LVS_ENABLED [expr ![info exists flags_map(-no_lvs)] ]
set DRC_ENABLED [expr ![info exists flags_map(-no_drc)] ]
set ANTENNACHECK_ENABLED [expr ![info exists flags_map(-no_antennacheck)] ]
set steps [dict create \
"synthesis" {run_synthesis "" } \
"floorplan" {run_floorplan ""} \
"placement" {run_placement_step ""} \
"cts" {run_cts_step ""} \
"routing" {run_routing_step ""}\
"diode_insertion" {run_diode_insertion_2_5_step ""} \
"gds_magic" {run_magic ""} \
"gds_drc_klayout" {run_klayout ""} \
"gds_xor_klayout" {run_klayout_gds_xor ""} \
"lvs" "run_lvs_step $LVS_ENABLED" \
"drc" "run_drc_step $DRC_ENABLED" \
"antenna_check" "run_antenna_check_step $ANTENNACHECK_ENABLED" \
"cvc" {run_lef_cvc}
]
set_if_unset arg_values(-to) "cvc";
if { [info exists ::env(CURRENT_STEP) ] } {
puts "\[INFO\]:Picking up where last execution left off"
puts [format "\[INFO\]:Current stage is %s " $::env(CURRENT_STEP)]
} else {
set ::env(CURRENT_STEP) "synthesis";
}
set_if_unset arg_values(-from) $::env(CURRENT_STEP);
set exe 0;
dict for {step_name step_exe} $steps {
if { [ string equal $arg_values(-from) $step_name ] } {
set exe 1;
}
if { $exe } {
# For when it fails
set ::env(CURRENT_STEP) $step_name
[lindex $step_exe 0] [lindex $step_exe 1] ;
}
if { [ string equal $arg_values(-to) $step_name ] } {
set exe 0:
break;
}
}
# for when it resumes
set steps_as_list [dict keys $steps]
set next_idx [expr [lsearch $steps_as_list $::env(CURRENT_STEP)] + 1]
set ::env(CURRENT_STEP) [lindex $steps_as_list $next_idx]
save_views \
-save_path $::env(RESULTS_DIR)/final \
-def_path $::env(CURRENT_DEF) \
-lef_path $::env(finishing_results)/$::env(DESIGN_NAME).lef \
-gds_path $::env(finishing_results)/$::env(DESIGN_NAME).gds \
-mag_path $::env(finishing_results)/$::env(DESIGN_NAME).mag \
-maglef_path $::env(finishing_results)/$::env(DESIGN_NAME).lef.mag \
-spice_path $::env(finishing_results)/$::env(DESIGN_NAME).spice \
-verilog_path $::env(CURRENT_NETLIST) \
-spef_path $::env(SPEF_TYPICAL) \
-sdf_path $::env(CURRENT_SDF) \
-sdc_path $::env(CURRENT_SDC)
calc_total_runtime
save_state
generate_final_summary_report
check_timing_violations
puts_success "Flow complete."
}
proc run_interactive_mode {args} {
set options {
{-design optional}
}
set flags {}
parse_key_args "run_interactive_mode" args arg_values $options flags_map $flags -no_consume
if { [info exists arg_values(-design)] } {
prep {*}$args
}
set ::env(TCLLIBPATH) $::auto_path
exec tclsh >&@stdout
}
proc run_magic_drc_batch {args} {
set options {
{-magicrc optional}
{-tech optional}
{-report required}
{-design required}
{-gds required}
}
set flags {}
parse_key_args "run_magic_drc_batch" args arg_values $options flags_mag $flags
if { [info exists arg_values(-magicrc)] } {
set magicrc [file normalize $arg_values(-magicrc)]
}
if { [info exists arg_values(-tech)] } {
set ::env(TECH) [file normalize $arg_values(-tech)]
}
set ::env(GDS_INPUT) [file normalize $arg_values(-gds)]
set ::env(REPORT_OUTPUT) [file normalize $arg_values(-report)]
set ::env(DESIGN_NAME) $arg_values(-design)
if { [info exists magicrc] } {
exec magic \
-noconsole \
-dnull \
-rcfile $magicrc \
$::env(OPENLANE_ROOT)/scripts/magic/drc_batch.tcl \
</dev/null |& tee /dev/tty
} else {
exec magic \
-noconsole \
-dnull \
$::env(OPENLANE_ROOT)/scripts/magic/drc_batch.tcl \
</dev/null |& tee /dev/tty
}
}
proc run_lvs_batch {args} {
# runs device level lvs on -gds/CURRENT_GDS and -net/CURRENT_NETLIST
# extracts gds only if EXT_NETLIST does not exist
set options {
{-design required}
{-gds optional}
{-net optional}
}
set flags {}
parse_key_args "run_lvs_batch" args arg_values $options flags_lvs $flags -no_consume
prep {*}$args
if { [info exists arg_values(-gds)] } {
set ::env(CURRENT_GDS) [file normalize $arg_values(-gds)]
} else {
set ::env(CURRENT_GDS) $::env(finishing_results)/$::env(DESIGN_NAME).gds
}
if { [info exists arg_values(-net)] } {
set ::env(CURRENT_NETLIST) [file normalize $arg_values(-net)]
}
if { ! [file exists $::env(CURRENT_GDS) ] } {
puts_err "Could not find GDS file \"$::env(CURRENT_GDS)\""
exit 1
}
if { ! [file exists $::env(CURRENT_NETLIST) ] } {
puts_err "Could not find NET file \"$::env(CURRENT_NETLIST)\""
exit 1
}
set ::env(MAGIC_EXT_USE_GDS) 1
set ::env(EXT_NETLIST) $::env(finishing_results)/$::env(DESIGN_NAME).gds.spice
if { [file exists $::env(EXT_NETLIST)] } {
puts_warn "Reusing $::env(EXT_NETLIST). Delete to remake."
} else {
run_magic_spice_export
}
run_lvs
}
proc run_file {args} {
set ::env(TCLLIBPATH) $::auto_path
exec tclsh {*}$args >&@stdout
}
set options {
{-file optional}
}
set flags {-interactive -it -drc -lvs -synth_explore}
parse_key_args "flow.tcl" argv arg_values $options flags_map $flags -no_consume
puts_info {
___ ____ ___ ____ _ ____ ____ ___
/ \ | \ / _]| \ | | / || \ / _]
| | | o ) [_ | _ || | | o || _ | / [_
| O | | _/ _]| | || |___ | || | || _]
| | | | | [_ | | || || _ || | || [_
\___/ |__| |_____||__|__||_____||__|__||__|__||_____|
}
if {[catch {exec cat $::env(OPENLANE_ROOT)/installed_version} ::env(OPENLANE_VERSION)]} {
if {[catch {exec git --git-dir $::env(OPENLANE_ROOT)/.git describe --tags} ::env(OPENLANE_VERSION)]} {
# if no tags yet
if {[catch {exec git --git-dir $::env(OPENLANE_ROOT)/.git log --pretty=format:'%h' -n 1} ::env(OPENLANE_VERSION)]} {
set ::env(OPENLANE_VERSION) "N/A"
}
}
}
puts_info "Version: $::env(OPENLANE_VERSION)"
if [catch {exec python3 $::env(OPENLANE_ROOT)/dependencies/verify_versions.py} ::env(VCHECK_OUTPUT)] {
puts_warn $::env(VCHECK_OUTPUT)
puts_warn "OpenLane may not function properly."
}
if { [info exists flags_map(-interactive)] || [info exists flags_map(-it)] } {
puts_info "Running interactively"
if { [info exists arg_values(-file)] } {
run_file [file normalize $arg_values(-file)] {*}$argv
} else {
run_interactive_mode {*}$argv
}
} elseif { [info exists flags_map(-drc)] } {
run_magic_drc_batch {*}$argv
} elseif { [info exists flags_map(-lvs)] } {
run_lvs_batch {*}$argv
} elseif { [info exists flags_map(-synth_explore)] } {
prep {*}$argv
run_synth_exploration
} else {
puts_info "Running non-interactively"
run_non_interactive_mode {*}$argv
}