From a3f25901b31393758224621cabe4beed8b187151 Mon Sep 17 00:00:00 2001 From: Florian Zaruba Date: Wed, 9 Jun 2021 17:19:52 +0200 Subject: [PATCH] Add `flushable_spill_register` (#119) * add flushable spill_register * make spill_register a wrapper of spill_register_flushable * fix dependency ordering of Bender.yml/src_files.yml * add sram to src_files (deprecated) * Adjust wrapper Co-authored-by: Georg Rutishauser --- Bender.yml | 9 +-- CHANGELOG.md | 8 +++ README.md | 113 ++++++++++++++++---------------- src/spill_register.sv | 84 +++++------------------- src/spill_register_flushable.sv | 105 +++++++++++++++++++++++++++++ src_files.yml | 12 ++-- 6 files changed, 200 insertions(+), 131 deletions(-) create mode 100644 src/spill_register_flushable.sv diff --git a/Bender.yml b/Bender.yml index d747608b..88727ca2 100644 --- a/Bender.yml +++ b/Bender.yml @@ -44,7 +44,7 @@ sources: - src/rstgen_bypass.sv - src/serial_deglitch.sv - src/shift_reg.sv - - src/spill_register.sv + - src/spill_register_flushable.sv - src/stream_demux.sv - src/stream_filter.sv - src/stream_fork.sv @@ -59,7 +59,6 @@ sources: - src/addr_decode.sv - src/cb_filter.sv - src/cdc_fifo_2phase.sv - - src/cdc_fifo_gray.sv - src/counter.sv - src/ecc_decode.sv - src/ecc_encode.sv @@ -67,19 +66,21 @@ sources: - src/lzc.sv - src/max_counter.sv - src/rstgen.sv + - src/spill_register.sv - src/stream_delay.sv - src/stream_fifo.sv - src/stream_fork_dynamic.sv - - src/stream_xbar.sv # Level 2 + - src/cdc_fifo_gray.sv - src/fall_through_register.sv - src/id_queue.sv - src/stream_to_mem.sv - src/stream_arbiter_flushable.sv - - src/stream_omega_net.sv - src/stream_register.sv + - src/stream_xbar.sv # Level 3 - src/stream_arbiter.sv + - src/stream_omega_net.sv - target: simulation files: diff --git a/CHANGELOG.md b/CHANGELOG.md index bf3cd4f7..87f9cc67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - `registers.svh`: Merge explicit and implicit register variants into `` `FF `` and `` `FFL `` macros +## 1.22.0 - 2021-06-09 +### Added +- Add `spill_register_flushable` + +### Changed +- `rr_arb_tree`: Allow flushing locked decision +- Improved `verific` compatibility + ## 1.21.0 - 2021-01-28 ### Changed - Remove `timeprecision/timeunit` arguments diff --git a/README.md b/README.md index 6ce1e9e1..e9a69784 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Please note that cells with status *deprecated* are not to be used for new desig ### Clocks and Resets -| Name | Description | Status | Superseded By | -|-------------------------|-----------------------------------------------------|--------------|---------------| +| Name | Description | Status | Superseded By | +| ----------------------- | --------------------------------------------------- | ------------ | ------------- | | `clk_div` | Clock divider with integer divisor | active | | | `clock_divider` | Clock divider with configuration registers | *deprecated* | `clk_div` | | `clock_divider_counter` | Clock divider using a counter | *deprecated* | `clk_div` | @@ -26,7 +26,7 @@ Please note that cells with status *deprecated* are not to be used for new desig ### Clock Domains and Asynchronous Crossings | Name | Description | Status | Superseded By | -|------------------------------|----------------------------------------------------------------------------------|--------------|---------------| +| ---------------------------- | -------------------------------------------------------------------------------- | ------------ | ------------- | | `cdc_2phase` | Clock domain crossing using two-phase handshake, with ready/valid interface | active | | | `cdc_fifo_2phase` | Clock domain crossing FIFO using two-phase handshake, with ready/valid interface | active | | | `cdc_fifo_gray` | Clock domain crossing FIFO using a gray-counter, with ready/valid interface | active | | @@ -43,8 +43,8 @@ Please note that cells with status *deprecated* are not to be used for new desig ### Counters and Shift Registers -| Name | Description | Status | Superseded By | -|---------------------|-------------------------------------------------------------------|--------------|---------------| +| Name | Description | Status | Superseded By | +| ------------------- | ----------------------------------------------------------------- | ------------ | ------------- | | `counter` | Generic up/down counter with overflow detection | active | | | `delta_counter` | Up/down counter with variable delta and overflow detection | active | | | `generic_LFSR_8bit` | 8-bit linear feedback shift register (LFSR) | *deprecated* | `lfsr_8bit` | @@ -56,52 +56,53 @@ Please note that cells with status *deprecated* are not to be used for new desig ### Data Path Elements -| Name | Description | Status | Superseded By | -|----------------------------|---------------------------------------------------------------------------------|--------------|---------------| -| `addr_decode ` | Address map decoder | active | | -| `ecc_decode` | SECDED Decoder (Single Error Correction, Double Error Detection) | active | | -| `ecc_encode` | SECDED Encoder (Single Error Correction, Double Error Detection) | active | | -| `binary_to_gray` | Binary to gray code converter | active | | -| `find_first_one` | Leading-one finder / leading-zero counter | *deprecated* | `lzc` | -| `gray_to_binary` | Gray code to binary converter | active | | -| `lzc` | Leading/trailing-zero counter | active | | -| `onehot_to_bin` | One-hot to binary converter | active | | -| `shift_reg` | Shift register for arbitrary types | active | | -| `rr_arb_tree` | Round-robin arbiter for req/gnt and vld/rdy interfaces with optional priority | active | | -| `rrarbiter` | Round-robin arbiter for req/ack interface with look-ahead | *deprecated* | `rr_arb_tree` | -| `prioarbiter` | Priority arbiter arbiter for req/ack interface with look-ahead | *deprecated* | `rr_arb_tree` | -| `fall_through_register` | Fall-through register with ready/valid interface | active | | -| `spill_register` | Register with ready/valid interface to cut all combinational interface paths | active | | -| `stream_arbiter` | Round-robin arbiter for ready/valid stream interface | active | | -| `stream_arbiter_flushable` | Round-robin arbiter for ready/valid stream interface and flush functionality | active | | -| `stream_demux` | Ready/valid interface demultiplexer | active | | -| `stream_join` | Ready/valid handshake join multiple to one common | active | | -| `stream_mux` | Ready/valid interface multiplexer | active | | -| `stream_register` | Register with ready/valid interface | active | | -| `stream_fork` | Ready/valid fork | active | | -| `stream_fork_dynamic` | Ready/valid fork, with selection mask for partial forking | active | | -| `stream_filter` | Ready/valid filter | active | | -| `stream_delay` | Randomize or delay ready/valid interface | active | | -| `stream_to_mem` | Use memories without flow control for output data in streams. | active | | -| `stream_xbar` | Fully connected crossbar with ready/valid interface. | active | | -| `stream_omega_net` | One-way stream omega-net with ready/valid interface. Isomorphic to a butterfly. | active | | -| `sub_per_hash` | Substitution-permutation hash function | active | | -| `popcount` | Combinatorial popcount (hamming weight) | active | | +| Name | Description | Status | Superseded By | +| -------------------------- | --------------------------------------------------------------------------------------------------------- | ------------ | ------------- | +| `addr_decode ` | Address map decoder | active | | +| `ecc_decode` | SECDED Decoder (Single Error Correction, Double Error Detection) | active | | +| `ecc_encode` | SECDED Encoder (Single Error Correction, Double Error Detection) | active | | +| `binary_to_gray` | Binary to gray code converter | active | | +| `find_first_one` | Leading-one finder / leading-zero counter | *deprecated* | `lzc` | +| `gray_to_binary` | Gray code to binary converter | active | | +| `lzc` | Leading/trailing-zero counter | active | | +| `onehot_to_bin` | One-hot to binary converter | active | | +| `shift_reg` | Shift register for arbitrary types | active | | +| `rr_arb_tree` | Round-robin arbiter for req/gnt and vld/rdy interfaces with optional priority | active | | +| `rrarbiter` | Round-robin arbiter for req/ack interface with look-ahead | *deprecated* | `rr_arb_tree` | +| `prioarbiter` | Priority arbiter arbiter for req/ack interface with look-ahead | *deprecated* | `rr_arb_tree` | +| `fall_through_register` | Fall-through register with ready/valid interface | active | | +| `spill_register_flushable` | Register with ready/valid interface to cut all combinational interface paths and additional flush signal. | active | | +| `spill_register` | Register with ready/valid interface to cut all combinational interface paths | active | | +| `stream_arbiter` | Round-robin arbiter for ready/valid stream interface | active | | +| `stream_arbiter_flushable` | Round-robin arbiter for ready/valid stream interface and flush functionality | active | | +| `stream_demux` | Ready/valid interface demultiplexer | active | | +| `stream_join` | Ready/valid handshake join multiple to one common | active | | +| `stream_mux` | Ready/valid interface multiplexer | active | | +| `stream_register` | Register with ready/valid interface | active | | +| `stream_fork` | Ready/valid fork | active | | +| `stream_fork_dynamic` | Ready/valid fork, with selection mask for partial forking | active | | +| `stream_filter` | Ready/valid filter | active | | +| `stream_delay` | Randomize or delay ready/valid interface | active | | +| `stream_to_mem` | Use memories without flow control for output data in streams. | active | | +| `stream_xbar` | Fully connected crossbar with ready/valid interface. | active | | +| `stream_omega_net` | One-way stream omega-net with ready/valid interface. Isomorphic to a butterfly. | active | | +| `sub_per_hash` | Substitution-permutation hash function | active | | +| `popcount` | Combinatorial popcount (hamming weight) | active | | ### Data Structures -| Name | Description | Status | Superseded By | -|----------------------|-------------------------------------------------|----------------|---------------| -| `cb_filter` | Counting-Bloom-Filter with combinational lookup | active | | -| `fifo` | FIFO register with upper threshold | *deprecated* | `fifo_v3` | -| `fifo_v2` | FIFO register with upper and lower threshold | *deprecated* | `fifo_v3` | -| `fifo_v3` | FIFO register with generic fill counts | active | | -| `stream_fifo` | FIFO register with ready/valid interface | active | | -| `generic_fifo` | FIFO register without thresholds | *deprecated* | `fifo_v3` | -| `generic_fifo_adv` | FIFO register without thresholds | *deprecated* | `fifo_v3` | -| `sram` | SRAM behavioral model | active | | -| `plru_tree` | Pseudo least recently used tree | active | | -| `unread` | Empty module to sink unconnected outputs into | active | | +| Name | Description | Status | Superseded By | +| ------------------ | ----------------------------------------------- | ------------ | ------------- | +| `cb_filter` | Counting-Bloom-Filter with combinational lookup | active | | +| `fifo` | FIFO register with upper threshold | *deprecated* | `fifo_v3` | +| `fifo_v2` | FIFO register with upper and lower threshold | *deprecated* | `fifo_v3` | +| `fifo_v3` | FIFO register with generic fill counts | active | | +| `stream_fifo` | FIFO register with ready/valid interface | active | | +| `generic_fifo` | FIFO register without thresholds | *deprecated* | `fifo_v3` | +| `generic_fifo_adv` | FIFO register without thresholds | *deprecated* | `fifo_v3` | +| `sram` | SRAM behavioral model | active | | +| `plru_tree` | Pseudo least recently used tree | active | | +| `unread` | Empty module to sink unconnected outputs into | active | | ## Header Contents @@ -142,8 +143,8 @@ easier to use them. They are identical with the macros used by [lowrisc](https:/ and just re-implemented here for the sake of easier use in PULP projects (the same include guard is used so they should not clash). #### Simple Assertion and Cover Macros -| Macro | Arguments | Description | -|--------------------|----------------------------------------|----------------------------------------------------------------------------| +| Macro | Arguments | Description | +| ----------------------------------------------------------- | -------------------------------------------------------------------------- | ----------- | | `` `ASSERT_I`` | `__name`, `__prop` | Immediate assertion | | `` `ASSERT_INIT`` | `__name`, `__prop` | Assertion in initial block. Can be used for things like parameter checking | | `` `ASSERT_FINAL`` | `__name`, `__prop` | Assertion in final block | @@ -154,8 +155,8 @@ and just re-implemented here for the sake of easier use in PULP projects (the sa - *The name of the clock and reset signals for implicit variants is `clk_i` and `rst_ni`, respectively.* #### Complex Assertion Macros -| Macro | Arguments | Description | -|-----------------------|----------------------------------------------------|---------------------------------------------------------------------------------------------------| +| Macro | Arguments | Description | +| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- | | `` `ASSERT_PULSE`` | `__name`, `__sig`, (`__clk`, `__rst`) | Assert that signal is an active-high pulse with pulse length of 1 clock cycle | | `` `ASSERT_IF`` | `__name`, `__prop`, `__enable`, (`__clk`, `__rst`) | Assert that a property is true only when an enable signal is set | | `` `ASSERT_KNOWN_IF`` | `__name`, `__sig`, `__enable`, (`__clk`, `__rst`) | Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is set | @@ -163,16 +164,16 @@ and just re-implemented here for the sake of easier use in PULP projects (the sa #### Assumption Macros -| Macro | Arguments | Description | -|----------------|----------------------------------------|------------------------------| +| Macro | Arguments | Description | +| ------------------------------------------------------- | ---------------------------- | ----------- | | `` `ASSUME`` | `__name`, `__prop`, (`__clk`, `__rst`) | Assume a concurrent property | | `` `ASSUME_I`` | `__name`, `__prop` | Assume an immediate property | - *The name of the clock and reset signals for implicit variants is `clk_i` and `rst_ni`, respectively.* #### Formal Verification Macros -| Macro | Arguments | Description | -|--------------------|----------------------------------------|--------------------------------------------------------------| +| Macro | Arguments | Description | +| ----------------------------------------------------------- | ------------------------------------------------------------ | ----------- | | `` `ASSUME_FPV`` | `__name`, `__prop`, (`__clk`, `__rst`) | Assume a concurrent property during formal verification only | | `` `ASSUME_I_FPV`` | `__name`, `__prop` | Assume a concurrent property during formal verification only | | `` `COVER_FPV`` | `__name`, `__prop`, (`__clk`, `__rst`) | Cover a concurrent property during formal verification | diff --git a/src/spill_register.sv b/src/spill_register.sv index d6f8d306..4fc0918b 100644 --- a/src/spill_register.sv +++ b/src/spill_register.sv @@ -12,15 +12,16 @@ // Fabian Schuiki -/// A register with handshakes that completely cuts any combinational paths -/// between the input and output. +/// Wrapper around the flushable spill register to maintain back-ward +/// compatibility. module spill_register #( parameter type T = logic, - parameter bit Bypass = 1'b0 // make this spill register transparent + parameter bit Bypass = 1'b0 // make this spill register transparent ) ( input logic clk_i , input logic rst_ni , input logic valid_i , + input logic flush_i , output logic ready_o , input T data_i , output logic valid_o , @@ -28,68 +29,19 @@ module spill_register #( output T data_o ); - if (Bypass) begin : gen_bypass - assign valid_o = valid_i; - assign ready_o = ready_i; - assign data_o = data_i; - end else begin : gen_spill_reg - // The A register. - T a_data_q; - logic a_full_q; - logic a_fill, a_drain; - logic a_en, a_en_data; + spill_register_flushable #( + .T(T), + .Bypass(Bypass) + ) spill_register_flushable_i ( + .clk_i, + .rst_ni, + .valid_i, + .flush_i(1'b0), + .ready_o, + .data_i, + .valid_o, + .ready_i, + .data_o + ); - always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_data - if (!rst_ni) - a_data_q <= '0; - else if (a_fill) - a_data_q <= data_i; - end - - always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_full - if (!rst_ni) - a_full_q <= 0; - else if (a_fill || a_drain) - a_full_q <= a_fill; - end - - // The B register. - T b_data_q; - logic b_full_q; - logic b_fill, b_drain; - - always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_data - if (!rst_ni) - b_data_q <= '0; - else if (b_fill) - b_data_q <= a_data_q; - end - - always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_full - if (!rst_ni) - b_full_q <= 0; - else if (b_fill || b_drain) - b_full_q <= b_fill; - end - - // Fill the A register when the A or B register is empty. Drain the A register - // whenever it is full and being filled. - assign a_fill = valid_i && ready_o; - assign a_drain = a_full_q && !b_full_q; - - // Fill the B register whenever the A register is drained, but the downstream - // circuit is not ready. Drain the B register whenever it is full and the - // downstream circuit is ready. - assign b_fill = a_drain && !ready_i; - assign b_drain = b_full_q && ready_i; - - // We can accept input as long as register B is not full. - assign ready_o = !a_full_q || !b_full_q; - - // The unit provides output as long as one of the registers is filled. - assign valid_o = a_full_q | b_full_q; - - // We empty the spill register before the slice register. - assign data_o = b_full_q ? b_data_q : a_data_q; - end endmodule diff --git a/src/spill_register_flushable.sv b/src/spill_register_flushable.sv new file mode 100644 index 00000000..c03ad274 --- /dev/null +++ b/src/spill_register_flushable.sv @@ -0,0 +1,105 @@ +// Copyright 2021 ETH Zurich and University of Bologna. +// +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. +// +// Fabian Schuiki + + +/// A register with handshakes that completely cuts any combinational paths +/// between the input and output. This spill register can be flushed. +module spill_register_flushable #( + parameter type T = logic, + parameter bit Bypass = 1'b0 // make this spill register transparent +) ( + input logic clk_i , + input logic rst_ni , + input logic valid_i , + input logic flush_i , + output logic ready_o , + input T data_i , + output logic valid_o , + input logic ready_i , + output T data_o +); + + if (Bypass) begin : gen_bypass + assign valid_o = valid_i; + assign ready_o = ready_i; + assign data_o = data_i; + end else begin : gen_spill_reg + // The A register. + T a_data_q; + logic a_full_q; + logic a_fill, a_drain; + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_data + if (!rst_ni) + a_data_q <= '0; + else if (a_fill) + a_data_q <= data_i; + end + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_full + if (!rst_ni) + a_full_q <= 0; + else if (a_fill || a_drain) + a_full_q <= a_fill; + end + + // The B register. + T b_data_q; + logic b_full_q; + logic b_fill, b_drain; + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_data + if (!rst_ni) + b_data_q <= '0; + else if (b_fill) + b_data_q <= a_data_q; + end + + always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_full + if (!rst_ni) + b_full_q <= 0; + else if (b_fill || b_drain) + b_full_q <= b_fill; + end + + // Fill the A register when the A or B register is empty. Drain the A register + // whenever it is full and being filled, or if a flush is requested. + assign a_fill = valid_i && ready_o && (!flush_i); + assign a_drain = (a_full_q && !b_full_q) || flush_i; + + // Fill the B register whenever the A register is drained, but the downstream + // circuit is not ready. Drain the B register whenever it is full and the + // downstream circuit is ready, or if a flush is requested. + assign b_fill = a_drain && (!ready_i) && (!flush_i); + assign b_drain = (b_full_q && ready_i) || flush_i; + + // We can accept input as long as register B is not full. + // Note: flush_i and valid_i must not be high at the same time, + // otherwise an invalid handshake may occur + assign ready_o = !a_full_q || !b_full_q; + + // The unit provides output as long as one of the registers is filled. + assign valid_o = a_full_q | b_full_q; + + // We empty the spill register before the slice register. + assign data_o = b_full_q ? b_data_q : a_data_q; + + // pragma translate_off + `ifndef VERILATOR + flush_valid : assert property ( + @(posedge clk_i) disable iff (~rst_ni) (flush_i |-> ~valid_i)) else + $warning("Trying to flush and feed the spill register simultaneously. You will lose data!"); + `endif + // pragma translate_on + end +endmodule diff --git a/src_files.yml b/src_files.yml index bdd673dc..a7b99aee 100644 --- a/src_files.yml +++ b/src_files.yml @@ -29,7 +29,7 @@ common_cells_all: - src/rstgen_bypass.sv - src/serial_deglitch.sv - src/shift_reg.sv - - src/spill_register.sv + - src/spill_register_flushable.sv - src/stream_demux.sv - src/stream_filter.sv - src/stream_fork.sv @@ -44,7 +44,6 @@ common_cells_all: - src/addr_decode.sv - src/cb_filter.sv - src/cdc_fifo_2phase.sv - - src/cdc_fifo_gray.sv - src/counter.sv - src/ecc_decode.sv - src/ecc_encode.sv @@ -52,21 +51,24 @@ common_cells_all: - src/lzc.sv - src/max_counter.sv - src/rstgen.sv + - src/spill_register.sv - src/stream_delay.sv - src/stream_fifo.sv - src/stream_fork_dynamic.sv - - src/stream_xbar.sv # Level 2 + - src/cdc_fifo_gray.sv - src/fall_through_register.sv - src/id_queue.sv - src/stream_to_mem.sv - src/stream_arbiter_flushable.sv - - src/stream_omega_net.sv - src/stream_register.sv + - src/stream_xbar.sv # Level 3 - src/stream_arbiter.sv + - src/stream_omega_net.sv # Deprecated modules # Level 0 + - src/deprecated/clock_divider.sv - src/deprecated/clock_divider_counter.sv - src/deprecated/find_first_one.sv - src/deprecated/generic_LFSR_8bit.sv @@ -74,7 +76,7 @@ common_cells_all: - src/deprecated/generic_fifo_adv.sv - src/deprecated/pulp_sync.sv - src/deprecated/pulp_sync_wedge.sv - - src/deprecated/clock_divider.sv + - src/deprecated/sram.sv # Level 1 - src/deprecated/fifo_v2.sv - src/deprecated/prioarbiter.sv