blob: b9a840772edfc8abf73d5b92f18c7155f5179308 [file] [log] [blame]
# 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.
proc set_core_dims {args} {
puts_info "Setting Core Dimensions..."
set options {}
parse_key_args "set_core_dims" args values $options
set def_units $::env(DEF_UNITS_PER_MICRON)
set out_tmp $::env(TMP_DIR)/dimensions.txt
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/defutil.py\
extract_core_dims\
--output-data $out_tmp\
--input-lef $::env(MERGED_LEF)\
$::env(CURRENT_DEF)
set dims [join [cat $out_tmp] " "]
set ::env(CORE_WIDTH) [lindex $dims 0]
set ::env(CORE_HEIGHT) [lindex $dims 1]
}
proc init_floorplan_or {args} {
handle_deprecated_command init_floorplan
}
proc init_floorplan {args} {
increment_index
puts_info "Running Initial Floorplanning..."
TIMER::timer_start
set ::env(SAVE_DEF) [index_file $::env(floorplan_tmpfiles)/initial_fp.def]
set ::env(SAVE_SDC) [index_file $::env(floorplan_tmpfiles)/initial_fp.sdc]
set ::env(fp_report_prefix) [index_file $::env(floorplan_reports)/initial_fp]
run_openroad_script $::env(SCRIPTS_DIR)/openroad/floorplan.tcl -indexed_log [index_file $::env(floorplan_logs)/initial_fp.log] -netlist_in
check_floorplan_missing_lef
check_floorplan_missing_pins
set die_area_file [open $::env(fp_report_prefix)_die_area.rpt]
set core_area_file [open $::env(fp_report_prefix)_core_area.rpt]
set ::env(DIE_AREA) [read $die_area_file]
set ::env(CORE_AREA) [read $core_area_file]
close $die_area_file
close $core_area_file
set core_width [expr {[lindex $::env(CORE_AREA) 2] - [lindex $::env(CORE_AREA) 0]}]
set core_height [expr {[lindex $::env(CORE_AREA) 3] - [lindex $::env(CORE_AREA) 1]}]
puts_verbose "Core area width: $core_width"
puts_verbose "Core area height: $core_height"
if { $::env(FP_PDN_AUTO_ADJUST) } {
if { $core_width <= [expr {$::env(FP_PDN_VOFFSET) + $::env(FP_PDN_VPITCH)}] ||\
$core_height <= [expr {$::env(FP_PDN_HOFFSET) + $::env(FP_PDN_HPITCH)}]} {
puts_warn "Current core area is too small for a power grid. The power grid will be minimized."
set ::env(FP_PDN_VOFFSET) [expr {$core_width/8.0}]
set ::env(FP_PDN_HOFFSET) [expr {$core_height/8.0}]
set ::env(FP_PDN_VPITCH) [expr {$core_width/4.0}]
set ::env(FP_PDN_HPITCH) [expr {$core_height/4.0}]
}
}
puts_verbose "Final Vertical PDN Offset: $::env(FP_PDN_VOFFSET)"
puts_verbose "Final Horizontal PDN Offset: $::env(FP_PDN_HOFFSET)"
puts_verbose "Final Vertical PDN Pitch: $::env(FP_PDN_VPITCH)"
puts_verbose "Final Horizontal PDN Pitch: $::env(FP_PDN_HPITCH)"
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "floorplan initialization - openroad"
set_def $::env(SAVE_DEF)
set ::env(CURRENT_SDC) $::env(SAVE_SDC)
set_core_dims
}
proc place_io_ol {args} {
increment_index
puts_info "Running IO Placement..."
TIMER::timer_start
set options {
{-lef optional}
{-def optional}
{-cfg optional}
{-horizontal_layer optional}
{-vertical_layer optional}
{-horizontal_mult optional}
{-horizontal_ext optional}
{-vertical_layer optional}
{-vertical_mult optional}
{-vertical_ext optional}
{-length optional}
{-output_def optional}
{-extra_args optional}
}
set flags {-unmatched_error optional}
parse_key_args "place_io_ol" args arg_values $options flags_map $flags
set_if_unset arg_values(-lef) $::env(MERGED_LEF)
set_if_unset arg_values(-def) $::env(CURRENT_DEF)
set_if_unset arg_values(-cfg) $::env(FP_PIN_ORDER_CFG)
set_if_unset arg_values(-horizontal_layer) $::env(FP_IO_HLAYER)
set_if_unset arg_values(-vertical_layer) $::env(FP_IO_VLAYER)
set_if_unset arg_values(-vertical_mult) $::env(FP_IO_VTHICKNESS_MULT)
set_if_unset arg_values(-horizontal_mult) $::env(FP_IO_HTHICKNESS_MULT)
set_if_unset arg_values(-vertical_ext) $::env(FP_IO_VEXTEND)
set_if_unset arg_values(-horizontal_ext) $::env(FP_IO_HEXTEND)
set_if_unset arg_values(-length) [expr max($::env(FP_IO_VLENGTH), $::env(FP_IO_HLENGTH))]
set_if_unset arg_values(-output_def) [index_file $::env(floorplan_tmpfiles)/io.def]
if { $::env(FP_IO_UNMATCHED_ERROR) } {
set_if_unset flags_map(-unmatched_error) "--unmatched-error"
} else {
set_if_unset flags_map(-unmatched_error) ""
}
set_if_unset arg_values(-extra_args) ""
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/io_place.py\
--input-lef $arg_values(-lef)\
--config $arg_values(-cfg)\
--hor-layer $arg_values(-horizontal_layer)\
--ver-layer $arg_values(-vertical_layer)\
--ver-width-mult $arg_values(-vertical_mult)\
--hor-width-mult $arg_values(-horizontal_mult)\
--hor-extension $arg_values(-horizontal_ext)\
--ver-extension $arg_values(-vertical_ext)\
--length $arg_values(-length)\
{*}$flags_map(-unmatched_error)\
-o $arg_values(-output_def)\
{*}$arg_values(-extra_args)\
$arg_values(-def) |& tee [index_file $::env(floorplan_logs)/place_io_ol.log] $::env(TERMINAL_OUTPUT)
set_def $arg_values(-output_def)
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "ioplace - io_place.py"
}
proc place_io {args} {
increment_index
puts_info "Running IO Placement..."
TIMER::timer_start
set ::env(SAVE_DEF) [index_file $::env(floorplan_tmpfiles)/io.def]
run_openroad_script $::env(SCRIPTS_DIR)/openroad/ioplacer.tcl -indexed_log [index_file $::env(floorplan_logs)/io.log]
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "ioplace - openroad"
set_def $::env(SAVE_DEF)
}
proc place_contextualized_io {args} {
increment_index
puts_info "Running Contextualized IO Placement..."
set options {{-lef required} {-def required}}
set flags {}
parse_key_args "place_contextualized_io" args arg_values $options flags_map $flags
if {[file exists $arg_values(-def)] && [file exists $arg_values(-lef)]} {
TIMER::timer_start
file copy -force $arg_values(-def) $::env(placement_tmpfiles)/top_level.def
file copy -force $arg_values(-lef) $::env(placement_tmpfiles)/top_level.lef
set prev_def $::env(CURRENT_DEF)
set ::env(SAVE_DEF) [index_file $::env(floorplan_tmpfiles)/io.context.def]
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/contextualize.py \
-md $prev_def -ml $::env(MERGED_LEF_UNPADDED) \
-td $::env(placement_tmpfiles)/top_level.def -tl $::env(placement_tmpfiles)/top_level.lef \
-o $::env(SAVE_DEF) |& \
tee [index_file $::env(floorplan_logs)/io.contextualize.log]
puts_info "Custom floorplan created"
set_def $::env(SAVE_DEF)
set ::env(SAVE_DEF) [index_file $::env(floorplan_tmpfiles)/io.def]
set old_mode $::env(FP_IO_MODE)
set ::env(FP_IO_MODE) 0; # set matching mode
set ::env(CONTEXTUAL_IO_FLAG) 1
run_openroad_script $::env(SCRIPTS_DIR)/openroad/ioplacer.tcl -indexed_log [index_file $::env(floorplan_logs)/io.log]
set ::env(FP_IO_MODE) $old_mode
move_pins -from $::env(SAVE_DEF) -to $prev_def
set_def $prev_def
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "ioplace - openroad (contextual)"
} else {
puts_err "Contextual IO placement: def/lef files don't exist, exiting"
return -code error
}
}
proc tap_decap_or {args} {
if { $::env(TAP_DECAP_INSERTION) } {
if {[info exists ::env(FP_WELLTAP_CELL)] && $::env(FP_WELLTAP_CELL) ne ""} {
increment_index
puts_info "Running Tap/Decap Insertion..."
TIMER::timer_start
set ::env(SAVE_DEF) $::env(floorplan_results)/$::env(DESIGN_NAME).def
run_openroad_script $::env(SCRIPTS_DIR)/openroad/tapcell.tcl -indexed_log [index_file $::env(floorplan_logs)/tap.log]
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "tap/decap insertion - openroad"
set_def $::env(SAVE_DEF)
} else {
puts_info "No tap cells found in this library. Skipping Tap/Decap Insertion."
}
} else {
puts_warn "Skipping Tap/Decap Insertion."
}
}
proc padframe_extract_area {args} {
puts_info "Extracting Padframe area..."
set options {{-cfg required}}
set flags {}
parse_key_args "padframe_extract_area" args arg_values $options flags_map $flags
set area [exec $::env(SCRIPTS_DIR)/padframe_extract_area.sh $arg_values(-cfg)]
return $area
}
proc chip_floorplan {args} {
puts_info "Running Chip Floorplanning..."
# intial fp
init_floorplan
# remove pins section and others
remove_pins -input $::env(CURRENT_DEF)
remove_empty_nets -input $::env(CURRENT_DEF)
}
proc apply_def_template {args} {
if { [info exists ::env(FP_DEF_TEMPLATE)] } {
set log [index_file $::env(floorplan_logs)/apply_def_template.log]
set def [index_file $::env(floorplan_tmpfiles)/apply_def_template.def]
puts_info "Applying DEF template. See log: $log"
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/apply_def_template.py\
--lef $::env(MERGED_LEF) \
--def-template $::env(FP_DEF_TEMPLATE)\
--log $log \
$::env(CURRENT_DEF)
}
}
proc run_power_grid_generation {args} {
if { [info exists ::env(VDD_NETS)] || [info exists ::env(GND_NETS)] } {
# they both must exist and be equal in length
# current assumption: they cannot have a common ground
if { ! [info exists ::env(VDD_NETS)] || ! [info exists ::env(GND_NETS)] } {
puts_err "VDD_NETS and GND_NETS must *both* either be defined or undefined"
return -code error
}
# standard cell power and ground nets are assumed to be the first net
set ::env(VDD_PIN) [lindex $::env(VDD_NETS) 0]
set ::env(GND_PIN) [lindex $::env(GND_NETS) 0]
} elseif { [info exists ::env(SYNTH_USE_PG_PINS_DEFINES)] } {
set ::env(VDD_NETS) [list]
set ::env(GND_NETS) [list]
# get the pins that are in $synthesis_tmpfiles.pg_define.v
# that are not in $synthesis_results.v
#
set full_pins {*}[extract_pins_from_yosys_netlist $::env(synthesis_tmpfiles)/pg_define.v]
puts_info $full_pins
set non_pg_pins {*}[extract_pins_from_yosys_netlist $::env(synthesis_results)/$::env(DESIGN_NAME).v]
puts_info $non_pg_pins
# assumes the pins are ordered correctly (e.g., vdd1, vss1, vcc1, vss1, ...)
foreach {vdd gnd} $full_pins {
if { $vdd ne "" && $vdd ni $non_pg_pins } {
lappend ::env(VDD_NETS) $vdd
}
if { $gnd ne "" && $gnd ni $non_pg_pins } {
lappend ::env(GND_NETS) $gnd
}
}
} else {
set ::env(VDD_NETS) $::env(VDD_PIN)
set ::env(GND_NETS) $::env(GND_PIN)
}
puts_info "Power planning with power {$::env(VDD_NETS)} and ground {$::env(GND_NETS)}..."
if { [llength $::env(VDD_NETS)] != [llength $::env(GND_NETS)] } {
puts_err "VDD_NETS and GND_NETS must be of equal lengths"
return -code error
}
# check internal macros' power connection definitions
if {[info exists ::env(FP_PDN_MACRO_HOOKS)]} {
set macro_hooks [dict create]
set pdn_hooks [split $::env(FP_PDN_MACRO_HOOKS) ","]
foreach pdn_hook $pdn_hooks {
set instance_name [lindex $pdn_hook 0]
set power_net [lindex $pdn_hook 1]
set ground_net [lindex $pdn_hook 2]
dict append macro_hooks $instance_name [subst {$power_net $ground_net}]
}
set power_net_indx [lsearch $::env(VDD_NETS) $power_net]
set ground_net_indx [lsearch $::env(GND_NETS) $ground_net]
# make sure that the specified power domains exist.
if { $power_net_indx == -1 || $ground_net_indx == -1 || $power_net_indx != $ground_net_indx } {
puts_err "Can't find $power_net and $ground_net domain. \
Make sure that both exist in $::env(VDD_NETS) and $::env(GND_NETS)."
}
}
gen_pdn
}
proc run_floorplan {args} {
# |----------------------------------------------------|
# |---------------- 2. FLOORPLAN ------------------|
# |----------------------------------------------------|
#
# intial fp
init_floorplan
# check for deprecated io variables
if { [info exists ::env(FP_IO_HMETAL)]} {
set ::env(FP_IO_HLAYER) [lindex $::env(TECH_METAL_LAYERS) [expr {$::env(FP_IO_HMETAL) - 1}]]
puts_warn "You're using FP_IO_HMETAL in your configuration, which is a deprecated variable that will be removed in the future."
puts_warn "We recommend you update your configuration as follows:"
puts_warn "\tset ::env(FP_IO_HLAYER) {$::env(FP_IO_HLAYER)}"
}
if { [info exists ::env(FP_IO_VMETAL)]} {
set ::env(FP_IO_VLAYER) [lindex $::env(TECH_METAL_LAYERS) [expr {$::env(FP_IO_VMETAL) - 1}]]
puts_warn "You're using FP_IO_VMETAL in your configuration, which is a deprecated variable that will be removed in the future."
puts_warn "We recommend you update your configuration as follows:"
puts_warn "\tset ::env(FP_IO_VLAYER) {$::env(FP_IO_VLAYER)}"
}
# place io
if { [info exists ::env(FP_PIN_ORDER_CFG)] } {
place_io_ol
} else {
if { [info exists ::env(FP_CONTEXT_DEF)] && [info exists ::env(FP_CONTEXT_LEF)] } {
place_io
global_placement_or
place_contextualized_io \
-lef $::env(FP_CONTEXT_LEF) \
-def $::env(FP_CONTEXT_DEF)
} else {
place_io
}
}
apply_def_template
if { [info exist ::env(EXTRA_LEFS)] } {
if { [info exist ::env(MACRO_PLACEMENT_CFG)] } {
file copy -force $::env(MACRO_PLACEMENT_CFG) $::env(placement_tmpfiles)/macro_placement.cfg
manual_macro_placement f
} else {
global_placement_or
basic_macro_placement
}
}
tap_decap_or
scrot_klayout -layout $::env(CURRENT_DEF) $::env(floorplan_logs)/screenshot.log
run_power_grid_generation
}
package provide openlane 0.9