Skip to content

antmicro/bedrock-rtl

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

970 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bedrock-RTL

GitHub License language - SystemVerilog build system - Bazel rtl-files

pre-commit bazel-build bazel-test-python bazel-test-stardoc bazel-test-verific bazel-test-ascentlint bazel-test-vcs bazel-test-verilator bazel-test-jg open bugs

High quality and composable RTL libraries in SystemVerilog

Bedrock-RTL

Dependencies

At minimum, you need to have the following tools installed in your environment.

  • Bazel == 9.1.0 (recommended to manage this using Bazelisk)

  • System Python interpreter >= 3.12

Additionally, several tools are needed to build and run all of the tests:

  • Open source

    • Elaboration

      • Slang

    • Linting

      • Verible

    • Simulation

      • Verilator

    • RTL wrapper generation

      • TopStitch

    • Additional tools included in the Docker image

      • Yosys, EQY, and Yices

      • Slang

      • XLS support libraries

  • Proprietary (not provided - purchase your own installation and licenses)

    • Elaboration

      • Verific tclmain

    • Linting

      • RealIntent AscentLint

    • Simulation

      • Synopsys VCS

    • Formal

      • Cadence JasperGold

      • Synopsys VCF

Note
We no longer support Altair DSim in CI. Nevertheless, the build system should continue to support it if you wish to use it for your own tests.

The provided Dockerfile can be used to build an image with the minimum dependencies and open source tools listed above. The Dockerfile uses RockyLinux 8 on x86-64 as the base image. If you want to run tests that leverage proprietary tools, you need to provide your own installations and licenses (which are typically compatible with RockyLinux 8 on x86-64).

If you bring your own EDA tools, you may need to provide a bit of your own Python code that implements the plugin API for verilog_runner.py. If you want to use a tool that isn’t already supported, update //bazel:verilog.bzl, implement a new verilog runner plugin, and reference your new tool in the appropriate Bazel test targets. Not all tests necessarily work with every tool. Refer to the BUILD.bazel files for specifics.

Using the Published Docker Image

Prebuilt linux/amd64 images are published to the Bedrock-RTL package on GitHub Container Registry. Each image has an immutable tag of the form YYYY-MM-DD-<full-git-sha>, where the date is the commit date in UTC. We intentionally do not publish a moving latest tag.

To use the latest image, open the package page linked above, copy the tag from the most recently published version, and run:

docker pull ghcr.io/xlsynth/bedrock-rtl:<tag>
docker run --rm -it -v "$(pwd)":/src -w /src ghcr.io/xlsynth/bedrock-rtl:<tag> /bin/bash

The package is public, so pulling it does not require GitHub Container Registry authentication. Using an immutable tag makes local and CI environments reproducible; pull a newer tag from the package page when you want to update the toolchain.

Building the Docker Image Locally

To build the image from the checked-out Dockerfile instead:

docker build --platform=linux/amd64 --tag=bedrock-rtl:${USER} .
docker run --rm -it -v "$(pwd)":/src -w /src bedrock-rtl:${USER} /bin/bash

Then once inside the container, try bazel build //…​ && bazel test //fifo/sim/…​ --test_tag_filters=verilator.

Deploying Docker Images

The docker-image-build job in .github/workflows/ci.yml builds the image for every pull request, push to main, and manual CI run. After that build succeeds, the docker-image-publish job deploys the image to ghcr.io/xlsynth/bedrock-rtl for pushes to main and manually dispatched CI runs. Pull requests build the image but do not publish it.

The publish job generates the immutable YYYY-MM-DD-<full-git-sha> tag, pushes the linux/amd64 image, attaches BuildKit provenance, and publishes a signed GitHub artifact attestation for the image digest. Repository maintainers can deploy an image manually by opening the CI workflow, selecting Run workflow, and choosing the Git ref to publish.

Pre-Commit Hooks

We use pre-commit hooks to enforce basic coding style. To install the hooks, run:

pre-commit install

This installs both the pre-commit and pre-push hooks configured by .pre-commit-config.yaml. They should automatically run on every commit and push. You can also run them manually via:

pre-commit run

We’ve tested with pre-commit version 4.0.1.

Building and Testing

