Warning
|
UNDER CONSTRUCTION. Everything is broken. |
High quality and composable base RTL libraries in Verilog
You need to have the following tools installed in your environment.
-
Bazel (tested with 7.3.1)
-
pre-commit (tested with 3.8.0)
-
Your own EDA tools (for running tests)
TODO(mgottscho): Add more as we implement more things.
We use pre-commit hooks to enforce code quality. To install the hooks, run:
pre-commit install
They should automatically run on every commit. You can also run them manually via:
pre-commit run
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!
By default, the Bazel tests will fail because they call a placeholder wrapper script that does not reference any particular vendor EDA tool. We do this because:
You will need to point Bazel to a "real" implementation of the wrapper script to be able to run the tests. |
The Bazel test rule implementations at //bazel:verilog.bzl
shell out to a program with a generic EDA vendor tool-agnostic API that actually implements the test.
By default, a placeholder tool called placeholder_verilog_runner.py
is used. It implements the argument parsing part of the API but does nothing other than fail the test.
This placeholder test is generated by Bazel during the build with //bazel:write_placeholder_verilog_runner_py.bzl
.
To use a real implementation of the script, you tell Bazel where to find it by setting --action_env=BAZEL_VERILOG_RUNNER_TOOL=/path/to/your/verilog_runner.py
on the command line or in the .bazelrc
file.
Using GitHub Actions, which currently just runs pre-commit checks.
TODO(mgottscho): Find a way to have CI run Bazel tests using real EDA tools.
We follow the xlsynth Verilog Style Guide, which is a fork of the lowRISC style guide with some minor differences.
This repository defines several generally-helpful Bazel Verilog rules that you can use in your own projects.
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"],
)
Please see bazel/verilog_rules.md for documentation on rules defined in this repository.
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")
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",
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"],
)
These macros conveniently wrap always_ff
blocks, improving readability and helping to structure user code into sequential and combinational portions.
The macros are named according to the following suffix convention.
-
A
: Asynchronous reset (if absent, then synchronous) -
I
: Initial value given (if absent, then 0) -
L
: Conditional load enable (if absent, then unconditional) -
N
: No reset (if absent, then reset) -
X
: Given explicit clock and reset names (if absent, thenclk
and eitherrst
if synchronous orarst
if asynchronous)
Important
|
Clocks are always positive-edge triggered. Resets are always active-high. |
Macro/define | Description | Implemented | Tested |
---|---|---|---|
|
Flip-flop register with unconditional load, asynchronous active-high reset named |
Yes |
Yes |
|
Flip-flop register with conditional load enable, asynchronous active-high reset named |
Yes |
Yes |
|
Flip-flop register with unconditional load, asynchronous active-high reset named |
Yes |
Yes |
|
Flip-flop register with conditional load enable, asynchronous active-high reset named |
Yes |
Yes |
|
Flip-flop register with conditional load enable, synchronous active-high reset named |
Yes |
Yes |
|
Flip-flop register with unconditional load, synchronous active-high reset named |
Yes |
Yes |
|
Flip-flop register with conditional load enable, synchronous active-high given reset, initial value given, positive-edge triggered given clock. |
Yes |
Yes |
|
Flip-flop register with unconditional load, synchronous active-high given reset, initial value given, positive-edge triggered given clock. |
Yes |
Yes |
|
Flip-flop register with load enable, no reset, positive-edge triggered clock named |
Yes |
Yes |
|
Flip-flop register with conditional load enable, synchronous active-high reset, initial value 0, positive-edge triggered given clock. |
Yes |
Yes |
|
Flip-flop register with conditional load enable, synchronous active-high reset named |
Yes |
Yes |
|
Flip-flop register with unconditional load, no reset, positive-edge triggered clock named |
Yes |
Yes |
|
Flip-flop register with unconditional load, synchronous active-high given reset, initial value 0, positive-edge triggered given clock. |
Yes |
Yes |
|
Flip-flop register with unconditional load, synchronous active-high reset named |
Yes |
Yes |
These assertion macros are intended for use by the user in their own designs. They are guarded (enabled) by the following defines:
-
ifdef BR_ASSERT_ON
-
ifdef BR_ENABLE_ASSERT_COMB
- only for guardingBR_ASSERT_COMB
(off by default).
Important
|
Clocks are always positive-edge triggered. Resets are always active-high. |
Macro/define | Description | Implemented | Tested |
---|---|---|---|
|
Static (elaboration-time) assertion for use within modules |
Yes |
Yes |
|
Static (elaboration-time) assertion for use within packages |
Yes |
Yes |
|
Concurrent assertion with implicit |
Yes |
Yes |
|
Concurrent assertion with explicit clock and reset names. |
Yes |
Yes |
|
Combinational/immediate assertion. Also passes if the expression is unknown.
Enable by defining |
Yes |
Yes |
|
Concurrent cover with implicit |
Yes |
Yes |
|
Concurrent cover with explicit clock and reset names. |
Yes |
Yes |
|
Combinational/immediate cover. |
Yes |
Yes |
|
Concurrent assumption with implicit |
Yes |
Yes |
|
Concurrent assumption with explicit clock and reset names. |
Yes |
Yes |
These assertion macros wrap the public assertions. They are intended only for internal use inside Bedrock libraries, but the user needs to know about them. They are guarded (enabled) by the following defines:
-
ifndef BR_DISABLE_INTG_CHECKS
for the integration cases -
ifdef BR_ENABLE_IMPL_CHECKS
for the implementation cases
Macro/define | Description | Implemented | Tested |
---|---|---|---|
|
Concurrent integration assertion with implicit |
Yes |
Yes |
|
Concurrent integration assertion with explicit clock and reset names.
Disable by defining |
Yes |
Yes |
|
Concurrent implementation assertion with implicit |
Yes |
Yes |
|
Concurrent implementation assertion with explicit clock and reset names.
Enable by defining |
Yes |
Yes |
|
Combinational/immediate integration assertion.
Disable by defining |
Yes |
Yes |
|
Combinational/immediate implementation assertion.
Enable by defining |
Yes |
Yes |
|
Concurrent integration cover with implicit |
Yes |
Yes |
|
Concurrent integration cover with explicit clock and reset names.
Disable by defining |
Yes |
Yes |
|
Concurrent implementation cover with implicit |
Yes |
Yes |
|
Concurrent implementation cover with explicit clock and reset names.
Enable by defining |
Yes |
Yes |
|
Combinational/immediate integration cover.
Disable by defining |
Yes |
Yes |
|
Combinational/immediate implementation cover.
Enable by defining |
Yes |
Yes |
These macros conveniently wrap module instantiations from the gate
category.
Macro/define | Description | Implemented | Tested |
---|---|---|---|
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
These macros conveniently wrap br_misc_tieoff*
module instantiations.
Macro/define | Description | Implemented | Tested |
---|---|---|---|
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Provided for convenience of the user grepping for |
Yes |
Yes |
|
Provided for convenience of the user grepping for |
Yes |
Yes |
These macros conveniently wrap br_misc_unused
module instantiations.
Macro/define | Description | Implemented | Tested |
---|---|---|---|
|
Instantiates |
Yes |
Yes |
|
Instantiates |
Yes |
Yes |
|
Provided for convenience of the user grepping for |
Yes |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Fixed priority |
Yes |
|
|
Least-recently used |
Yes |
|
|
Round-robin |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Single-bit CDC |
||
|
Bus CDC using a dual-clock FIFO controller for a 1R1W dual-clock SRAM
|
||
|
Bus CDC using a dual-clock FIFO with internal flop-RAM
|
Module | Description | Implemented | Verified |
---|---|---|---|
|
Decrementing counter |
Yes |
|
|
Incrementing counter |
Yes |
|
|
Up-down saturating counter |
||
|
Up-down counter |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Credit counter |
Yes |
|
|
Credit/valid to ready/valid converter (credit-loop receiver-side) |
Yes |
|
|
Ready/valid to credit/valid converter (credit-loop sender-side) |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
With reset |
Yes |
|
|
Without reset |
Yes, but want to merge with |
|
|
With self-gating (valid-next) and without reset |
Yes, but want to merge with |
|
|
With self-gating (valid-next) |
Yes |
|
|
With self-gating (valid) |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
One-hot demultiplexer |
Yes |
|
|
Binary-select demultiplexer |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Binary to gray |
Yes |
|
|
Binary to onehot |
Yes |
|
|
Gray to binary |
Yes |
|
|
One-hot to binary |
Yes |
|
|
Priority encoder |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Single-error-correcting, double-error-detecting (SECDED) decoder |
||
|
Single-error-correcting, double-error-detecting (SECDED) encoder |
||
|
Single-error-detecting (SED) decoder |
Yes |
|
|
Single-error-detecting (SED) encoder |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
FIFO controller with external RAM port for 1R1W
|
||
|
FIFO controller with external RAM port for 1R1W
|
||
|
FIFO controller with external RAM port for 1R1W
|
Yes |
|
|
FIFO controller with external RAM port for 1R1W
|
Yes |
|
|
FIFO with internal flop RAM
|
||
|
FIFO with internal flop RAM
|
Yes |
|
|
FIFO with internal flop RAM
|
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Fixed priority arbiter |
Yes |
|
|
Least-recently used arbiter |
Yes |
|
|
Round-robin arbiter |
Yes |
|
|
Registered demultiplexer, external select |
Yes |
|
|
Combinational demultiplexer, external select, with unstable flow control |
Yes |
|
|
Datapath flow control split |
Yes |
|
|
Datapath flow control join |
Yes |
|
|
Arbitrated multiplexer, fixed priority |
Yes |
|
|
Arbitrated multiplexer, least-recently used |
Yes |
|
|
Arbitrated multiplexer, round-robin |
Yes |
|
|
Registered multiplexer, user select |
Yes |
|
|
Combinational multiplexer, external select, with unstable flow control |
Yes |
|
|
Pipeline register, registered forward and reverse signals |
Yes |
|
|
Pipeline register, registered forward signals |
Yes |
|
|
Pipeline register, registered backward signals |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Wire buffer/repeater |
Yes |
|
|
Clock wire buffer/repeater |
Yes |
|
|
Inverter |
Yes |
|
|
Two-input AND gate |
Yes |
|
|
Two-input OR gate |
Yes |
|
|
Two-input XOR gate |
Yes |
|
|
Two-input multiplexer |
Yes |
|
|
Two-input clock multiplexer |
Yes |
|
|
Integrated clock gate |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Drive an expression to constant 1s and internally waive relevant lint rules |
Yes |
Yes |
|
Drive an expression to constant 0s and internally waive relevant lint rules |
Yes |
Yes |
|
Sink an unused expression and internally waive relevant lint rules |
Yes |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
One-hot multiplexer |
Yes |
|
|
Binary-select multiplexer |
Yes |
Module | Description | Implemented | Verified |
---|---|---|---|
|
Address decoder tree for a tiled RAM |
WIP |
|
|
Address decoder for a tiled RAM |
Yes |
|
|
One-tile flop-RAM with one read port and one write port |
Yes |
|
|
Tiled flop-RAM with one read port and one write port |
Yes |
|
|
One-tile flop-RAM with one port (shared for read and write) |
||
|
Tiled flop-RAM with one port (shared for read and write) |
||
|
Pipeline for reading data from a tiled RAM |
Yes |
Function | Description | Implemented | Tested |
---|---|---|---|
|
Return integer ceiling division |
Yes |
Yes |
|
Return integer floor division |
Yes |
Yes |
|
Return integer ceiling of base- |
Yes |
Yes |
|
Return 1 if an integer is a power of 2 |
Yes |
Yes |
|
Return 1 if an integer is even |
Yes |
Yes |