From 7823b916bfd298441d5fdabf0b03d0ae8dc210e8 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 16 Aug 2023 12:50:12 -0700 Subject: [PATCH] Implement MARK_WHEN_FULL option in FIFOs Signed-off-by: Alex Forencich --- rtl/axis_async_fifo.v | 58 +++++++++++++--- rtl/axis_async_fifo_adapter.v | 5 ++ rtl/axis_fifo.v | 67 +++++++++++++++++-- rtl/axis_fifo_adapter.v | 5 ++ tb/axis_async_fifo/Makefile | 1 + tb/axis_async_fifo/test_axis_async_fifo.py | 35 +++++++--- tb/axis_async_fifo_adapter/Makefile | 1 + .../test_axis_async_fifo_adapter.py | 36 +++++++--- tb/axis_fifo/Makefile | 1 + tb/axis_fifo/test_axis_fifo.py | 35 +++++++--- tb/axis_fifo_adapter/Makefile | 1 + .../test_axis_fifo_adapter.py | 36 +++++++--- 12 files changed, 232 insertions(+), 49 deletions(-) diff --git a/rtl/axis_async_fifo.v b/rtl/axis_async_fifo.v index 4d793d9..76eeb8d 100644 --- a/rtl/axis_async_fifo.v +++ b/rtl/axis_async_fifo.v @@ -81,6 +81,10 @@ module axis_async_fifo # // When set, s_axis_tready is always asserted // Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set parameter DROP_WHEN_FULL = 0, + // Mark incoming frames as bad frames when full + // When set, s_axis_tready is always asserted + // Requires FRAME_FIFO to be clear + parameter MARK_WHEN_FULL = 0, // Enable pause request input parameter PAUSE_ENABLE = 0, // Pause between frames @@ -164,10 +168,20 @@ initial begin $finish; end - if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin + if ((DROP_BAD_FRAME || MARK_WHEN_FULL) && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin $error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"); $finish; end + + if (MARK_WHEN_FULL && FRAME_FIFO) begin + $error("Error: MARK_WHEN_FULL is not compatible with FRAME_FIFO (instance %m)"); + $finish; + end + + if (MARK_WHEN_FULL && !LAST_ENABLE) begin + $error("Error: MARK_WHEN_FULL set requires LAST_ENABLE set (instance %m)"); + $finish; + end end localparam KEEP_OFFSET = DATA_WIDTH; @@ -262,6 +276,7 @@ reg s_frame_reg = 1'b0; reg m_frame_reg = 1'b0; reg drop_frame_reg = 1'b0; +reg mark_frame_reg = 1'b0; reg send_frame_reg = 1'b0; reg overflow_reg = 1'b0; reg bad_frame_reg = 1'b0; @@ -288,17 +303,17 @@ reg good_frame_sync2_reg = 1'b0; reg good_frame_sync3_reg = 1'b0; reg good_frame_sync4_reg = 1'b0; -assign s_axis_tready = (FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg; +assign s_axis_tready = (FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : (!full || MARK_WHEN_FULL)) && !s_rst_sync3_reg; wire [WIDTH-1:0] s_axis; generate assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata; if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep; - if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast; + if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast | mark_frame_reg; if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid; if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest; - if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser; + if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = mark_frame_reg ? USER_BAD_FRAME_VALUE : s_axis_tuser; endgenerate wire [WIDTH-1:0] m_axis = m_axis_pipe_reg[RAM_PIPELINE+1-1]; @@ -468,22 +483,48 @@ always @(posedge s_clk) begin end else begin // normal FIFO mode if (s_axis_tready && s_axis_tvalid) begin - // transfer in - mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; if (drop_frame_reg && LAST_ENABLE) begin // currently dropping frame - // (only for frame transfers interrupted by sink reset) if (s_axis_tlast) begin + // end of frame + if (!full && mark_frame_reg && MARK_WHEN_FULL) begin + // terminate marked frame + mark_frame_reg <= 1'b0; + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_temp = wr_ptr_reg + 1; + wr_ptr_reg <= wr_ptr_temp; + wr_ptr_commit_reg <= wr_ptr_temp; + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); + end // end of frame, clear drop flag drop_frame_reg <= 1'b0; + overflow_reg <= 1'b1; + end + end else if ((full || mark_frame_reg) && MARK_WHEN_FULL) begin + // full or marking frame + // drop frame; mark if this isn't the first cycle + drop_frame_reg <= 1'b1; + mark_frame_reg <= mark_frame_reg || s_frame_reg; + if (s_axis_tlast) begin + drop_frame_reg <= 1'b0; + overflow_reg <= 1'b1; end end else begin - // update pointers + // transfer in + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; wr_ptr_temp = wr_ptr_reg + 1; wr_ptr_reg <= wr_ptr_temp; wr_ptr_commit_reg <= wr_ptr_temp; wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); end + end else if ((!full && !drop_frame_reg && mark_frame_reg) && MARK_WHEN_FULL) begin + // terminate marked frame + mark_frame_reg <= 1'b0; + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_temp = wr_ptr_reg + 1; + wr_ptr_reg <= wr_ptr_temp; + wr_ptr_commit_reg <= wr_ptr_temp; + wr_ptr_gray_reg <= bin2gray(wr_ptr_temp); end end @@ -509,6 +550,7 @@ always @(posedge s_clk) begin s_frame_reg <= 1'b0; drop_frame_reg <= 1'b0; + mark_frame_reg <= 1'b0; send_frame_reg <= 1'b0; overflow_reg <= 1'b0; bad_frame_reg <= 1'b0; diff --git a/rtl/axis_async_fifo_adapter.v b/rtl/axis_async_fifo_adapter.v index 291fd92..7796996 100644 --- a/rtl/axis_async_fifo_adapter.v +++ b/rtl/axis_async_fifo_adapter.v @@ -86,6 +86,10 @@ module axis_async_fifo_adapter # // When set, s_axis_tready is always asserted // Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set parameter DROP_WHEN_FULL = 0, + // Mark incoming frames as bad frames when full + // When set, s_axis_tready is always asserted + // Requires FRAME_FIFO to be clear + parameter MARK_WHEN_FULL = 0, // Enable pause request input parameter PAUSE_ENABLE = 0, // Pause between frames @@ -268,6 +272,7 @@ axis_async_fifo #( .DROP_OVERSIZE_FRAME(DROP_OVERSIZE_FRAME), .DROP_BAD_FRAME(DROP_BAD_FRAME), .DROP_WHEN_FULL(DROP_WHEN_FULL), + .MARK_WHEN_FULL(MARK_WHEN_FULL), .PAUSE_ENABLE(PAUSE_ENABLE), .FRAME_PAUSE(FRAME_PAUSE) ) diff --git a/rtl/axis_fifo.v b/rtl/axis_fifo.v index f185d40..e9c9258 100644 --- a/rtl/axis_fifo.v +++ b/rtl/axis_fifo.v @@ -81,6 +81,10 @@ module axis_fifo # // When set, s_axis_tready is always asserted // Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set parameter DROP_WHEN_FULL = 0, + // Mark incoming frames as bad frames when full + // When set, s_axis_tready is always asserted + // Requires FRAME_FIFO to be clear + parameter MARK_WHEN_FULL = 0, // Enable pause request input parameter PAUSE_ENABLE = 0, // Pause between frames @@ -156,10 +160,20 @@ initial begin $finish; end - if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin + if ((DROP_BAD_FRAME || MARK_WHEN_FULL) && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin $error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"); $finish; end + + if (MARK_WHEN_FULL && FRAME_FIFO) begin + $error("Error: MARK_WHEN_FULL is not compatible with FRAME_FIFO (instance %m)"); + $finish; + end + + if (MARK_WHEN_FULL && !LAST_ENABLE) begin + $error("Error: MARK_WHEN_FULL set requires LAST_ENABLE set (instance %m)"); + $finish; + end end localparam KEEP_OFFSET = DATA_WIDTH; @@ -188,7 +202,10 @@ wire empty = wr_ptr_commit_reg == rd_ptr_reg; // overflow within packet wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}}); +reg s_frame_reg = 1'b0; + reg drop_frame_reg = 1'b0; +reg mark_frame_reg = 1'b0; reg send_frame_reg = 1'b0; reg [ADDR_WIDTH:0] depth_reg = 0; reg [ADDR_WIDTH:0] depth_commit_reg = 0; @@ -196,17 +213,17 @@ reg overflow_reg = 1'b0; reg bad_frame_reg = 1'b0; reg good_frame_reg = 1'b0; -assign s_axis_tready = FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : !full; +assign s_axis_tready = FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : (!full || MARK_WHEN_FULL); wire [WIDTH-1:0] s_axis; generate assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata; if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep; - if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast; + if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast | mark_frame_reg; if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid; if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest; - if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser; + if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = mark_frame_reg ? USER_BAD_FRAME_VALUE : s_axis_tuser; endgenerate wire [WIDTH-1:0] m_axis = m_axis_pipe_reg[RAM_PIPELINE+1-1]; @@ -245,6 +262,11 @@ always @(posedge clk) begin bad_frame_reg <= 1'b0; good_frame_reg <= 1'b0; + if (s_axis_tready && s_axis_tvalid && LAST_ENABLE) begin + // track input frame status + s_frame_reg <= !s_axis_tlast; + end + if (FRAME_FIFO) begin // frame FIFO mode if (s_axis_tready && s_axis_tvalid) begin @@ -286,7 +308,39 @@ always @(posedge clk) begin end else begin // normal FIFO mode if (s_axis_tready && s_axis_tvalid) begin - // transfer in + if (drop_frame_reg && MARK_WHEN_FULL) begin + // currently dropping frame + if (s_axis_tlast) begin + // end of frame + if (!full && mark_frame_reg) begin + // terminate marked frame + mark_frame_reg <= 1'b0; + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_reg <= wr_ptr_reg + 1; + wr_ptr_commit_reg <= wr_ptr_reg + 1; + end + // end of frame, clear drop flag + drop_frame_reg <= 1'b0; + overflow_reg <= 1'b1; + end + end else if ((full || mark_frame_reg) && MARK_WHEN_FULL) begin + // full or marking frame + // drop frame; mark if this isn't the first cycle + drop_frame_reg <= 1'b1; + mark_frame_reg <= mark_frame_reg || s_frame_reg; + if (s_axis_tlast) begin + drop_frame_reg <= 1'b0; + overflow_reg <= 1'b1; + end + end else begin + // transfer in + mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; + wr_ptr_reg <= wr_ptr_reg + 1; + wr_ptr_commit_reg <= wr_ptr_reg + 1; + end + end else if ((!full && !drop_frame_reg && mark_frame_reg) && MARK_WHEN_FULL) begin + // terminate marked frame + mark_frame_reg <= 1'b0; mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis; wr_ptr_reg <= wr_ptr_reg + 1; wr_ptr_commit_reg <= wr_ptr_reg + 1; @@ -297,7 +351,10 @@ always @(posedge clk) begin wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}}; wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}}; + s_frame_reg <= 1'b0; + drop_frame_reg <= 1'b0; + mark_frame_reg <= 1'b0; send_frame_reg <= 1'b0; overflow_reg <= 1'b0; bad_frame_reg <= 1'b0; diff --git a/rtl/axis_fifo_adapter.v b/rtl/axis_fifo_adapter.v index 7054cd2..44ecc5c 100644 --- a/rtl/axis_fifo_adapter.v +++ b/rtl/axis_fifo_adapter.v @@ -86,6 +86,10 @@ module axis_fifo_adapter # // When set, s_axis_tready is always asserted // Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set parameter DROP_WHEN_FULL = 0, + // Mark incoming frames as bad frames when full + // When set, s_axis_tready is always asserted + // Requires FRAME_FIFO to be clear + parameter MARK_WHEN_FULL = 0, // Enable pause request input parameter PAUSE_ENABLE = 0, // Pause between frames @@ -260,6 +264,7 @@ axis_fifo #( .DROP_OVERSIZE_FRAME(DROP_OVERSIZE_FRAME), .DROP_BAD_FRAME(DROP_BAD_FRAME), .DROP_WHEN_FULL(DROP_WHEN_FULL), + .MARK_WHEN_FULL(MARK_WHEN_FULL), .PAUSE_ENABLE(PAUSE_ENABLE), .FRAME_PAUSE(FRAME_PAUSE) ) diff --git a/tb/axis_async_fifo/Makefile b/tb/axis_async_fifo/Makefile index ef0aaef..10ffd63 100644 --- a/tb/axis_async_fifo/Makefile +++ b/tb/axis_async_fifo/Makefile @@ -51,6 +51,7 @@ export PARAM_USER_BAD_FRAME_MASK := 1 export PARAM_DROP_OVERSIZE_FRAME := $(PARAM_FRAME_FIFO) export PARAM_DROP_BAD_FRAME := $(PARAM_DROP_OVERSIZE_FRAME) export PARAM_DROP_WHEN_FULL := 0 +export PARAM_MARK_WHEN_FULL := 0 export PARAM_PAUSE_ENABLE := 1 export PARAM_FRAME_PAUSE := 1 diff --git a/tb/axis_async_fifo/test_axis_async_fifo.py b/tb/axis_async_fifo/test_axis_async_fifo.py index d999697..4b126a7 100644 --- a/tb/axis_async_fifo/test_axis_async_fifo.py +++ b/tb/axis_async_fifo/test_axis_async_fifo.py @@ -468,14 +468,14 @@ async def run_test_overflow(dut): for k in range((depth//byte_lanes)*3): await RisingEdge(dut.s_clk) - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: assert tb.source.idle() else: assert not tb.source.idle() tb.sink.pause = False - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: for k in range((depth//byte_lanes)*3): await RisingEdge(dut.s_clk) @@ -484,9 +484,14 @@ async def run_test_overflow(dut): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + assert rx_frame.tdata == test_data assert not rx_frame.tuser + rx_count += 1 + assert rx_count < count else: @@ -529,8 +534,11 @@ async def run_test_oversize(dut): else: rx_frame = await tb.sink.recv() - assert rx_frame.tdata == test_data - assert not rx_frame.tuser + if dut.MARK_WHEN_FULL.value: + assert rx_frame.tuser + else: + assert rx_frame.tdata == test_data + assert not rx_frame.tuser assert tb.sink.empty() @@ -566,7 +574,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): cur_id = (cur_id + 1) % id_count - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: cycles = 0 while cycles < 100: cycles += 1 @@ -577,9 +585,14 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + + assert not rx_frame.tuser + while True: test_frame = test_frames.pop(0) - 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: + if rx_frame.tid == test_frame.tid and rx_frame.tdest == test_frame.tdest and rx_frame.tdata == test_frame.tdata: break assert len(test_frames) < 512 @@ -653,13 +666,16 @@ def incrementing_payload(length): @pytest.mark.parametrize(("s_clk", "m_clk"), [(10, 10), (10, 11), (11, 10)]) -@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", "drop_when_full"), - [(0, 0, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0), (1, 1, 1, 1)]) +@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", + "drop_when_full", "mark_when_full"), + [(0, 0, 0, 0, 0), (1, 0, 0, 0, 0), (1, 1, 0, 0, 0), (1, 1, 1, 0, 0), + (1, 1, 1, 1, 0), (0, 0, 0, 0, 1)]) @pytest.mark.parametrize(("ram_pipeline", "output_fifo"), [(0, 0), (1, 0), (4, 0), (0, 1), (1, 1), (4, 1)]) @pytest.mark.parametrize("data_width", [8, 16, 32, 64]) def test_axis_async_fifo(request, data_width, ram_pipeline, output_fifo, - frame_fifo, drop_oversize_frame, drop_bad_frame, drop_when_full, s_clk, m_clk): + frame_fifo, drop_oversize_frame, drop_bad_frame, + drop_when_full, mark_when_full, s_clk, m_clk): dut = "axis_async_fifo" 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, parameters['DROP_OVERSIZE_FRAME'] = drop_oversize_frame parameters['DROP_BAD_FRAME'] = drop_bad_frame parameters['DROP_WHEN_FULL'] = drop_when_full + parameters['MARK_WHEN_FULL'] = mark_when_full parameters['PAUSE_ENABLE'] = 1 parameters['FRAME_PAUSE'] = 1 diff --git a/tb/axis_async_fifo_adapter/Makefile b/tb/axis_async_fifo_adapter/Makefile index fb75781..e709461 100644 --- a/tb/axis_async_fifo_adapter/Makefile +++ b/tb/axis_async_fifo_adapter/Makefile @@ -55,6 +55,7 @@ export PARAM_USER_BAD_FRAME_MASK := 1 export PARAM_DROP_OVERSIZE_FRAME := $(PARAM_FRAME_FIFO) export PARAM_DROP_BAD_FRAME := $(PARAM_DROP_OVERSIZE_FRAME) export PARAM_DROP_WHEN_FULL := 0 +export PARAM_MARK_WHEN_FULL := 0 export PARAM_PAUSE_ENABLE := 1 export PARAM_FRAME_PAUSE := 1 diff --git a/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py b/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py index 8533c68..5d09b07 100644 --- a/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py +++ b/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py @@ -465,14 +465,14 @@ async def run_test_overflow(dut): for k in range((depth//byte_lanes)*3): await RisingEdge(dut.s_clk) - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: assert tb.source.idle() else: assert not tb.source.idle() tb.sink.pause = False - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: for k in range((depth//byte_lanes)*3): await RisingEdge(dut.s_clk) @@ -481,9 +481,14 @@ async def run_test_overflow(dut): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + assert rx_frame.tdata == test_data assert not rx_frame.tuser + rx_count += 1 + assert rx_count < count else: @@ -526,8 +531,11 @@ async def run_test_oversize(dut): else: rx_frame = await tb.sink.recv() - assert rx_frame.tdata == test_data - assert not rx_frame.tuser + if dut.MARK_WHEN_FULL.value: + assert rx_frame.tuser + else: + assert rx_frame.tdata == test_data + assert not rx_frame.tuser assert tb.sink.empty() @@ -563,7 +571,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): cur_id = (cur_id + 1) % id_count - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: cycles = 0 while cycles < 100: cycles += 1 @@ -574,9 +582,14 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + + assert not rx_frame.tuser + while True: test_frame = test_frames.pop(0) - 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: + if rx_frame.tid == test_frame.tid and rx_frame.tdest == test_frame.tdest and rx_frame.tdata == test_frame.tdata: break assert len(test_frames) < 512 @@ -649,11 +662,15 @@ def incrementing_payload(length): rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) -@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", "drop_when_full"), - [(0, 0, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0), (1, 1, 1, 1)]) +@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", + "drop_when_full", "mark_when_full"), + [(0, 0, 0, 0, 0), (1, 0, 0, 0, 0), (1, 1, 0, 0, 0), (1, 1, 1, 0, 0), + (1, 1, 1, 1, 0), (0, 0, 0, 0, 1)]) @pytest.mark.parametrize("m_data_width", [8, 16, 32]) @pytest.mark.parametrize("s_data_width", [8, 16, 32]) -def test_axis_async_fifo_adapter(request, s_data_width, m_data_width, frame_fifo, drop_oversize_frame, drop_bad_frame, drop_when_full): +def test_axis_async_fifo_adapter(request, s_data_width, m_data_width, + frame_fifo, drop_oversize_frame, drop_bad_frame, + drop_when_full, mark_when_full): dut = "axis_async_fifo_adapter" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut @@ -687,6 +704,7 @@ def test_axis_async_fifo_adapter(request, s_data_width, m_data_width, frame_fifo parameters['DROP_OVERSIZE_FRAME'] = drop_oversize_frame parameters['DROP_BAD_FRAME'] = drop_bad_frame parameters['DROP_WHEN_FULL'] = drop_when_full + parameters['MARK_WHEN_FULL'] = mark_when_full parameters['PAUSE_ENABLE'] = 1 parameters['FRAME_PAUSE'] = 1 diff --git a/tb/axis_fifo/Makefile b/tb/axis_fifo/Makefile index 41641c7..c10508e 100644 --- a/tb/axis_fifo/Makefile +++ b/tb/axis_fifo/Makefile @@ -51,6 +51,7 @@ export PARAM_USER_BAD_FRAME_MASK := 1 export PARAM_DROP_OVERSIZE_FRAME := $(PARAM_FRAME_FIFO) export PARAM_DROP_BAD_FRAME := $(PARAM_DROP_OVERSIZE_FRAME) export PARAM_DROP_WHEN_FULL := 0 +export PARAM_MARK_WHEN_FULL := 0 export PARAM_PAUSE_ENABLE := 1 export PARAM_FRAME_PAUSE := 1 diff --git a/tb/axis_fifo/test_axis_fifo.py b/tb/axis_fifo/test_axis_fifo.py index 7a41994..e89c0a5 100644 --- a/tb/axis_fifo/test_axis_fifo.py +++ b/tb/axis_fifo/test_axis_fifo.py @@ -254,14 +254,14 @@ async def run_test_overflow(dut): for k in range((depth//byte_lanes)*3): await RisingEdge(dut.clk) - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: assert tb.source.idle() else: assert not tb.source.idle() tb.sink.pause = False - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: for k in range((depth//byte_lanes)*3): await RisingEdge(dut.clk) @@ -270,9 +270,14 @@ async def run_test_overflow(dut): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + assert rx_frame.tdata == test_data assert not rx_frame.tuser + rx_count += 1 + assert rx_count < count else: @@ -315,8 +320,11 @@ async def run_test_oversize(dut): else: rx_frame = await tb.sink.recv() - assert rx_frame.tdata == test_data - assert not rx_frame.tuser + if dut.MARK_WHEN_FULL.value: + assert rx_frame.tuser + else: + assert rx_frame.tdata == test_data + assert not rx_frame.tuser assert tb.sink.empty() @@ -352,7 +360,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): cur_id = (cur_id + 1) % id_count - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: cycles = 0 while cycles < 100: cycles += 1 @@ -363,11 +371,16 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + + assert not rx_frame.tuser + assert len(test_frames) > 0 while True: test_frame = test_frames.pop(0) - 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: + if rx_frame.tid == test_frame.tid and rx_frame.tdest == test_frame.tdest and rx_frame.tdata == test_frame.tdata: break assert len(test_frames) < 512 @@ -434,13 +447,16 @@ def incrementing_payload(length): rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) -@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", "drop_when_full"), - [(0, 0, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0), (1, 1, 1, 1)]) +@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", + "drop_when_full", "mark_when_full"), + [(0, 0, 0, 0, 0), (1, 0, 0, 0, 0), (1, 1, 0, 0, 0), (1, 1, 1, 0, 0), + (1, 1, 1, 1, 0), (0, 0, 0, 0, 1)]) @pytest.mark.parametrize(("ram_pipeline", "output_fifo"), [(0, 0), (1, 0), (4, 0), (0, 1), (1, 1), (4, 1)]) @pytest.mark.parametrize("data_width", [8, 16, 32, 64]) def test_axis_fifo(request, data_width, ram_pipeline, output_fifo, - frame_fifo, drop_oversize_frame, drop_bad_frame, drop_when_full): + frame_fifo, drop_oversize_frame, drop_bad_frame, + drop_when_full, mark_when_full): dut = "axis_fifo" module = os.path.splitext(os.path.basename(__file__))[0] @@ -471,6 +487,7 @@ def test_axis_fifo(request, data_width, ram_pipeline, output_fifo, parameters['DROP_OVERSIZE_FRAME'] = drop_oversize_frame parameters['DROP_BAD_FRAME'] = drop_bad_frame parameters['DROP_WHEN_FULL'] = drop_when_full + parameters['MARK_WHEN_FULL'] = mark_when_full parameters['PAUSE_ENABLE'] = 1 parameters['FRAME_PAUSE'] = 1 diff --git a/tb/axis_fifo_adapter/Makefile b/tb/axis_fifo_adapter/Makefile index 0a995cd..65234e8 100644 --- a/tb/axis_fifo_adapter/Makefile +++ b/tb/axis_fifo_adapter/Makefile @@ -55,6 +55,7 @@ export PARAM_USER_BAD_FRAME_MASK := 1 export PARAM_DROP_OVERSIZE_FRAME := $(PARAM_FRAME_FIFO) export PARAM_DROP_BAD_FRAME := $(PARAM_DROP_OVERSIZE_FRAME) export PARAM_DROP_WHEN_FULL := 0 +export PARAM_MARK_WHEN_FULL := 0 export PARAM_PAUSE_ENABLE := 1 export PARAM_FRAME_PAUSE := 1 diff --git a/tb/axis_fifo_adapter/test_axis_fifo_adapter.py b/tb/axis_fifo_adapter/test_axis_fifo_adapter.py index 03c2a34..5b4b992 100644 --- a/tb/axis_fifo_adapter/test_axis_fifo_adapter.py +++ b/tb/axis_fifo_adapter/test_axis_fifo_adapter.py @@ -254,14 +254,14 @@ async def run_test_overflow(dut): for k in range((depth//byte_lanes)*3): await RisingEdge(dut.clk) - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: assert tb.source.idle() else: assert not tb.source.idle() tb.sink.pause = False - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: for k in range((depth//byte_lanes)*3): await RisingEdge(dut.clk) @@ -270,9 +270,14 @@ async def run_test_overflow(dut): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + assert rx_frame.tdata == test_data assert not rx_frame.tuser + rx_count += 1 + assert rx_count < count else: @@ -315,8 +320,11 @@ async def run_test_oversize(dut): else: rx_frame = await tb.sink.recv() - assert rx_frame.tdata == test_data - assert not rx_frame.tuser + if dut.MARK_WHEN_FULL.value: + assert rx_frame.tuser + else: + assert rx_frame.tdata == test_data + assert not rx_frame.tuser assert tb.sink.empty() @@ -352,7 +360,7 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): cur_id = (cur_id + 1) % id_count - if dut.DROP_WHEN_FULL.value: + if dut.DROP_WHEN_FULL.value or dut.MARK_WHEN_FULL.value: cycles = 0 while cycles < 100: cycles += 1 @@ -363,9 +371,14 @@ async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): while not tb.sink.empty(): rx_frame = await tb.sink.recv() + if dut.MARK_WHEN_FULL.value and rx_frame.tuser: + continue + + assert not rx_frame.tuser + while True: test_frame = test_frames.pop(0) - 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: + if rx_frame.tid == test_frame.tid and rx_frame.tdest == test_frame.tdest and rx_frame.tdata == test_frame.tdata: break assert len(test_frames) < 512 @@ -432,11 +445,15 @@ def incrementing_payload(length): rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) -@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", "drop_when_full"), - [(0, 0, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0), (1, 1, 1, 1)]) +@pytest.mark.parametrize(("frame_fifo", "drop_oversize_frame", "drop_bad_frame", + "drop_when_full", "mark_when_full"), + [(0, 0, 0, 0, 0), (1, 0, 0, 0, 0), (1, 1, 0, 0, 0), (1, 1, 1, 0, 0), + (1, 1, 1, 1, 0), (0, 0, 0, 0, 1)]) @pytest.mark.parametrize("m_data_width", [8, 16, 32]) @pytest.mark.parametrize("s_data_width", [8, 16, 32]) -def test_axis_fifo_adapter(request, s_data_width, m_data_width, frame_fifo, drop_oversize_frame, drop_bad_frame, drop_when_full): +def test_axis_fifo_adapter(request, s_data_width, m_data_width, + frame_fifo, drop_oversize_frame, drop_bad_frame, + drop_when_full, mark_when_full): dut = "axis_fifo_adapter" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut @@ -470,6 +487,7 @@ def test_axis_fifo_adapter(request, s_data_width, m_data_width, frame_fifo, drop parameters['DROP_OVERSIZE_FRAME'] = drop_oversize_frame parameters['DROP_BAD_FRAME'] = drop_bad_frame parameters['DROP_WHEN_FULL'] = drop_when_full + parameters['MARK_WHEN_FULL'] = mark_when_full parameters['PAUSE_ENABLE'] = 1 parameters['FRAME_PAUSE'] = 1