Skip to main content

FPGA project controller for Vivado

Project description

xviv

PyPI PyPI - Python Version License: MIT Tests

CLI project controller for Vivado and Vitis.

pip install xviv

Work in progress. xviv is being actively developed alongside another project and the API is not stable.


Unlike traditional C++ or Python development, RTL/FPGA projects built with Vivado are notoriously hostile to version control and team collaboration.

Vivado's default Project Mode tightly couples the developer to its GUI. It buries absolute file paths inside its project files and indiscriminately mixes source code with massive generated build artifacts. This makes version control a mess and means a project that builds on one machine will likely break on another.

Vivado's Non-Project Mode solves the version control issue, but lacks a modern developer experience - forcing teams to manually manage complex Tcl scripts just to maintain a workflow.

xviv bridges this gap. It provides a configuration-driven CLI that enforces a strict separation between source files and build artifacts. The build directory remains entirely git-ignored, meaning a clean clone is all you need to reproduce the project on any system. It automates the scriptable parts of the Non-Project flow, while seamlessly allowing developers to spin up the Vivado GUI for tasks where it genuinely shines - like editing IP Packaging, configuring cores, or designing Block Diagrams.


Install

pip install xviv

Requires Python 3.11+. Vivado and Vitis must be on your PATH (source settings64.sh), or set XVIV_VIVADO_SOURCE_SCRIPT and xviv will source it for you:

# .env1 at project root (recommended, add to .gitignore)
XVIV_VIVADO_SOURCE_SCRIPT=/tools/Xilinx/Vivado/2024.1/settings64.sh

pyslang (already a declared dependency) is used for SV wrapper generation ([[wrapper]] sections).

For development:

git clone https://github.com/laperex/xviv.git
cd xviv
pip install -e ".[dev]"
pre-commit install

Getting started

A minimal project for a bare RTL design:

# project.toml

[[fpga]]
name      = "main"
fpga_part = "xc7a200tfbg484-1"

[[design]]
name    = "top"
sources = ["srcs/rtl/**/*.sv"]

[[synth]]
design      = "top"
constraints = ["constraints/top.xdc"]
xviv synth --design top

That runs the full pipeline: synth_designopt_designplace_designphys_opt_designroute_designwrite_bitstream. Checkpoints land in build/synth/top/checkpoints/. Open any of them with:

xviv open --dcp build/synth/top/checkpoints/route.dcp

Every command also generates a project.lock file at the project root — a TOML snapshot of the fully-resolved configuration (all globs expanded, all defaults applied). Useful for debugging and as an audit trail.


project.toml

All sections except [project] are arrays of tables. A real project uses some combination of the following:

[[fpga]] — part number and optional board definition. The first entry is the default; later sections can override with fpga = "name".

[[design]] — RTL sources and top module for a synthesisable design. Sources can be bare glob strings or structured entries with used_in stage filtering ("synth", "impl", "ooc", "sim").

[[ip]] — custom IP to package with the Vivado IP Packager. xviv handles the packaging and wires the IP repo into the project. Use [[wrapper]] alongside it if the IP has interface ports that need flattening (requires pyslang).

[[core]] — an instance of a catalog IP (Xilinx built-in or custom packaged). Identified by a partial VLNV that resolves against the live catalog; tab completion works here.

[[bd]] — a block design. xviv creates it, opens the editor, and writes its state as a re-runnable TCL snapshot under scripts/xviv/bd/. After that, create --bd <name> recreates it non-interactively from the snapshot on any machine.

[[synth]] — a synthesis run. Identified by one of design, bd, or core. Controls the full pipeline (which stages to run, incremental flows, directive overrides, reports, output artifacts).

[[simulation]] — a simulation target. Backends: xsim (default) or verilator. Supports UVM (see [[uvm]]), SDF back-annotation, and post-synthesis / post-implementation modes.

[[uvm]] — a UVM test configuration attached to a [[simulation]]. Each entry defines a test name, verbosity, and version. Multiple tests can target the same simulation.

[[platform]] / [[app]] — Vitis embedded flow. platform generates a BSP from the XSA produced by synthesis; app scaffolds and builds a Vitis application against it. The properties key on [[platform]] sets BSP properties (e.g. CONFIG.stdout) directly from the TOML.

[[formal]] — SymbiYosys formal verification target. Modes: bmc, prove, cover. Vivado is not required for this flow.

[project] — optional global settings: work_dir (default: "build"), log_file, board_repo, ip_repo.

A complete example:

[project]
work_dir = "build"

[[fpga]]
name      = "main"
fpga_part = "xc7a200tfbg484-1"

[[ip]]
name    = "gamma_axi"
sources = ["srcs/ip/gamma_axi/**/*.sv"]

[[bd]]
name = "system"

[[synth]]
bd          = "system"
constraints = ["constraints/system.xdc"]
run_synth   = true
run_place   = true
run_route   = true

[[platform]]
name = "mb_platform"
bd   = "system"
cpu  = "microblaze_0"
os   = "standalone"

