xlsynth / bedrock-rtl

High quality and composable base RTL libraries in SystemVerilog
Apache License 2.0
11 stars 2 forks source link
hardware rtl verilog

// Copyright 2024 The Bedrock-RTL Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.

= Bedrock-RTL

WARNING: UNDER CONSTRUCTION. Many things are broken.

High quality and composable base RTL libraries in Verilog

== Prerequisites

You need to have the following tools installed in your environment.

== Pre-Commit Hooks

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

[source,shell]

pre-commit install

They should automatically run on every commit. You can also run them manually via:

[source,shell]

pre-commit run

== Building and Testing

:bazel: https://bazel.build/

We use the powerful {bazel}[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:

[source,shell]

bazel test //...

[IMPORTANT] .Action required for tests to pass!

By default, the Bazel tests will fail because the repository does not currently provide any EDA tool plugins for the verilog_runner.py tool. We do this 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.

You will need to implement the plugin API by subclassing //python/verilog_runner/eda_tool.py for the tool(s) of interest and then point to them with the VERILOG_RUNNER_PLUGIN_PATH environment variable. You should also set this environment variable in the .bazelrc file 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.

== Continuous Integration

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.

== Style Guide

:xlsynth-verilog-style-guide: https://github.com/xlsynth/verilog-style-guides/blob/master/VerilogCodingStyle.md :lowrisc-verilog-style-guide: https://github.com/lowrisc/verilog-style-guides/blob/master/VerilogCodingStyle.md

We follow the {xlsynth-verilog-style-guide}[xlsynth Verilog Style Guide^], which is a fork of the {lowrisc-verilog-style-guide}[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)

:verilog-library: https://github.com/hdl/bazel_rules_hdl/blob/main/verilog/providers.bzl

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 {verilog-library}[here^]. We pick up that rule dependency transitively (see the top-level MODULE.bazel).

.Using verilog_library [%collapsible]

[source,bazel]

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 link:bazel/verilog_rules.md[] for documentation on rules defined in this repository.

== Using Bedrock

:bzlmod: https://docs.bazel.build/versions/5.1.0/bzlmod.html

Usage is best illustrated with an example using the {bzlmod}[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 [%collapsible]

[source,bzl]

module(name = "your-project")

bazel_dep(name = "bedrock-rtl", version = "0.0.1") git_override( module_name = "bedrock-rtl", commit = , 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 [%collapsible]

[source,verilog]

// 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 [%collapsible]

[source,bzl]

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"], )

====

== macros: Macros and Defines

=== br_registers.svh: Flip-Flop Inference Macros

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.

IMPORTANT: Clocks are always positive-edge triggered. Resets are always active-high.

[cols="1,4,1,1"] |=== | Macro/define | Description | Implemented | Tested

| BR_REGA | Flip-flop register with unconditional load, asynchronous active-high reset named arst, initial value 0, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGAIL | Flip-flop register with conditional load enable, asynchronous active-high reset named arst, initial value given, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGAI | Flip-flop register with unconditional load, asynchronous active-high reset named arst, initial value given, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGAL | Flip-flop register with conditional load enable, asynchronous active-high reset named arst, initial value 0, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGIL | Flip-flop register with conditional load enable, synchronous active-high reset named rst, initial value given, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGI | Flip-flop register with unconditional load, synchronous active-high reset named rst, initial value given, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGILX | Flip-flop register with conditional load enable, synchronous active-high given reset, initial value given, positive-edge triggered given clock. | Yes | Yes

| BR_REGIX | Flip-flop register with unconditional load, synchronous active-high given reset, initial value given, positive-edge triggered given clock. | Yes | Yes

| BR_REGLN | Flip-flop register with load enable, no reset, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGLX | Flip-flop register with conditional load enable, synchronous active-high reset, initial value 0, positive-edge triggered given clock. | Yes | Yes

| BR_REGL | Flip-flop register with conditional load enable, synchronous active-high reset named rst, initial value 0, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGN | Flip-flop register with unconditional load, no reset, positive-edge triggered clock named clk. | Yes | Yes

| BR_REGX | Flip-flop register with unconditional load, synchronous active-high given reset, initial value 0, positive-edge triggered given clock. | Yes | Yes

| BR_REG | Flip-flop register with unconditional load, synchronous active-high reset named rst, initial value 0, positive-edge triggered clock named clk. | Yes | Yes

|===

=== br_asserts.svh: Public Assertions

These assertion macros are intended for use by the user in their own designs. They are guarded (enabled) by the following defines:

IMPORTANT: Clocks are always positive-edge triggered. Resets are always active-high.

[cols="1,4,1,1"] |=== | Macro/define | Description | Implemented | Tested

| BR_ASSERT_STATIC | Static (elaboration-time) assertion for use within modules | Yes | Yes

| BR_ASSERT_STATIC_IN_PACKAGE | Static (elaboration-time) assertion for use within packages | Yes | Yes

| BR_ASSERT | Concurrent assertion with implicit clk and rst names. | Yes | Yes

| BR_ASSERT_CR | Concurrent assertion with explicit clock and reset names. | Yes | Yes

| BR_ASSERT_COMB a| Combinational/immediate assertion. Also passes if the expression is unknown. Enable by defining BR_ENABLE_ASSERT_COMB. | Yes | Yes

| BR_COVER | Concurrent cover with implicit clk and rst names. | Yes | Yes

| BR_COVER_CR | Concurrent cover with explicit clock and reset names. | Yes | Yes

| BR_COVER_COMB | Combinational/immediate cover. | Yes | Yes

| BR_ASSUME | Concurrent assumption with implicit clk and rst names. | Yes | Yes

| BR_ASSUME_CR | Concurrent assumption with explicit clock and reset names. | Yes | Yes

|===

=== br_asserts_internal.svh: Bedrock-internal Assertions

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:

[cols="1,4,1,1"] |=== | Macro/define | Description | Implemented | Tested

| BR_ASSERT_INTG a| Concurrent integration assertion with implicit clk and rst names. Disable by defining BR_DISABLE_INTG_CHECKS. | Yes | Yes

| BR_ASSERT_CR_INTG a| Concurrent integration assertion with explicit clock and reset names. Disable by defining BR_DISABLE_INTG_CHECKS. | Yes | Yes

| BR_ASSERT_IMPL a| Concurrent implementation assertion with implicit clk and rst names. Enable by defining BR_ENABLE_IMPL_CHECKS. | Yes | Yes

| BR_ASSERT_CR_IMPL a| Concurrent implementation assertion with explicit clock and reset names. Enable by defining BR_ENABLE_IMPL_CHECKS. | Yes | Yes

| BR_ASSERT_COMB_INTG a| Combinational/immediate integration assertion. Disable by defining BR_DISABLE_INTG_CHECKS. | Yes | Yes

| BR_ASSERT_COMB_IMPL a| Combinational/immediate implementation assertion. Enable by defining BR_ENABLE_IMPL_CHECKS. | Yes | Yes

| BR_COVER_INTG a| Concurrent integration cover with implicit clk and rst names. Disable by defining BR_DISABLE_INTG_CHECKS. | Yes | Yes

| BR_COVER_CR_INTG a| Concurrent integration cover with explicit clock and reset names. Disable by defining BR_DISABLE_INTG_CHECKS. | Yes | Yes

| BR_COVER_IMPL a| Concurrent implementation cover with implicit clk and rst names. Enable by defining BR_ENABLE_IMPL_CHECKS. | Yes | Yes

| BR_COVER_CR_IMPL a| Concurrent implementation cover with explicit clock and reset names. Enable by defining BR_ENABLE_IMPL_CHECKS. | Yes | Yes

| BR_COVER_COMB_INTG a| Combinational/immediate integration cover. Disable by defining BR_DISABLE_INTG_CHECKS. | Yes | Yes

| BR_COVER_COMB_IMPL a| Combinational/immediate implementation cover. Enable by defining BR_ENABLE_IMPL_CHECKS. | Yes | Yes

|===

=== br_gates.svh: Gate Convenience Wrappers

These macros conveniently wrap module instantiations from the gate category.

[cols="1,4,1,1"] |=== | Macro/define | Description | Implemented | Tested

| BR_GATE_BUF | Instantiates br_gate_buf. | Yes | Yes

| BR_GATE_CLK_BUF | Instantiates br_gate_clk_buf. | Yes | Yes

| BR_GATE_INV | Instantiates br_gate_inv. | Yes | Yes

| BR_GATE_AND2 | Instantiates br_gate_and2. | Yes | Yes

| BR_GATE_OR2 | Instantiates br_gate_or2. | Yes | Yes

| BR_GATE_XOR2 | Instantiates br_gate_xor2. | Yes | Yes

| BR_GATE_MUX2 | Instantiates br_gate_mux2. | Yes | Yes

| BR_GATE_CLK_MUX2 | Instantiates br_gate_clk_mux2. | Yes | Yes

| BR_GATE_ICG | Instantiates br_gate_icg. | Yes | Yes

|===

=== br_tieoff.svh: Tie-off Convenience Wrappers

These macros conveniently wrap br_misc_tieoff* module instantiations.

[cols="1,4,1,1"] |=== | Macro/define | Description | Implemented | Tested

| BR_TIEOFF_ZERO_NAMED | Instantiates br_tieoff_zero with a given submodule instance suffix. | Yes | Yes

| BR_TIEOFF_ONE_NAMED | Instantiates br_tieoff_one with a given submodule instance suffix. | Yes | Yes

| BR_TIEOFF_ZERO | Instantiates br_tieoff_zero with a derived submodule instance suffix. | Yes | Yes

| BR_TIEOFF_ONE | Instantiates br_tieoff_one with a derived submodule instance suffix. | Yes | Yes

| BR_TIEOFF_ZERO_TODO a| Provided for convenience of the user grepping for TODO in the codebase, to help prevent accidental tie-offs that result in bugs. Instantiates br_tieoff_zero with a derived submodule instance suffix. | Yes | Yes

| BR_TIEOFF_ONE_TODO a| Provided for convenience of the user grepping for TODO in the codebase, to help prevent accidental tie-offs that result in bugs. Instantiates br_tieoff_one with a derived submodule instance suffix. | Yes | Yes

|===

=== br_unused.svh: Unused Signal Convenience Wrappers

These macros conveniently wrap br_misc_unused module instantiations.

[cols="1,4,1,1"] |=== | Macro/define | Description | Implemented | Tested

| BR_UNUSED_NAMED | Instantiates br_misc_unused with a given submodule instance suffix. | Yes | Yes

| BR_UNUSED | Instantiates br_misc_unused with a derived submodule instance suffix. | Yes | Yes

| BR_UNUSED_TODO a| Provided for convenience of the user grepping for TODO in the codebase, to help prevent accidental unused signals that result in bugs. Instantiates br_misc_unused with a derived submodule instance suffix. | Yes | Yes

|===

== Modules

=== arb: Arbiters

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_arb_fixed Fixed priority Yes
br_arb_lru Least-recently used Yes
br_arb_rr Round-robin Yes

|===

=== cdc: Clock Domain Crossings

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_cdc_bit Single-bit CDC

| br_cdc_fifo_ctrl_1r1w a| Bus CDC using a dual-clock FIFO controller for a 1R1W dual-clock SRAM

| br_cdc_fifo_flops a| Bus CDC using a dual-clock FIFO with internal flop-RAM

|===

=== counter: Wrapping and Saturating Counters

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_counter_decr Decrementing counter Yes
br_counter_incr Incrementing counter Yes
br_counter_sat Up-down saturating counter
br_counter Up-down counter Yes

|===

=== credit: Credit/Valid Flow Control

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_credit_counter Credit counter Yes
br_credit_receiver Credit/valid to ready/valid converter (credit-loop receiver-side) Yes
br_credit_sender Ready/valid to credit/valid converter (credit-loop sender-side) Yes

|===

=== delay: Fixed-Delay Pipelines

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_delay With reset Yes
br_delay_nr Without reset Yes, but want to merge with br_delay (https://github.com/xlsynth/bedrock-rtl/issues/137)
br_delay_valid_next_nr With self-gating (valid-next) and without reset Yes, but want to merge with br_delay_valid_next (https://github.com/xlsynth/bedrock-rtl/issues/137)
br_delay_valid_next With self-gating (valid-next) Yes
br_delay_valid With self-gating (valid) Yes
br_delay_shift_reg Loadable shift register Yes

|===

=== demux: Simple Demultiplexers

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_demux_onehot One-hot demultiplexer Yes
br_demux_bin Binary-select demultiplexer Yes

|===

=== enc: Combinational encoders

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_enc_bin2gray Binary to gray Yes
br_enc_bin2onehot Binary to onehot Yes
br_enc_countones Count the number of ones in a vector Yes
br_enc_gray2bin Gray to binary Yes
br_enc_onehot2bin One-hot to binary Yes
br_enc_priority_encoder Priority encoder Yes

|===

=== ecc: Error Correcting Codes

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_ecc_secded_decoder Single-error-correcting, double-error-detecting (SECDED) decoder Yes
br_ecc_secded_encoder Single-error-correcting, double-error-detecting (SECDED) encoder Yes
br_ecc_sed_decoder Single-error-detecting (SED) decoder Yes
br_ecc_sed_encoder Single-error-detecting (SED) encoder Yes

|===

=== fifo: First-In-First-Out Queues

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

| br_fifo_ctrl_1r1w_bare a| FIFO controller with external RAM port for 1R1W

| br_fifo_ctrl_1r1w_pop_credit a| FIFO controller with external RAM port for 1R1W

| br_fifo_ctrl_1r1w_push_credit a| FIFO controller with external RAM port for 1R1W

| br_fifo_ctrl_1r1w a| FIFO controller with external RAM port for 1R1W

| br_fifo_flops_pop_credit a| FIFO with internal flop RAM

| br_fifo_flops_push_credit a| FIFO with internal flop RAM

| br_fifo_flops a| FIFO with internal flop RAM

|===

=== flow: Ready/Valid Flow Control

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_flow_arb_fixed Fixed priority arbiter Yes
br_flow_arb_lru Least-recently used arbiter Yes
br_flow_arb_rr Round-robin arbiter Yes
br_flow_demux_select Registered demultiplexer, external select Yes
br_flow_demux_select_unstable Combinational demultiplexer, external select, with unstable flow control Yes
br_flow_fork Datapath flow control split Yes
br_flow_join Datapath flow control join Yes
br_flow_mux_fixed Arbitrated multiplexer, fixed priority Yes
br_flow_mux_lru Arbitrated multiplexer, least-recently used Yes
br_flow_mux_rr Arbitrated multiplexer, round-robin Yes
br_flow_mux_select Registered multiplexer, user select Yes
br_flow_mux_select_unstable Combinational multiplexer, external select, with unstable flow control Yes
br_flow_reg_both Pipeline register, registered forward and reverse signals Yes
br_flow_reg_fwd Pipeline register, registered forward signals Yes
br_flow_reg_rev Pipeline register, registered backward signals Yes

|===

=== gate: Behavioral Gate Primitives

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_gate_buf Wire buffer/repeater Yes
br_gate_clk_buf Clock wire buffer/repeater Yes
br_gate_inv Inverter Yes
br_gate_and2 Two-input AND gate Yes
br_gate_or2 Two-input OR gate Yes
br_gate_xor2 Two-input XOR gate Yes
br_gate_mux2 Two-input multiplexer Yes
br_gate_clk_mux2 Two-input clock multiplexer Yes
br_gate_icg Integrated clock gate Yes

|===

=== misc: Miscellaneous

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

| br_misc_tieoff_one | Drive an expression to constant 1s and internally waive relevant lint rules | Yes | Yes

| br_misc_tieoff_zero | Drive an expression to constant 0s and internally waive relevant lint rules | Yes | Yes

| br_misc_unused | Sink an unused expression and internally waive relevant lint rules | Yes | Yes

|===

=== mux: Simple Multiplexers

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_mux_onehot One-hot multiplexer Yes
br_mux_bin Binary-select multiplexer Yes

|===

=== ram: Memories

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

br_ram_addr_decoder_tree Address decoder tree for a tiled RAM WIP
br_ram_addr_decoder Address decoder for a tiled RAM Yes
br_ram_flops_1r1w_tile One-tile flop-RAM with one read port and one write port Yes
br_ram_flops_1r1w Tiled flop-RAM with one read port and one write port Yes
br_ram_flops_1rw_tile One-tile flop-RAM with one port (shared for read and write)
br_ram_flops_1rw Tiled flop-RAM with one port (shared for read and write)
br_ram_data_rd_pipe Pipeline for reading data from a tiled RAM Yes

|===

=== timer: Saturating and Wrapping Timers

[cols="1,4,1,1"] |=== | Module | Description | Implemented | Verified

| br_timer_sat | Tick down from a threshold and saturate at zero; signal continuously at zero

| br_timer | Tick down from a threshold and signal a pulse every time when wrapping past zero

|===

== Packages

=== br_math: Non-synthesizable Math Helper Functions

[cols="1,4,1,1"] |=== | Function | Description | Implemented | Tested

| ceil_div | Return integer ceiling division | Yes | Yes

| floor_div | Return integer floor division | Yes | Yes

| clogb | Return integer ceiling of base-b logarithm where b is a power-of-2 | Yes | Yes

| is_power_of_2 | Return 1 if an integer is a power of 2 | Yes | Yes

| is_even | Return 1 if an integer is even | Yes | Yes

|===