-
Notifications
You must be signed in to change notification settings - Fork 200
Expand file tree
/
Copy pathcc_lossy_valid_to_stream.sv
More file actions
133 lines (121 loc) · 5.59 KB
/
Copy pathcc_lossy_valid_to_stream.sv
File metadata and controls
133 lines (121 loc) · 5.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//-----------------------------------------------------------------------------
// Title : cc_lossy_valid_to_stream
// -----------------------------------------------------------------------------
// File : cc_lossy_valid_to_stream.sv Author : Manuel Eggimann
// <meggimann@iis.ee.ethz.ch> 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 cc_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
// -----------------------------------------------------------------------------
`include "common_cells/registers.svh"
module cc_lossy_valid_to_stream #(
/// Default data width if the fifo is of type logic
parameter int unsigned DataWidth = 32,
parameter type data_t = logic [DataWidth-1:0]
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic clr_i, // Synchronous clear active high
// Input Interface (the input is always ready so there is no ready_o signal)
input logic valid_i,
input data_t data_i,
// Output Interface
output logic valid_o,
input logic ready_i,
output data_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;
data_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
`FFARNC(read_ptr_q, read_ptr_d, clr_i, '0, clk_i, rst_ni)
`FFARNC(write_ptr_q, write_ptr_d, clr_i, '0, clk_i, rst_ni)
`FFARNC(pending_tx_counter_q, pending_tx_counter_d, clr_i, '0, clk_i, rst_ni)
`FFARNC(mem_q, mem_d, clr_i, {2{data_t'('0)}}, clk_i, rst_ni)
assign busy_o = pending_tx_counter_q != 0;
endmodule