rules_vivado: FPGA Synthesis and Place-and-Route in Bazel

August 10, 2026

rules_vivado drives the AMD/Xilinx Vivado FPGA toolchain from Bazel: VHDL and Verilog compile, elaborate, simulate, synthesize, place-and-route, generate a bitstream, and program the device, all as hermetic Bazel build actions rather than clicks in a GUI or a pile of ad-hoc TCL. This is the module that turns the Cocoapuffs board flow into bazel build.

This post kicks off a short series. Over the Cocoapuffs project and its parent repo a200t_examples I ended up writing a fair number of Bazel modules to make an FPGA-based RISC-V system reproducible from source. I have written about some already (rules_ghdl, rules_shar, fshlib, bazel-ebook, and build-in-docker); over the coming months I will cover the rest, one module per post: this one, then grlib, rules_fusesoc, rules_dtc, OpenSBI, rules_osvvm, rules_vunit, vhdl_ls_gen, and gotopt2.

What it does

Vivado is a large, license-encumbered, GUI-and-TCL-centric tool, which is exactly the kind of thing Bazel usually cannot touch. rules_vivado runs the Vivado tools inside a locally-built Docker container (the same “build-in-docker” idea behind my bid rules; the container image setup itself is delegated to Andrew Goessling’s rules_vivado), so an otherwise monolithic EDA flow becomes reproducible and incremental.

The rule set is broad. The ones I lean on most:

  • vivado_library compiles VHDL/Verilog sources into a named Vivado logical library, with a selectable VHDL standard and deps on other libraries.
  • vivado_simulation and vivado_test run an XSim behavioral simulation, the latter wired as a self-checking Bazel test.
  • vivado_synthesis and vivado_place_and_route take RTL to a routed design and a bitstream.
  • vivado_program_device and vivado_program_flash push the result onto an attached FPGA over the hw_server.
  • vivado_ip configures a parameterized AMD IP block, and vivado_unisims_library builds the Xilinx UNISIM primitives for simulation.

There are also niceties like vivado_ila/vivado_read_ila for an Integrated Logic Analyzer, and vivado_repl/vivado_gui for an interactive TCL prompt inside the container.

In a200t_examples

This is the primary synthesis and simulation backend for the Artix-7 xc7a200t. The board flow lives in boards/noelv/tool.vivado: vivado_library targets assemble the SoC from grlib and local IP, then :sim, :synth, :pnr, and :prog form the sim to bitstream to programming chain. Board-level generics splice the firmware images (the SERV loader and NOEL-V boot images) into the RTL. Across the repo there are dozens of vivado_library targets and a couple dozen vivado_simulation runs, many of them boot-debug traces from the Zircon bring-up.

Prior art and references

  • agoessling/rules_vivado is the predecessor that requires a host Vivado install; my rules build on it for the container setup.
  • hw-bzl/rules_vivado is an independent set of Vivado Bazel rules.
  • bazel_rules_hdl is the broad “EDA under Bazel” precedent (Verilator, Yosys, OpenROAD).
  • FuseSoC and Edalize solve the same “assemble and drive an FPGA flow” problem outside Bazel.

For the payoff, see From zero to RISC-V in hardware in 6 minutes and the Cocoapuffs post. The source is at filmil/bazel_rules_vivado, published through my Bazel registry.