[platform.properties]
CONFIG.stdout = "mdm_1"
CONFIG.stdin  = "mdm_1"

[[app]]
name     = "firmware"
platform = "mb_platform"
template = "empty_application"

[[simulation]]
name    = "tb_gamma"
sources = ["srcs/sim/tb_gamma.sv", "srcs/rtl/**/*.sv"]
backend = "xsim"

[[uvm]]
simulation = "tb_gamma"
test       = "gamma_basic_test"
verbosity  = "UVM_MEDIUM"

[[formal]]
name    = "gamma_props"
top     = "gamma_axi"
mode    = "prove"
sources = ["srcs/ip/gamma_axi/gamma_axi.sv", "srcs/formal/gamma_axi_props.sv"]
depth   = 30
defines = ["FORMAL"]

Commands

Working with IPs and BDs

# Package a custom IP
xviv create --ip gamma_axi
xviv edit   --ip gamma_axi              # opens IP Packager GUI

# Re-package and regenerate all XCI instances that use this IP (in parallel)
xviv create --ip gamma_axi --regenerate

# Create a block design from scratch (opens GUI)
xviv create --bd system

# Import from an existing TCL snapshot, no GUI
xviv create --bd system --nogui

# Import from snapshot and generate output products
xviv create --bd system --generate

# After editing, generate (or force-regenerate) output products
xviv generate --bd system
xviv generate --bd system --force
xviv generate --bd system --reset      # reset stale products first

# Instantiate a catalog IP core
xviv create --core clk_wiz_0
xviv create --core clk_wiz_0 --generate
xviv edit   --core clk_wiz_0

# Search the IP catalog
xviv search clk_wiz
xviv search "axi dma"

Synthesis

xviv synth --design top          # RTL design
xviv synth --bd     system       # block design
xviv synth --core   clk_wiz_0    # out-of-context IP core

# Parallel OOC synthesis of all sub-cores before the top-level run
xviv synth --bd system --parallel

# Resume from an existing checkpoint
xviv synth --design top --resume auto      # detect latest checkpoint automatically
xviv synth --design top --resume synth     # resume from after synth_design
xviv synth --design top --resume place     # resume from after place_design
xviv synth --design top --resume route     # re-run write_bitstream only

# Preview the generated TCL without running
xviv synth --design top --dry-run

# Open a checkpoint (path tab-completes)
xviv open --dcp build/synth/system/checkpoints/route.dcp

By default, every synth run embeds the short git SHA into the bitstream USR_ACCESS field (bit 28 is set if the working tree was dirty). Fine-grained control is in project.toml: run_synth, run_place, run_route, incremental flows, directive overrides, reports, netlists.

Simulation

xviv simulate --target tb_gamma
xviv simulate --target tb_gamma --run 1000ns
xviv simulate --target tb_gamma --mode post_synth_functional
xviv simulate --target tb_gamma --mode post_impl_timing

# Run a specific UVM test
xviv simulate --target tb_gamma --uvm gamma_basic_test

# Open the waveform DB or hot-reload in a live xsim session
xviv open   --wdb tb_gamma
xviv reload --target tb_gamma

Available --mode values: default, post_synth_functional, post_synth_timing, post_impl_functional, post_impl_timing.

Embedded

xviv create --platform mb_platform
xviv build  --platform mb_platform

xviv create --app firmware
xviv build  --app firmware
xviv build  --app firmware --info   # also print ELF section sizes

# Program the board (derive paths from config)
xviv program --platform mb_platform --app firmware

# Explicit paths or custom JTAG target filters
xviv program --bitstream path/to/custom.bit --elf path/to/custom.elf
xviv program --platform mb_platform --fpga "xc7a35t*" --processor "MicroBlaze #0*"
xviv program --platform mb_platform --reset-duration 1000   # ms before loading ELF

xviv processor --reset
xviv processor --status

Validate

Validate XDC constraint files against RTL port declarations without running Vivado. The engine uses Python's native Tcl interpreter to evaluate XDC files and pyslang to extract ports directly from SystemVerilog source.

# Check XDC I/O pins against RTL ports for a design
xviv validate synth --design top --io short
xviv validate synth --design top --io full

# Same for a block design
xviv validate synth --bd system --io full

# Control which issues are reported
xviv validate synth --design top --io full --level error   # errors only
xviv validate synth --design top --io full --level info    # all (default)

--io short prints a summary table; --io full shows every port with its constraint status (PACKAGE_PIN, IOSTANDARD, timing constraints, and any unmapped or unconstrained pins).

Formal

# Run all [[formal]] targets
xviv formal

# Run a specific target
xviv formal --target gamma_props

On failure, the counterexample trace path is printed with a gtkwave command ready to paste.

Every command accepts --dry-run to print the generated TCL without executing.


Shell completion

activate-global-python-argcomplete          # system-wide
eval "$(register-python-argcomplete xviv)"  # or per-shell (bash)

# Add to ~/.bashrc for persistence
echo 'eval "$(register-python-argcomplete xviv)"' >> ~/.bashrc

