blob: 311f81d42f69284b297e407a6d9d35f1a45f9462 [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 get_yosys_bin {} {
return $::env(SYNTH_BIN)
}
proc convert_pg_pins {lib_in lib_out} {
try_catch sed -E {s/^([[:space:]]+)pg_pin(.*)/\1pin\2\n\1 direction : "inout";/g} $lib_in > $lib_out
}
proc run_yosys {args} {
set ::env(CURRENT_STAGE) synthesis
set options {
{-output optional}
}
set flags {
-no_set_netlist
}
parse_key_args "run_yosys" args arg_values $options flags_map $flags
if { [info exists arg_values(-output)] } {
set ::env(SAVE_NETLIST) $arg_values(-output)
} else {
set ::env(SAVE_NETLIST) $::env(synthesis_results)/$::env(DESIGN_NAME).v
}
if { [ info exists ::env(SYNTH_ADDER_TYPE)] && ($::env(SYNTH_ADDER_TYPE) in [list "RCA" "CSA"]) } {
set ::env(SYNTH_READ_BLACKBOX_LIB) 1
}
set ::env(synth_report_prefix) [index_file $::env(synthesis_reports)/synthesis]
set ::env(LIB_SYNTH_COMPLETE_NO_PG) [list]
foreach lib $::env(LIB_SYNTH_COMPLETE) {
set fbasename [file rootname [file tail $lib]]
set lib_path [index_file $::env(synthesis_tmpfiles)/$fbasename.no_pg.lib]
convert_pg_pins $lib $lib_path
lappend ::env(LIB_SYNTH_COMPLETE_NO_PG) $lib_path
}
try_catch $::env(SYNTH_BIN) \
-c $::env(SYNTH_SCRIPT) \
-l [index_file $::env(synthesis_logs)/synthesis.log] \
|& tee $::env(TERMINAL_OUTPUT)
if { ! [info exists flags_map(-no_set_netlist)] } {
set_netlist $::env(SAVE_NETLIST)
}
if { $::env(LEC_ENABLE) && [file exists $::env(PREV_NETLIST)] } {
logic_equiv_check -rhs $::env(PREV_NETLIST) -lhs $::env(CURRENT_NETLIST)
}
# The following is a naive workaround to the defparam issue.. it should be handled with
# an issue to the OpenROAD verilog parser.
if { [info exists ::env(SYNTH_EXPLORE)] && $::env(SYNTH_EXPLORE) } {
puts_info "This is a Synthesis Exploration and so no need to remove the defparam lines."
} else {
try_catch sed -i {/defparam/d} $::env(SAVE_NETLIST)
}
}
proc run_synth_exploration {args} {
if { $::env(SYNTH_NO_FLAT) } {
puts_err "Cannot run synthesis exploration with SYNTH_NO_FLAT."
return -code error
}
puts_info "Running Synthesis Exploration..."
set ::env(SYNTH_EXPLORE) 1
run_yosys
set exploration_report [index_file $::env(synthesis_reports)/exploration_analysis.html]
puts_info "Generating exploration report..."
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/synth_exp/analyze.py\
--output $exploration_report\
[index_file $::env(synthesis_logs)/synthesis.log]
set exploration_report_relative [relpath . $exploration_report]
puts_success "Done with synthesis exploration: See report at '$exploration_report_relative'."
# Following two cannot be indexed- referenced by path in the HTML file.
file copy $::env(SCRIPTS_DIR)/synth_exp/table.css $::env(synthesis_reports)
file copy $::env(SCRIPTS_DIR)/synth_exp/utils.js $::env(synthesis_reports)
}
proc run_synthesis {args} {
increment_index
TIMER::timer_start
puts_info "Running Synthesis..."
set ::env(CURRENT_SDC) $::env(BASE_SDC_FILE)
# in-place insertion
if { [file exists $::env(synthesis_results)/$::env(DESIGN_NAME).v] } {
puts_warn "A netlist at $::env(synthesis_results)/$::env(DESIGN_NAME).v already exists. Synthesis will be skipped."
set_netlist $::env(synthesis_results)/$::env(DESIGN_NAME).v
} else {
run_yosys
}
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "synthesis - yosys"
run_sta -pre_cts -log $::env(synthesis_logs)/sta.log
set ::env(LAST_TIMING_REPORT_TAG) [index_file $::env(synthesis_reports)/syn_sta]
if { $::env(RUN_SIMPLE_CTS) && $::env(CLOCK_TREE_SYNTH) } {
if { ! [info exists ::env(CLOCK_NET)] } {
set ::env(CLOCK_NET) $::env(CLOCK_PORT)
}
simple_cts \
-verilog $::env(synthesis_results)/$::env(DESIGN_NAME).v \
-fanout $::env(CLOCK_BUFFER_FANOUT) \
-clk_net $::env(CLOCK_NET) \
-root_clk_buf $::env(ROOT_CLK_BUFFER) \
-clk_buf $::env(CLK_BUFFER) \
-clk_buf_input $::env(CLK_BUFFER_INPUT) \
-clk_buf_output $::env(CLK_BUFFER_OUTPUT) \
-cell_clk_port $::env(CELL_CLK_PORT) \
-output $::env(synthesis_results)/$::env(DESIGN_NAME).v
}
if { $::env(CHECK_ASSIGN_STATEMENTS) == 1 } {
check_assign_statements
}
if { $::env(CHECK_UNMAPPED_CELLS) == 1 } {
check_synthesis_failure
}
if { [info exists ::env(SYNTH_USE_PG_PINS_DEFINES)] } {
puts_info "Creating a netlist with power/ground pins."
if { ! [info exists ::env(SYNTH_DEFINES)] } {
set ::env(SYNTH_DEFINES) [list]
}
lappend ::env(SYNTH_DEFINES) {*}$::env(SYNTH_USE_PG_PINS_DEFINES)
run_yosys -output $::env(synthesis_tmpfiles)/pg_define.v -no_set_netlist
}
}
proc verilog_elaborate {args} {
# usually run on structural verilog (top-level netlists)
set synth_script_old $::env(SYNTH_SCRIPT)
set ::env(SYNTH_SCRIPT) $::env(SCRIPTS_DIR)/yosys/synth_top.tcl
run_yosys {*}$args
set ::env(SYNTH_SCRIPT) $synth_script_old
}
proc yosys_rewrite_verilog {filename} {
if { !$::env(LEC_ENABLE) } {
puts_verbose "Skipping Verilog rewrite (logic equivalency checks are disabled)..."
return
}
if { !$::env(YOSYS_REWRITE_VERILOG) } {
puts_verbose "Skipping Verilog rewrite."
return
}
if { ! [file exists $filename] } {
puts_err "Failed to rewrite Verilog file $filename: File does not exist."
return -code error
}
set ::env(SAVE_NETLIST) $filename
increment_index
TIMER::timer_start
puts_info "Rewriting $filename to $::env(SAVE_NETLIST) using Yosys..."
try_catch $::env(SYNTH_BIN) \
-c $::env(SCRIPTS_DIR)/yosys/rewrite_verilog.tcl \
-l [index_file $::env(synthesis_logs)/rewrite_verilog.log]
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "verilog rewrite - yosys"
}
proc logic_equiv_check {args} {
set options {
{-lhs required}
{-rhs required}
}
set flags {}
set args_copy $args
parse_key_args "logic_equiv_check" args arg_values $options flags_map $flags
if { [file exists $arg_values(-lhs).without_power_pins.v] } {
set ::env(LEC_LHS_NETLIST) $arg_values(-lhs).without_power_pins.v
} else {
set ::env(LEC_LHS_NETLIST) $arg_values(-lhs)
}
if { [file exists $arg_values(-rhs).without_power_pins.v] } {
set ::env(LEC_RHS_NETLIST) $arg_values(-rhs).without_power_pins.v
} else {
set ::env(LEC_RHS_NETLIST) $arg_values(-rhs)
}
increment_index
TIMER::timer_start
puts_info "Running LEC: $::env(LEC_LHS_NETLIST) Vs. $::env(LEC_RHS_NETLIST)"
if { [catch {exec $::env(SYNTH_BIN) -c $::env(SCRIPTS_DIR)/yosys/logic_equiv_check.tcl -l [index_file $::env(synthesis_logs).equiv.log] |& tee $::env(TERMINAL_OUTPUT)} ]} {
puts_err "$::env(LEC_LHS_NETLIST) is not logically equivalent to $::env(LEC_RHS_NETLIST)."
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "logic equivalence check - yosys"
return -code error
}
puts_info "$::env(LEC_LHS_NETLIST) and $::env(LEC_RHS_NETLIST) are proven equivalent"
TIMER::timer_stop
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "logic equivalence check - yosys"
}
package provide openlane 0.9