gateweavers_rules_fpga provides production-grade Bazel rules and toolchain integrations for FPGA development, synthesis, implementation (Place & Route), bitstream generation, and interactive GUI debugging. It natively supports AMD/Xilinx Vivado and Yosys backends.
- End-to-End Workflows: Orchestrate complete FPGA builds with
fpga_flowor compose fine-grained pipeline steps (fpga_project,fpga_synthesis,fpga_implementation,fpga_bitstream). - Block Design & IP Management: Declare reusable IP cores with
fpga_ip, instantiate them inline or Out-of-Context (OOC) withfpga_ip_inst, and generate block designs automatically usingfpga_design. - Interactive GUI Debugging: Inspect projects and routed checkpoints in Vivado GUI directly via
bazel run <target>.guiwithout manual environment setup. - Hermetic & Bzlmod-Ready: Modular toolchain resolution via Bzlmod (
vivado_toolchains), seamless interop with@gateweavers_rules_vhdl. - Multi FPGA TOolchain: By default Vivado is fully supported, Yosys and Lattice toolchains are work in progress.
Add gateweavers_rules_fpga and @gateweavers_rules_vhdl to your MODULE.bazel:
module(
name = "my_fpga_project",
version = "0.1.0",
)
bazel_dep(name = "gateweavers_rules_fpga", version = "0.3.0")
bazel_dep(name = "gateweavers_rules_vhdl", version = "0.1.0")
# 1. Configure Vivado Toolchain Backend
vivado_toolchains = use_extension("@gateweavers_rules_fpga//vivado:extensions.bzl", "vivado_toolchains")
vivado_toolchains.vivado(
name = "vivado_2024_2",
path = "/opt/Xilinx/Vivado/2024.2/",
version = "2024.2",
is_default = True,
)
use_repo(vivado_toolchains, "fpga_toolchains")
# 2. Register Toolchains
register_toolchains("@fpga_toolchains//:all")Defines a Vivado FPGA toolchain instance. It packages environment setup commands, command binaries, and TCL workflow templates into an FpgaToolchainInfo provider wrapped within Bazel's standard platform_common.ToolchainInfo.
When targets such as fpga_synthesis, fpga_implementation, fpga_bitstream, fpga_project, or fpga_design resolve the //fpga:toolchain_type toolchain, they obtain this provider and delegate action generation and TCL emission to the functions configured here.
Instances of vivado_toolchain are generated automatically by the vivado_toolchains module extension (from //vivado:extensions.bzl). However, this rule may also be instantiated manually in a BUILD file to define a bespoke Vivado toolchain with customized TCL templates or invocation wrappers.
| Attribute | Type | Mandatory | Default | Description |
|---|---|---|---|---|
name |
string |
Yes | - | A unique name for this target. |
cmd |
string |
No | "vivado" |
The command name or absolute path to the Vivado executable. |
setup_cmd |
string |
No | "" |
Optional shell command executed prior to running Vivado (e.g. 'source /opt/Xilinx/Vivado/2024.2/settings64.sh'). |
create_project_tpl |
label |
No | //vivado/templates:create_project.tcl |
TCL template used by fpga_project to generate the project creation script. |
synthesis_tpl |
label |
No | //vivado/templates:synthesis.tcl |
TCL template used by fpga_synthesis to execute in-memory or project-based synthesis. |
implementation_tpl |
label |
No | //vivado/templates:implementation.tcl |
TCL template used by fpga_implementation for Place & Route (opt_design, place_design, phys_opt_design, route_design). |
bitstream_tpl |
label |
No | //vivado/templates:bitstream.tcl |
TCL template used by fpga_bitstream to generate bitstreams (.bit), debug probes (.ltx), and hardware platforms (.xsa). |
clock_domain_tpl |
label |
No | //vivado/templates:clock_domain.tcl |
TCL template providing clock/reset automation and AXI connection procedures used by fpga_design. |
load("@gateweavers_rules_fpga//vivado:toolchain.bzl", "vivado_toolchain")
vivado_toolchain(
name = "custom_vivado_impl",
cmd = "vivado",
setup_cmd = "source /opt/Xilinx/Vivado/2024.2/settings64.sh",
synthesis_tpl = "//my_toolchain_templates:synthesis.tcl",
implementation_tpl = "//my_toolchain_templates:implementation.tcl",
)
toolchain(
name = "custom_vivado",
toolchain = ":custom_vivado_impl",
toolchain_type = "@gateweavers_rules_fpga//fpga:toolchain_type",
)load("@gateweaver_rules_vhdl//vhdl:vhdl.bzl", "vhdl_library")
load("@gateweavers_rules_fpga//fpga:rules.bzl", "fpga_flow")
vhdl_library(
name = "blinky_lib",
srcs = ["vhdl/blinky.vhd"],
library_name = "blinky_lib",
vhdl_version = "2008",
)
fpga_flow(
name = "blinky_pynq_z1",
top = "blinky",
part = "xc7z020clg400-1",
deps = [":blinky_lib"],
constraints = ["constraints/pynq_z1.xdc"],
generics = {
"CLK_PERIOD_NS": "10",
},
synth_options = ["-flatten_hierarchy none"],
impl_options = {
"opt": ["-directive Explore"],
"place": ["-directive Explore"],
},
bit_options = ["-bin_file"],
)Build commands:
# Build bitstream (.bit, .ltx, .xsa)
bazel build //examples/blinky:blinky_pynq_z1
# Open project in GUI
bazel run //examples/blinky:blinky_pynq_z1.guiload("@gateweavers_rules_fpga//fpga:rules.bzl",
"fpga_clock_domain",
"fpga_ip",
"fpga_ip_inst",
"fpga_design",
"fpga_flow",
)
# 1. Define clock domain
fpga_clock_domain(
name = "main_clk",
clock_frequency = "100MHz",
clock_pin = "ps7_0/FCLK_CLK0",
reset_pin = "ps7_0/FCLK_RESET0_N",
reset_type = "active_low",
)
# 2. Declare IP module
fpga_ip(
name = "crc_ip",
entity_name = "crc_top_wrapper",
clock_port = "s_axi_aclk",
reset_port = "s_axi_aresetn",
generics = {"C_S_AXI_ADDR_WIDTH": "6"},
inst_tcl = "//examples/zynq/ip/ip-crc/src:vivado_inst_crc.tcl",
interfaces = {
"s_axi": "slave",
"M_AXI": "master",
},
deps = ["//examples/zynq/ip/ip-crc/src:src"],
)
# 3. Create IP instances
fpga_ip_inst(
name = "crc_0",
ip = ":crc_ip",
clock_domain = ":main_clk",
generics = {"C_S_AXI_ADDR_WIDTH": "7"},
memory_mapping = {
"SEG_CRC": "0x43DB0000",
"SEG_CRC_DMA": "0x43DC0000",
},
ooc = False,
)
fpga_ip_inst(
name = "crc_1",
ip = ":crc_ip",
clock_domain = ":main_clk",
memory_mapping = {
"SEG_CRC": "0x43D90000",
"SEG_CRC_DMA": "0x43D60000",
},
ooc = False,
)
# 4. Generate block design
fpga_design(
name = "zynq_design",
top = "zynq_design_wrapper",
part = "xc7z010clg400-1",
ips = [":crc_0", ":crc_1"],
pre_bd_hook = ":ps.tcl",
post_bd_hook = ":ps_master.tcl",
)
# 5. Run complete flow
fpga_flow(
name = "zynq_flow",
top = "zynq_design_wrapper",
part = "xc7z010clg400-1",
design = ":zynq_design",
max_threads = 4,
)load("@gateweavers_rules_fpga//fpga:rules.bzl",
"fpga_sources",
"fpga_project",
"fpga_synthesis",
"fpga_implementation",
"fpga_bitstream",
)
fpga_sources(
name = "core_srcs",
srcs = ["src/core.vhd"],
constraints = ["constraints/pins.xdc"],
library_name = "core_lib",
)
fpga_project(
name = "core_project",
top = "core_top",
part = "xc7z020clg400-1",
deps = [":core_srcs"],
)
fpga_synthesis(
name = "core_synthesis",
top = "core_top",
part = "xc7z020clg400-1",
project = ":core_project",
synth_options = ["-flatten_hierarchy full"],
)
fpga_implementation(
name = "core_implementation",
part = "xc7z020clg400-1",
synthesis = ":core_synthesis",
impl_options = {
"opt": ["-directive Explore"],
"place": ["-directive Explore"],
},
)
fpga_bitstream(
name = "core_bitstream",
part = "xc7z020clg400-1",
implementation = ":core_implementation",
bit_options = ["-bin_file"],
)rules_fpga includes a comprehensive test suite using @bazel_skylib//lib:unittest.bzl:
- Pure Starlark Tests: File classification, depset merging, VHDL library unit extraction.
- Analysis Tests: Validates provider propagation, lazy TCL script writing, Out-of-Context deduplication, template expansion actions, and action inputs/outputs.
- Hermetic Execution: All tests execute during the analysis phase without invoking Vivado or requiring EDA licenses.
Run the test suite locally:
bazel test //fpga/tests:all //vivado/tests:allValidate examples without hardware tools:
bazel build //examples/blinky:all //examples/zynq/... --nobuildThis project is licensed under the Apache 2.0 License - see the LICENSE file for details.