Completion is dynamic:

  • IP, BD, design, simulation, core, platform, app, and formal target names come from project.toml
  • VLNV strings for [[core]] come from the live Vivado IP catalog with descriptions inline
  • DCP paths complete from known checkpoint locations for each synth run
  • UVM test names filter to the selected simulation target
  • Bitstream and ELF paths complete from known output locations

Project layout

project/
├── project.toml               # single source of truth — commit this
├── project.lock               # auto-generated resolved config snapshot
├── .env                       # optional: XVIV_VIVADO_SOURCE_SCRIPT=...
├── srcs/
│   ├── rtl/
│   ├── ip/
│   ├── sim/
│   └── sw/
├── constraints/
├── scripts/
│   └── xviv/
│       └── bd/
│           └── system.tcl     # BD TCL snapshot — version control this
└── build/                     # gitignore everything here
    ├── log/
    │   └── xviv.log
    ├── synth/<name>/
    │   ├── checkpoints/       # synth.dcp, place.dcp, route.dcp
    │   ├── reports/
    │   ├── netlists/
    │   ├── <name>.bit
    │   └── <name>.xsa
    ├── core/                  # .xci files
    ├── ip/                    # packaged IP repos
    ├── bd/
    ├── sim/<name>/
    ├── platform/<name>/
    ├── app/<name>/
    └── formal/<name>/

scripts/xviv/ is the only generated directory that belongs in version control. Everything under build/ is reproducible from project.toml and the BD TCL snapshots.


Validate

xviv validate cross-references XDC constraints against RTL port declarations without invoking Vivado. It runs entirely in Python:

  • XDC parsing — uses Python's built-in tkinter.Tcl engine to evaluate XDC files natively. Handles set_property, create_clock, set_input_delay, set_output_delay, set_false_path, set_max_delay, and Vivado-style glob/bus wildcards ([*], [?]).
  • RTL extraction — uses pyslang to extract port declarations (name, direction, width) from SystemVerilog sources.
  • Reporting — renders a colour-coded ASCII table showing every port, its assigned PACKAGE_PIN, IOSTANDARD, and timing constraint coverage. Unconstrained or unmatched pins are flagged.
xviv validate synth --design top --io full

Roadmap

Roughly in order of priority.

Near-term

  • validate synth --core — XDC/port validation for standalone OOC core targets (currently only --design and --bd are supported).
  • DPI support — C/C++ testbenches that call into the simulator via DPI-C.
  • Configurable HSI targets — the FPGA part and processor target passed to hsi during BSP generation are currently driven by the [[platform]] properties dict; exposing typed config keys would be cleaner.
  • Subcore support for custom IPs — declare that a custom IP depends on another IP internally (e.g. a clk_wiz sub-core), so the packager carries the dependency correctly. BDs get automatic subcore tracking already; standalone IPs don't.

Feature additions

  • ILA / debug core insertion — add and configure Integrated Logic Analyzer cores during implementation, with an optional GUI mode for probe assignment.
  • QSPI flash programming — extend program to write bitstreams to QSPI flash over JTAG, not just direct FPGA configuration.
  • HLS support — bring Vitis HLS projects under the same project.toml and CLI. Synthesised HLS output would export as a first-class IP feeding directly into [[ip]] and the BD flow.
  • Dependency graphgraph command to print or visualise the full entity dependency tree (fpga → ip → core → bd → synth → platform → app).

Infrastructure

  • CI/CD — automatically run synthesis and validation from git push/PR events using xviv's CLI, typically on self-hosted infrastructure due to Vivado resource and licensing constraints.
  • Remote synthesis server — transparently dispatch synthesis jobs to a licensed network machine while preserving the same local xviv command workflow.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xviv-0.2.8.tar.gz (152.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xviv-0.2.8-py3-none-any.whl (101.7 kB view details)

Uploaded Python 3

File details

Details for the file xviv-0.2.8.tar.gz.

File metadata

  • Download URL: xviv-0.2.8.tar.gz
  • Upload date:
  • Size: 152.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for xviv-0.2.8.tar.gz
Algorithm Hash digest
SHA256 6fefa98e6661d38e5b9c58b4ca2befd7fee94ed735386e6f2139e99996f07ee5
MD5 1c2e7ccd3d88f07ed0c1dc45d7bf50ab
BLAKE2b-256 7995707a5813c3dc2e6ea7440ba1cb433f5eb8cf756367df2ecb3901226a4155

See more details on using hashes here.

File details

Details for the file xviv-0.2.8-py3-none-any.whl.

File metadata

  • Download URL: xviv-0.2.8-py3-none-any.whl
  • Upload date:
  • Size: 101.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for xviv-0.2.8-py3-none-any.whl
Algorithm Hash digest
SHA256 b8c81735a4063421f7b1b33525e07c73d787b2641825fc543d7d862671aaf9bc
MD5 b10c0a9dc5a0c121de80b47169e8634a
BLAKE2b-256 d40cab0b1806b5151f9e64f76e856f804ef2772f5d3b6b1a64d6beb50b0bf51d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page