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_xparshelpers each take the driver handle plus a list of property names and automatically iterate over every sister instance, emitting the appropriate#definemacros and configuration table entries. Most production drivers in theembeddedswtree 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_ipsto retrieve the complete set of IP instances that bind to the driver, then iterate over the set withforeachand read instance properties withcommon::get_property. Use::hsi::utils::get_driver_param_nameto construct uniqueXPAR_*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.