#----------------------------------------------------------------------------
# The confidential and proprietary information contained in this file may
# only be used by a person authorised under and to the extent permitted
# by a subsisting licensing agreement from Arm Limited or its affiliates.
#
# (C) COPYRIGHT 2024 Arm Limited or its affiliates.
# ALL RIGHTS RESERVED
#
# This entire notice must be reproduced on all copies of this file
# and copies of this file may only be made by a person if such person is
# permitted to do so under the terms of a subsisting license agreement
# from Arm Limited or its affiliates.
#
# Release Information : $State$
#
#----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Function: Read the RTL, setup DFT and synthesise to generic gates
# -----------------------------------------------------------------------------
set step_name "syn_generic"
puts "ARM_INFO: Step syn_generic"
## MJ Metrics 04/12/23
push_snapshot_stack
# -----------------------------------------------------------------------------
# Source flow setup files and initialise the step
# -----------------------------------------------------------------------------
source $env(CONFIG_PATH)/technology.tcl
source $env(CONFIG_PATH)/design.tcl
source $env(CONFIG_PATH)/setup.tcl
#START_FLEX_INSERT_ANCHOR: genus pre db load config
################################################################################
# Genus attributes (design & library not required)
################################################################################
set_db source_verbose true
set_db flow_verbose false
set_db information_level 9
################################################################################
# ATTRIBUTES APPLIED BEFORE LOADING A LIBRARY OR DATABASE
################################################################################
# General attributes
#-------------------------------------------------------------------------------
set_multi_cpu_usage -local_cpu $env(LSB_MAX_NUM_PROCESSORS)
# Force timing and capacitance unit to be ns and pf
# It avoids discrepancy issue due to libraries having different units
# Need to be set before reading of libraries it also force sdc and reports units
set_db timing_time_unit 1ns
set_db timing_cap_unit 1pf
set_db super_thread_debug_directory "./thread_debug_logs"
set_db wlec_set_cdn_synth_root true
set_db error_on_lib_lef_pin_inconsistency true
set_db write_vlog_empty_module_for_logic_abstract false
set_db gen_module_prefix "arcadia_complex_"
## to enable output of mask statements in tracks etc
set_db def_output_version 5.8
# Design attributes [get_db -category design]
set_db remove_assigns true
#-------------------------------------------------------------------------------
set_db design_process_node 5
# HDL attributes [get_db -category hdl]
#-------------------------------------------------------------------------------
set_db hdl_error_on_blackbox true
set_db hdl_error_on_latch $design_vars(error_on_latch)
set_db hdl_error_on_logic_abstract true
set_db hdl_error_on_negedge true
set_db hdl_array_naming_style %s_%d
set_db hdl_flatten_complex_port true
set_db hdl_generate_index_style %s_%d
set_db hdl_generate_separator _
set_db hdl_record_naming_style %s_%s_
set_db hdl_reg_naming_style %s_reg%s
set_db hdl_resolve_instance_with_libcell true
set_db hdl_use_cw_first true
# Alias the pins name of CDN_flop to be able to put a constraints on an un-mapped flop
set_db hdl_rename_cdn_flop_pins {{clk CK} {d D}}
# Force synthesis to not assume any value on any unconnected pins
set_db hdl_unconnected_value none
# Avoid merging flops: could avoid merging flop being duplicated only by user (timing reason mainly)...
set_db optimize_merge_flops false
#This attribute helps with detecting where combinational loops are
set_db print_ports_nets_preserved_for_cb true
# Optimization attributes [get_db -category netlist]
#-------------------------------------------------------------------------------
set_db syn_generic_effort high
set_db syn_map_effort high
set_db syn_opt_effort high
set_db use_multibit_cells true
set_db use_multibit_combo_cells true
set_db multibit_cells_from_different_busses false
set_db multibit_prefix_string "MBIT_"
set_db use_multibit_iso_cells true
set_db multibit_mapping_effort_level high
set_db force_merge_seqs_into_multibit_cells false
set_db force_merge_combos_into_multibit_cells false
set_db dft_shift_register_with_mbci false
set_db use_multibit_seq_and_tristate_cells true
set_db auto_ungroup none
# Disable register replication
set_db iopt_sequential_duplication false
# Timing attributes [get_db -category tim]
#-------------------------------------------------------------------------------
set_db time_recovery_arcs true
# Datapath attributes [get_db -category dp]
#-------------------------------------------------------------------------------
# Leakage Power attributes [get_db -category lp_opt lib_ui]
#-------------------------------------------------------------------------------
set_db lp_insert_clock_gating true
if { [get_db program_major_version] >= 21.10 } {
set_db design_power_effort high
} else {
set_db leakage_power_effort high
}
# DFT attributes [get_db -category dft]
#-------------------------------------------------------------------------------
set_db dft_wait_for_license true
## Define the Test Clock Waveform Attributes to target ATPG speed of 200MHz
set_db dft_clock_waveform_divide_fall 100
set_db dft_clock_waveform_divide_period 100
set_db dft_clock_waveform_divide_rise 90
set_db dft_clock_waveform_fall 50
set_db dft_clock_waveform_period 5000
set_db dft_clock_waveform_rise 1
set_db dft_include_test_signal_outputs_in_abstract_model false
# ensure scan flop input be only used for scan
## CCR 2463365 Ensure RAM scan segment having SI/SO in different power domains is included in power domain aware scan chain of inst PD
if {[regsub {\-.*} [get_db program_version] {}] >= 21.11} {
set_db dft_use_abstract_segment_instance_power_domain_for_scan_connection true
}
set_db use_scan_seqs_for_non_dft false
if {[regsub {\-.*} [get_db program_version] {}] >= 21.10} {
# pick up instance power domain rather than pin power domain for memory scan connections. CCR 2649133
set_db dft_use_abstract_segment_instance_power_domain_for_scan_connection true
}
# Physical attributes [get_db -category phys]
#-------------------------------------------------------------------------------
# set_db scale_of_cap_per_unit_length 1.15
# set_db scale_of_res_per_unit_length 1.15
# Prevent merging unused bits into MBIT FFs/Combo cells,
# which will cause MBIT cell re-naming issue in INVS Multi-Bit
# optimization flow and CLP:ISO_MISSING_MATCHING_CELL errors
# on optimized input pins of Combo cells
set_db multibit_allow_unused_bits false
#END_FLEX_INSERT_ANCHOR: genus pre db load config
puts "ARM_INFO: Set variables"
# Setup the number of CPUs to use
#START_FLEX_INSERT_ANCHOR: CPU Usage
set_db max_cpus_per_server $env(LSB_DJOB_NUMPROC)
#END_FLEX_INSERT_ANCHOR: CPU Usage
#REVISIT: This should be removed when Genus fully supports the set_data_check command
#Genus currently does not support set_data_check when it is applied between different instances. This variable is used to skip sections of the SDC constraints file
set ARM_SKIP_SET_DATA_CHECKS true
#REVISIT: This should be removed when Genus fully supports the set_max_delay command (expected 19.12)
#Genus currently does not support set_max_delay -ignore_clock_latency. This variable is used to skip sections of the SDC constraints file
set ARM_SKIP_SET_MAX_DELAY_IGNORE_CLOCK_LATENCY true
# Create the report dir
set report_dir [file normalize [file join ../reports $step_name]]
file mkdir $report_dir
#START_FLEX_INSERT_ANCHOR: Log Message Handling
# -----------------------------------------------------------------------------
# Log message to upgrade
# -----------------------------------------------------------------------------
foreach el $flow_vars(${step_name}_messages_to_upgrade) {
set message_code [lindex $el 0]
set reason [lindex $el 1]
set new_severity [lindex $el 2]
#Unlike demoting, when choosing to upgrade a message a user shouldn't use "default" because what's the point?
puts "ARM_WARNING: Upgrading message $message_code, Reason: $reason"
puts "ARM_INFO: New severity = $new_severity"
set_db [get_db messages $message_code] .severity $new_severity
if {[llength $el] > 3} {
set max_print [lindex $el 3]
puts "ARM_INFO: Maximum print = $max_print"
set_db [get_db messages $message_code] .max_print $max_print
}
}
# -----------------------------------------------------------------------------
# Log message to downgrade
# -----------------------------------------------------------------------------
foreach el $flow_vars(${step_name}_messages_to_downgrade) {
set message_code [lindex $el 0]
set reason [lindex $el 1]
set new_severity [lindex $el 2]
puts "ARM_WARNING: Downgrading/Hiding message $message_code, Reason: $reason"
if {$new_severity != "default"} {
puts "ARM_INFO: New severity = $new_severity"
set_db [get_db messages $message_code] .severity $new_severity
}
if {[llength $el] > 3} {
set max_print [lindex $el 3]
puts "ARM_INFO: Maximum print = $max_print"
set_db [get_db messages $message_code] .max_print $max_print
}
}
#END_FLEX_INSERT_ANCHOR: Log Message Handling
#- Store non-default root attributes to metrics
set flow_root_config [report_obj -tcl]
foreach key [dict keys $flow_root_config] {
if {[string length [dict get $flow_root_config $key]] > 200} {
dict set flow_root_config $key "\[long value truncated\]"
}
}
set_metric -name flow.root_config -value $flow_root_config
set detected_errors 0
#START_FLEX_INSERT_ANCHOR: genus dp_analytical setting
#END_FLEX_INSERT_ANCHOR: genus dp_analytical setting
# -----------------------------------------------------------------------------
# Initialise the design
# -----------------------------------------------------------------------------
if {[get_db current_design] eq ""} {
#- setup library information
read_mmmc $env(CONFIG_PATH)/mmmc_config.synthesis.tcl
read_physical -lef $tech_vars(synthesis,lef)
#- read and elaborate design
source ../constraints/syn_load_rtl.tcl
set_db init_hdl_search_path $dir_list
if {[info exists elab_only]} {
set_db statistics_automatic_logging false
set_db statistics_log_data false
set_db statistics_metrics false
set_db wireload_mode none
}
set cmd "read_hdl -sv $verilog_filelist"
puts "FLOW: started $cmd"
eval $cmd
#Determine if parameters are needed for elaboration
set params_list ""
if {($design_vars(elab_params) != "") && ($design_vars(elab_params_file) != "")} {
puts "ARM_ERROR: both design_vars(elab_params) & design_vars(elab_params_file) have been defined. Only one can be defined"
exit 1
} elseif {$design_vars(elab_params) != ""} {
puts "ARM_INFO: Elaboration with following parameters: $design_vars(elab_params)"
set params_list $design_vars(elab_params)
} elseif {$design_vars(elab_params_file) != ""} {
source $design_vars(elab_params_file)
if {$design_vars(elab_params_variable) != ""} {
puts "ARM_INFO: Elaboration with following parameters: [set $design_vars(elab_params_variable)]"
set params_list [set $design_vars(elab_params_variable)]
} else {
puts "ARM_ERROR: $design_vars(elab_params_variable) from $design_vars(elab_params_file) was not found"
exit 1
}
}
#Elaborate Design
if {[llength $params_list] > 0} {
elaborate -parameter $params_list arcadia_complex
} else {
puts "ARM_INFO: Elaboration without parameters"
elaborate arcadia_complex
}
# REVISIT: moving the elaborated design to "arcadia_complex" so that it doesn't have all the parameter names on the end
# REVISIT: This is temporary so that it works with existing SDC files etc. as we may want to keep parameters on the design name in the future
rename_obj [find_unique_design] arcadia_complex
#- optionally setup power intent from UPF/CPF/1801
read_power_intent ${env(LOGICAL_ROOT)}/arcadia/logical/arcadia/power_intent/upf/arcadia_complex0.upf
# create_cost_group genus_uniquify
set_db ui_respects_preserve false
uniquify [current_design]
set_db ui_respects_preserve true
#Add any top-level port connections
foreach hookup_list $design_vars(pin_to_port_hookup_list) {
#Sanity check we have the correct number of elements defined
if {([llength $hookup_list] == 5) || ([llength $hookup_list] == 7)} {
set instance_pattern [lindex $hookup_list 0]
set module_pattern [lindex $hookup_list 1]
set pin_pattern [lindex $hookup_list 2]
set top_level_port_name [lindex $hookup_list 3]
set top_level_port_direction [lindex $hookup_list 4]
# Check if the design actually has the pin_pattern, note the pin could be a bus so check for both pin_pattern and pin_pattern[*]
# Store the output from get_db to speed up runtime
set all_matching_pins [get_db pins *${pin_pattern} *${pin_pattern}\[*\] -if {.inst.name==$instance_pattern && .inst.base_cell.name==$module_pattern}]
if {[llength $all_matching_pins] > 0} {
# First determine pairs of pins and ports that must be connected together. If the signal is a single bit connection
# then the list will be made up of {pin port}, if a MSB and LSB of the signal has been defined then the list is
# made up of {pin[lsb] port[lsb] pin[lsb+1] port[lsb+1]...pin[msb] port[msb]}
if {[llength $hookup_list] == 7} {
set msb [lindex $hookup_list 5]
set lsb [lindex $hookup_list 6]
#To be used when creating the top level port
set left_bit "-left_bit $msb"; set right_bit "-right_bit $lsb"
set pin_port_pair_list {}
for {set i $lsb} {$i <= $msb} {incr i} {
lappend pin_port_pair_list ${pin_pattern}\[$i\] $top_level_port_name\[$i\]
}
} else {
set pin_port_pair_list [list $pin_pattern $top_level_port_name]
#To be used when creating the top level port
set left_bit "" ; set right_bit ""
}
# Create the top level port for the connection
# if the pin_port_pair_list has more than 2 elements we know a lsb/msb was defined so we can
# create the port as a bus of (msb+1-lsb) bits otherwise simply create a single bit top-level port
if ![llength [get_port -quiet $top_level_port_name ]] {
eval "create_port_bus -name $top_level_port_name $left_bit $right_bit -$top_level_port_direction"
}
# Finally: All the pins matching the instance_pattern and module_pattern along with the pin from the pin_port_pair_list are
# found and then connected with the port defined in the pair
foreach {pin port} $pin_port_pair_list {
foreach inst_pin [get_db $all_matching_pins *${pin}] {
disconnect $inst_pin
puts "ARM_INFO: Connecting $inst_pin with port $port"
connect [get_ports $port] $inst_pin -prefix [regsub -all -- {[^[:alnum:]_]+} $port {_}]
}
}
} else {
puts "ARM_ERROR: No pins found with:\n Instance pattern=$instance_pattern\n Module pattern=$module_pattern\n Pin pattern=${pin_pattern}"
}
} else {
puts "ARM_ERROR: [llength $hookup_list] elements found in design_vars(pin_to_port_hookup_list) entry. Either 5 or 7 entries expected. Entries = $hookup_list"
exit 1
}
}
#START_FLEX_INSERT_ANCHOR: Add top level ports
# -----------------------------------------------------------------------------
# Function: create power interface
# -----------------------------------------------------------------------------
# REVISIT(ramsri01, BET, add_top_level_ports.tcl script in NFF master needs to be made generic to work with RAM connections in different power domains, NUFLEXFLOW-643)
# This script is currently here as workaround till we clean up add_top_level_ports.tcl to work for both power gated and non power gated design.
# Below version will work for designs like A55 with 2 domains or Hayes with 5 domains
proc arm_create_port {port_name dir {left_bit ""} {right_bit ""} } {
if { $left_bit != "" } {
set left_bit "-left_bit $left_bit"
}
if { $right_bit != ""} {
set right_bit "-right_bit $right_bit"
}
if ![llength [get_port -quiet $port_name ]] {
set cmd "create_port_bus -name $port_name $left_bit $right_bit -$dir"
eval $cmd
puts "ARM_INFO: Port $port_name created"
} else {
puts "ARM_INFO: Port $port_name already exists"
}
}
proc arm_netlist_connect { port pin {object ""}} {
foreach obj_pin [get_db [get_pin -quiet -of_objects [get_cell * -hier -filter "ref_name =~$object"] -filter "full_name=~$pin"]] {
disconnect $obj_pin
puts "ARM_USER_INFO: Connecting $obj_pin with port $port"
connect [get_ports $port] $obj_pin -prefix [regsub -all -- {[^[:alnum:]_]+} $port {_}]
}
}
uniquify [find_unique_design]
if {[llength [get_db insts .pins.name *EMA*]] > 0} {
# Single port register file - RFS and FCI*RFS
if {[get_cell * -hier -filter "ref_name =~ *RFS*"] != ""} {
arm_create_port RF_EMA input 2 0
arm_create_port RF_EMAW input 1 0
arm_create_port RF_EMAS input
uniquify [find_unique_design]
# Single port register file: EMA connections
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect RF_EMA[${i}] *EMA[${i}] *RFS*
}
for {set i 0} {$i < 2} {incr i} {
arm_netlist_connect RF_EMAW[${i}] *EMAW[${i}] *RFS*
}
arm_netlist_connect RF_EMAS *EMAS *RFS*
}
# Dual port register file
if {[get_cell * -hier -filter "ref_name =~ *RF2P*"] != ""} {
arm_create_port RF2P_EMAA input 2 0
arm_create_port RF2P_EMAB input 2 0
arm_create_port RF2P_EMASA input
edit_netlist uniquify [find_unique_design]
# Dual ports register file: EMA connections
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect RF2P_EMAA[${i}] *EMAA[${i}] *RF2P*
}
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect RF2P_EMAB[${i}] *EMAB[${i}] *RF2P*
}
arm_netlist_connect RF2P_EMASA *EMASA *RF2P*
}
# Single port SRAM memory
if {[get_cell * -hier -filter "ref_name =~ *SRAM*"] != ""} {
arm_create_port SRAM_EMA input 2 0
arm_create_port SRAM_EMAW input 1 0
arm_create_port SRAM_EMAS input
edit_netlist uniquify [find_unique_design]
# SRAM memories
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect SRAM_EMA[${i}] *EMA[${i}] *SRAM*
}
for {set i 0} {$i < 2} {incr i} {
arm_netlist_connect SRAM_EMAW[${i}] *EMAW[${i}] *SRAM*
}
arm_netlist_connect SRAM_EMAS *EMAS *SRAM*
# Create read assist mask port only if the port exists in the RAM.
if {[get_pins -of_objects [get_cell * -hier -filter "ref_name =~ *SRAM*"] -filter " full_name=~*RAWL* " ] != ""} {
arm_create_port SRAM_RAWLM input 1 0
arm_create_port SRAM_RAWL input
edit_netlist uniquify [find_unique_design]
for {set i 0} {$i < 2} {incr i} {
arm_netlist_connect SRAM_RAWLM[${i}] *RAWLM[${i}] *SRAM*
}
arm_netlist_connect SRAM_RAWL *RAWL *SRAM*
}
# Create write assist mask port only if the port exists in the RAM.
if {[get_pins -of_objects [get_cell * -hier -filter "ref_name =~ *SRAM*"] -filter " full_name=~*WABL* " ] != ""} {
arm_create_port SRAM_WABLM input 2 0
arm_create_port SRAM_WABL input
edit_netlist uniquify [find_unique_design]
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect SRAM_WABLM[${i}] *WABLM[${i}] *SRAM*
}
arm_netlist_connect SRAM_WABL *WABL *SRAM*
}
}
}
#END_FLEX_INSERT_ANCHOR: Add top level ports
# do not init dft if comb-only block
if { [llength [get_db insts -if .is_sequential]] } {
# Always map the flops to scannable flops, even if insert_dft = false
set_db current_design .dft_scan_map_mode force_all
#Jalves - create DFT hinst for compressor
create_module -name DFT
create_hinst -name u_dft -module [get_db modules *DFT] -parent [get_db designs .name]
set_db [get_db hinsts u_dft] .preserve true
# DFT setup
source ../scripts/cdns_dft/setup_for_dft.tcl
source ../scripts/cdns_dft/dft_flow_and_execution_set_variables.tcl
source ../scripts/cdns_dft/create_dft_ports.tcl
set_db root: .ui_respects_preserve false
#reading ctl abstract model for resync FF
if {[info exists tech_vars(resynchro_flop_ctl_view)]} {
foreach model $tech_vars(resynchro_flop_ctl_view) {
set model_name [file rootname [file tail ${model}]]
set uniquify 0
get_db insts -if ".is_sequential && !.is_macro && .base_cell.name == ${model_name}" -foreach {
puts "ARM_INFO: instance: $obj(.name)"
puts "ARM_INFO: ctlFile : ${model}"
puts "ARM_INFO: reading dft abstract model for instance $obj(.name)"
read_dft_abstract_model -ctl -segment_prefix "[file tail $obj(.name)]_${uniquify}_" -instance $obj(.name) ${model}
incr uniquify
}
}
}
source ../scripts/cdns_dft/run_me_setup_for_DFT.tcl
set_db root: .ui_respects_preserve true
redirect $report_dir/dft_check_setup.rpt {check_dft_rules}
# REVISIT: echarra
# REVISIT: why does the cdn script dedicated code not do the job?
# REVISIT: Message is printed
# REVISIT: DFT_INFO: ... Connecting 'DFTRAMBYP' for instance 'inst: ...
# REVISIT: but connection is not actually done if we do not add code below.
# Workaround: Force reconnection of DFTRAMBYP in case not connected
foreach instance [get_db insts * -if {.is_memory}] {
if { [llength [get_db pins [get_db ${instance} .name]/DFTRAMBYP] ] > 0} {
puts "ARM_INFO: ... Connecting DFTRAMBYP for instance [get_db $instance .name]"
disconnect [get_db ${instance} .pins */DFTRAMBYP]
connect [get_port DFTRAMBYP] [get_pins [get_db ${instance} .name]/DFTRAMBYP] -prefix DFTRAMBYP
}
}
}
#- initialize library and design information
init_design
if {[file exists ../scripts/genus/memory_daisychain.tcl]} {
source -verbose ../scripts/genus/memory_daisychain.tcl
}
puts "ARM_INFO: sdc_failed commands $::dc::sdc_failed_commands"
check_dft_rules > $report_dir/dft_check_setup.rpt
foreach testpin {nISOLATE_PDCOMPLEX nISOLATE_PDCORE0 nISOLATE_PDCORE1 nISOLATE_PDVPU} {
define_test_mode -active high -scan_shift $testpin
}
#- Load floorplan DEF file
puts "ARM_INFO: Load floorplan /arm/projectscratch/pd/arcadia_pj33000026/impl/users/fraric01/2024-02-22_103/arcadia/implementation/arcadia_complex.def.gz "
set_db find_fuzzy_match true
# read_def $flow_vars(floorplan_def) -add_power_switch -keep_welltap_cells -keep_filler_cells
# read_def /dpc/tsmc_project41/mdatta/Arm_Hayes_N5/EC87704/users/jalves/arcadia/downloads/240317/flow3/data/syn_map/arcadia_complex.def.gz -add_power_switch -keep_welltap_cells -keep_filler_cells
# read_def /dpc/tsmc_project41/mdatta/Arm_Hayes_N5/EC87704/users/jalves/arcadia/downloads/arcadia_complex.def.gz -add_power_switch -keep_welltap_cells -keep_filler_cells
read_def /dpc/tsmc_project41/mdatta/Arm_Hayes_N5/EC87704/users/jalves/arcadia/downloads/240319/arcadia_complex_tag_fix.def.gz -add_power_switch -keep_welltap_cells -keep_filler_cells
set_db find_fuzzy_match false
# Check the PSO networks are well connected or not after read_def
set PSO_ports [concat [get_object_name [get_db ports nPWRUP_*]] [get_object_name [get_db ports nPWRUPHAMMER_*]] [get_object_name [get_db ports nPWRUPACK_*]] [get_object_name [get_db ports nPWRUPHAMMERACK_*]]]
set pso_check_errors 0
foreach port $PSO_ports {
if {[llength [get_db ports $port -if {.direction == in}]] == 1 && ([get_db [get_db ports $port] .net.num_loads] == 0 || [get_db [get_db ports $port] .net.num_loads] == "")} {
puts "ARM_ERROR: [get_object_name $port] without any PSW connection, please check the input DEF file"
incr pso_check_errors
} elseif {[llength [get_db ports $port -if {.direction == out}]] == 1 && ([get_db [get_db ports $port] .net.num_drivers] == 0 || [get_db [get_db ports $port] .net.num_drivers] == "")} {
puts "ARM_ERROR: [get_object_name $port] without any PSW connection, please check the input DEF file"
incr pso_check_errors
} else {
puts "ARM_INFO: [get_object_name $port] is well connected"
}
}
if {$pso_check_errors} {
puts "ARM_ERROR: At least $pso_check_errors error(s) detected in the PSO connection check"
write_db -to_file ../data/dbs/syn_elab.db
exit 1
}
#ARM_INTERNAL Checks to make sure RTL is ok for synthesis
check_timing_intent -verbose > $report_dir/timing_lint_elab.rpt
check_design -multiple_driver -undriven -unresolved > $report_dir/check_design_elab.rpt
# DFT not present if comb-only block
if { [llength [get_db insts -if .is_sequential]] } {
#Check the output of the check_dft_rules
set dft_report [open $report_dir/dft_check_setup.rpt r]
while { [gets $dft_report line] >= 0} {
if {[regexp {that fail DFT rules:\s+(\d+)} $line -> num_failures]} {
if {$num_failures > 0} {
puts "ARM_ERROR: DFT rules failed with $num_failures failing elements, please see $report_dir/dft_check_setup.rpt"
incr detected_errors
}
} elseif {[regexp {registers that are scannable:\s+([\d\.]+)} $line -> percentage_scannable]} {
if {$percentage_scannable < 100} {
puts "ARM_ERROR: DFT rules failed with <100% scannable elements, please see $report_dir/dft_check_setup.rpt"
incr detected_errors
}
}
}
close $dft_report
}
#Check for Cadence loop breaker instances in the netlist
# *cdn_loop_breaker* cells are only added after a timing analysis has been done
# Therefore you can only perform this below check after an init_design and a call to
# either report_timing or check_timing_intent has been done
if {[llength [get_db insts .name *cdn_loop_breaker*]] > 0} {
puts "ARM_ERROR: Combinational loops detected in the design, search the log for ELABUTL-133 for more details"
write_hdl > ../data/elab.v
report_loop
incr detected_errors
}
if {[check_design -multiple_driver -status]} {
puts "ARM_ERROR: Signals with multiple drivers are detected, review the list in $report_dir/check_design_elab.rpt"
incr detected_errors
}
# Check sdc_vars(list_of_useful_skew) hierarchies are valid and otherwise error out
puts "ARM_INFO: sdc_vars(list_of_useful_skew) is used, running a check to see if hierarchy exists"
foreach user_selected_group_for_useful_skew $sdc_vars(list_of_useful_skew) {
set hierarchy_name [lindex $user_selected_group_for_useful_skew 1]
if {[get_db pins ${hierarchy_name}] != ""} {
puts "ARM_INFO: User selected hierarchy for useful skew: ${hierarchy_name} exists"
} else {
puts "ARM_ERROR: User selected hierarchy for useful skew: ${hierarchy_name} does not exist"
incr detected_errors
}
}
#Stop here if errors have been detected in the elaboration and setup of the design
if {$detected_errors} {
puts "ARM_ERROR: At least $detected_errors error(s) detected in the elaboration and setup of the design"
write_db ../data/dbs/syn_elab.db
exit 1
}
#ARM_INTERNAL end of checks for RTL
#If we are doing elaboration only (for RTL health check) then stop here
if {[info exists elab_only]} {
write_sdc -view [lindex [get_db analysis_views -if {.is_setup}] 0] > ../data/dbs/syn_elab.sdc
write_db ../data/dbs/syn_elab.db
exit
}
#- add cells and commit power rules
# REVISIT(kenlin01, EAC, Need to enable extra attribute for level shifter inserion since Genus 19.14, PJ02607-7721)
# Allow Genus to insert low power cells on power switch networks
set_db cpi_insert_on_switch_network true
puts "ARM_INFO: Commit power intent"
commit_power_intent
# List of preserve register
foreach flop $design_vars(preserve_register_list) {
set_db [get_db insts $flop -if {.is_sequential}] .preserve map_size_ok
}
## load tool configs which require design information
#START_FLEX_INSERT_ANCHOR: genus post db load config
################################################################################
# ATTRIBUTES APPLIED AFTER LOADING A LIBRARY OR DATABASE
################################################################################
# General attributes
#-------------------------------------------------------------------------------
set_db number_of_routing_layers [get_db [get_db layers -if .name==$tech_vars(max_route_layer)] .route_index]
# Low-power attributes [get_db -category lp_cg]
#-------------------------------------------------------------------------------
set_db current_design .lp_clock_gating_min_flops $design_vars(lp_clock_gating_min_flops)
set_db current_design .lp_clock_gating_max_flops 64
set_db current_design .lp_clock_gating_auto_path_adjust fixed
set_db lp_clock_gating_infer_enable false
# Reporting attributes
#-------------------------------------------------------------------------------
set_db timing_report_time_unit ns
set_db timing_report_load_unit pf
set_db timing_report_fields { timing_point cell fanout load transition delay arrival user_derate total_derate }
#END_FLEX_INSERT_ANCHOR: genus post db load config
}
# -----------------------------------------------------------------------------
# Update the clock max uncertainty for this step
# -----------------------------------------------------------------------------
#START_FLEX_INSERT_ANCHOR: Uncertainty update
foreach constraint_mode [get_db [get_db analysis_views -if {.is_setup}] .constraint_mode.name] {
if {[info exists sdc_vars($constraint_mode,overconstraint)] && ([lsearch -exact -index 0 $sdc_vars($constraint_mode,overconstraint) $step_name] >= 0)} {
set step_overconstraint_list_index [lsearch -exact -index 0 $sdc_vars($constraint_mode,overconstraint) $step_name]
set overconstraint_value_list [lrange [lindex $sdc_vars($constraint_mode,overconstraint) $step_overconstraint_list_index] 1 end]
set_interactive_constraint_mode $constraint_mode
puts "ARM_INFO: update clock max uncertainty for $constraint_mode"
for {set index 0} {$index < [llength $sdc_vars(real_clocks)]} {incr index} {
set clock [lindex $sdc_vars(real_clocks) $index]
regsub {__.*} $constraint_mode {} pvt
set clock_period [format "%.3f" [expr 1 / [lindex $sdc_vars($constraint_mode,frequency_target) $index]]]
set setup_margin [expr $tech_vars($pvt,clock_margin_offset)+min($tech_vars(clock_margin_ratio)*$clock_period, $tech_vars(max_setup_margin))]
if {[llength $overconstraint_value_list] > 1} {
if {[llength $overconstraint_value_list] != [llength $sdc_vars(real_clocks)]} {
puts "ARM_ERROR: There is more than 1 value defined in the overconstraint list, but the length of the list does not match the number of clocks defined in sdc_vars(real_clocks)"
exit 1
} else {
set overconstraint [lindex $overconstraint_value_list $index]
}
} else {
set overconstraint $overconstraint_value_list
}
set clock_max_uncertainty [format "%.3f" [expr $setup_margin + $overconstraint]]
set duty_cycle_uncertainty [format "%.3f" [expr ($clock_period * $tech_vars(clock_duty_cycle_variation))]]
if {[get_clocks -quiet ${clock}] != ""} {
puts "ARM_INFO: CLOCKS: Updating the uncertainty for the following clock:"
puts "ARM_INFO: CLOCKS: Clock Name: $clock"
puts "ARM_INFO: CLOCKS: Max Uncertainty: ${clock_max_uncertainty}ns"
puts "ARM_INFO: CLOCKS: Duty Cycle Variation: ${duty_cycle_uncertainty}ns"
set_clock_uncertainty ${clock_max_uncertainty} -setup [get_clocks ${clock} ]
set_clock_uncertainty ${duty_cycle_uncertainty} -rise_from [get_clocks ${clock} ] -fall_to [get_clocks ${clock} ]
set_clock_uncertainty ${duty_cycle_uncertainty} -fall_from [get_clocks ${clock} ] -rise_to [get_clocks ${clock} ]
}
}
} else {
puts "ARM_INFO: No max uncertainty overconstraint defined for $constraint_mode in the $step_name step"
}
}
#END_FLEX_INSERT_ANCHOR: Uncertainty update
# -----------------------------------------------------------------------------
# Coarse clock skewing for endpoints defined in sdc_vars(list_of_useful_skew)
# -----------------------------------------------------------------------------
#START_FLEX_INSERT_ANCHOR: Endpoint skewing
foreach constraint_mode [get_db [get_db analysis_views -if {.is_setup}] .constraint_mode.name] {
puts "ARM_INFO: Useful skew set up for $constraint_mode"
set_interactive_constraint_mode $constraint_mode
if {![info exists sdc_vars(list_of_useful_skew)]} {
puts "ARM_ERROR: sdc_vars(list_of_useful_skew) is not defined"
exit 0
}
foreach el $sdc_vars(list_of_useful_skew) {
# Extract reference clock
set pin_found 0
set pins [get_db pins [lindex $el 1] -if {.is_clock}]
if { [llength $pins] } {
foreach pin $pins {
set target_clock [lindex [get_db $pin .clocks.base_name] 0]
set clk_match 0
for {set index 0} {$index < [llength $sdc_vars(real_clocks)]} {incr index} {
set clock [lindex $sdc_vars(real_clocks) $index]
# Escape square brackets for clocks with buses
set clk_pattern [string map {\[ \\[ \] \\]} $clock]
if { [string match $clk_pattern $target_clock] } {
incr clk_match
set pre_cts_clock_latency [lindex $sdc_vars($constraint_mode,network_latency) $index]
set pre_cts_clock_frequency [lindex $sdc_vars($constraint_mode,frequency_target) $index]
}
}
if { $clk_match <= 0 } {
puts "ARM_WARNING: $target_clock doesn't match any clock in sdc_vars(real_clocks)."
} elseif { $clk_match > 1 } {
puts "ARM_WARNING: $target_clock match more than one clock in sdc_vars(real_clocks), last defined one will be used to set preskew."
}
set clock_period [expr 1/$pre_cts_clock_frequency]
foreach p $pin {
set pin_latency($p) [expr ${pre_cts_clock_latency} + ([lindex $el 0] * $clock_period)]
}
}
} else {
puts "ARM_WARNING: No pin matching pattern [lindex $el 1] has been found"
}
}
set preskew_sdc [ open "./preskew.sdc" w ]
foreach pin [array names pin_latency] {
set cmd "set_clock_latency $pin_latency($pin) \[get_pin [get_db $pin .name]\]"
puts "ARM_INFO: $cmd"
puts $preskew_sdc $cmd
eval $cmd
}
close $preskew_sdc
}
#END_FLEX_INSERT_ANCHOR: Endpoint skewing
# Loop through all given patterns and set dont_touch according to config
foreach pattern {*HANDINST* *DFT_ANCHOR_BUF*} {
get_db insts $pattern -foreach { set_db $object .dont_touch size_ok }
}
#START_FLEX_INSERT_ANCHOR: Clock Gate Adjusts
set all_cg_list [get_db insts -if {.is_integrated_clock_gating}]
foreach v [get_db [get_db analysis_views -if { .is_setup==true } ] .name] {
if { [info exists design_vars($v,ckg_path_adjust)] } {
foreach pa $design_vars($v,ckg_path_adjust) {
set pattern [lindex $pa 0]
set value [lindex $pa 1]
puts "ARM_INFO: creates list of clock gates using pattern \"$pattern\", and apply ${value}ns path_adjust on them"
set cg_list [get_db $all_cg_list -if {.name==$pattern}]
if {[llength $cg_list]} {
#The value used is converted to ps as genus works in ps
set_path_adjust -view $v -to $cg_list -delay [expr $value * 1000]
} else {
puts "ARM_WARNING: \"$pattern\" does not match any clock gates"
}
}
}
}
#END_FLEX_INSERT_ANCHOR: Clock Gate Adjusts
# manage_dont_use
foreach cell [get_db lib_cells -if { .is_integrated_clock_gating } -unique] {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use false
}
#START_FLEX_INSERT_ANCHOR: Libscore dont use cell setting
#END_FLEX_INSERT_ANCHOR: Libscore dont use cell setting
foreach cell $tech_vars(dont_use_list) {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use true
}
foreach cell $tech_vars(tie_cells) {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use false
}
foreach cell $tech_vars(cts_clock_gating_cells) {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use false
}
# create_cost_group genus_set_derating
foreach analysis_view [get_db analysis_views -if {.is_setup}] {
set delay_corner [get_db $analysis_view .delay_corner.name]
set constraint_mode [get_db $analysis_view .constraint_mode.name]
puts "delay_corner $delay_corner"
regsub "__.*" $delay_corner "" corner
puts "corner $corner"
#START_FLEX_INSERT_ANCHOR: cell and net derates
if {[file exist $env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl]} {
puts "ARM_INFO: applying cell and net derating for $delay_corner from file : $env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl"
source $env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl
} else {
puts "ARM_ERROR: couldn't find cell and net derating for $delay_corner from file: ($env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl)"
}
#END_FLEX_INSERT_ANCHOR: cell and net derates
if {[info exists tech_vars($corner,cell_check_late)]} {
puts "Execute set_timing_derate -cell_check -late $tech_vars($corner,cell_check_late)"
set_timing_derate -cell_check -late $tech_vars($corner,cell_check_late) -delay_corner $corner
}
if {[info exist sdc_vars($constraint_mode,ram_derate) ]} {
foreach ram_derate $sdc_vars($constraint_mode,ram_derate) {
set ram_cell_name [lindex $ram_derate 0]
set cell_delay_derate [lindex $ram_derate 1]
set cell_check_derate [lindex $ram_derate 2]
if { [get_cells -hier -filter "ref_name =~ $ram_cell_name" -quiet] != "" } {
puts "ARM_INFO: DERATE: Derating $ram_cell_name by $cell_delay_derate on cell_delay and $cell_check_derate on cell_check"
set_timing_derate $cell_delay_derate -delay_corner $delay_corner -late -cell_delay [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
set_timing_derate $cell_check_derate -delay_corner $delay_corner -late -cell_check [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
set_timing_derate $cell_delay_derate -delay_corner $delay_corner -early -cell_delay [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
set_timing_derate $cell_check_derate -delay_corner $delay_corner -early -cell_check [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
}
}
}
}
# create_cost_group genus_ungrouping
foreach inst $design_vars(ungroup_inst_list) {
set hinst_list [get_db [get_db hinsts $inst] .name]
if { $hinst_list != ""} {
puts "ARM_INFO: $inst forces to be ungrouped"
ungroup -flatten $hinst_list -only_user_hierarchy
} else {
puts "ARM WARNING: $inst to be removed from ungroup list ..."
}
}
foreach inst $design_vars(no_autoungroup_list) {
puts "ARM_INFO: $inst wont be ungrouped"
set_db [get_db hinsts $inst] .ungroup_ok false
}
foreach inst [get_db insts -if { .is_integrated_clock_gating==true && (.name==*_clk_gate*)}] {
puts "ARM_INFO: $inst wont be ungrouped"
if {[regsub {\-.*} [get_db program_version] {}] >= 20.10} {
set_db $inst .parent.ungroup_ok false
} else {
set_db $inst .ungroup_ok false
}
}
#START_FLEX_INSERT_ANCHOR: Additional syn_generic settings
# CDN CCMPR02168913: Resolve potentially redundant AON buffer for on --> off crossing where fanout is in multiple domains
set_db pias_aon_enable_mode_analysis true
set_db pias_aon_check_pg_together 1
#END_FLEX_INSERT_ANCHOR: Additional syn_generic settings
#START_FLEX_INSERT_ANCHOR: Hierarchical flow setup
#END_FLEX_INSERT_ANCHOR: Hierarchical flow setup
## Define cost and path groups to allow genus to optimise each group independently
set inps [all_inputs -no_clocks]
set outs [all_outputs]
set seqs [all_registers]
set regs [filter_collection $seqs "is_integrated_clock_gating_cell == false && is_macro == false" ]
set icgs [filter_collection $seqs "is_integrated_clock_gating_cell == true" ]
set mems [filter_collection $seqs "is_macro == true" ]
set l1_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_l1/.*"]
set l2_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/u_l2/.*"]
set dpu_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_dpu/.*"]
set ifu_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_ifu/.*"]
set tlb_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/u_tlb/.*"]
set etm_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_etm/.*"]
set vpu_shared_insts [filter_collection -regexp $seqs "(hierarchical_name =~ u_vcomplex/.*u_vpu/.*)"]
set vpu_core_insts [filter_collection -regexp $seqs "(hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_vpu_core/.*)"]
## Define cost and path groups to allow genus to optimise each group independently
define_cost_group -name in2out
define_cost_group -name in2reg
define_cost_group -name in2icg
define_cost_group -name reg2reg
define_cost_group -name reg2out
define_cost_group -name clkgate
define_cost_group -name reg2mem
define_cost_group -name mem2reg
define_cost_group -name mem2mem
define_cost_group -name l1
define_cost_group -name l2
define_cost_group -name dpu
define_cost_group -name vpushared
define_cost_group -name vpucore
define_cost_group -name ifu
define_cost_group -name tlb
define_cost_group -name etm
define_cost_group -name l12dpu
define_cost_group -name dpu2l1
define_cost_group -name ifu2dpu
define_cost_group -name dpu2ifu
define_cost_group -name ifu2l1
define_cost_group -name l12ifu
define_cost_group -name l12l2
define_cost_group -name l22l1
define_cost_group -name dpu2vpushared
define_cost_group -name vpushared2dpu
define_cost_group -name dpu2vpucore
define_cost_group -name vpucore2dpu
define_cost_group -name l12vpucore
define_cost_group -name vpucore2l1
define_cost_group -name vpucore2vpushared
define_cost_group -name vpushared2vpucore
foreach view [get_db [get_db analysis_views -if {.is_setup}] .constraint_mode.name] {
path_group -view $view -from $inps -to $outs -group in2out -name in2out
path_group -view $view -from $inps -to $regs -group in2reg -name in2reg
path_group -view $view -from $inps -to $icgs -group in2icg -name in2icg
path_group -view $view -from $regs -to $regs -group reg2reg -name reg2reg
path_group -view $view -from $regs -to $outs -group reg2out -name reg2out
path_group -view $view -from $regs -to $icgs -group clkgate -name clkgate
path_group -view $view -from $regs -to $mems -group reg2mem -name reg2mem
path_group -view $view -from $mems -to $regs -group mem2reg -name mem2reg
path_group -view $view -from $mems -to $mems -group mem2mem -name mem2mem
path_group -view $view -from $seqs -to $l1_insts -group l1 -name l1
path_group -view $view -from $seqs -to $l2_insts -group l2 -name l2
path_group -view $view -from $seqs -to $dpu_insts -group dpu -name dpu
path_group -view $view -from $seqs -to $ifu_insts -group ifu -name ifu
path_group -view $view -from $seqs -to $tlb_insts -group tlb -name tlb
path_group -view $view -from $seqs -to $etm_insts -group etm -name etm
path_group -view $view -from $seqs -to $vpu_shared_insts -group vpushared -name vpushared
path_group -view $view -from $seqs -to $vpu_core_insts -group vpucore -name vpucore
path_group -view $view -from $l1_insts -to $dpu_insts -group l12dpu -name l12dpu
path_group -view $view -from $dpu_insts -to $l1_insts -group dpu2l1 -name dpu2l1
path_group -view $view -from $ifu_insts -to $dpu_insts -group ifu2dpu -name ifu2dpu
path_group -view $view -from $dpu_insts -to $ifu_insts -group dpu2ifu -name dpu2ifu
path_group -view $view -from $ifu_insts -to $l1_insts -group ifu2l1 -name ifu2l1
path_group -view $view -from $l1_insts -to $ifu_insts -group l12ifu -name l12ifu
path_group -view $view -from $l1_insts -to $l2_insts -group l12l2 -name l12l2
path_group -view $view -from $l2_insts -to $l1_insts -group l22l1 -name l22l1
path_group -view $view -from $vpu_shared_insts -to $dpu_insts -group vpushared2dpu -name vpushared2dpu
path_group -view $view -from $dpu_insts -to $vpu_core_insts -group dpu2vpucore -name dpu2vpucore
path_group -view $view -from $vpu_core_insts -to $dpu_insts -group vpucore2dpu -name vpucore2dpu
path_group -view $view -from $l1_insts -to $vpu_core_insts -group l12vpucore -name l12vpucore
path_group -view $view -from $vpu_core_insts -to $l1_insts -group vpucore2l1 -name vpucore2l1
path_group -view $view -from $dpu_insts -to $vpu_shared_insts -group dpu2vpushared -name dpu2vpushared
path_group -view $view -from $vpu_core_insts -to $vpu_shared_insts -group vpucore2vpushared -name vpucore2vpushared
path_group -view $view -from $vpu_shared_insts -to $vpu_core_insts -group vpushared2vpucore -name vpushared2vpucore
}
# Dump out all the database attributes into a report
# Do this just before the main optimisation super command to understand what is affecting the QoR
redirect $report_dir/tool_settings.rpt "get_db *"
# -----------------------------------------------------------------------------
# Run the generic synthesis
# -----------------------------------------------------------------------------
# Using a physical syn_gen on the given floorplan def in the build
puts "ARM_INFO: A floorplan def file exists in this build, using this def file to run `syn_generic -physical`"
syn_generic
write_reports -directory ../reports/ -tag ${step_name}
# -----------------------------------------------------------------------------
# Write out the design information and exit
# -----------------------------------------------------------------------------
puts "ARM_INFO: write Netlist"
set basename [file join ../data ${step_name} [get_db current_design .name]]
write_hdl > ${basename}.v.gz
write_hdl -pg > ${basename}_pg.v.gz
write_hdl -lec > ${basename}_lec.v.gz
if {[info exist no_intermediate_db ] && $no_intermediate_db == "true"} {
puts "ARM_INFO: No intermediate DB will be written out, set $no_intermediate_db to false if DB are required"
} else {
write_db ../data/dbs/${step_name}.db
}
## MJ 04/12/23 For metrics collection
pop_snapshot_stack
create_snapshot -name ${step_name}
if {![info exist all_steps ]} {
time_info syn_generic
exit
}
#----------------------------------------------------------------------------
# The confidential and proprietary information contained in this file may
# only be used by a person authorised under and to the extent permitted
# by a subsisting licensing agreement from Arm Limited or its affiliates.
#
# (C) COPYRIGHT 2024 Arm Limited or its affiliates.
# ALL RIGHTS RESERVED
#
# This entire notice must be reproduced on all copies of this file
# and copies of this file may only be made by a person if such person is
# permitted to do so under the terms of a subsisting license agreement
# from Arm Limited or its affiliates.
#
# Release Information : $State$
#
#----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Function: Read the RTL, setup DFT and synthesise to generic gates
# -----------------------------------------------------------------------------
set step_name "syn_generic"
puts "ARM_INFO: Step syn_generic"
## MJ Metrics 04/12/23
push_snapshot_stack
# -----------------------------------------------------------------------------
# Source flow setup files and initialise the step
# -----------------------------------------------------------------------------
source $env(CONFIG_PATH)/technology.tcl
source $env(CONFIG_PATH)/design.tcl
source $env(CONFIG_PATH)/setup.tcl
#START_FLEX_INSERT_ANCHOR: genus pre db load config
################################################################################
# Genus attributes (design & library not required)
################################################################################
set_db source_verbose true
set_db flow_verbose false
set_db information_level 9
################################################################################
# ATTRIBUTES APPLIED BEFORE LOADING A LIBRARY OR DATABASE
################################################################################
# General attributes
#-------------------------------------------------------------------------------
set_multi_cpu_usage -local_cpu $env(LSB_MAX_NUM_PROCESSORS)
# Force timing and capacitance unit to be ns and pf
# It avoids discrepancy issue due to libraries having different units
# Need to be set before reading of libraries it also force sdc and reports units
set_db timing_time_unit 1ns
set_db timing_cap_unit 1pf
set_db super_thread_debug_directory "./thread_debug_logs"
set_db wlec_set_cdn_synth_root true
set_db error_on_lib_lef_pin_inconsistency true
set_db write_vlog_empty_module_for_logic_abstract false
set_db gen_module_prefix "arcadia_complex_"
## to enable output of mask statements in tracks etc
set_db def_output_version 5.8
# Design attributes [get_db -category design]
set_db remove_assigns true
#-------------------------------------------------------------------------------
set_db design_process_node 5
# HDL attributes [get_db -category hdl]
#-------------------------------------------------------------------------------
set_db hdl_error_on_blackbox true
set_db hdl_error_on_latch $design_vars(error_on_latch)
set_db hdl_error_on_logic_abstract true
set_db hdl_error_on_negedge true
set_db hdl_array_naming_style %s_%d
set_db hdl_flatten_complex_port true
set_db hdl_generate_index_style %s_%d
set_db hdl_generate_separator _
set_db hdl_record_naming_style %s_%s_
set_db hdl_reg_naming_style %s_reg%s
set_db hdl_resolve_instance_with_libcell true
set_db hdl_use_cw_first true
# Alias the pins name of CDN_flop to be able to put a constraints on an un-mapped flop
set_db hdl_rename_cdn_flop_pins {{clk CK} {d D}}
# Force synthesis to not assume any value on any unconnected pins
set_db hdl_unconnected_value none
# Avoid merging flops: could avoid merging flop being duplicated only by user (timing reason mainly)...
set_db optimize_merge_flops false
#This attribute helps with detecting where combinational loops are
set_db print_ports_nets_preserved_for_cb true
# Optimization attributes [get_db -category netlist]
#-------------------------------------------------------------------------------
set_db syn_generic_effort high
set_db syn_map_effort high
set_db syn_opt_effort high
set_db use_multibit_cells true
set_db use_multibit_combo_cells true
set_db multibit_cells_from_different_busses false
set_db multibit_prefix_string "MBIT_"
set_db use_multibit_iso_cells true
set_db multibit_mapping_effort_level high
set_db force_merge_seqs_into_multibit_cells false
set_db force_merge_combos_into_multibit_cells false
set_db dft_shift_register_with_mbci false
set_db use_multibit_seq_and_tristate_cells true
set_db auto_ungroup none
# Disable register replication
set_db iopt_sequential_duplication false
# Timing attributes [get_db -category tim]
#-------------------------------------------------------------------------------
set_db time_recovery_arcs true
# Datapath attributes [get_db -category dp]
#-------------------------------------------------------------------------------
# Leakage Power attributes [get_db -category lp_opt lib_ui]
#-------------------------------------------------------------------------------
set_db lp_insert_clock_gating true
if { [get_db program_major_version] >= 21.10 } {
set_db design_power_effort high
} else {
set_db leakage_power_effort high
}
# DFT attributes [get_db -category dft]
#-------------------------------------------------------------------------------
set_db dft_wait_for_license true
## Define the Test Clock Waveform Attributes to target ATPG speed of 200MHz
set_db dft_clock_waveform_divide_fall 100
set_db dft_clock_waveform_divide_period 100
set_db dft_clock_waveform_divide_rise 90
set_db dft_clock_waveform_fall 50
set_db dft_clock_waveform_period 5000
set_db dft_clock_waveform_rise 1
set_db dft_include_test_signal_outputs_in_abstract_model false
# ensure scan flop input be only used for scan
## CCR 2463365 Ensure RAM scan segment having SI/SO in different power domains is included in power domain aware scan chain of inst PD
if {[regsub {\-.*} [get_db program_version] {}] >= 21.11} {
set_db dft_use_abstract_segment_instance_power_domain_for_scan_connection true
}
set_db use_scan_seqs_for_non_dft false
if {[regsub {\-.*} [get_db program_version] {}] >= 21.10} {
# pick up instance power domain rather than pin power domain for memory scan connections. CCR 2649133
set_db dft_use_abstract_segment_instance_power_domain_for_scan_connection true
}
# Physical attributes [get_db -category phys]
#-------------------------------------------------------------------------------
# set_db scale_of_cap_per_unit_length 1.15
# set_db scale_of_res_per_unit_length 1.15
# Prevent merging unused bits into MBIT FFs/Combo cells,
# which will cause MBIT cell re-naming issue in INVS Multi-Bit
# optimization flow and CLP:ISO_MISSING_MATCHING_CELL errors
# on optimized input pins of Combo cells
set_db multibit_allow_unused_bits false
#END_FLEX_INSERT_ANCHOR: genus pre db load config
puts "ARM_INFO: Set variables"
# Setup the number of CPUs to use
#START_FLEX_INSERT_ANCHOR: CPU Usage
set_db max_cpus_per_server $env(LSB_DJOB_NUMPROC)
#END_FLEX_INSERT_ANCHOR: CPU Usage
#REVISIT: This should be removed when Genus fully supports the set_data_check command
#Genus currently does not support set_data_check when it is applied between different instances. This variable is used to skip sections of the SDC constraints file
set ARM_SKIP_SET_DATA_CHECKS true
#REVISIT: This should be removed when Genus fully supports the set_max_delay command (expected 19.12)
#Genus currently does not support set_max_delay -ignore_clock_latency. This variable is used to skip sections of the SDC constraints file
set ARM_SKIP_SET_MAX_DELAY_IGNORE_CLOCK_LATENCY true
# Create the report dir
set report_dir [file normalize [file join ../reports $step_name]]
file mkdir $report_dir
#START_FLEX_INSERT_ANCHOR: Log Message Handling
# -----------------------------------------------------------------------------
# Log message to upgrade
# -----------------------------------------------------------------------------
foreach el $flow_vars(${step_name}_messages_to_upgrade) {
set message_code [lindex $el 0]
set reason [lindex $el 1]
set new_severity [lindex $el 2]
#Unlike demoting, when choosing to upgrade a message a user shouldn't use "default" because what's the point?
puts "ARM_WARNING: Upgrading message $message_code, Reason: $reason"
puts "ARM_INFO: New severity = $new_severity"
set_db [get_db messages $message_code] .severity $new_severity
if {[llength $el] > 3} {
set max_print [lindex $el 3]
puts "ARM_INFO: Maximum print = $max_print"
set_db [get_db messages $message_code] .max_print $max_print
}
}
# -----------------------------------------------------------------------------
# Log message to downgrade
# -----------------------------------------------------------------------------
foreach el $flow_vars(${step_name}_messages_to_downgrade) {
set message_code [lindex $el 0]
set reason [lindex $el 1]
set new_severity [lindex $el 2]
puts "ARM_WARNING: Downgrading/Hiding message $message_code, Reason: $reason"
if {$new_severity != "default"} {
puts "ARM_INFO: New severity = $new_severity"
set_db [get_db messages $message_code] .severity $new_severity
}
if {[llength $el] > 3} {
set max_print [lindex $el 3]
puts "ARM_INFO: Maximum print = $max_print"
set_db [get_db messages $message_code] .max_print $max_print
}
}
#END_FLEX_INSERT_ANCHOR: Log Message Handling
#- Store non-default root attributes to metrics
set flow_root_config [report_obj -tcl]
foreach key [dict keys $flow_root_config] {
if {[string length [dict get $flow_root_config $key]] > 200} {
dict set flow_root_config $key "\[long value truncated\]"
}
}
set_metric -name flow.root_config -value $flow_root_config
set detected_errors 0
#START_FLEX_INSERT_ANCHOR: genus dp_analytical setting
#END_FLEX_INSERT_ANCHOR: genus dp_analytical setting
# -----------------------------------------------------------------------------
# Initialise the design
# -----------------------------------------------------------------------------
if {[get_db current_design] eq ""} {
#- setup library information
read_mmmc $env(CONFIG_PATH)/mmmc_config.synthesis.tcl
read_physical -lef $tech_vars(synthesis,lef)
#- read and elaborate design
source ../constraints/syn_load_rtl.tcl
set_db init_hdl_search_path $dir_list
if {[info exists elab_only]} {
set_db statistics_automatic_logging false
set_db statistics_log_data false
set_db statistics_metrics false
set_db wireload_mode none
}
set cmd "read_hdl -sv $verilog_filelist"
puts "FLOW: started $cmd"
eval $cmd
#Determine if parameters are needed for elaboration
set params_list ""
if {($design_vars(elab_params) != "") && ($design_vars(elab_params_file) != "")} {
puts "ARM_ERROR: both design_vars(elab_params) & design_vars(elab_params_file) have been defined. Only one can be defined"
exit 1
} elseif {$design_vars(elab_params) != ""} {
puts "ARM_INFO: Elaboration with following parameters: $design_vars(elab_params)"
set params_list $design_vars(elab_params)
} elseif {$design_vars(elab_params_file) != ""} {
source $design_vars(elab_params_file)
if {$design_vars(elab_params_variable) != ""} {
puts "ARM_INFO: Elaboration with following parameters: [set $design_vars(elab_params_variable)]"
set params_list [set $design_vars(elab_params_variable)]
} else {
puts "ARM_ERROR: $design_vars(elab_params_variable) from $design_vars(elab_params_file) was not found"
exit 1
}
}
#Elaborate Design
if {[llength $params_list] > 0} {
elaborate -parameter $params_list arcadia_complex
} else {
puts "ARM_INFO: Elaboration without parameters"
elaborate arcadia_complex
}
# REVISIT: moving the elaborated design to "arcadia_complex" so that it doesn't have all the parameter names on the end
# REVISIT: This is temporary so that it works with existing SDC files etc. as we may want to keep parameters on the design name in the future
rename_obj [find_unique_design] arcadia_complex
#- optionally setup power intent from UPF/CPF/1801
read_power_intent ${env(LOGICAL_ROOT)}/arcadia/logical/arcadia/power_intent/upf/arcadia_complex0.upf
# create_cost_group genus_uniquify
set_db ui_respects_preserve false
uniquify [current_design]
set_db ui_respects_preserve true
#Add any top-level port connections
foreach hookup_list $design_vars(pin_to_port_hookup_list) {
#Sanity check we have the correct number of elements defined
if {([llength $hookup_list] == 5) || ([llength $hookup_list] == 7)} {
set instance_pattern [lindex $hookup_list 0]
set module_pattern [lindex $hookup_list 1]
set pin_pattern [lindex $hookup_list 2]
set top_level_port_name [lindex $hookup_list 3]
set top_level_port_direction [lindex $hookup_list 4]
# Check if the design actually has the pin_pattern, note the pin could be a bus so check for both pin_pattern and pin_pattern[*]
# Store the output from get_db to speed up runtime
set all_matching_pins [get_db pins *${pin_pattern} *${pin_pattern}\[*\] -if {.inst.name==$instance_pattern && .inst.base_cell.name==$module_pattern}]
if {[llength $all_matching_pins] > 0} {
# First determine pairs of pins and ports that must be connected together. If the signal is a single bit connection
# then the list will be made up of {pin port}, if a MSB and LSB of the signal has been defined then the list is
# made up of {pin[lsb] port[lsb] pin[lsb+1] port[lsb+1]...pin[msb] port[msb]}
if {[llength $hookup_list] == 7} {
set msb [lindex $hookup_list 5]
set lsb [lindex $hookup_list 6]
#To be used when creating the top level port
set left_bit "-left_bit $msb"; set right_bit "-right_bit $lsb"
set pin_port_pair_list {}
for {set i $lsb} {$i <= $msb} {incr i} {
lappend pin_port_pair_list ${pin_pattern}\[$i\] $top_level_port_name\[$i\]
}
} else {
set pin_port_pair_list [list $pin_pattern $top_level_port_name]
#To be used when creating the top level port
set left_bit "" ; set right_bit ""
}
# Create the top level port for the connection
# if the pin_port_pair_list has more than 2 elements we know a lsb/msb was defined so we can
# create the port as a bus of (msb+1-lsb) bits otherwise simply create a single bit top-level port
if ![llength [get_port -quiet $top_level_port_name ]] {
eval "create_port_bus -name $top_level_port_name $left_bit $right_bit -$top_level_port_direction"
}
# Finally: All the pins matching the instance_pattern and module_pattern along with the pin from the pin_port_pair_list are
# found and then connected with the port defined in the pair
foreach {pin port} $pin_port_pair_list {
foreach inst_pin [get_db $all_matching_pins *${pin}] {
disconnect $inst_pin
puts "ARM_INFO: Connecting $inst_pin with port $port"
connect [get_ports $port] $inst_pin -prefix [regsub -all -- {[^[:alnum:]_]+} $port {_}]
}
}
} else {
puts "ARM_ERROR: No pins found with:\n Instance pattern=$instance_pattern\n Module pattern=$module_pattern\n Pin pattern=${pin_pattern}"
}
} else {
puts "ARM_ERROR: [llength $hookup_list] elements found in design_vars(pin_to_port_hookup_list) entry. Either 5 or 7 entries expected. Entries = $hookup_list"
exit 1
}
}
#START_FLEX_INSERT_ANCHOR: Add top level ports
# -----------------------------------------------------------------------------
# Function: create power interface
# -----------------------------------------------------------------------------
# REVISIT(ramsri01, BET, add_top_level_ports.tcl script in NFF master needs to be made generic to work with RAM connections in different power domains, NUFLEXFLOW-643)
# This script is currently here as workaround till we clean up add_top_level_ports.tcl to work for both power gated and non power gated design.
# Below version will work for designs like A55 with 2 domains or Hayes with 5 domains
proc arm_create_port {port_name dir {left_bit ""} {right_bit ""} } {
if { $left_bit != "" } {
set left_bit "-left_bit $left_bit"
}
if { $right_bit != ""} {
set right_bit "-right_bit $right_bit"
}
if ![llength [get_port -quiet $port_name ]] {
set cmd "create_port_bus -name $port_name $left_bit $right_bit -$dir"
eval $cmd
puts "ARM_INFO: Port $port_name created"
} else {
puts "ARM_INFO: Port $port_name already exists"
}
}
proc arm_netlist_connect { port pin {object ""}} {
foreach obj_pin [get_db [get_pin -quiet -of_objects [get_cell * -hier -filter "ref_name =~$object"] -filter "full_name=~$pin"]] {
disconnect $obj_pin
puts "ARM_USER_INFO: Connecting $obj_pin with port $port"
connect [get_ports $port] $obj_pin -prefix [regsub -all -- {[^[:alnum:]_]+} $port {_}]
}
}
uniquify [find_unique_design]
if {[llength [get_db insts .pins.name *EMA*]] > 0} {
# Single port register file - RFS and FCI*RFS
if {[get_cell * -hier -filter "ref_name =~ *RFS*"] != ""} {
arm_create_port RF_EMA input 2 0
arm_create_port RF_EMAW input 1 0
arm_create_port RF_EMAS input
uniquify [find_unique_design]
# Single port register file: EMA connections
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect RF_EMA[${i}] *EMA[${i}] *RFS*
}
for {set i 0} {$i < 2} {incr i} {
arm_netlist_connect RF_EMAW[${i}] *EMAW[${i}] *RFS*
}
arm_netlist_connect RF_EMAS *EMAS *RFS*
}
# Dual port register file
if {[get_cell * -hier -filter "ref_name =~ *RF2P*"] != ""} {
arm_create_port RF2P_EMAA input 2 0
arm_create_port RF2P_EMAB input 2 0
arm_create_port RF2P_EMASA input
edit_netlist uniquify [find_unique_design]
# Dual ports register file: EMA connections
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect RF2P_EMAA[${i}] *EMAA[${i}] *RF2P*
}
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect RF2P_EMAB[${i}] *EMAB[${i}] *RF2P*
}
arm_netlist_connect RF2P_EMASA *EMASA *RF2P*
}
# Single port SRAM memory
if {[get_cell * -hier -filter "ref_name =~ *SRAM*"] != ""} {
arm_create_port SRAM_EMA input 2 0
arm_create_port SRAM_EMAW input 1 0
arm_create_port SRAM_EMAS input
edit_netlist uniquify [find_unique_design]
# SRAM memories
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect SRAM_EMA[${i}] *EMA[${i}] *SRAM*
}
for {set i 0} {$i < 2} {incr i} {
arm_netlist_connect SRAM_EMAW[${i}] *EMAW[${i}] *SRAM*
}
arm_netlist_connect SRAM_EMAS *EMAS *SRAM*
# Create read assist mask port only if the port exists in the RAM.
if {[get_pins -of_objects [get_cell * -hier -filter "ref_name =~ *SRAM*"] -filter " full_name=~*RAWL* " ] != ""} {
arm_create_port SRAM_RAWLM input 1 0
arm_create_port SRAM_RAWL input
edit_netlist uniquify [find_unique_design]
for {set i 0} {$i < 2} {incr i} {
arm_netlist_connect SRAM_RAWLM[${i}] *RAWLM[${i}] *SRAM*
}
arm_netlist_connect SRAM_RAWL *RAWL *SRAM*
}
# Create write assist mask port only if the port exists in the RAM.
if {[get_pins -of_objects [get_cell * -hier -filter "ref_name =~ *SRAM*"] -filter " full_name=~*WABL* " ] != ""} {
arm_create_port SRAM_WABLM input 2 0
arm_create_port SRAM_WABL input
edit_netlist uniquify [find_unique_design]
for {set i 0} {$i < 3} {incr i} {
arm_netlist_connect SRAM_WABLM[${i}] *WABLM[${i}] *SRAM*
}
arm_netlist_connect SRAM_WABL *WABL *SRAM*
}
}
}
#END_FLEX_INSERT_ANCHOR: Add top level ports
# do not init dft if comb-only block
if { [llength [get_db insts -if .is_sequential]] } {
# Always map the flops to scannable flops, even if insert_dft = false
set_db current_design .dft_scan_map_mode force_all
#Jalves - create DFT hinst for compressor
create_module -name DFT
create_hinst -name u_dft -module [get_db modules *DFT] -parent [get_db designs .name]
set_db [get_db hinsts u_dft] .preserve true
# DFT setup
source ../scripts/cdns_dft/setup_for_dft.tcl
source ../scripts/cdns_dft/dft_flow_and_execution_set_variables.tcl
source ../scripts/cdns_dft/create_dft_ports.tcl
set_db root: .ui_respects_preserve false
#reading ctl abstract model for resync FF
if {[info exists tech_vars(resynchro_flop_ctl_view)]} {
foreach model $tech_vars(resynchro_flop_ctl_view) {
set model_name [file rootname [file tail ${model}]]
set uniquify 0
get_db insts -if ".is_sequential && !.is_macro && .base_cell.name == ${model_name}" -foreach {
puts "ARM_INFO: instance: $obj(.name)"
puts "ARM_INFO: ctlFile : ${model}"
puts "ARM_INFO: reading dft abstract model for instance $obj(.name)"
read_dft_abstract_model -ctl -segment_prefix "[file tail $obj(.name)]_${uniquify}_" -instance $obj(.name) ${model}
incr uniquify
}
}
}
source ../scripts/cdns_dft/run_me_setup_for_DFT.tcl
set_db root: .ui_respects_preserve true
redirect $report_dir/dft_check_setup.rpt {check_dft_rules}
# REVISIT: echarra
# REVISIT: why does the cdn script dedicated code not do the job?
# REVISIT: Message is printed
# REVISIT: DFT_INFO: ... Connecting 'DFTRAMBYP' for instance 'inst: ...
# REVISIT: but connection is not actually done if we do not add code below.
# Workaround: Force reconnection of DFTRAMBYP in case not connected
foreach instance [get_db insts * -if {.is_memory}] {
if { [llength [get_db pins [get_db ${instance} .name]/DFTRAMBYP] ] > 0} {
puts "ARM_INFO: ... Connecting DFTRAMBYP for instance [get_db $instance .name]"
disconnect [get_db ${instance} .pins */DFTRAMBYP]
connect [get_port DFTRAMBYP] [get_pins [get_db ${instance} .name]/DFTRAMBYP] -prefix DFTRAMBYP
}
}
}
#- initialize library and design information
init_design
if {[file exists ../scripts/genus/memory_daisychain.tcl]} {
source -verbose ../scripts/genus/memory_daisychain.tcl
}
puts "ARM_INFO: sdc_failed commands $::dc::sdc_failed_commands"
check_dft_rules > $report_dir/dft_check_setup.rpt
foreach testpin {nISOLATE_PDCOMPLEX nISOLATE_PDCORE0 nISOLATE_PDCORE1 nISOLATE_PDVPU} {
define_test_mode -active high -scan_shift $testpin
}
#- Load floorplan DEF file
puts "ARM_INFO: Load floorplan /arm/projectscratch/pd/arcadia_pj33000026/impl/users/fraric01/2024-02-22_103/arcadia/implementation/arcadia_complex.def.gz "
set_db find_fuzzy_match true
#read_def $flow_vars(floorplan_def) -add_power_switch -keep_welltap_cells -keep_filler_cells
#read_def /dpc/tsmc_project41/mdatta/Arm_Hayes_N5/EC87704/users/jalves/arcadia/downloads/240317/flow3/data/syn_map/arcadia_complex.def.gz -add_power_switch -keep_welltap_cells -keep_filler_cells
#read_def /dpc/tsmc_project41/mdatta/Arm_Hayes_N5/EC87704/users/jalves/arcadia/downloads/arcadia_complex.def.gz -add_power_switch -keep_welltap_cells -keep_filler_cells
read_def /dpc/tsmc_project41/mdatta/Arm_Hayes_N5/EC87704/users/jalves/arcadia/downloads/240319/arcadia_complex_tag_fix.def.gz -add_power_switch -keep_welltap_cells -keep_filler_cells
set_db find_fuzzy_match false
# Check the PSO networks are well connected or not after read_def
set PSO_ports [concat [get_object_name [get_db ports nPWRUP_*]] [get_object_name [get_db ports nPWRUPHAMMER_*]] [get_object_name [get_db ports nPWRUPACK_*]] [get_object_name [get_db ports nPWRUPHAMMERACK_*]]]
set pso_check_errors 0
foreach port $PSO_ports {
if {[llength [get_db ports $port -if {.direction == in}]] == 1 && ([get_db [get_db ports $port] .net.num_loads] == 0 || [get_db [get_db ports $port] .net.num_loads] == "")} {
puts "ARM_ERROR: [get_object_name $port] without any PSW connection, please check the input DEF file"
incr pso_check_errors
} elseif {[llength [get_db ports $port -if {.direction == out}]] == 1 && ([get_db [get_db ports $port] .net.num_drivers] == 0 || [get_db [get_db ports $port] .net.num_drivers] == "")} {
puts "ARM_ERROR: [get_object_name $port] without any PSW connection, please check the input DEF file"
incr pso_check_errors
} else {
puts "ARM_INFO: [get_object_name $port] is well connected"
}
}
if {$pso_check_errors} {
puts "ARM_ERROR: At least $pso_check_errors error(s) detected in the PSO connection check"
write_db -to_file ../data/dbs/syn_elab.db
exit 1
}
#ARM_INTERNAL Checks to make sure RTL is ok for synthesis
check_timing_intent -verbose > $report_dir/timing_lint_elab.rpt
check_design -multiple_driver -undriven -unresolved > $report_dir/check_design_elab.rpt
# DFT not present if comb-only block
if { [llength [get_db insts -if .is_sequential]] } {
#Check the output of the check_dft_rules
set dft_report [open $report_dir/dft_check_setup.rpt r]
while { [gets $dft_report line] >= 0} {
if {[regexp {that fail DFT rules:\s+(\d+)} $line -> num_failures]} {
if {$num_failures > 0} {
puts "ARM_ERROR: DFT rules failed with $num_failures failing elements, please see $report_dir/dft_check_setup.rpt"
incr detected_errors
}
} elseif {[regexp {registers that are scannable:\s+([\d\.]+)} $line -> percentage_scannable]} {
if {$percentage_scannable < 100} {
puts "ARM_ERROR: DFT rules failed with <100% scannable elements, please see $report_dir/dft_check_setup.rpt"
incr detected_errors
}
}
}
close $dft_report
}
#Check for Cadence loop breaker instances in the netlist
# *cdn_loop_breaker* cells are only added after a timing analysis has been done
# Therefore you can only perform this below check after an init_design and a call to
# either report_timing or check_timing_intent has been done
if {[llength [get_db insts .name *cdn_loop_breaker*]] > 0} {
puts "ARM_ERROR: Combinational loops detected in the design, search the log for ELABUTL-133 for more details"
write_hdl > ../data/elab.v
report_loop
incr detected_errors
}
if {[check_design -multiple_driver -status]} {
puts "ARM_ERROR: Signals with multiple drivers are detected, review the list in $report_dir/check_design_elab.rpt"
incr detected_errors
}
# Check sdc_vars(list_of_useful_skew) hierarchies are valid and otherwise error out
puts "ARM_INFO: sdc_vars(list_of_useful_skew) is used, running a check to see if hierarchy exists"
foreach user_selected_group_for_useful_skew $sdc_vars(list_of_useful_skew) {
set hierarchy_name [lindex $user_selected_group_for_useful_skew 1]
if {[get_db pins ${hierarchy_name}] != ""} {
puts "ARM_INFO: User selected hierarchy for useful skew: ${hierarchy_name} exists"
} else {
puts "ARM_ERROR: User selected hierarchy for useful skew: ${hierarchy_name} does not exist"
incr detected_errors
}
}
#Stop here if errors have been detected in the elaboration and setup of the design
if {$detected_errors} {
puts "ARM_ERROR: At least $detected_errors error(s) detected in the elaboration and setup of the design"
write_db ../data/dbs/syn_elab.db
exit 1
}
#ARM_INTERNAL end of checks for RTL
#If we are doing elaboration only (for RTL health check) then stop here
if {[info exists elab_only]} {
write_sdc -view [lindex [get_db analysis_views -if {.is_setup}] 0] > ../data/dbs/syn_elab.sdc
write_db ../data/dbs/syn_elab.db
exit
}
#- add cells and commit power rules
# REVISIT(kenlin01, EAC, Need to enable extra attribute for level shifter inserion since Genus 19.14, PJ02607-7721)
# Allow Genus to insert low power cells on power switch networks
set_db cpi_insert_on_switch_network true
puts "ARM_INFO: Commit power intent"
commit_power_intent
# List of preserve register
foreach flop $design_vars(preserve_register_list) {
set_db [get_db insts $flop -if {.is_sequential}] .preserve map_size_ok
}
## load tool configs which require design information
#START_FLEX_INSERT_ANCHOR: genus post db load config
################################################################################
# ATTRIBUTES APPLIED AFTER LOADING A LIBRARY OR DATABASE
################################################################################
# General attributes
#-------------------------------------------------------------------------------
set_db number_of_routing_layers [get_db [get_db layers -if .name==$tech_vars(max_route_layer)] .route_index]
# Low-power attributes [get_db -category lp_cg]
#-------------------------------------------------------------------------------
set_db current_design .lp_clock_gating_min_flops $design_vars(lp_clock_gating_min_flops)
set_db current_design .lp_clock_gating_max_flops 64
set_db current_design .lp_clock_gating_auto_path_adjust fixed
set_db lp_clock_gating_infer_enable false
# Reporting attributes
#-------------------------------------------------------------------------------
set_db timing_report_time_unit ns
set_db timing_report_load_unit pf
set_db timing_report_fields { timing_point cell fanout load transition delay arrival user_derate total_derate }
#END_FLEX_INSERT_ANCHOR: genus post db load config
}
# -----------------------------------------------------------------------------
# Update the clock max uncertainty for this step
# -----------------------------------------------------------------------------
#START_FLEX_INSERT_ANCHOR: Uncertainty update
foreach constraint_mode [get_db [get_db analysis_views -if {.is_setup}] .constraint_mode.name] {
if {[info exists sdc_vars($constraint_mode,overconstraint)] && ([lsearch -exact -index 0 $sdc_vars($constraint_mode,overconstraint) $step_name] >= 0)} {
set step_overconstraint_list_index [lsearch -exact -index 0 $sdc_vars($constraint_mode,overconstraint) $step_name]
set overconstraint_value_list [lrange [lindex $sdc_vars($constraint_mode,overconstraint) $step_overconstraint_list_index] 1 end]
set_interactive_constraint_mode $constraint_mode
puts "ARM_INFO: update clock max uncertainty for $constraint_mode"
for {set index 0} {$index < [llength $sdc_vars(real_clocks)]} {incr index} {
set clock [lindex $sdc_vars(real_clocks) $index]
regsub {__.*} $constraint_mode {} pvt
set clock_period [format "%.3f" [expr 1 / [lindex $sdc_vars($constraint_mode,frequency_target) $index]]]
set setup_margin [expr $tech_vars($pvt,clock_margin_offset)+min($tech_vars(clock_margin_ratio)*$clock_period, $tech_vars(max_setup_margin))]
if {[llength $overconstraint_value_list] > 1} {
if {[llength $overconstraint_value_list] != [llength $sdc_vars(real_clocks)]} {
puts "ARM_ERROR: There is more than 1 value defined in the overconstraint list, but the length of the list does not match the number of clocks defined in sdc_vars(real_clocks)"
exit 1
} else {
set overconstraint [lindex $overconstraint_value_list $index]
}
} else {
set overconstraint $overconstraint_value_list
}
set clock_max_uncertainty [format "%.3f" [expr $setup_margin + $overconstraint]]
set duty_cycle_uncertainty [format "%.3f" [expr ($clock_period * $tech_vars(clock_duty_cycle_variation))]]
if {[get_clocks -quiet ${clock}] != ""} {
puts "ARM_INFO: CLOCKS: Updating the uncertainty for the following clock:"
puts "ARM_INFO: CLOCKS: Clock Name: $clock"
puts "ARM_INFO: CLOCKS: Max Uncertainty: ${clock_max_uncertainty}ns"
puts "ARM_INFO: CLOCKS: Duty Cycle Variation: ${duty_cycle_uncertainty}ns"
set_clock_uncertainty ${clock_max_uncertainty} -setup [get_clocks ${clock} ]
set_clock_uncertainty ${duty_cycle_uncertainty} -rise_from [get_clocks ${clock} ] -fall_to [get_clocks ${clock} ]
set_clock_uncertainty ${duty_cycle_uncertainty} -fall_from [get_clocks ${clock} ] -rise_to [get_clocks ${clock} ]
}
}
} else {
puts "ARM_INFO: No max uncertainty overconstraint defined for $constraint_mode in the $step_name step"
}
}
#END_FLEX_INSERT_ANCHOR: Uncertainty update
# -----------------------------------------------------------------------------
# Coarse clock skewing for endpoints defined in sdc_vars(list_of_useful_skew)
# -----------------------------------------------------------------------------
#START_FLEX_INSERT_ANCHOR: Endpoint skewing
foreach constraint_mode [get_db [get_db analysis_views -if {.is_setup}] .constraint_mode.name] {
puts "ARM_INFO: Useful skew set up for $constraint_mode"
set_interactive_constraint_mode $constraint_mode
if {![info exists sdc_vars(list_of_useful_skew)]} {
puts "ARM_ERROR: sdc_vars(list_of_useful_skew) is not defined"
exit 0
}
foreach el $sdc_vars(list_of_useful_skew) {
# Extract reference clock
set pin_found 0
set pins [get_db pins [lindex $el 1] -if {.is_clock}]
if { [llength $pins] } {
foreach pin $pins {
set target_clock [lindex [get_db $pin .clocks.base_name] 0]
set clk_match 0
for {set index 0} {$index < [llength $sdc_vars(real_clocks)]} {incr index} {
set clock [lindex $sdc_vars(real_clocks) $index]
# Escape square brackets for clocks with buses
set clk_pattern [string map {\[ \\[ \] \\]} $clock]
if { [string match $clk_pattern $target_clock] } {
incr clk_match
set pre_cts_clock_latency [lindex $sdc_vars($constraint_mode,network_latency) $index]
set pre_cts_clock_frequency [lindex $sdc_vars($constraint_mode,frequency_target) $index]
}
}
if { $clk_match <= 0 } {
puts "ARM_WARNING: $target_clock doesn't match any clock in sdc_vars(real_clocks)."
} elseif { $clk_match > 1 } {
puts "ARM_WARNING: $target_clock match more than one clock in sdc_vars(real_clocks), last defined one will be used to set preskew."
}
set clock_period [expr 1/$pre_cts_clock_frequency]
foreach p $pin {
set pin_latency($p) [expr ${pre_cts_clock_latency} + ([lindex $el 0] * $clock_period)]
}
}
} else {
puts "ARM_WARNING: No pin matching pattern [lindex $el 1] has been found"
}
}
set preskew_sdc [ open "./preskew.sdc" w ]
foreach pin [array names pin_latency] {
set cmd "set_clock_latency $pin_latency($pin) \[get_pin [get_db $pin .name]\]"
puts "ARM_INFO: $cmd"
puts $preskew_sdc $cmd
eval $cmd
}
close $preskew_sdc
}
#END_FLEX_INSERT_ANCHOR: Endpoint skewing
# Loop through all given patterns and set dont_touch according to config
foreach pattern {*HANDINST* *DFT_ANCHOR_BUF*} {
get_db insts $pattern -foreach { set_db $object .dont_touch size_ok }
}
#START_FLEX_INSERT_ANCHOR: Clock Gate Adjusts
set all_cg_list [get_db insts -if {.is_integrated_clock_gating}]
foreach v [get_db [get_db analysis_views -if { .is_setup==true } ] .name] {
if { [info exists design_vars($v,ckg_path_adjust)] } {
foreach pa $design_vars($v,ckg_path_adjust) {
set pattern [lindex $pa 0]
set value [lindex $pa 1]
puts "ARM_INFO: creates list of clock gates using pattern \"$pattern\", and apply ${value}ns path_adjust on them"
set cg_list [get_db $all_cg_list -if {.name==$pattern}]
if {[llength $cg_list]} {
#The value used is converted to ps as genus works in ps
set_path_adjust -view $v -to $cg_list -delay [expr $value * 1000]
} else {
puts "ARM_WARNING: \"$pattern\" does not match any clock gates"
}
}
}
}
#END_FLEX_INSERT_ANCHOR: Clock Gate Adjusts
# manage_dont_use
foreach cell [get_db lib_cells -if { .is_integrated_clock_gating } -unique] {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use false
}
#START_FLEX_INSERT_ANCHOR: Libscore dont use cell setting
#END_FLEX_INSERT_ANCHOR: Libscore dont use cell setting
foreach cell $tech_vars(dont_use_list) {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use true
}
foreach cell $tech_vars(tie_cells) {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use false
}
foreach cell $tech_vars(cts_clock_gating_cells) {
set_db [get_db [get_lib_cells $cell] .base_cell] .dont_use false
}
# create_cost_group genus_set_derating
foreach analysis_view [get_db analysis_views -if {.is_setup}] {
set delay_corner [get_db $analysis_view .delay_corner.name]
set constraint_mode [get_db $analysis_view .constraint_mode.name]
puts "delay_corner $delay_corner"
regsub "__.*" $delay_corner "" corner
puts "corner $corner"
#START_FLEX_INSERT_ANCHOR: cell and net derates
if {[file exist $env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl]} {
puts "ARM_INFO: applying cell and net derating for $delay_corner from file : $env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl"
source $env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl
} else {
puts "ARM_ERROR: couldn't find cell and net derating for $delay_corner from file: ($env(CONFIG_PATH)/cln05fb41001.signoff.$delay_corner.cell.net.derates.tcl)"
}
#END_FLEX_INSERT_ANCHOR: cell and net derates
if {[info exists tech_vars($corner,cell_check_late)]} {
puts "Execute set_timing_derate -cell_check -late $tech_vars($corner,cell_check_late)"
set_timing_derate -cell_check -late $tech_vars($corner,cell_check_late) -delay_corner $corner
}
if {[info exist sdc_vars($constraint_mode,ram_derate) ]} {
foreach ram_derate $sdc_vars($constraint_mode,ram_derate) {
set ram_cell_name [lindex $ram_derate 0]
set cell_delay_derate [lindex $ram_derate 1]
set cell_check_derate [lindex $ram_derate 2]
if { [get_cells -hier -filter "ref_name =~ $ram_cell_name" -quiet] != "" } {
puts "ARM_INFO: DERATE: Derating $ram_cell_name by $cell_delay_derate on cell_delay and $cell_check_derate on cell_check"
set_timing_derate $cell_delay_derate -delay_corner $delay_corner -late -cell_delay [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
set_timing_derate $cell_check_derate -delay_corner $delay_corner -late -cell_check [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
set_timing_derate $cell_delay_derate -delay_corner $delay_corner -early -cell_delay [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
set_timing_derate $cell_check_derate -delay_corner $delay_corner -early -cell_check [get_cells -hierarchical -filter "ref_name =~ $ram_cell_name"]
}
}
}
}
# create_cost_group genus_ungrouping
foreach inst $design_vars(ungroup_inst_list) {
set hinst_list [get_db [get_db hinsts $inst] .name]
if { $hinst_list != ""} {
puts "ARM_INFO: $inst forces to be ungrouped"
ungroup -flatten $hinst_list -only_user_hierarchy
} else {
puts "ARM WARNING: $inst to be removed from ungroup list ..."
}
}
foreach inst $design_vars(no_autoungroup_list) {
puts "ARM_INFO: $inst wont be ungrouped"
set_db [get_db hinsts $inst] .ungroup_ok false
}
foreach inst [get_db insts -if { .is_integrated_clock_gating==true && (.name==*_clk_gate*)}] {
puts "ARM_INFO: $inst wont be ungrouped"
if {[regsub {\-.*} [get_db program_version] {}] >= 20.10} {
set_db $inst .parent.ungroup_ok false
} else {
set_db $inst .ungroup_ok false
}
}
#START_FLEX_INSERT_ANCHOR: Additional syn_generic settings
# CDN CCMPR02168913: Resolve potentially redundant AON buffer for on --> off crossing where fanout is in multiple domains
set_db pias_aon_enable_mode_analysis true
set_db pias_aon_check_pg_together 1
#END_FLEX_INSERT_ANCHOR: Additional syn_generic settings
#START_FLEX_INSERT_ANCHOR: Hierarchical flow setup
#END_FLEX_INSERT_ANCHOR: Hierarchical flow setup
## Define cost and path groups to allow genus to optimise each group independently
set inps [all_inputs -no_clocks]
set outs [all_outputs]
set seqs [all_registers]
set regs [filter_collection $seqs "is_integrated_clock_gating_cell == false && is_macro == false" ]
set icgs [filter_collection $seqs "is_integrated_clock_gating_cell == true" ]
set mems [filter_collection $seqs "is_macro == true" ]
set l1_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_l1/.*"]
set l2_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/u_l2/.*"]
set dpu_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_dpu/.*"]
set ifu_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_ifu/.*"]
set tlb_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/u_tlb/.*"]
set etm_insts [filter_collection -regexp $seqs "hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_etm/.*"]
set vpu_shared_insts [filter_collection -regexp $seqs "(hierarchical_name =~ u_vcomplex/.*u_vpu/.*)"]
set vpu_core_insts [filter_collection -regexp $seqs "(hierarchical_name =~ u_vcomplex/g_cpu_[01]_u_cpu/u_vpu_core/.*)"]
## Define cost and path groups to allow genus to optimise each group independently
define_cost_group -name in2out
define_cost_group -name in2reg
define_cost_group -name in2icg
define_cost_group -name reg2reg
define_cost_group -name reg2out
define_cost_group -name clkgate
define_cost_group -name reg2mem
define_cost_group -name mem2reg
define_cost_group -name mem2mem
define_cost_group -name l1
define_cost_group -name l2
define_cost_group -name dpu
define_cost_group -name vpushared
define_cost_group -name vpucore
define_cost_group -name ifu
define_cost_group -name tlb
define_cost_group -name etm
define_cost_group -name l12dpu
define_cost_group -name dpu2l1
define_cost_group -name ifu2dpu
define_cost_group -name dpu2ifu
define_cost_group -name ifu2l1
define_cost_group -name l12ifu
define_cost_group -name l12l2
define_cost_group -name l22l1
define_cost_group -name dpu2vpushared
define_cost_group -name vpushared2dpu
define_cost_group -name dpu2vpucore
define_cost_group -name vpucore2dpu
define_cost_group -name l12vpucore
define_cost_group -name vpucore2l1
define_cost_group -name vpucore2vpushared
define_cost_group -name vpushared2vpucore
foreach view [get_db [get_db analysis_views -if {.is_setup}] .constraint_mode.name] {
path_group -view $view -from $inps -to $outs -group in2out -name in2out
path_group -view $view -from $inps -to $regs -group in2reg -name in2reg
path_group -view $view -from $inps -to $icgs -group in2icg -name in2icg
path_group -view $view -from $regs -to $regs -group reg2reg -name reg2reg
path_group -view $view -from $regs -to $outs -group reg2out -name reg2out
path_group -view $view -from $regs -to $icgs -group clkgate -name clkgate
path_group -view $view -from $regs -to $mems -group reg2mem -name reg2mem
path_group -view $view -from $mems -to $regs -group mem2reg -name mem2reg
path_group -view $view -from $mems -to $mems -group mem2mem -name mem2mem
path_group -view $view -from $seqs -to $l1_insts -group l1 -name l1
path_group -view $view -from $seqs -to $l2_insts -group l2 -name l2
path_group -view $view -from $seqs -to $dpu_insts -group dpu -name dpu
path_group -view $view -from $seqs -to $ifu_insts -group ifu -name ifu
path_group -view $view -from $seqs -to $tlb_insts -group tlb -name tlb
path_group -view $view -from $seqs -to $etm_insts -group etm -name etm
path_group -view $view -from $seqs -to $vpu_shared_insts -group vpushared -name vpushared
path_group -view $view -from $seqs -to $vpu_core_insts -group vpucore -name vpucore
path_group -view $view -from $l1_insts -to $dpu_insts -group l12dpu -name l12dpu
path_group -view $view -from $dpu_insts -to $l1_insts -group dpu2l1 -name dpu2l1
path_group -view $view -from $ifu_insts -to $dpu_insts -group ifu2dpu -name ifu2dpu
path_group -view $view -from $dpu_insts -to $ifu_insts -group dpu2ifu -name dpu2ifu
path_group -view $view -from $ifu_insts -to $l1_insts -group ifu2l1 -name ifu2l1
path_group -view $view -from $l1_insts -to $ifu_insts -group l12ifu -name l12ifu
path_group -view $view -from $l1_insts -to $l2_insts -group l12l2 -name l12l2
path_group -view $view -from $l2_insts -to $l1_insts -group l22l1 -name l22l1
path_group -view $view -from $vpu_shared_insts -to $dpu_insts -group vpushared2dpu -name vpushared2dpu
path_group -view $view -from $dpu_insts -to $vpu_core_insts -group dpu2vpucore -name dpu2vpucore
path_group -view $view -from $vpu_core_insts -to $dpu_insts -group vpucore2dpu -name vpucore2dpu
path_group -view $view -from $l1_insts -to $vpu_core_insts -group l12vpucore -name l12vpucore
path_group -view $view -from $vpu_core_insts -to $l1_insts -group vpucore2l1 -name vpucore2l1
path_group -view $view -from $dpu_insts -to $vpu_shared_insts -group dpu2vpushared -name dpu2vpushared
path_group -view $view -from $vpu_core_insts -to $vpu_shared_insts -group vpucore2vpushared -name vpucore2vpushared
path_group -view $view -from $vpu_shared_insts -to $vpu_core_insts -group vpushared2vpucore -name vpushared2vpucore
}
# Dump out all the database attributes into a report
# Do this just before the main optimisation super command to understand what is affecting the QoR
redirect $report_dir/tool_settings.rpt "get_db *"
# -----------------------------------------------------------------------------
# Run the generic synthesis
# -----------------------------------------------------------------------------
# Using a physical syn_gen on the given floorplan def in the build
puts "ARM_INFO: A floorplan def file exists in this build, using this def file to run `syn_generic -physical`"
syn_generic
write_reports -directory ../reports/ -tag ${step_name}
# -----------------------------------------------------------------------------
# Write out the design information and exit
# -----------------------------------------------------------------------------
puts "ARM_INFO: write Netlist"
set basename [file join ../data ${step_name} [get_db current_design .name]]
write_hdl > ${basename}.v.gz
write_hdl -pg > ${basename}_pg.v.gz
write_hdl -lec > ${basename}_lec.v.gz
if {[info exist no_intermediate_db ] && $no_intermediate_db == "true"} {
puts "ARM_INFO: No intermediate DB will be written out, set $no_intermediate_db to false if DB are required"
} else {
write_db ../data/dbs/${step_name}.db
}
## MJ 04/12/23 For metrics collection
pop_snapshot_stack
create_snapshot -name ${step_name}
if {![info exist all_steps ]} {
time_info syn_generic
exit
}
Write, Run & Share TCL code online using OneCompiler's TCL online compiler for free. It's one of the robust, feature-rich online compilers for TCL language, running the latest TCL version 8.6. Getting started with the OneCompiler's TCL editor is easy and fast. The editor shows sample boilerplate code when you choose language as TCL and start coding.
OneCompiler's TCL online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample TCL program which takes name as input and prints hello message with your name.
set name [gets stdin]
puts "Hello $name"
Tool Command Language(TCL) is a general purpose scripting language which is commonly used for GUIs and for testing. Everything is by default string in TCL. It was created by John Osterhout in 1989.
Variable is a identifier which is used to hold the value. set is used to create variables.
set name onecompiler
When ever you want to perform a set of operations based on a condition IF-ELSE is used.
if(conditional-expression) {
#code
} else {
#code
}
You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.
Switch is an alternative to If-Else-If ladder.
switch(conditional-expression) {
value1 {
# code
}
value1 {
# code
}
...
default {
# code
}
For loop is used to iterate a set of statements based on a condition.
for{start}{test}{next}{
# code
}
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while(condition) {
# code
}
Array is a collection of similar data which is stored in continuous memory addresses. Array values can be fetched using index. Index starts from 0 to size-1.
set ArrayName(Index) value
Procedure is a sub-routine which contains set of statements. Uusually procedures are required when multiple calls are made to same set of statements. Procedures increases re-usuability and modularity.
proc procedureName {arguments} {
# code
}