Bazelizing mmRISC-2: A Full RISC-V SoC with rules_openxc7
Converting existing open-source FPGA projects to Bazel and rules_openxc7 transforms fragile, vendor-locked hardware build scripts into reproducible, sandboxed workflows. This case study examines our complete Bazelization of mmRISC-2, a comprehensive, silicon-proven RISC-V system-on-chip authored by Munetomo Maruyama.
By pairing Bazel’s fine-grained dependency tracking with open-source EDA tools (Yosys, Slang, nextpnr-xilinx, Project X-Ray, and openFPGALoader), developers can clone the repository and produce a fully placed, routed, and verified bitstream for the Digilent Arty A7-100T board with a single terminal command.
About mmRISC-2
The mmRISC-2 system-on-chip is a complete microcontroller-class RISC-V processor subsystem. Its notable features include:
- Configurable CPU Core: Supports either RV32IMAC or RV64GC instruction set architectures with hardware integer multiply/divide and optional floating-point support.
- Standard Interconnect: An AXI4-compliant bus architecture connecting instruction and data memory controllers.
- On-Chip Debug: A standard RISC-V debug module (Debug Transport Module and Debug Module) for JTAG-based runtime control.
- Comprehensive Peripherals: High-speed UARTs, SPI controllers, I2C masters, GPIOs, and interrupt controllers.
- Hardware Proven: Silicon-tested and evaluated on FPGA platforms including the Xilinx Artix-7 100T.
Prior to Bazelization, building mmRISC-2 required proprietary Vivado GUI project files (.xpr) or complex, machine-dependent Tcl scripts. Such setups introduce hidden dependencies on specific vendor versions, path variables, and GUI interactions that break automated CI/CD pipelines.
The Technical Challenges
Converting mmRISC-2 to a fully hermetic Bazel build with open-source synthesis highlighted three primary engineering hurdles:
1. Large-Scale SystemVerilog with Forward References
Unlike plain Verilog-2001, mmRISC-2 uses modern SystemVerilog syntax across dozens of packages, parameter structs, and hierarchical interfaces. The traditional Yosys Verilog parser (read_verilog -sv) struggles with forward references and complex package scoping found in production SystemVerilog codebases.
To solve this, we integrated the Slang frontend plugin (read_slang) inside rules_openxc7. Using the Slang parser provides robust compliance with IEEE 1800-2017:
# Synthesis invocation with Slang frontend flags
read_slang --allow-use-before-declare --unroll-limit 100000 -I... <sources>
These flags ensure that package definitions and cross-module parameterizations resolve without artificial source reordering.
2. Device Support for Artix-7 100T (xc7a100tcsg324-1)
The Digilent Arty A7-100T board is powered by the Xilinx Artix-7 100T FPGA (xc7a100tcsg324-1). Standard openXC7 distributions traditionally targeted smaller devices like the Artix-7 35T (xc7a35t).
In rules_openxc7 PR #14, we added part definitions and Project X-Ray chip database mappings for xc7a100tcsg324-1:
# openxc7/private/parts.bzl
"xc7a100tcsg324-1": struct(
device = "xc7a100t",
package = "csg324-1",
chipdb = "@openxc7_chipdb_xc7a100t//file",
),
This unlocked full synthesis, placement, routing, and FASM-to-bitstream generation for the 100T family.
3. Fine-Grained Module Decomposition
To avoid monolithic build targets, we organized mmRISC-2’s source tree into modular Bazel targets inside RTL/BUILD.bazel:
- Core CPU logic (
//RTL:cpu_srcs) - Bus and interconnect fabric (
//RTL:bus_srcs) - Peripheral controllers (
//RTL:peripheral_srcs) - Top-level Arty A7 integration (
//RTL:arty_top)
Hardware primitives such as clock management (MMCME2_BASE) and global buffers (BUFG) were mapped to openXC7 simulation and techmap models cleanly.
Building and Flashing mmRISC-2 with Bazel
With rules_openxc7 configured in MODULE.bazel, building the entire SoC requires zero manual tool installations. Bazel automatically fetches pinned, precompiled binaries for Yosys, nextpnr, and openFPGALoader:
# 1. Synthesize the complete SoC with Yosys
bazel build //:top_synth
# 2. Place and route with nextpnr-xilinx, generating top_pnr.bit
bazel build //:top_pnr
# 3. Flash directly to an attached Arty A7-100T over USB via openFPGALoader
bazel run //:top_prog
During synthesis, Yosys mapped 39,010 logic cells, and nextpnr-xilinx successfully placed and routed the entire design without timing violations or unroutable nets.
Upstream Contributions and Community
The entire conversion has been submitted as an open pull request to the original repository:
- Pull Request: filmil/mmRISC-2 PR #1
- Upstream Project: munetomo-maruyama/mmRISC-2 by Munetomo Maruyama
By adopting Bazel, the mmRISC-2 community gains:
- Deterministic, repeatable builds across Linux, macOS, and containerized CI runners.
- Elimination of proprietary toolchain licenses for synthesis and place-and-route.
- One-command FPGA programming directly from the build system.
For a comprehensive guide on implementing hermetic hardware workflows in your own projects, explore our book Hardware Development with Bazel.