Bender is a dependency management tool for hardware design projects. It provides a way to define dependencies among IPs, execute unit tests, and verify that the source files are valid input for various simulation and synthesis tools.
Bender.yml
)
bender.yml
, Bender.local
)Bender is built around the following core principles:
Be as opt-in as possible. We do not assume any specific EDA tool, workflow, or directory layout (besides a few key files). All features are designed to be as modular as possible, such that the user can integrate them into their respective flow.
Allow for reproducible builds. Bender maintains a precise lock file which tracks the exact git hash a dependency has been resolved to. This allows the source code of a package to be reliable reconstructed after the fact.
Collect source files. The first feature tier of Bender is to collect the source files in a hardware IP. In doing this, it shall do the following:
Manage dependencies. The second feature tier of Bender is to maintain other packages an IP may depend on, and to provide a local checkout of the necessary source files. Specifically, it shall:
Generate tool scripts. The third feature tier of Bender is the ability to generate source file listings and compilation scripts for various tools.
To use Bender for a single project, the simplest is to download and use a precompiled binary. We provide binaries for all current versions of Ubuntu and CentOS, as well as generic Linux, on each release. Open a terminal and enter the following command:
sh
curl --proto '=https' --tlsv1.2 https://fabianschuiki.github.io/bender/init -sSf | sh
The command downloads and executes a script that detects your distribution and downloads the appropriate bender
binary of the latest release to your current directory. If you need a specific version of Bender (e.g., 0.21.0
), append -s -- 0.21.0
to that command. Alternatively, you can manually download a precompiled binary from our Releases on GitHub.
If you prefer building your own binary, you need to install Rust. You can then build and install Bender for the current user with the following command:
sh
cargo install bender
If you need a specific version of Bender (e.g., 0.21.0
), append --version 0.21.0
to that command.
To install Bender system-wide, you can simply copy the binary you have obtained from one of the above methods to one of the system directories on your PATH
. Even better, some Linux distributions have Bender in their repositories. We are currently aware of:
- ArchLinux: Bender (AUR)
Please extend this list through a PR if you know additional distributions.
The workflow of bender is based on a configuration and a lock file. The configuration file lists the sources, dependencies, and tests of the package at hand. The lock file is used by the tool to track which exact version of a package is being used. Adding this file to version control, e.g. for chips that will be taped out, makes it easy to reconstruct the exact IPs that were used during a simulation, synthesis, or tapeout.
Upon executing any command, bender checks to see if dependencies have been added to the configuration file that are not in the lock file. It then tries to find a revision for each added dependency that is compatible with the other dependencies and add that to the lock file. In a second step, bender tries to ensure that the checked out revisions match the ones in the lock file. If not possible, appropriate errors are generated.
The update command reevaluates all dependencies in the configuration file and tries to find for each a revision that satisfies all recursive constraints. If semantic versioning is used, this will update the dependencies to newer versions within the bounds of the version requirement provided in the configuration file.
Bender looks for the following three files in a package:
Bender.yml
: This is the main package manifest, and the only required file for a directory to be recognized as a Bender package. It contains metadata, dependencies, and source file lists.
Bender.lock
: The lock file is generated once all dependencies have been successfully resolved. It contains the exact revision of each dependency. This file may be put under version control to allow for reproducible builds. This is handy for example upon taping out a design. If the lock file is missing or a new dependency has been added, it is regenerated.
Bender.local
: This optional file contains local configuration overrides. It should be ignored in version control, i.e. added to .gitignore
. This file can be used to override dependencies with local variants. It is also used when the user asks for a local working copy of a dependency.
Bender.yml
)The package manifest describes the package, its metadata, its dependencies, and its source files. All paths in the manifest may be relative, in which case they are understood to be relative to the directory that contains the manifest.
```yaml
package: # The name of the package. Required. name: magic-chip
# The list of package authors and contributors. Optional. # By convention, authors should be listed in the form shown below. authors: ["John Doe john@doe.si"]
dependencies: # Path dependency. axi: { path: "../axi" }
# Registry dependency. Not supported at the moment. # common_verification: "0.2"
# Git version dependency. commonverification: { git: "git@github.com:pulp-platform/commonverification.git", version: "0.1" }
# Git revision dependency. commoncells: { git: "git@github.com:pulp-platform/commoncells.git", rev: master }
frozen: true
sources: # Individual source files are simple string entries: - src/package.sv - src/file1.vhd - src/file2.vhd
# Source files can be grouped: - files: - src/stuff/pkg.sv - src/stuff/top.sv
# Grouped source files may have additional include dirs, defines, and target: - includedirs: - src/include - src/stuff/include defines: # Define without a value. EXCLUDEMAGIC: ~ # Define with a value. PREFIX_NAME: stuff target: all(asic, synthesis, freepdk45) files: - src/core/pkg.sv - src/core/alu.sv - src/core/top.sv
exportincludedirs: - include - uvm/magic/include
workspace: # Create symlinks to dependencies. # A list of paths at which bender will create a symlink to the checked-out # version of the corresponding package. packagelinks: links/axi: axi common: commoncells
# A directory where the dependencies will be checked out. Optional. # If specified, bender will check out the dependencies once and leave them # for the user to modify and keep up to date. # CAUTION: Bender will not touch these after the initial checkout. # Useful for chip packages, if the intent is to commit all dependencies into # the chip's version control. checkout_dir: deps
bender <cmd>
.plugins: hello: scripts/hello.sh ```
Dependencies are specified in the dependencies
section of the package manifest, or the overrides
section in the configuration file. There are different kinds of dependencies, as described in the following.
mydep: { path: "../path/to/mydep" }
Path dependencies are not considered versioned. Either all versions of dependency mydep
point to the same path, or otherwise the resolution will fail.
mydep: { git: "git@github.com:pulp-platform/common_verification.git", rev: "<commit-ish>" }
mydep: { git: "git@github.com:pulp-platform/common_verification.git", version: "1.1" }
Git dependencies are automatically checked out and cloned, and are considered for version resolution. The version
field can be any of the semver predicates. The rev
field can be a git "commit-ish", which essentially is a commit hash, a tag name, or a branch name.
All git tags of the form vX.Y.Z
are considered a version of the package.
Relevant dependency resolution code
The source files listed in the sources
section of the package manifest are a recursive structure. Each entry in the list can either be a single source file, or a group of source files:
```yaml
sources
section in the manifest:sources:
-
# A source file is formatted as follows: - src/top.sv
# A source group is formatted as follows.
# Be careful about the -
, which may appear on the same line as the first
# field of the source group.
-
# List of include directories. Optional.
include_dirs:
-
The target
specification configures a source group to be included or excluded under certain circumstances. See below for details. The include_dirs
field specifies the +incdir+...
statements to be added to any compilation command for the group. The defines
field specifies the +define+...
statements to be added add to any compilation command for this group.
Targets are flags that can be used to filter source files and dependencies. They are used to differentiate the steps in the ASIC/FPGA design flow, the EDA tools, technology targets, and more. They can also be used to have different versions of an IP optimized for different chips or technologies.
Targets specify a simple expression language, as follows:
*
matches any targetname
matches the target "name"all(T1, ..., TN)
matches if all of the targets T1 to TN match (boolean AND)any(T1, ..., TN)
matches if any of the targets T1 to TN match (boolean OR)not(T)
matches if target T does not match (boolean NOT)The following targets are automatically set by various bender subcommands:
synthesis
for synthesis tool script generationsimulation
for simulation tool script generationIndividual commands may also set tool-specific targets:
vsim
vcs
verilator
synopsys
riviera
genus
vivado
Individual commands may also set vendor-specific targets:
xilinx
synopsys
Individual commands may also set technology-specific targets:
asic
fpga
Additionally, we suggest to use the following targets to identify source code and netlists at different stages in the design process:
test
for testbench codertl
for synthesizable RTL codegate
for gate-level netlistsbender.yml
, Bender.local
)Bender looks for a configuration file in the following places:
/etc/bender.yml
$HOME/.config/bender.yml
It will also look recursively upwards from the current working directory for the following:
.bender.yml
Bender.local
The contents of these files are merged as they are encountered, such that a configuration in foo/bar/.bender.yml
will overwrite a configuration in foo/.bender.yml
.
The configuration file generally looks as follows:
```yaml
database: some/directory
git
. Optional.git: git-wrapper.sh
dependencies
in a package manifest.overrides: commoncells: { path: "/var/magic/commoncells" }
plugins
listed in their manifests.dependencies
in a package manifest.plugins: additional-tools: { path: "/usr/local/additional-tools" } ```
bender
is the entry point to the dependency management system. Bender always operates within a package; starting at the current working directory, search upwards the file hierarchy until a Bender.yml
is found, which marks the package.
path
--- Get the path of a checked-out packageThe bender path <PKG>
prints the path of the checked-out version of package PKG
.
Useful in scripts:
#!/bin/bash
cat `bender path mydep`/src/hello.txt
packages
--- Display the dependency graphbender packages
: List the package dependencies. The list is sorted and grouped according to a topological sorting of the dependencies. That is, leaf dependencies are compiled first, then dependent ones.bender packages -f
: Produces the same list, but flattened.bender packages -g
: Produces a graph description of the dependencies of the form <pkg>TAB<dependencies...>
.sources
--- List source filesProduces a sources manifest, a JSON description of all files needed to build the project.
The manifest is recursive by default; meaning that dependencies and groups are nested. Use the -f
/--flatten
switch to produce a simple flat listing.
To enable specific targets, use the -t
/--target
option.
config
--- Emit the current configurationThe bender config
command prints the currently active configuration as JSON to standard output.
script
--- Generate tool-specific scriptsThe bender script <format>
command can generate scripts to feed the source code of a package and its dependencies into a vendor tool.
Supported formats:
flist
: A flat file list amenable to be directly inlined into the invocation command of a tool, e.g. verilate $(bender script flist)
.vsim
: A Tcl compilation script for Mentor ModelSim/QuestaSim.vcs
: A Tcl compilation script for VCS.verilator
: Command line arguments for Verilator.synopsys
: A Tcl compilation script for Synopsys DC and DE.riviera
: A Tcl compilation script for Aldec Riviera-PRO.genus
: A Tcl compilation script for Cadence Genus.vivado
: A Tcl file addition script for Xilinx Vivado.vivado-sim
: Same as vivado
, but specifically for simulation targets.update
--- Re-resolve dependenciesWhenever you update the list of dependencies, you likely have to run bender update
to re-resolve the dependency versions, and recreate the Bender.lock
file.
Note: Actually this should be done automatically if you add a new dependency. But due to the lack of coding time, this has to be done manually as of now.
clone
--- Checkout dependency to make modificationsThe bender clone <PKG>
command checks out the package PKG
into a directory (default working_dir
, can be overridden with -p / --path <DIR>
).
To ensure the package is correctly linked in bender, the Bender.local
file is modified to include a path
dependency override, linking to the corresponding package.
This can be used for development of dependent packages within the parent repository, allowing to test uncommitted and committed changes, without the worry that bender would update the dependency.
To clean up once the changes are added, ensure the correct version is referenced by the calling packages and remove the path dependency in Bender.local.
Note: The location of the override may be updated in the future to prevent modifying the human-editable
Bender.local
file.
parents
--- Lists packages calling the specified packageThe bender parents <PKG>
command lists all packages calling the PKG
package.