Skip to content

Commit 71dc96f

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 <[email protected]>
1 parent b0e3b14 commit 71dc96f

File tree

1 file changed

+96
-14
lines changed

1 file changed

+96
-14
lines changed

library/util_axis_fifo_asym/util_axis_fifo_asym.v

Lines changed: 96 additions & 14 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;
@@ -146,6 +158,46 @@ module util_axis_fifo_asym #(
146158
// write or slave logic
147159
generate
148160

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

151203
for (i=0; i<RATIO; i=i+1) begin
@@ -205,12 +257,18 @@ module util_axis_fifo_asym #(
205257

206258
// FULL/ALMOST_FULL is driven by the current atomic instance
207259
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)
212260
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}}};
261+
262+
// FIFO room behavior relies on the TKEEP_EN parameter
263+
// When TKEEP_EN == 0, the FIFO has the same room as
264+
// the last atomic instance multiplied by RATIO. The
265+
// value of the room is only updated every RATIO reads.
266+
// s_axis_room == {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}}
267+
//
268+
// When TKEEP_EN == 1, it is using a counter whose decrement
269+
// relies on the tkeep.
270+
// s_axis_room == s_input_room
271+
assign s_axis_room = (TKEEP_EN) ? s_input_room : {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}};
214272

215273
end
216274

@@ -227,7 +285,7 @@ module util_axis_fifo_asym #(
227285
end
228286

229287
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) ;
288+
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
231289

232290
// VALID/EMPTY/ALMOST_EMPTY is driven by the current atomic instance
233291
assign m_axis_valid_int = m_axis_valid_int_s >> m_axis_counter;
@@ -244,13 +302,29 @@ module util_axis_fifo_asym #(
244302

245303
assign m_axis_tlast = m_axis_tlast_int_s >> m_axis_counter;
246304

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}}};
305+
// FIFO level behavior relies on the TKEEP_EN parameter
306+
// When TKEEP_EN == 0, the FIFO has the same level as
307+
// the last atomic instance multiplied by RATIO. The
308+
// value of the level is only updated every RATIO reads.
309+
// m_axis_level == {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}}
310+
//
311+
// When TKEEP_EN == 1, it is using a counter whose increment
312+
// relies on the tkeep.
313+
// m_axis_level == m_output_level
314+
assign m_axis_level = (TKEEP_EN) ? m_output_level : {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}};
251315
assign m_axis_almost_empty = m_axis_almost_empty_int_s[RATIO-1];
252316
assign m_axis_empty = m_axis_empty_int_s[RATIO-1];
253317

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

256330
for (i=0; i<RATIO; i=i+1) begin
@@ -260,14 +334,13 @@ module util_axis_fifo_asym #(
260334
for (i=0; i<RATIO; i=i+1) begin
261335
assign m_axis_tkeep[i*A_WIDTH/8+:A_WIDTH/8] = ((m_axis_tlast_int_s[i:0] == 0) ||
262336
(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}};
337+
m_axis_tkeep_int_s[i*A_WIDTH/8+:A_WIDTH/8] :
338+
{(A_WIDTH/8){1'b0}};
265339
end
266340

267341
assign m_axis_data = m_axis_data_int_s;
268342
// if every instance has a valid data, the interface has valid data,
269343
// 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;
271344
if (TLAST_EN) begin
272345
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;
273346
end else begin
@@ -285,12 +358,21 @@ module util_axis_fifo_asym #(
285358

286359
end
287360

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

290372
generate
291373
if (RATIO == 1) begin
292374
initial begin
293-
s_axis_counter = 1'b1;
375+
s_axis_counter = 1'b1; //s_axis_counter == 1 is never executed in small_slave
294376
end
295377
end else if (RATIO > 1) begin
296378
if (RATIO_TYPE) begin

0 commit comments

Comments
 (0)