We use the powerful Bazel build system to assemble filelists and to run all tests (elaboration, lint, simulation, and formal).

A one-step command builds and runs all tests:

bazel test //...
Important
Action required for tests to pass!

The repository includes a Verilator plugin for open-source simulation tests, but most EDA tool plugins are intentionally not provided. Many Bazel tests will fail unless your local or CI environment provides plugins for the proprietary tools used by those tests. We keep those plugins outside the repository because:

  1. We want to keep test definitions as vendor-agnostic as possible.

  2. Certain vendors may have non-disclosure agreements that protect usage of their APIs or licensing agreements that restrict where and how the tools can be run.

For additional tools, implement the plugin API by subclassing //python/verilog_runner/eda_tool.py and point to the plugin module search directories with the VERILOG_RUNNER_PLUGIN_PATH environment variable. You can set this environment variable in user.bazelrc so that it is used in all Bazel test invocations.

The Bazel test rule implementations at //bazel:verilog.bzl shell out the //python/verilog_runner/verilog_runner.py tool that presents a generic tool-agnostic API that actually implements the test.

The repository includes a Slang plugin for open-source elaboration tests. Select Slang explicitly for verilog_elab_test targets:

verilog_elab_test(
    name = "example_elab_test",
    tool = "slang",
    top = "example",
    deps = [":example"],
)

Slang performs parsing, semantic analysis, hierarchy elaboration, and type checking. The plugin supports source and header dependencies, preprocessor defines, and top-level parameter overrides supplied through the rule. For package-only source sets, set compile_only = True to perform compilation and type checking without module elaboration.

Continuous Integration

We run continuous integration tests with GitHub Actions. The main CI workflow currently covers pre-commit, build, Python/ecc codegen tests, Stardoc, Verific, Slang, AscentLint, VCS, and Verilator. Sampled JasperGold formal tests run in the nightly workflow. See .github/workflows/ci.yml and .github/workflows/nightly.yml for details.

Style Guide

We follow the xlsynth Verilog Style Guide, which is a fork of the lowRISC style guide with some minor differences.

Bazel Rules for Verilog

This repository defines several generally-helpful Bazel Verilog rules that you can use in your own projects.

verilog_library (external)

The verilog_library rule is used to collect Verilog source and header files and track their dependencies. The original definition of the verilog_library rule can be found here. We pick up that rule dependency transitively (see the top-level MODULE.bazel).

Using verilog_library
load("@rules_hdl//verilog:providers.bzl", "verilog_library")

verilog_library(
    name = "bar",
    srcs = ["bar.sv"],
    hdrs = ["baz.svh"]
)

verilog_library(
    name = "foo",
    srcs = ["foo.sv"],
    deps = [":bar"],
)

Other rules

Please see bazel/verilog_rules.md for documentation on rules defined in this repository.

Using Bedrock

Usage is best illustrated with an example using the bzlmod dependency management system in Bazel.

Tip
You are not required to use Bazel to depend on Bedrock-RTL. You can also use the Verilog files directly in your own projects (e.g., with git submodule, git subtree, or some other method).

In your project’s MODULE.bazel:

MODULE.bazel
module(name = "your-project")

bazel_dep(name = "bedrock-rtl", version = "0.0.1")
git_override(
    module_name = "bedrock-rtl",
    commit = <fill_in_git_commit_sha>,
    remote = "https://github.com/xlsynth/bedrock-rtl",
)

rules_hdl_extension = use_extension("@bedrock-rtl//dependency_support/rules_hdl:extension.bzl", "rules_hdl_extension")
use_repo(rules_hdl_extension, "rules_hdl")

If you need to redirect the rules_hdl wrapper module in a larger Bazel dependency graph, load the extension through a root-module rules_hdl dependency instead:

bazel_dep(name = "rules_hdl", version = "0.0.0", repo_name = "rules_hdl_wrapper_module")

# Use an override only if your root module needs to provide the rules_hdl wrapper
# from a local checkout or another non-registry source.
local_path_override(
    module_name = "rules_hdl",
    path = "<path-to-rules-hdl-wrapper>",
)

