1 # this file has been generated by sv2nmigen
3 from nmigen
import Signal
, Module
, Const
, Cat
, Elaboratable
6 class axi_buffer_rab_bram(Elaboratable
):
9 self
.clk
= Signal() # input
10 self
.rstn
= Signal() # input
11 self
.data_out
= Signal(DATA_WIDTH
) # output
12 self
.valid_out
= Signal() # output
13 self
.ready_in
= Signal() # input
14 self
.valid_in
= Signal() # input
15 self
.data_in
= Signal(DATA_WIDTH
) # input
16 self
.ready_out
= Signal() # output
17 self
.almost_full
= Signal() # output
18 self
.underfull
= Signal() # output
19 self
.drop_req
= Signal() # input
20 self
.drop_len
= Signal(8) # input
22 def elaborate(self
, platform
=None):
27 # // Copyright 2018 ETH Zurich and University of Bologna.
28 # // Copyright and related rights are licensed under the Solderpad Hardware
29 # // License, Version 0.51 (the "License"); you may not use this file except in
30 # // compliance with the License. You may obtain a copy of the License at
31 # // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
32 # // or agreed to in writing, software, hardware and materials distributed under
33 # // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
34 # // CONDITIONS OF ANY KIND, either express or implied. See the License for the
35 # // specific language governing permissions and limitations under the License.
37 # ////import CfMath::log2;
39 # module axi_buffer_rab_bram
41 # // parameter DATA_WIDTH,
42 # // parameter BUFFER_DEPTH
49 # output logic [DATA_WIDTH-1:0] data_out,
50 # output logic valid_out,
51 # input logic ready_in,
54 # input logic valid_in,
55 # input logic [DATA_WIDTH-1:0] data_in,
56 # output logic ready_out,
58 # // Status and drop control
59 # output logic almost_full,
60 # output logic underfull,
61 # input logic drop_req,
62 # // Number of items to drop. As for AXI lengths, counting starts at zero, i.e., `drop_len == 0`
63 # // and `drop_req` means drop one item.
64 # input logic [7:0] drop_len
68 // The BRAM needs to be in "write-first" mode for first-word fall-through FIFO behavior.
69 // To still push and pop simultaneously if the buffer is full, we internally increase the
71 localparam ACT_BUFFER_DEPTH = BUFFER_DEPTH+1;
72 localparam ACT_LOG_BUFFER_DEPTH = log2(ACT_BUFFER_DEPTH+1);
75 * Internal data structures
77 // Location to which we last wrote
78 logic [ACT_LOG_BUFFER_DEPTH-1:0] ptr_in_d, ptr_in_q;
79 // Location from which we last sent
80 logic [ACT_LOG_BUFFER_DEPTH-1:0] ptr_out_d, ptr_out_q;
81 // Required for fall-through behavior on the first word
82 logic [ACT_LOG_BUFFER_DEPTH-1:0] ptr_out_bram;
83 // Number of elements in the buffer. Can be negative if elements that have been dropped have not
85 logic signed [ACT_LOG_BUFFER_DEPTH:0] n_elems_d, n_elems_q;
87 logic [DATA_WIDTH-1:0] data_out_bram, data_out_q;
92 assign almost_full = (n_elems_q == BUFFER_DEPTH-1);
93 assign full = (n_elems_q == BUFFER_DEPTH);
95 always_ff @(posedge clk, negedge rstn) begin
101 n_elems_q <= n_elems_d;
102 ptr_in_q <= ptr_in_d;
103 ptr_out_q <= ptr_out_d;
107 // Update the number of elements.
109 n_elems_d = n_elems_q;
111 n_elems_d -= (drop_len + 1);
113 if (valid_in && ready_out) begin
116 if (valid_out && ready_in) begin
121 // Update the output pointer.
123 ptr_out_d = ptr_out_q;
125 if ((ptr_out_q + drop_len + 1) > (ACT_BUFFER_DEPTH - 1)) begin
126 ptr_out_d = drop_len + 1 - (ACT_BUFFER_DEPTH - ptr_out_q);
128 ptr_out_d += (drop_len + 1);
131 if (valid_out && ready_in) begin
132 if (ptr_out_d == (ACT_BUFFER_DEPTH - 1)) begin
140 // The BRAM has a read latency of one cycle, so apply the new address one cycle earlier for
141 // first-word fall-through FIFO behavior.
142 //assign ptr_out_bram = (ptr_out_q == (ACT_BUFFER_DEPTH-1)) ? '0 : (ptr_out_q + 1);
143 assign ptr_out_bram = ptr_out_d;
145 // Update the input pointer.
148 if (valid_in && ready_out) begin
149 if (ptr_in_d == (ACT_BUFFER_DEPTH - 1)) begin
157 // Update output ports.
158 assign valid_out = (n_elems_q > $signed(0));
159 assign underfull = (n_elems_q < $signed(0));
160 assign ready_out = ~full;
162 ram_tp_write_first #(
163 .ADDR_WIDTH ( ACT_LOG_BUFFER_DEPTH ),
164 .DATA_WIDTH ( DATA_WIDTH )
169 .we ( valid_in & ~full ),
171 .addr1 ( ptr_out_bram ),
174 .d1_o ( data_out_bram )
177 // When reading from/writing two the same address on both ports ("Write-Read Collision"),
178 // the data on the read port is invalid (during the write cycle). In this implementation,
179 // this can happen only when the buffer is empty. Thus, we forward the data from an
180 // register in this case.
181 always @(posedge clk) begin
182 if (rstn == 1'b0) begin
184 end else if ( (ptr_out_bram == ptr_in_q) && (valid_in && !full) ) begin
185 data_out_q <= data_in;
189 always @(posedge clk) begin
190 if (rstn == 1'b0) begin
193 valid_out_q <= valid_out;
199 if (valid_out && !valid_out_q) begin // We have just written to an empty FIFO
200 data_out = data_out_q;
202 data_out = data_out_bram;