-
Notifications
You must be signed in to change notification settings - Fork 188
Lossy valid to stream #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| //----------------------------------------------------------------------------- | ||
| // Title : lossy_valid_to_stream | ||
| // ----------------------------------------------------------------------------- | ||
| // File : lossy_valid_to_stream.sv Author : Manuel Eggimann | ||
| // <[email protected]> Created : 17.05.2023 | ||
| // ----------------------------------------------------------------------------- | ||
| // Description : | ||
| // | ||
| // This module helps to deal with sources that use a valid-only interface, that | ||
| // is they do not support backpressure i.e. cannot handle the case where the | ||
| // sink is not ready to accept a value. The module is implemented as FIFO with 2 | ||
| // elements. In contrast to a regular FIFO that stops accepting new transactions | ||
| // once the FIFO is full, this IP overwrites the last element entered into the | ||
| // FIFO. This means the input is always ready to accept new transactions, | ||
| // however, intermediate transactions might be overwritten by the latest one. On | ||
| // the output side, the module behaves like a regular ready-valid source i.e. | ||
| // once valid is asserted, data_o remains stable until the sink consumes them | ||
| // (by asserting ready_i). | ||
|
|
||
| // IMPORTANT: As the name implies, this module might drop intermediate | ||
| // transactions if the input generates transactions faster than the sink can | ||
| // consume them. The input side can check if the last transaction was | ||
| // successfully comitted to the output by checking the | ||
| // busy_o signal. If it is de-asserted (low), there are no | ||
| // more outstanding transactions and the most recent value presented at the | ||
| // input side has been comitted to the output. | ||
| // | ||
| // | ||
| // The lossy_valid_to_stream module is helpful to connect configuration registers with | ||
| // IPs that could cause back pressure. In this case we might not care how long | ||
| // it takes for the config value to be sent to the IP but if we change the | ||
| // config value we want the latest value to be used regardless whether the | ||
| // previous value has already been forwarded or not. | ||
| // | ||
| // | ||
| //----------------------------------------------------------------------------- | ||
| // Copyright (C) 2023 ETH Zurich, 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. | ||
| // SPDX-License-Identifier: SHL-0.51 | ||
| // ----------------------------------------------------------------------------- | ||
|
|
||
| module lossy_valid_to_stream #( | ||
| /// Default data width if the fifo is of type logic | ||
| parameter int unsigned DATA_WIDTH = 32, | ||
| parameter type T = logic [DATA_WIDTH-1:0] | ||
| ) ( | ||
| input logic clk_i, | ||
| input logic rst_ni, | ||
| // Input Interface (the input is always ready so there is no ready_o signal) | ||
| input logic valid_i, | ||
| input T data_i, | ||
| // Output Interface | ||
| output logic valid_o, | ||
| input logic ready_i, | ||
| output T data_o, | ||
| // Status port | ||
| output busy_o | ||
| ); | ||
|
|
||
| // Implement a FIFO with depth == 2 where the write logic can overwrite the | ||
| // last element. | ||
|
|
||
| logic read_ptr_d, read_ptr_q; | ||
| logic write_ptr_d, write_ptr_q; | ||
| logic [1:0] pending_tx_counter_d, pending_tx_counter_q; | ||
| T[1:0] mem_d, mem_q; | ||
|
|
||
| assign valid_o = pending_tx_counter_q != 0 || valid_i; | ||
|
|
||
| always_comb begin : write_logic | ||
| write_ptr_d = write_ptr_q; | ||
| mem_d = mem_q; | ||
| if (valid_i) begin | ||
| // If the FIFO is empty and the output is currently ready, fall through | ||
| // the FIFO and don't update anything | ||
| if (pending_tx_counter_q != 0 || !ready_i) begin | ||
| // If the FIFO is full and the output is still stalling, update the | ||
| // previous element instead of writing a new one and do not update the | ||
| // write pointer | ||
| if (pending_tx_counter_q == 2 && !ready_i) begin | ||
| mem_d[write_ptr_q - 1'b1] = data_i; | ||
| end else begin | ||
| mem_d[write_ptr_q] = data_i; | ||
| write_ptr_d = write_ptr_q + 1'b1; | ||
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| always_comb begin : read_logic | ||
| read_ptr_d = read_ptr_q; | ||
| data_o = mem_q[read_ptr_q]; | ||
| // Handle the fall-through case | ||
| if (pending_tx_counter_q == 0 && valid_i) begin | ||
| data_o = data_i; | ||
| end else if (valid_o && ready_i) begin | ||
| read_ptr_d = read_ptr_q + 1'b1; | ||
| end | ||
| end | ||
|
|
||
| always_comb begin: count_transactions | ||
| pending_tx_counter_d = pending_tx_counter_q; | ||
| if (valid_i && valid_o && ready_i) begin | ||
| pending_tx_counter_d = pending_tx_counter_q; | ||
| end else if (valid_i && !(valid_o && ready_i)) begin | ||
| // If the FIFO is already full, do not update the counter | ||
| if (pending_tx_counter_q != 2) begin | ||
| pending_tx_counter_d = pending_tx_counter_q + 1'b1; | ||
| end | ||
| end else if (!valid_i && (valid_o && ready_i)) begin | ||
| pending_tx_counter_d = pending_tx_counter_q - 1'b1; | ||
| end | ||
| end | ||
|
|
||
| // Registers | ||
| always_ff @(posedge clk_i, negedge rst_ni) begin | ||
| if (!rst_ni) begin | ||
| read_ptr_q <= '0; | ||
| write_ptr_q <= '0; | ||
| pending_tx_counter_q <= '0; | ||
| mem_q <= '0; | ||
| end else begin | ||
| read_ptr_q <= read_ptr_d; | ||
| write_ptr_q <= write_ptr_d; | ||
| pending_tx_counter_q <= pending_tx_counter_d; | ||
| mem_q <= mem_d; | ||
| end | ||
| end | ||
|
|
||
| assign busy_o = pending_tx_counter_q != 0; | ||
|
|
||
| endmodule | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| //----------------------------------------------------------------------------- | ||
| // Copyright (C) 2023 ETH Zurich, 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. | ||
| // SPDX-License-Identifier: SHL-0.51 | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| // Author: Manuel Eggimann <[email protected]> | ||
|
|
||
| module lossy_valid_to_stream_tb #( | ||
| /// Theu number of requests to simulate | ||
| parameter int unsigned NumReq = 32'd10000, | ||
| /// Clock cycle time. | ||
| parameter time CyclTime = 20ns | ||
| ); | ||
|
|
||
| logic clk; | ||
| logic rst_n; | ||
|
|
||
| localparam type payload_t = logic [$clog2(NumReq)-1:0]; | ||
|
|
||
|
|
||
|
|
||
| // clock generator | ||
| clk_rst_gen #( | ||
| .ClkPeriod (CyclTime), | ||
| .RstClkCycles(5) | ||
| ) i_clk_rst_gen ( | ||
| .clk_o (clk), | ||
| .rst_no(rst_n) | ||
| ); | ||
|
|
||
| typedef stream_test::stream_driver#( | ||
| .payload_t(payload_t), | ||
| .TA(CyclTime * 0.2), | ||
| .TT(CyclTime * 0.8) | ||
| ) stream_driver_in_t; | ||
|
|
||
| STREAM_DV #(.payload_t(payload_t)) dut_in (.clk_i(clk)); | ||
| stream_driver_in_t stream_source = new(dut_in); | ||
|
|
||
| typedef stream_test::stream_driver#( | ||
| .payload_t(payload_t), | ||
| .TA(CyclTime * 0.2), | ||
| .TT(CyclTime * 0.8) | ||
| ) stream_driver_out_t; | ||
| STREAM_DV #(.payload_t(payload_t)) dut_out (.clk_i(clk)); | ||
| stream_driver_out_t stream_sink = new(dut_out); | ||
|
|
||
|
|
||
| payload_t payload_queue[$]; | ||
| logic is_busy; | ||
|
|
||
| assign dut_in.ready = 1'b1; | ||
| lossy_valid_to_stream #( | ||
| .T(payload_t) | ||
| ) i_lossy_valid_to_stream ( | ||
| .clk_i (clk), | ||
| .rst_ni (rst_n), | ||
| .valid_i(dut_in.valid), | ||
| .data_i (dut_in.data), | ||
| .data_o (dut_out.data), | ||
| .valid_o(dut_out.valid), | ||
| .ready_i(dut_out.ready), | ||
| .busy_o(is_busy) | ||
| ); | ||
|
|
||
| initial begin : apply_stimuli | ||
| automatic int unsigned wait_cycl; | ||
|
|
||
| @(posedge rst_n); | ||
| stream_source.reset_in(); | ||
| for (int i = 0; i < NumReq; i++) begin | ||
| wait_cycl = $urandom_range(0, 5); | ||
| repeat (wait_cycl) @(posedge clk); | ||
| stream_source.send(i); | ||
| if (payload_queue.size() == 2 && !dut_out.ready) | ||
| payload_queue[0] = i; | ||
| else | ||
| payload_queue.push_front(i); | ||
| end | ||
| $stop(); | ||
| end | ||
|
|
||
| initial begin : receive_responses | ||
| automatic payload_t data; | ||
| automatic payload_t expected_data; | ||
| automatic int unsigned wait_cycl; | ||
| @(posedge rst_n); | ||
| stream_sink.reset_out(); | ||
| forever begin | ||
| wait_cycl = $urandom_range(0, 5); | ||
| repeat (wait_cycl) @(posedge clk); | ||
| stream_sink.recv(data); | ||
| assert (payload_queue.size() > 0) else | ||
| $error("Receieved transaction at output even though the input side did not send any new data."); | ||
| expected_data = payload_queue.pop_back(); | ||
| assert (data == expected_data) else | ||
| $error("Received the wrong data.x Was %d instead of %d", data, expected_data); | ||
| end | ||
| end | ||
|
|
||
| endmodule |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed it is. That was a voluntarily decision to make the three cases (push, pop and simultaneous push and pop) a bit more clear in the code.