Skip to content

Commit 7823b91

Browse files
committed
Implement MARK_WHEN_FULL option in FIFOs
Signed-off-by: Alex Forencich <[email protected]>
1 parent 6020d09 commit 7823b91

File tree

12 files changed

+232
-49
lines changed

12 files changed

+232
-49
lines changed

rtl/axis_async_fifo.v

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ module axis_async_fifo #
8181
// When set, s_axis_tready is always asserted
8282
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
8383
parameter DROP_WHEN_FULL = 0,
84+
// Mark incoming frames as bad frames when full
85+
// When set, s_axis_tready is always asserted
86+
// Requires FRAME_FIFO to be clear
87+
parameter MARK_WHEN_FULL = 0,
8488
// Enable pause request input
8589
parameter PAUSE_ENABLE = 0,
8690
// Pause between frames
@@ -164,10 +168,20 @@ initial begin
164168
$finish;
165169
end
166170

167-
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
171+
if ((DROP_BAD_FRAME || MARK_WHEN_FULL) && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
168172
$error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)");
169173
$finish;
170174
end
175+
176+
if (MARK_WHEN_FULL && FRAME_FIFO) begin
177+
$error("Error: MARK_WHEN_FULL is not compatible with FRAME_FIFO (instance %m)");
178+
$finish;
179+
end
180+
181+
if (MARK_WHEN_FULL && !LAST_ENABLE) begin
182+
$error("Error: MARK_WHEN_FULL set requires LAST_ENABLE set (instance %m)");
183+
$finish;
184+
end
171185
end
172186

173187
localparam KEEP_OFFSET = DATA_WIDTH;
@@ -262,6 +276,7 @@ reg s_frame_reg = 1'b0;
262276
reg m_frame_reg = 1'b0;
263277

264278
reg drop_frame_reg = 1'b0;
279+
reg mark_frame_reg = 1'b0;
265280
reg send_frame_reg = 1'b0;
266281
reg overflow_reg = 1'b0;
267282
reg bad_frame_reg = 1'b0;
@@ -288,17 +303,17 @@ reg good_frame_sync2_reg = 1'b0;
288303
reg good_frame_sync3_reg = 1'b0;
289304
reg good_frame_sync4_reg = 1'b0;
290305

291-
assign s_axis_tready = (FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg;
306+
assign s_axis_tready = (FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : (!full || MARK_WHEN_FULL)) && !s_rst_sync3_reg;
292307

293308
wire [WIDTH-1:0] s_axis;
294309

295310
generate
296311
assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata;
297312
if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep;
298-
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast;
313+
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast | mark_frame_reg;
299314
if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid;
300315
if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest;
301-
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser;
316+
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = mark_frame_reg ? USER_BAD_FRAME_VALUE : s_axis_tuser;
302317
endgenerate
303318

304319
wire [WIDTH-1:0] m_axis = m_axis_pipe_reg[RAM_PIPELINE+1-1];
@@ -468,22 +483,48 @@ always @(posedge s_clk) begin
468483
end else begin
469484
// normal FIFO mode
470485
if (s_axis_tready && s_axis_tvalid) begin
471-
// transfer in
472-
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
473486
if (drop_frame_reg && LAST_ENABLE) begin
474487
// currently dropping frame
475-
// (only for frame transfers interrupted by sink reset)
476488
if (s_axis_tlast) begin
489+
// end of frame
490+
if (!full && mark_frame_reg && MARK_WHEN_FULL) begin
491+
// terminate marked frame
492+
mark_frame_reg <= 1'b0;
493+
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
494+
wr_ptr_temp = wr_ptr_reg + 1;
495+
wr_ptr_reg <= wr_ptr_temp;
496+
wr_ptr_commit_reg <= wr_ptr_temp;
497+
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
498+
end
477499
// end of frame, clear drop flag
478500
drop_frame_reg <= 1'b0;
501+
overflow_reg <= 1'b1;
502+
end
503+
end else if ((full || mark_frame_reg) && MARK_WHEN_FULL) begin
504+
// full or marking frame
505+
// drop frame; mark if this isn't the first cycle
506+
drop_frame_reg <= 1'b1;
507+
mark_frame_reg <= mark_frame_reg || s_frame_reg;
508+
if (s_axis_tlast) begin
509+
drop_frame_reg <= 1'b0;
510+
overflow_reg <= 1'b1;
479511
end
480512
end else begin
481-
// update pointers
513+
// transfer in
514+
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
482515
wr_ptr_temp = wr_ptr_reg + 1;
483516
wr_ptr_reg <= wr_ptr_temp;
484517
wr_ptr_commit_reg <= wr_ptr_temp;
485518
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
486519
end
520+
end else if ((!full && !drop_frame_reg && mark_frame_reg) && MARK_WHEN_FULL) begin
521+
// terminate marked frame
522+
mark_frame_reg <= 1'b0;
523+
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
524+
wr_ptr_temp = wr_ptr_reg + 1;
525+
wr_ptr_reg <= wr_ptr_temp;
526+
wr_ptr_commit_reg <= wr_ptr_temp;
527+
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
487528
end
488529
end
489530

@@ -509,6 +550,7 @@ always @(posedge s_clk) begin
509550
s_frame_reg <= 1'b0;
510551

511552
drop_frame_reg <= 1'b0;
553+
mark_frame_reg <= 1'b0;
512554
send_frame_reg <= 1'b0;
513555
overflow_reg <= 1'b0;
514556
bad_frame_reg <= 1'b0;

rtl/axis_async_fifo_adapter.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ module axis_async_fifo_adapter #
8686
// When set, s_axis_tready is always asserted
8787
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
8888
parameter DROP_WHEN_FULL = 0,
89+
// Mark incoming frames as bad frames when full
90+
// When set, s_axis_tready is always asserted
91+
// Requires FRAME_FIFO to be clear
92+
parameter MARK_WHEN_FULL = 0,
8993
// Enable pause request input
9094
parameter PAUSE_ENABLE = 0,
9195
// Pause between frames
@@ -268,6 +272,7 @@ axis_async_fifo #(
268272
.DROP_OVERSIZE_FRAME(DROP_OVERSIZE_FRAME),
269273
.DROP_BAD_FRAME(DROP_BAD_FRAME),
270274
.DROP_WHEN_FULL(DROP_WHEN_FULL),
275+
.MARK_WHEN_FULL(MARK_WHEN_FULL),
271276
.PAUSE_ENABLE(PAUSE_ENABLE),
272277
.FRAME_PAUSE(FRAME_PAUSE)
273278
)

