Tcl Generate Invocation for Multi-Instance IP - Tcl Generate Invocation for Multi-Instance IP - 2026.1 English - UG1400

Vitis Unified Software Platform Documentation: Embedded Software Development (UG1400)

Document_ID
UG1400
Release_Date
2026-07-31
Version
2026.1 English

During platform and BSP generation, the Vitis Unified IDE executes driver Tcl code to produce software artifacts from the hardware design. The IDE invokes the driver-defined generate procedure to allow the driver to emit configuration data and instance-specific output.

When the IDE processes a hardware design, it groups all IP instances that bind to the same driver and selects a single IP instance as the representative for each driver group. The Vitis Unified IDE invokes the generate procedure once per driver group and passes only the representative driver handle to that procedure. The IDE does not invoke generate separately for each IP instance and does not provide a list of all instance handles. Because the IDE can select a different representative instance across runs, drivers must not depend on instance names or instance ordering.

Implications for Driver Authors

Designs can include multiple IP cores that share a single driver, and driver authors must ensure the driver handles all such instances. Because the Vitis Unified IDE invokes the generate procedure only once per driver group, drivers must treat this invocation as a group-level entry point rather than an instance-specific callback.

If a driver initializes only the representative instance that the generate procedure passes, the driver can skip additional instances that bind to the same driver. Drivers that initialize only the representative instance omit instance-specific configuration data or output from the platform or BSP artifacts.

Required Driver Design Pattern

A correct generate procedure must emit output for every IP instance that binds to the driver, not just the representative instance. The HSI Tcl library provides two complementary mechanisms for this:

  • High-level helpers. The ::hsi::utils::define_include_file, ::hsi::utils::define_config_file, and ::hsi::utils::define_canonical_xpars helpers each take the driver handle plus a list of property names and automatically iterate over every sister instance, emitting the appropriate #define macros and configuration table entries. Most production drivers in the embeddedsw tree use only these helpers.
  • Custom logic — manual iteration. When the high-level helpers do not cover what the driver needs to emit (for example, when the driver must compute a value per instance from multiple properties), use ::hsi::utils::get_common_driver_ips to retrieve the complete set of IP instances that bind to the driver, then iterate over the set with foreach and read instance properties with common::get_property. Use ::hsi::utils::get_driver_param_name to construct unique XPAR_* macro names for each instance.

Whichever mechanism the driver uses, the generate procedure must never depend on the instance name or instance ordering of the representative handle.

Example Tcl Patterns

The following examples show both mechanisms applied to a driver named XGpio. The high-level helpers handle multi-instance discovery and iteration internally; the manual pattern shows what to do when the helpers do not cover the required output.

The recommended high-level pattern emits xparameters.h, canonical XPAR_* definitions, and the xgpio_g.c configuration table for every instance that binds to the driver in a single call to each helper:

proc generate {drv_handle} {
    ::hsi::utils::define_include_file    $drv_handle "xparameters.h" "XGpio" \
        "NUM_INSTANCES" "C_BASEADDR" "C_HIGHADDR" "DEVICE_ID" \
        "C_INTERRUPT_PRESENT" "C_IS_DUAL"

    ::hsi::utils::define_config_file     $drv_handle "xgpio_g.c"     "XGpio" \
        "DEVICE_ID" "C_BASEADDR" "C_INTERRUPT_PRESENT" "C_IS_DUAL"

    ::hsi::utils::define_canonical_xpars $drv_handle "xparameters.h" "Gpio"  \
        "C_BASEADDR" "C_HIGHADDR" "DEVICE_ID" "C_INTERRUPT_PRESENT" "C_IS_DUAL"
}

When the driver must emit something the high-level helpers do not produce, use ::hsi::utils::get_common_driver_ips to enumerate every IP instance that binds to the driver, then iterate. The following pattern opens an include file, walks the full instance set, reads per-instance properties, and emits a unique macro for each instance:

proc generate_custom_params {drv_handle file_name} {
    set file_handle [::hsi::utils::open_include_file $file_name]

    # Retrieve every IP instance that binds to this driver.
    set ips [::hsi::utils::get_common_driver_ips $drv_handle]

    foreach ip $ips {
        set ip_name [common::get_property NAME $ip]
        set value   [common::get_property CONFIG.C_BASEADDR $ip]

        # Emit a unique XPAR_* macro per instance.
        puts $file_handle \
            "\#define [::hsi::utils::get_driver_param_name $ip \"CUSTOM_PARAM\"] $value"

        puts "generate: processed $ip_name"
    }
    close $file_handle
}

Both patterns treat generate as a driver-level entry point: the high-level helpers iterate internally over every sister instance, and the manual pattern iterates explicitly with foreach. In neither case does the driver rely on the representative instance handle as if it were the only instance.

Example Scenario

A design instantiates sentinel_0, sentinel_1, and sentinel_2, all of which bind to the same driver. During generation, the Vitis Unified IDE invokes the driver's generate procedure only once for the driver group and passes a single representative handle. With the high-level helpers shown above, a single call to ::hsi::utils::define_config_file emits three rows in the configuration table — one for sentinel_0, one for sentinel_1, and one for sentinel_2 — and ::hsi::utils::define_include_file emits a corresponding #define block per instance in xparameters.h. The driver must not rely on multiple generate invocations.

Verification

To verify correct driver behavior, create a design that includes multiple IP instances that bind to the same driver and run platform or BSP generation in the Vitis Unified IDE. In the output xparameters.h, confirm that XPAR_<DRV>_NUM_INSTANCES matches the number of instances in the design and that an XPAR_<INSTANCE>_* block exists for every instance. In the output x<drv>_g.c, confirm that the configuration table contains one row per instance. If entries appear for only one instance, the driver is bypassing the high-level helpers and iterating incorrectly — switch to the helper pattern shown above, or add explicit instance discovery with ::hsi::utils::get_common_driver_ips.