// axis_filter: an AXI-Stream stage that drops every packet whose header beat (the first beat // of a packet) carries DROP_TYPE in byte 0. Other packets pass unchanged. A beat moves on a port // at an edge where TVALID and TREADY are both 1; the beat with TLAST = 1 ends its packet. module axis_filter #(parameter logic [7:0] DROP_TYPE = 8'hd0) ( input logic clk, input logic rst_n, // active-low, asynchronous input logic s_tvalid, // the stream in output logic s_tready, input logic [31:0] s_tdata, // byte lane l is s_tdata[8l+7:8l]; lane 0 comes first input logic [3:0] s_tkeep, // 1: this lane holds a byte of the packet input logic s_tlast, output logic m_tvalid, // the stream out input logic m_tready, output logic [31:0] m_tdata, output logic [3:0] m_tkeep, output logic m_tlast ); // The packet state. logic first_q; // the next beat to arrive is a header beat logic drop_q; // the packet in progress is being dropped wire take = s_tvalid && s_tready; // a beat arrives at this edge wire drop = first_q ? (s_tdata[7:0] == DROP_TYPE) : drop_q; // decided once per packet wire fwd = take && !drop; // the beat arriving goes on to the output always_ff @(posedge clk or negedge rst_n) if (!rst_n) begin first_q <= 1'b1; drop_q <= 1'b0; end else if (take) begin first_q <= s_tlast; // after a last beat comes a header beat drop_q <= drop && !s_tlast; // hold the decision until the last beat end // The output stage: a main register and a skid register (R4.4). A dropped beat is taken // from the input and never reaches them. logic skid_valid; logic [36:0] main_q, skid_q; // {last, keep, data} wire move = m_tready || !m_tvalid; // the main register may load at this edge assign s_tready = !skid_valid; // from a flop always_ff @(posedge clk or negedge rst_n) if (!rst_n) begin m_tvalid <= 1'b0; skid_valid <= 1'b0; end else if (move) begin if (skid_valid) begin m_tvalid <= 1'b1; skid_valid <= 1'b0; end // drain the skid first else m_tvalid <= fwd; end else if (fwd) begin skid_valid <= 1'b1; // main is stalled: the beat waits in the skid end always_ff @(posedge clk) // the payload registers have no reset if (move) begin if (skid_valid) main_q <= skid_q; else if (fwd) main_q <= {s_tlast, s_tkeep, s_tdata}; end else if (fwd) begin skid_q <= {s_tlast, s_tkeep, s_tdata}; end assign {m_tlast, m_tkeep, m_tdata} = main_q; endmodule