rtl/axis_fifo.v

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ module axis_fifo #
8181
// When set, s_axis_tready is always asserted
8282
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
8383
parameter DROP_WHEN_FULL = 0,
84+
// Mark incoming frames as bad frames when full
85+
// When set, s_axis_tready is always asserted
86+
// Requires FRAME_FIFO to be clear
87+
parameter MARK_WHEN_FULL = 0,
8488
// Enable pause request input
8589
parameter PAUSE_ENABLE = 0,
8690
// Pause between frames
@@ -156,10 +160,20 @@ initial begin
156160
$finish;
157161
end
158162

159-
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
163+
if ((DROP_BAD_FRAME || MARK_WHEN_FULL) && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
160164
$error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)");
161165
$finish;
162166
end
167+
168+
if (MARK_WHEN_FULL && FRAME_FIFO) begin
169+
$error("Error: MARK_WHEN_FULL is not compatible with FRAME_FIFO (instance %m)");
170+
$finish;
171+
end
172+
173+
if (MARK_WHEN_FULL && !LAST_ENABLE) begin
174+
$error("Error: MARK_WHEN_FULL set requires LAST_ENABLE set (instance %m)");
175+
$finish;
176+
end
163177
end
164178

165179
localparam KEEP_OFFSET = DATA_WIDTH;
@@ -188,25 +202,28 @@ wire empty = wr_ptr_commit_reg == rd_ptr_reg;
188202
// overflow within packet
189203
wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
190204

205+
reg s_frame_reg = 1'b0;
206+
191207
reg drop_frame_reg = 1'b0;
208+
reg mark_frame_reg = 1'b0;
192209
reg send_frame_reg = 1'b0;
193210
reg [ADDR_WIDTH:0] depth_reg = 0;
194211
reg [ADDR_WIDTH:0] depth_commit_reg = 0;
195212
reg overflow_reg = 1'b0;
196213
reg bad_frame_reg = 1'b0;
197214
reg good_frame_reg = 1'b0;
198215

199-
assign s_axis_tready = FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full;
216+
assign s_axis_tready = FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : (!full || MARK_WHEN_FULL);
200217

201218
wire [WIDTH-1:0] s_axis;
202219

203220
generate
204221
assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata;
205222
if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep;
206-
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast;
223+
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast | mark_frame_reg;
207224
if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid;
208225
if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest;
209-
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser;
226+
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = mark_frame_reg ? USER_BAD_FRAME_VALUE : s_axis_tuser;
210227
endgenerate
211228