rules_hdl_extension = use_extension("@rules_hdl_wrapper_module//:extension.bzl", "rules_hdl_extension")
use_repo(rules_hdl_extension, "rules_hdl")
Note
Bazel only applies module overrides from the root module. If rules_hdl is available from your configured Bazel registries, no override is needed. Otherwise, your root MODULE.bazel must provide the rules_hdl module with an override such as local_path_override, archive_override, or git_override. The direct @bedrock-rtl//dependency_support/rules_hdl:extension.bzl load shown in the main example keeps @rules_hdl//…​ labels available, but root-module overrides for rules_hdl will not affect that direct extension load.

Then suppose you have the following SystemVerilog module called datapath_join.sv:

datapath_join.sv
// An example design using two Bedrock-RTL modules: br_flow_reg_fwd and br_flow_join.
//
// Joins two or more equal-width datapaths into a single output datapath.
// Uses ready/valid protocol on all flows.
// Push-side is registered.

`include "br_asserts.svh"

module datapath_join #(
    parameter int NumFlows = 2,  // must be at least 2
    parameter int WidthPerFlow = 32  // must be at least 1
) (
    input logic clk,
    input logic rst,
    output logic [NumFlows-1:0] push_ready,
    input logic [NumFlows-1:0] push_valid,
    input logic [NumFlows-1:0][WidthPerFlow-1:0] push_data,
    input logic pop_ready,
    output logic pop_valid,
    output logic [(NumFlows*WidthPerFlow)-1:0] pop_data
);

  `BR_ASSERT_STATIC(numflows_gte_2_a, NumFlows >= 2)
  `BR_ASSERT_STATIC(widthperflow_gte_1_a, WidthPerFlow >= 1)

  logic [NumFlows-1:0] inter_ready;
  logic [NumFlows-1:0] inter_valid;
  logic [NumFlows-1:0][WidthPerFlow-1:0] inter_data;

  for (genvar i = 0; i < NumFlows; i++) begin : gen_regs
    br_flow_reg_fwd #(
        .Width(WidthPerFlow)
    ) br_flow_reg_fwd (
        .clk,
        .rst,
        .push_ready(push_ready[i]),
        .push_valid(push_valid[i]),
        .push_data (push_data[i]),
        .pop_ready (inter_ready[i]),
        .pop_valid (inter_valid[i]),
        .pop_data  (inter_data[i])
    );
  end

  br_flow_join #(
      .NumFlows(NumFlows)
  ) br_flow_join (
      .clk,
      .rst,
      .push_ready(inter_ready),
      .push_valid(inter_valid),
      .pop_ready (pop_ready),
      .pop_valid (pop_valid)
  );

  assign pop_data = inter_data;  // direct concat

endmodule : datapath_join

Your BUILD.bazel file could then do this:

BUILD.bazel
load("@bedrock-rtl//bazel:verilog.bzl", "verilog_elab_and_lint_test_suite", "verilog_elab_test", "verilog_lint_test")
load("@rules_hdl//verilog:providers.bzl", "verilog_library")

package(default_visibility = ["//visibility:private"])

verilog_library(
    name = "datapath_join",
    srcs = ["datapath_join.sv"],
    deps = [
        "@bedrock-rtl//flow/rtl:br_flow_join",
        "@bedrock-rtl//flow/rtl:br_flow_reg_fwd",
        "@bedrock-rtl//macros:br_asserts",
    ],
)

verilog_elab_test(
    name = "datapath_join_elab_test",
    tool = "slang",
    deps = [":datapath_join"],
)

verilog_lint_test(
    name = "datapath_join_lint_test",
    deps = [":datapath_join"],
)

verilog_elab_and_lint_test_suite(
    name = "datapath_join_test_suite",
    params = {
        "NumFlows": [
            "2",
            "3",
        ],
        "WidthPerFlow": [
            "1",
            "64",
        ],
    },
    deps = [":datapath_join"],
)

SystemVerilog Macros

See SystemVerilog Macros for the list of available macros and defines.

RTL Libraries

See RTL Libraries for the list of available public RTL modules, packages, and formal libraries.

About

High quality and composable RTL libraries in SystemVerilog

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • SystemVerilog 80.4%
  • Starlark 13.7%
  • Tcl 2.0%
  • Python 1.7%
  • Jinja 1.7%
  • Rust 0.2%
  • Other 0.3%