diff options
Diffstat (limited to 'fpga/usrp3/lib/axi/axis_packet_flush.v')
-rw-r--r-- | fpga/usrp3/lib/axi/axis_packet_flush.v | 148 |
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 |