212229
wire [WIDTH-1:0] m_axis = m_axis_pipe_reg[RAM_PIPELINE+1-1];
@@ -245,6 +262,11 @@ always @(posedge clk) begin
245262
bad_frame_reg <= 1'b0;
246263
good_frame_reg <= 1'b0;
247264

265+
if (s_axis_tready && s_axis_tvalid && LAST_ENABLE) begin
266+
// track input frame status
267+
s_frame_reg <= !s_axis_tlast;
268+
end
269+
248270
if (FRAME_FIFO) begin
249271
// frame FIFO mode
250272
if (s_axis_tready && s_axis_tvalid) begin
@@ -286,7 +308,39 @@ always @(posedge clk) begin
286308
end else begin
287309
// normal FIFO mode
288310
if (s_axis_tready && s_axis_tvalid) begin
289-
// transfer in
311+
if (drop_frame_reg && MARK_WHEN_FULL) begin
312+
// currently dropping frame
313+
if (s_axis_tlast) begin
314+
// end of frame
315+
if (!full && mark_frame_reg) begin
316+
// terminate marked frame
317+
mark_frame_reg <= 1'b0;
318+
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
319+
wr_ptr_reg <= wr_ptr_reg + 1;
320+
wr_ptr_commit_reg <= wr_ptr_reg + 1;
321+
end
322+
// end of frame, clear drop flag
323+
drop_frame_reg <= 1'b0;
324+
overflow_reg <= 1'b1;
325+
end
326+
end else if ((full || mark_frame_reg) && MARK_WHEN_FULL) begin
327+
// full or marking frame
328+
// drop frame; mark if this isn't the first cycle
329+
drop_frame_reg <= 1'b1;
330+
mark_frame_reg <= mark_frame_reg || s_frame_reg;
331+
if (s_axis_tlast) begin
332+
drop_frame_reg <= 1'b0;
333+
overflow_reg <= 1'b1;
334+
end
335+
end else begin
336+
// transfer in
337+
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
338+
wr_ptr_reg <= wr_ptr_reg + 1;
339+
wr_ptr_commit_reg <= wr_ptr_reg + 1;
340+
end
341+
end else if ((!full && !drop_frame_reg && mark_frame_reg) && MARK_WHEN_FULL) begin
342+
// terminate marked frame
343+
mark_frame_reg <= 1'b0;
290344
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
291345
wr_ptr_reg <= wr_ptr_reg + 1;
292346
wr_ptr_commit_reg <= wr_ptr_reg + 1;
@@ -297,7 +351,10 @@ always @(posedge clk) begin
297351
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
298352
wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}};
299353

354+
s_frame_reg <= 1'b0;
355+
300356
drop_frame_reg <= 1'b0;
357+
mark_frame_reg <= 1'b0;
301358
send_frame_reg <= 1'b0;
302359
overflow_reg <= 1'b0;
303360
bad_frame_reg <= 1'b0;

rtl/axis_fifo_adapter.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ module axis_fifo_adapter #
8686
// When set, s_axis_tready is always asserted
8787
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
8888
parameter DROP_WHEN_FULL = 0,
89+
// Mark incoming frames as bad frames when full
90+
// When set, s_axis_tready is always asserted
91+
// Requires FRAME_FIFO to be clear
92+
parameter MARK_WHEN_FULL = 0,
8993
// Enable pause request input
9094
parameter PAUSE_ENABLE = 0,
9195
// Pause between frames
@@ -260,6 +264,7 @@ axis_fifo #(
260264
.DROP_OVERSIZE_FRAME(DROP_OVERSIZE_FRAME),
261265
.DROP_BAD_FRAME(DROP_BAD_FRAME),
262266
.DROP_WHEN_FULL(DROP_WHEN_FULL),
267+
.MARK_WHEN_FULL(MARK_WHEN_FULL),
263268
.PAUSE_ENABLE(PAUSE_ENABLE),
264269
.FRAME_PAUSE(FRAME_PAUSE)
265270
)

tb/axis_async_fifo/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export PARAM_USER_BAD_FRAME_MASK := 1
5151
export PARAM_DROP_OVERSIZE_FRAME := $(PARAM_FRAME_FIFO)
5252
export PARAM_DROP_BAD_FRAME := $(PARAM_DROP_OVERSIZE_FRAME)
5353
export PARAM_DROP_WHEN_FULL := 0
54+
export PARAM_MARK_WHEN_FULL := 0
5455
export PARAM_PAUSE_ENABLE := 1
5556
export PARAM_FRAME_PAUSE := 1
5657

