#---------------------------------------------------------------------------- # 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
}