Packages¶
Packages are the fundamental organizational unit in DV Flow. A package is a parameterized namespace that defines tasks, types, and configuration. Packages serve two key purposes:
Organization - Group related tasks and provide a namespace to avoid name conflicts
Reusability - Enable sharing and reuse of task definitions across projects
Package Structure¶
Each package has a unique name and contains zero or more tasks. The minimal package definition looks like this:
package:
name: my_project
tasks:
- name: task1
uses: std.Message
with:
msg: "Hello from my_project!"
Built-in Packages¶
DV Flow Manager includes the std package as part of its core installation. The std package provides fundamental tasks that are commonly used across all flows:
std.FileSet - Collect files matching patterns
std.Message - Display messages during execution
std.CreateFile - Create files from literal content
std.SetEnv - Set environment variables
std.IncDirs - Extract include directories from filesets
Shell commands are executed by specifying shell: bash with run:.
The std package is always available and does not require an explicit import.
Plugin Packages¶
Additional packages are installed as Python plugins using Python’s entry point
mechanism. When DV Flow Manager starts, it automatically discovers and loads all
packages registered under the dv_flow.mgr entry point group.
Common plugin packages include:
hdlsim packages - HDL simulation support (Verilator, Xcelium, VCS, etc.)
pss packages - Portable Stimulus Specification (PSS) support
ide packages - IDE integration (file lists, etc.)
Installing Plugin Packages¶
Plugin packages are typically installed via pip alongside dv-flow-mgr:
pip install dv-flow-libhdlsim # HDL simulator support
pip install dv-flow-libpss # PSS support
Once installed, plugin packages are automatically discovered and their tasks become available without explicit imports.
Creating Plugin Packages¶
To create your own plugin package, add an entry point in your pyproject.toml:
[project.entry-points."dv_flow.mgr"]
my_plugin = "my_package.plugin"
Your plugin module should provide a dfm_packages() function that returns
a dictionary mapping package names to their flow.yaml file paths:
# my_package/plugin.py
import os
def dfm_packages():
pkg_dir = os.path.dirname(__file__)
return {
"my_tool": os.path.join(pkg_dir, "flow.yaml")
}
See the developer documentation for complete details on creating plugin packages.
Using Built-in and Plugin Packages¶
All packages are referenced using dot notation, independent of their source:
tasks:
- name: files
uses: std.FileSet
with:
include: "*.sv"
- name: sim
uses: hdlsim.vlt.SimImage
needs: [files]
Importing Packages¶
Packages can import other packages to use their tasks and extend their functionality. There are several ways to import packages:
Import by Path¶
Import a package from a file or directory path:
package:
name: top
imports:
- subdir/flow.yaml
- packages/my_lib
tasks:
- name: use_imported
uses: my_lib.some_task
When a directory is specified, DV Flow searches for flow.yaml or flow.yaml
files in the subdirectory tree.
Import with Alias¶
Use the as keyword to give an imported package an alias:
package:
name: proj
imports:
- name: hdlsim.vlt
as: sim
tasks:
- name: build
uses: sim.SimImage # References hdlsim.vlt.SimImage
Import Resolution¶
When resolving imports, DV Flow searches in the following order:
Relative to current file - Paths relative to the importing package’s location
Relative to project root - Allows sibling packages to find each other
Package registry - Built-in and installed packages
This allows sub-packages to import sibling packages naturally:
# In packages/ip1/flow.yaml
package:
name: ip1
imports:
- packages/ip2/flow.yaml # Finds sibling relative to project root
Package Parameters¶
Packages can define parameters that control their behavior. Parameters can be overridden when the package is imported or instantiated:
package:
name: configurable_ip
with:
debug:
type: int
value: 0
width:
type: int
value: 32
tasks:
- name: build
uses: std.Message
with:
msg: "Building with width=${{ width }}, debug=${{ debug }}"
Package Fragments¶
Large packages can be split into multiple files using fragments. Fragments allow you to organize tasks across multiple files while maintaining a single package namespace:
# Main package file
package:
name: big_project
fragments:
- src/rtl/flow.yaml
- src/tb/flow.yaml
- tests/
tasks:
- name: top_task
needs: [rtl.build, tb.build]
Fragment files use the fragment keyword instead of package:
# src/rtl/flow.yaml
fragment:
tasks:
- name: build
uses: std.FileSet
with:
include: "*.sv"
All fragments contribute to the same package namespace. Task names must be unique
across all fragments - you cannot define build in multiple fragments of the
same package.
Task Namespacing¶
Tasks within a package are referenced using dot notation: package_name.task_name.
Local vs. Qualified References¶
Within a package, you can reference tasks by their short name:
package:
name: my_pkg
tasks:
- name: task1
uses: std.Message
- name: task2
needs: [task1] # Short name - refers to my_pkg.task1
From outside the package, use the fully-qualified name:
package:
name: top
imports:
- packages/my_pkg
tasks:
- name: runner
needs: [my_pkg.task1] # Fully-qualified reference
Best Practices¶
Package Organization
Use packages to group related tasks by function (e.g., RTL compilation, verification, synthesis)
Keep package names short but descriptive
Use fragments for large packages to improve maintainability
Reusability
Make packages parameterizable when they need to work in different contexts
Document package parameters and their effects
Avoid hard-coded paths - use parameters or dataflow
Dependencies
Import only the packages you need
Use aliases to simplify long package names
Keep import chains shallow when possible
Naming
Use descriptive task names that indicate their purpose
Avoid generic names like
task1,task2Use consistent naming conventions across related packages
Package Configurations¶
Packages can define multiple configurations that customize behavior for different scenarios (debug builds, different tools, deployment targets, etc.). Configurations provide a way to organize variations without duplicating the core package definition.
Defining Configurations¶
Configurations are defined in the package using the configs field:
package:
name: my_project
with:
debug:
type: bool
value: false
tasks:
- name: build
uses: std.Message
with:
msg: "Building in default mode"
configs:
- name: debug
with:
debug:
value: true
tasks:
- name: build
override: build
with:
msg: "Building in debug mode"
- name: release
with:
debug:
value: false
overrides:
- override: hdlsim
with: hdlsim.xcelium
A configuration can specify:
with: Parameter values for this configuration
uses: Base configuration to inherit from
overrides: Package/parameter overrides
extensions: Task extensions (see below)
tasks: Additional or overriding tasks
types: Additional or overriding types
imports: Additional imports for this configuration
fragments: Additional fragments for this configuration
Selecting a Configuration¶
Configurations are selected via the command line:
dfm run build -c debug
When a configuration is selected:
Base package is loaded
Configuration parameters override package parameters
Configuration overrides are applied
Configuration tasks/types/imports/fragments are merged
Task graph is built using the merged definition
Configurations enable:
Build variants: debug, release, profiling builds
Tool selection: Switch between different tool vendors
Target platforms: Customize for different deployment targets
Test modes: Normal vs. regression vs. continuous integration
Package Extensions¶
Extensions allow you to modify existing tasks by adding parameters, dependencies, or other attributes without replacing the entire task. This is useful for augmenting tasks from imported packages.
Defining Extensions¶
Extensions are typically defined in configurations:
package:
name: my_project
imports:
- hdlsim.vlt
configs:
- name: coverage
extensions:
- task: hdlsim.vlt.SimImage
with:
coverage:
type: bool
value: true
needs:
- coverage_setup
The extension above adds a coverage parameter and an additional dependency
to the hdlsim.vlt.SimImage task.
Extension Capabilities¶
Extensions can modify tasks by:
Adding parameters: Introduce new configuration options
Adding dependencies: Include additional
needsChanging base: Specify a different
usesbase task
Extensions are particularly useful when:
Working with third-party packages that need customization
Adding instrumentation or monitoring to existing tasks
Implementing cross-cutting concerns (logging, metrics, etc.)
Extension Inheritance¶
Extensions can inherit from other extensions using uses:
configs:
- name: base_instrumentation
extensions:
- task: my_tool.Compile
with:
verbose:
type: bool
value: false
- name: debug_instrumentation
uses: base_instrumentation
extensions:
- task: my_tool.Compile
uses: base_instrumentation.my_tool.Compile
with:
verbose:
value: true
trace:
type: bool
value: true
This allows building up complex configurations incrementally.