Skip to content

Commit b4e690a

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 b4e15c4 commit b4e690a

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
@@ -210,12 +262,18 @@ module util_axis_fifo_asym #(
210262

211263
// FULL/ALMOST_FULL is driven by the current atomic instance
212264
assign s_axis_almost_full = s_axis_almost_full_int_s >> s_axis_counter;
213-
214-
// the FIFO has the same room as the last atomic instance
215-
// (NOTE: this is not the real room value, rather the value will be updated
216-
// after every RATIO number of writes)
217265
assign s_axis_full = s_axis_full_int_s[RATIO-1];
218-
assign s_axis_room = {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}};
266+
267+
// FIFO room behavior relies on the TKEEP_EN parameter
268+
// When TKEEP_EN == 0, the FIFO has the same room as
269+
// the last atomic instance multiplied by RATIO. The
270+
// value of the room is only updated every RATIO reads.
271+
// s_axis_room == {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}}
272+
//
273+
// When TKEEP_EN == 1, it is using a counter whose decrement
274+
// relies on the tkeep.
275+
// s_axis_room == s_input_room
276+
assign s_axis_room = (TKEEP_EN) ? s_input_room : {s_axis_room_int_s[A_ADDRESS*(RATIO-1)+:A_ADDRESS], {$clog2(RATIO){1'b1}}};
219277

220278
end
221279

@@ -232,7 +290,7 @@ module util_axis_fifo_asym #(
232290
end
233291

234292
assign m_axis_data = m_axis_data_int_s >> (m_axis_counter*A_WIDTH) ;
235-
assign m_axis_tkeep = m_axis_tkeep_int_s >> (m_axis_counter*A_WIDTH/8) ;
293+
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
236294

237295
// VALID/EMPTY/ALMOST_EMPTY is driven by the current atomic instance
238296
assign m_axis_valid_int = m_axis_valid_int_s >> m_axis_counter;
@@ -249,13 +307,29 @@ module util_axis_fifo_asym #(
249307

250308
assign m_axis_tlast = m_axis_tlast_int_s >> m_axis_counter;
251309

252-
// the FIFO has the same level as the last atomic instance
253-
// (NOTE: this is not the real level value, rather the value will be updated
254-
// after every RATIO number of reads)
255-
assign m_axis_level = {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}};
310+
// FIFO level behavior relies on the TKEEP_EN parameter
311+
// When TKEEP_EN == 0, the FIFO has the same level as
312+
// the last atomic instance multiplied by RATIO. The
313+
// value of the level is only updated every RATIO reads.
314+
// m_axis_level == {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}}
315+
//
316+
// When TKEEP_EN == 1, it is using a counter whose increment
317+
// relies on the tkeep.
318+
// m_axis_level == m_output_level
319+
assign m_axis_level = (TKEEP_EN) ? m_output_level : {m_axis_level_int_s[A_ADDRESS-1:0], {$clog2(RATIO){1'b0}}};
256320
assign m_axis_almost_empty = m_axis_almost_empty_int_s[RATIO-1];
257321
assign m_axis_empty = m_axis_empty_int_s[RATIO-1];
258322

323+
sync_data #(
324+
.NUM_OF_BITS (ADDRESS_WIDTH),
325+
.ASYNC_CLK (ASYNC_CLK)
326+
) i_sdi_level_sync (
327+
.in_clk (s_axis_aclk),
328+
.in_data (s_input_level),
329+
.out_clk (m_axis_aclk),
330+
.out_data (m_output_level)
331+
);
332+
259333
end else begin : big_master
260334

261335
for (i=0; i<RATIO; i=i+1) begin
@@ -265,14 +339,13 @@ module util_axis_fifo_asym #(
265339
for (i=0; i<RATIO; i=i+1) begin
266340
assign m_axis_tkeep[i*A_WIDTH/8+:A_WIDTH/8] = ((m_axis_tlast_int_s[i:0] == 0) ||
267341
(m_axis_tlast_int_s[i])) ?
268-
m_axis_tkeep_int_s[i*A_WIDTH/8+:A_WIDTH/8] :
269-
{(A_WIDTH/8){1'b0}};
342+
m_axis_tkeep_int_s[i*A_WIDTH/8+:A_WIDTH/8] :
343+
{(A_WIDTH/8){1'b0}};
270344
end
271345

272346
assign m_axis_data = m_axis_data_int_s;
273347
// if every instance has a valid data, the interface has valid data,
274348
// otherwise valid is asserted only if TLAST is asserted
275-
// 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;
276349
if (TLAST_EN) begin
277350
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;
278351
end else begin
@@ -290,12 +363,21 @@ module util_axis_fifo_asym #(
290363

291364
end
292365

366+
sync_event #(
367+
.NUM_OF_EVENTS (1),
368+
.ASYNC_CLK (ASYNC_CLK)
369+
) i_sdi_output_read_sync (
370+
.in_clk (m_axis_aclk),
371+
.in_event (m_axis_ready & m_axis_valid),
372+
.out_clk (s_axis_aclk),
373+
.out_event (sdi_output_read_sync));
374+
293375
endgenerate
294376

295377
generate
296378
if (RATIO == 1) begin
297379
initial begin
298-
s_axis_counter = 1'b1;
380+
s_axis_counter = 1'b1; //s_axis_counter == 1 is never executed in small_slave
299381
end
300382
end else if (RATIO > 1) begin
301383
if (RATIO_TYPE) begin

0 commit comments

Comments
 (0)