aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi/axis_packet_flush.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/axi/axis_packet_flush.v')
-rw-r--r--fpga/usrp3/lib/axi/axis_packet_flush.v148
1 files changed, 148 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/axi/axis_packet_flush.v b/fpga/usrp3/lib/axi/axis_packet_flush.v
new file mode 100644
index 000000000..f8b57e0a0
--- /dev/null
+++ b/fpga/usrp3/lib/axi/axis_packet_flush.v
@@ -0,0 +1,148 @@
+//
+// Copyright 2018-2019 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: axis_packet_flush
+// Description:
+// When this module is inserted in an AXI-Stream link, it allows
+// the client to flip a bit to make the stream lossy. When enable=1
+// all data coming through the input is dropped. This module can
+// start and stop flushing at packet boundaries to ensure no partial
+// packets are introduces into the stream. Set FLUSH_PARTIAL_PKTS = 1
+// to disable that behavior. An optional timeout can be set to
+// determine if flushing was done (without turning it off).
+//
+// Parameters:
+// - WIDTH: The bitwidth of the AXI-Stream bus
+// - TIMEOUT_W: Width of the timeout counter
+// - FLUSH_PARTIAL_PKTS: Start flusing immediately even if a packet is in flight
+// - PIPELINE: Which ports to pipeline? {NONE, IN, OUT, INOUT}
+//
+// Signals:
+// - s_axis_* : Input AXI-Stream
+// - m_axis_* : Output AXI-Stream
+// - enable : Enable flush mode
+// - timeout : Flush timeout (# of cycles of inactivity until done)
+// - flushing : The module is currently flushing
+// - done : Finished flushing (but is still active)
+
+module axis_packet_flush #(
+ parameter WIDTH = 64,
+ parameter TIMEOUT_W = 32,
+ parameter FLUSH_PARTIAL_PKTS = 0,
+ parameter PIPELINE = "NONE"
+)(
+ // Clock and reset
+ input wire clk,
+ input wire reset,
+ // Control and status
+ input wire enable,
+ input wire [TIMEOUT_W-1:0] timeout,
+ output wire flushing,
+ output reg done = 1'b0,
+ // Input stream
+ input wire [WIDTH-1:0] s_axis_tdata,
+ input wire s_axis_tlast,
+ input wire s_axis_tvalid,
+ output wire s_axis_tready,
+ // Output stream
+ output wire [WIDTH-1:0] m_axis_tdata,
+ output wire m_axis_tlast,
+ output wire m_axis_tvalid,
+ input wire m_axis_tready
+);
+
+ //----------------------------------------------
+ // Pipeline Logic
+ //----------------------------------------------
+
+ wire [WIDTH-1:0] i_pipe_tdata, o_pipe_tdata;
+ wire i_pipe_tlast, o_pipe_tlast;
+ wire i_pipe_tvalid, o_pipe_tvalid;
+ wire i_pipe_tready, o_pipe_tready;
+
+ generate
+ if (PIPELINE == "IN" || PIPELINE == "INOUT") begin
+ axi_fifo_flop2 #(.WIDTH(WIDTH+1)) in_pipe_i (
+ .clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata({s_axis_tlast, s_axis_tdata}), .i_tvalid(s_axis_tvalid), .i_tready(s_axis_tready),
+ .o_tdata({i_pipe_tlast, i_pipe_tdata}), .o_tvalid(i_pipe_tvalid), .o_tready(i_pipe_tready),
+ .space(), .occupied()
+ );
+ end else begin
+ assign {i_pipe_tlast, i_pipe_tdata, i_pipe_tvalid} = {s_axis_tlast, s_axis_tdata, s_axis_tvalid};
+ assign s_axis_tready = i_pipe_tready;
+ end
+
+ if (PIPELINE == "OUT" || PIPELINE == "INOUT") begin
+ axi_fifo_flop2 #(.WIDTH(WIDTH+1)) out_pipe_i (
+ .clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata({o_pipe_tlast, o_pipe_tdata}), .i_tvalid(o_pipe_tvalid), .i_tready(o_pipe_tready),
+ .o_tdata({m_axis_tlast, m_axis_tdata}), .o_tvalid(m_axis_tvalid), .o_tready(m_axis_tready),
+ .space(), .occupied()
+ );
+ end else begin
+ assign {m_axis_tlast, m_axis_tdata, m_axis_tvalid} = {o_pipe_tlast, o_pipe_tdata, o_pipe_tvalid};
+ assign o_pipe_tready = m_axis_tready;
+ end
+ endgenerate
+
+ //----------------------------------------------
+ // Flushing Logic
+ //----------------------------------------------
+
+ // Shortcuts
+ wire xfer_stb = i_pipe_tvalid & i_pipe_tready;
+ wire pkt_stb = xfer_stb & i_pipe_tlast;
+
+ // Packet boundary detector
+ reg mid_pkt = 1'b0;
+ always @(posedge clk) begin
+ if (reset) begin
+ mid_pkt <= 1'b0;
+ end else if (xfer_stb) begin
+ mid_pkt <= ~pkt_stb;
+ end
+ end
+
+ // Flush startup state machine
+ reg active = 1'b0;
+ always @(posedge clk) begin
+ if (reset) begin
+ active <= 1'b0;
+ end else begin
+ if (enable & (pkt_stb | (~mid_pkt & ~xfer_stb))) begin
+ active <= 1'b1;
+ end else if (~enable) begin
+ active <= 1'b0;
+ end
+ end
+ end
+ assign flushing = (FLUSH_PARTIAL_PKTS == 0) ? active : enable;
+
+ // Flush done detector based on timeout
+ reg [TIMEOUT_W-1:0] cyc_to_go = {TIMEOUT_W{1'b1}};
+ wire done_tmp = (cyc_to_go == {TIMEOUT_W{1'b0}});
+ always @(posedge clk) begin
+ if (reset | ~enable) begin
+ cyc_to_go <= {TIMEOUT_W{1'b1}};
+ done <= 1'b0;
+ end else if (enable & ~active) begin
+ cyc_to_go <= timeout;
+ end else begin
+ if (~done_tmp) begin
+ cyc_to_go <= xfer_stb ? timeout : (cyc_to_go - 1'b1);
+ end
+ done <= done_tmp;
+ end
+ end
+
+ // When flushing, drop all input data and quiet output data
+ // When no flushing, pass data without interruption
+ assign o_pipe_tdata = i_pipe_tdata;
+ assign o_pipe_tlast = i_pipe_tlast;
+ assign o_pipe_tvalid = flushing ? 1'b0 : i_pipe_tvalid;
+ assign i_pipe_tready = flushing ? 1'b1 : o_pipe_tready;
+
+endmodule \ No newline at end of file