Skip to content

Commit cad7bd5

Browse files
committed
library/util_axis_fifo_asym: fix room and level signals
ROOM and LEVEL signals are incorrect when there is an imbalance between the size of the input and output and TKEEP_EN == 1. This commit fixes this issue by inserting two counters, which are better for timing than performing a sum reduce ROOM and LEVEL of the internal symmetrical FIFOs Signed-off-by: Carlos Souza <carlos.souza@analog.com>
1 parent b0e3b14 commit cad7bd5

File tree

1 file changed

+97
-16
lines changed

1 file changed

+97
-16
lines changed

library/util_axis_fifo_asym/util_axis_fifo_asym.v

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ module util_axis_fifo_asym #(
8585
reg [$clog2(RATIO)-1:0] s_axis_counter;
8686
reg [$clog2(RATIO)-1:0] m_axis_counter;
8787

88+
// FIFO level signals
89+
reg s_axis_ready_d;
90+
reg s_axis_valid_d;
91+
reg [ 2:0] word_counter;
92+
reg [ 2:0] num_of_words;
93+
reg [ADDRESS_WIDTH-1:0] s_input_level;
94+
reg [ADDRESS_WIDTH-1:0] s_input_room;
95+
reg [ADDRESS_WIDTH-1:0] s_input_level_next;
96+
reg [ADDRESS_WIDTH-1:0] s_input_room_next;
97+
wire [ADDRESS_WIDTH-1:0] m_output_level;
98+
wire sdi_output_read_sync;
99+
88100
wire [RATIO-1:0] m_axis_ready_int_s;
89101
wire [RATIO-1:0] m_axis_valid_int_s;
90102
wire [RATIO*A_WIDTH-1:0] m_axis_data_int_s;
@@ -117,8 +129,7 @@ module util_axis_fifo_asym #(
117129
.ALMOST_EMPTY_THRESHOLD (A_ALMOST_EMPTY_THRESHOLD),
118130
.ALMOST_FULL_THRESHOLD (A_ALMOST_FULL_THRESHOLD),
119131
.TKEEP_EN (TKEEP_EN),
120-
.TLAST_EN (TLAST_EN),
121-
.REMOVE_NULL_BEAT_EN(0)
132+
.TLAST_EN (TLAST_EN)
122133
) i_fifo (
123134
.m_axis_aclk (m_axis_aclk),
124135
.m_axis_aresetn (m_axis_aresetn),
@@ -146,6 +157,46 @@ module util_axis_fifo_asym #(
146157
// write or slave logic
147158
generate
148159

160+
integer j;
161+
always @(posedge s_axis_aclk) begin
162+
if (!s_axis_aresetn) begin
163+
num_of_words <= 1;
164+
s_axis_ready_d <= 0;
165+
s_axis_valid_d <= 0;
166+
end else begin
167+
s_axis_ready_d <= s_axis_ready;
168+
s_axis_valid_d <= s_axis_valid;
169+
word_counter = 0;
170+
for (j = 0; j < RATIO; j = j + 1) begin
171+
word_counter = word_counter + (|s_axis_tkeep[M_DATA_WIDTH/8*j+:M_DATA_WIDTH/8]);
172+
end
173+
num_of_words <= word_counter;
174+
end
175+
end
176+
177+
always @(posedge s_axis_aclk) begin
178+
if (!s_axis_aresetn) begin
179+
s_input_level <= 0;
180+
s_input_room <= {ADDRESS_WIDTH{1'b1}};
181+
end else begin
182+
s_input_room <= s_input_room_next;
183+
s_input_level <= s_input_level_next;
184+
end
185+
end
186+
187+
always @(*) begin
188+
s_input_level_next = s_input_level;
189+
s_input_room_next = s_input_room;
190+
if (s_axis_ready_d && s_axis_valid_d) begin
191+
s_input_level_next = s_input_level_next + num_of_words;
192+
s_input_room_next = s_input_room_next - 1;
193+
end
194+
if (sdi_output_read_sync) begin
195+
s_input_level_next = s_input_level_next - 1;
196+
s_input_room_next = s_input_room_next + num_of_words;
197+
end
198+
end
199+
149200
if (RATIO_TYPE) begin : big_slave
150201

151202
for (i=0; i<RATIO; i=i+1) begin
@@ -205,12 +256,18 @@ module util_axis_fifo_asym #(
205256

206257
// FULL/ALMOST_FULL is driven by the current atomic instance
207258
assign s_axis_almost_full = s_axis_almost_full_int_s >> s_axis_counter;
208-
209-
// the FIFO has the same room as the last atomic instance
210-
// (NOTE: this is not the real room value, rather the value will be updated
211-
// after every RATIO number of writes)
212259
assign s_axis_full = s_axis_full_int_s[RATIO-1];
213-
assign s_axis_room = {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}};
260+
261+
// FIFO room behavior relies on the TKEEP_EN parameter
262+
// When TKEEP_EN == 0, the FIFO has the same room as
263+
// the last atomic instance multiplied by RATIO. The
264+
// value of the room is only updated every RATIO reads.
265+
// s_axis_room == {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}}
266+
//
267+
// When TKEEP_EN == 1, it is using a counter whose decrement
268+
// relies on the tkeep.
269+
// s_axis_room == s_input_room
270+
assign s_axis_room = (TKEEP_EN) ? s_input_room : {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}};
214271

215272
end
216273

@@ -227,7 +284,7 @@ module util_axis_fifo_asym #(
227284
end
228285

229286
assign m_axis_data = m_axis_data_int_s >> (m_axis_counter*A_WIDTH) ;
230-
assign m_axis_tkeep = m_axis_tkeep_int_s >> (m_axis_counter*A_WIDTH/8) ;
287+
assign m_axis_tkeep = m_axis_tkeep_int_s >> (m_axis_counter*A_WIDTH/8); //m_axis_tkeep is always high when TKEEP_EN == 0
231288

232289
// VALID/EMPTY/ALMOST_EMPTY is driven by the current atomic instance
233290
assign m_axis_valid_int = m_axis_valid_int_s >> m_axis_counter;
@@ -244,13 +301,29 @@ module util_axis_fifo_asym #(
244301

245302
assign m_axis_tlast = m_axis_tlast_int_s >> m_axis_counter;
246303

247-
// the FIFO has the same level as the last atomic instance
248-
// (NOTE: this is not the real level value, rather the value will be updated
249-
// after every RATIO number of reads)
250-
assign m_axis_level = {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}};
304+
// FIFO level behavior relies on the TKEEP_EN parameter
305+
// When TKEEP_EN == 0, the FIFO has the same level as
306+
// the last atomic instance multiplied by RATIO. The
307+
// value of the level is only updated every RATIO reads.
308+
// m_axis_level == {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}}
309+
//
310+
// When TKEEP_EN == 1, it is using a counter whose increment
311+
// relies on the tkeep.
312+
// m_axis_level == m_output_level
313+
assign m_axis_level = (TKEEP_EN) ? m_output_level : {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}};
251314
assign m_axis_almost_empty = m_axis_almost_empty_int_s[RATIO-1];
252315
assign m_axis_empty = m_axis_empty_int_s[RATIO-1];
253316

