Quartus® II Tcl Example: Make All Pins Virtual

author-image

By

If you use a modular Logic Lock Region design flow in your project, you may choose to make all the I/O pins in a module virtual I/O pins as a way to easily import the module in a top-level design. Also, if you want to compile an IP core to see how many resources it uses but it uses too many pins for your target device, making the pins virtual may allow the core to fit.

The following simple procedure makes all pins in your design virtual I/O pins. First, the design is synthesized to determine which nodes are pins. Next, a collection of name IDs is set to correspond to the pins in the design, then a VIRTUAL_PIN assignment is applied to every pin. Finally, the export_assignments command writes all new assignments to the project's Quartus II Settings File (.qsf).

The example uses the get_names and get_name_info commands, which are available beginning in version 4.0 of the Quartus II software (version 2.0 of the ::quartus::project package). Refer to the last example on this page for code that will work beginning with version 3.0 of the Quartus II software, and has more advanced capabilities.

load_package flow

proc make_all_pins_virtual {} {

    execute_module -tool map

    set name_ids [get_names -filter * -node_type pin]

    foreach_in_collection name_id $name_ids {
        set pin_name [get_name_info -info full_path $name_id]
        post_message "Making VIRTUAL_PIN assignment to $pin_name"
        set_instance_assignment -to $pin_name -name VIRTUAL_PIN ON
    }
    export_assignments
}

Improving the Sample Code

There are a variety of ways the sample code can be improved.

Remove Existing VIRTUAL_PIN Assignments

You can add the following command to the beginning of the procedure to remove all existing VIRTUAL_PIN assignments. This is a useful step to ensure the assignments are in a known state. Add this command before the execute_module command.

remove_all_instance_assignments -name VIRTUAL_PIN

Manually Exclude Certain Pins, Such as Clocks

For the Quartus II software to perform timing optimization as it fits a design, the clocks have to be connected to top-level I/O pins in the target device, and the clocks must have clock settings applied. This is true even if all other pins in a design are virtual I/O pins. Therefore, the basic example above prevents the Quartus II software from optimizing timing during compilation because all pins, including clocks, have a VIRTUAL_PIN assignment applied.

You can add a parameter to the procedure that accepts a list of signals to exclude from the VIRTUAL_PIN assignments. This list would typically be the names of clock pins in your design. The following example accepts a list of names to exclude. It also includes the command to remove any existing VIRTUAL_PIN assignments, discussed above.

load_package flow
package require cmdline

proc make_all_pins_virtual { args } {

    set options {\
        { "exclude.arg" "" "List of signals to exclude" } \
    }
    array set opts [::cmdline::getoptions quartus(args) $options]

    remove_all_instance_assignments -name VIRTUAL_PIN
    execute_module -tool map
    set name_ids [get_names -filter * -node_type pin]

    foreach_in_collection name_id $name_ids {
        set pin_name [get_name_info -info full_path $name_id]

        if { -1 == [lsearch -exact $opts(excludes) $pin_name] } {
            post_message "Making VIRTUAL_PIN assignment to $pin_name"
            set_instance_assignment -to $pin_name -name VIRTUAL_PIN ON
        } else {
            post_message "Skipping VIRTUAL_PIN assignment to $pin_name"
        }
    }
    export_assignments
}

You can call the procedure with this command. This example assumes you have two clocks in your design, named clk_a and clk_b.

make_all_pins_virtual -exclude { clk_a clk_b }

Automatically Identify & Handle Clocks

The previous example to exclude certain signals has the disadvantage that they must be entered by hand. It is possible to determine clock signals with commands in the ::quartus::advanced_timing package. This package is available for loading in only the quartus_tan executable, so you must use quartus_tan to run scripts with the following example. The commands in this example are all supported beginning with version 3.0 of the Quartus II software.

Automatically identifying clocks has the advantage of allowing you to automate the application of the USE_CLK_FOR_VIRTUAL_PIN assignment. You can use the USE_CLK_FOR_VIRTUAL_PIN assignment in conjunction with the VIRTUAL_PIN assignment to associate clock settings with clocks in your design. This provides the Quartus II Fitter with accurate information about timing requirements when you compile a design with virtual I/O pins. For more information about this assignment, refer to the Virtual Pin Clock logic option topic in the Quartus II Help.

The following example procedure makes all I/O pins in your design virtual I/O pins. It also makes virtual pin clock setting assignments where appropriate.

The example code first synthesizes your design. Then it attempts to delete any existing timing netlist before creating a new one. The get_timing_nodes commands create two collections of nodes from the timing netlist: pin_ids and clk_ids. The two collections are exclusive; no node in the clk_ids collection is in the pin_ids collection, even though the clock may be on an I/O pin.

The first foreach_in_collection loop gets the name of each pin in the design (excluding clock pins) and makes a VIRTUAL_PIN assignment to it.

The second foreach_in_collection loop gets the name of each clock in the design. The get_instance_assignment command retrieves the corresponding clock setting, if it exists. If a clock setting for the clock does exist (the string is not empty), the script makes a USE_CLOCK_FOR_VIRTUAL_PIN assignment to the clock name with the value of the clock setting name.

load_package flow
load_package timing
load_package advanced_timing

proc make_all_pins_virtual { } {

    remove_all_instance_assignments -name VIRTUAL_PIN
    remove_all_instance_assignments -name USE_CLK_FOR_VIRTUAL_PIN

    execute_module -tool map
    catch { delete_timing_netlist }
    create_timing_netlist -post_map
    
    set pin_ids [get_timing_nodes -type pin]
    set clk_ids [get_timing_nodes -type clk]
    
    # Make VIRTUAL_PIN assignments to every pin in the design
    foreach_in_collection pin_id $pin_ids {

        set pin_name [get_timing_node_info -info name $pin_id]
        post_message "Making VIRTUAL_PIN assignment to $pin_name"
        set_instance_assignment -to $pin_name -name VIRTUAL_PIN ON
    }

    # For each clock in the design, check whether it has a 
    # corresponding CLOCK_SETTINGS assignment.
    foreach_in_collection clk_id $clk_ids {

        set clk_name [get_timing_node_info -info name $clk_id]
        set clk_stgs [get_instance_assignment -to $clk_name -name \ 
           CLOCK_SETTINGS]

        # If there is a clock setting for this clock, make the
        # USE_CLK_FOR_VIRTUAL_PIN assignment
        if { ![string equal "" $clk_stgs] } {
            post_message "Making USE_CLK_FOR_VIRTUAL_PIN assignment \
                to $clk_name with value $clk_stgs"
            set_instance_assignment -to $clk_name \
                -name USE_CLK_FOR_VIRTUAL_PIN $clk_stgs
        }
    }
    export_assignments
}