Features and overrides¶
In hardware design, different build targets often require different source configurations—for example, switching between simulation verification models, FPGA prototypes, and ASIC foundry technology cells.
astli manages these variations cleanly through features and overrides.
Features¶
Much like Cargo features in Rust, an astli feature allows you to conditionally activate additional source files, include directories, optional dependencies, or downstream dependency features.
Features are additive: enabling a feature adds sources to your build, but never removes base sources. This guarantees that combining features always yields a well-defined design.
[features]
# Features enabled by default when another package depends on this one
default = ["vip"]
# A custom feature that introduces extra sources and activates a dependency feature
vip = { sources = ["hw/vip/**"], include-dirs = ["hw/vip/include"], dependencies = ["axi/vip"] }
Controlling features on the command line¶
When working inside a package directly, astli enables all declared features by default. You can fine-tune this on the command line:
# Disable all features declared in this package
astli files --no-features
# Disable defaults and explicitly enable only the 'vip' feature
astli files --no-features --features vip
Configuring dependency features¶
When you declare a dependency in [dependencies], it automatically activates that dependency's default features. You can request additional features or turn off defaults:
[dependencies]
axi = { git = "https://github.com/pulp-platform/axi.git", version = "0.39", features = ["vip"], default-features = false }
Optional dependencies¶
You can make an entire dependency conditional on a feature. When you reference a dependency name in a feature's dependencies list (e.g. dependencies = ["tech_foundry"]), that dependency is only pulled into the design when the feature is enabled:
[features]
asic = { dependencies = ["tech_foundry"] }
[dependencies]
tech_foundry = { git = "https://github.com/my-org/tech_foundry.git", version = "1.0" }
Development dependencies
For packages only needed during internal verification (like UVM test harnesses or mock VIP), place them in [dev-dependencies]. Downstream dependents will never download or compile them.
Overrides¶
In ASIC and FPGA development, high-level code often instantiates generic primitives (such as clock gates, reset synchronizers, or SRAM macros) that must be replaced by technology-specific macros in foundry builds.
The [overrides] table allows a root package to substitute module, interface, or package implementations provided by a dependency:
[features]
ihp13 = { sources = ["target/asic/ihp13/**"] }
[overrides]
# Instructs astli to replace matching modules in tech_cells_generic
tech_cells_generic = ["tc_sram_impl", "tc_clk_*"]
How overrides work¶
- Symbol matching: When
astliencounters an override pattern (supporting*wildcards), it identifies which source files in the specified dependency declare matching modules or interfaces. - File substitution: If your local package declares a module with the same name,
astliexcludes the dependency's file containing the generic implementation from the build, substituting your local implementation instead. - Feature gating: If the overriding source file belongs to a feature (such as
ihp13above), the override is only applied when that feature is active.
File granularity and collisions
astliexcludes files at the whole-file level. If a dependency file defines both an overridden module and an unrelated module that your design still needs,astliwill flag an error. Keep overridable cells isolated in individual files.- Two packages cannot attempt to override the same symbol. Overrides must be unambiguous.
- Header files (included via
`include) cannot be overridden; dependencies always resolve their own internal headers first.