317+
sync_data #(
318+
.NUM_OF_BITS (ADDRESS_WIDTH),
319+
.ASYNC_CLK (ASYNC_CLK)
320+
) i_sdi_level_sync (
321+
.in_clk (s_axis_aclk),
322+
.in_data (s_input_level),
323+
.out_clk (m_axis_aclk),
324+
.out_data (m_output_level)
325+
);
326+
254327
end else begin : big_master
255328

256329
for (i=0; i<RATIO; i=i+1) begin
@@ -260,14 +333,13 @@ module util_axis_fifo_asym #(
260333
for (i=0; i<RATIO; i=i+1) begin
261334
assign m_axis_tkeep[i*A_WIDTH/8+:A_WIDTH/8] = ((m_axis_tlast_int_s[i:0] == 0) ||
262335
(m_axis_tlast_int_s[i])) ?
263-
m_axis_tkeep_int_s[i*A_WIDTH/8+:A_WIDTH/8] :
264-
{(A_WIDTH/8){1'b0}};
336+
m_axis_tkeep_int_s[i*A_WIDTH/8+:A_WIDTH/8] :
337+
{(A_WIDTH/8){1'b0}};
265338
end
266339

267340
assign m_axis_data = m_axis_data_int_s;
268341
// if every instance has a valid data, the interface has valid data,
269342
// otherwise valid is asserted only if TLAST is asserted
270-
// assign m_axis_valid_int = (|(m_axis_tlast_int_s & m_axis_valid_int_s)) ? |m_axis_valid_int_s : &m_axis_valid_int_s;
271343
if (TLAST_EN) begin
272344
assign m_axis_valid_int = (|(m_axis_tlast_int_s & m_axis_valid_int_s)) ? |m_axis_valid_int_s : &m_axis_valid_int_s;
273345
end else begin
@@ -285,12 +357,21 @@ module util_axis_fifo_asym #(
285357

286358
end
287359

360+
sync_event #(
361+
.NUM_OF_EVENTS (1),
362+
.ASYNC_CLK (ASYNC_CLK)
363+
) i_sdi_output_read_sync (
364+
.in_clk (m_axis_aclk),
365+
.in_event (m_axis_ready & m_axis_valid),
366+
.out_clk (s_axis_aclk),
367+
.out_event (sdi_output_read_sync));
368+
288369
endgenerate
289370

290371
generate
291372
if (RATIO == 1) begin
292373
initial begin
293-
s_axis_counter = 1'b1;
374+
s_axis_counter = 1'b1; //s_axis_counter == 1 is never executed in small_slave
294375
end
295376
end else if (RATIO > 1) begin
296377
if (RATIO_TYPE) begin

0 commit comments

Comments
 (0)