tb/axis_async_fifo/test_axis_async_fifo.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -468,14 +468,14 @@ async def run_test_overflow(dut):
468468
for k in range((depth//byte_lanes)*3):
469469
await RisingEdge(dut.s_clk)
470470

471-
if dut.DROP_WHEN_FULL.value:
471+
if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value:
472472
assert tb.source.idle()
473473
else:
474474
assert not tb.source.idle()
475475

476476
tb.sink.pause = False
477477

478-
if dut.DROP_WHEN_FULL.value:
478+
if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value:
479479
for k in range((depth//byte_lanes)*3):
480480
await RisingEdge(dut.s_clk)
481481

@@ -484,9 +484,14 @@ async def run_test_overflow(dut):
484484
while not tb.sink.empty():
485485
rx_frame = await tb.sink.recv()
486486

487+
if dut.MARK_WHEN_FULL.value and rx_frame.tuser:
488+
continue
489+
487490
assert rx_frame.tdata == test_data
488491
assert not rx_frame.tuser
489492

493+
rx_count += 1
494+
490495
assert rx_count < count
491496

492497
else:
@@ -529,8 +534,11 @@ async def run_test_oversize(dut):
529534
else:
530535
rx_frame = await tb.sink.recv()
531536

532-
assert rx_frame.tdata == test_data
533-
assert not rx_frame.tuser
537+
if dut.MARK_WHEN_FULL.value:
538+
assert rx_frame.tuser
539+
else:
540+
assert rx_frame.tdata == test_data
541+
assert not rx_frame.tuser
534542

535543
assert tb.sink.empty()
536544

@@ -566,7 +574,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):
566574

567575
cur_id = (cur_id + 1) % id_count
568576

569-
if dut.DROP_WHEN_FULL.value:
577+
if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value:
570578
cycles = 0
571579
while cycles < 100:
572580
cycles += 1
@@ -577,9 +585,14 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None):
577585
while not tb.sink.empty():
578586
rx_frame = await tb.sink.recv()
579587

588+
if dut.MARK_WHEN_FULL.value and rx_frame.tuser:
589+
continue
590+
591+
assert not rx_frame.tuser
592+
580593
while True:
581594
test_frame = test_frames.pop(0)
582-
if not rx_frame.tuser and rx_frame.tid == test_frame.tid and rx_frame.tdest == test_frame.tdest and rx_frame.tdata == test_frame.tdata:
595+
if rx_frame.tid == test_frame.tid and rx_frame.tdest == test_frame.tdest and rx_frame.tdata == test_frame.tdata:
583596
break
584597

585598
assert len(test_frames) < 512
@@ -653,13 +666,16 @@ def incrementing_payload(length):
653666

654667

655668
@pytest.mark.parametrize(("s_clk", "m_clk"), [(10, 10), (10, 11), (11, 10)])
656-
@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", "drop_when_full"),
657-
[(0, 0, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0), (1, 1, 1, 1)])
669+
@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame",
670+
"drop_when_full", "mark_when_full"),
671+
[(0, 0, 0, 0, 0), (1, 0, 0, 0, 0), (1, 1, 0, 0, 0), (1, 1, 1, 0, 0),
672+
(1, 1, 1, 1, 0), (0, 0, 0, 0, 1)])
658673
@pytest.mark.parametrize(("ram_pipeline", "output_fifo"),
659674
[(0, 0), (1, 0), (4, 0), (0, 1), (1, 1), (4, 1)])
660675
@pytest.mark.parametrize("data_width", [8, 16, 32, 64])
661676
def test_axis_async_fifo(request, data_width, ram_pipeline, output_fifo,
662-
frame_fifo, drop_oversize_frame, drop_bad_frame, drop_when_full, s_clk, m_clk):
677+
frame_fifo, drop_oversize_frame, drop_bad_frame,
678+
drop_when_full, mark_when_full, s_clk, m_clk):
663679

664680
dut = "axis_async_fifo"
665681
module = os.path.splitext(os.path.basename(__file__))[0]
@@ -690,6 +706,7 @@ def test_axis_async_fifo(request, data_width, ram_pipeline, output_fifo,
690706
parameters['DROP_OVERSIZE_FRAME'] = drop_oversize_frame
691707
parameters['DROP_BAD_FRAME'] = drop_bad_frame
692708
parameters['DROP_WHEN_FULL'] = drop_when_full
709+
parameters['MARK_WHEN_FULL'] = mark_when_full
693710
parameters['PAUSE_ENABLE'] = 1
694711
parameters['FRAME_PAUSE'] = 1
695712

0 commit comments

Comments
 (0)