fpga: lib: Add axis_packetize module
This module takes an AXI-Stream without TLAST and outputs the same AXI-Stream with TLAST based on the provided packet size input. Original-commit: b0b3849a18e1f2d3cb255a507b01ac5e7a9416a0
This commit is contained in:
committed by
Aaron Rossetto
parent
0c67c21d6c
commit
3e1e0be3bc
@@ -34,4 +34,5 @@ axis_upsizer.v \
|
|||||||
axis_downsizer.v \
|
axis_downsizer.v \
|
||||||
axis_width_conv.v \
|
axis_width_conv.v \
|
||||||
axis_split.v \
|
axis_split.v \
|
||||||
|
axis_packetize.v \
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 Ettus Research, A National Instruments Brand
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// Module: axis_packetize
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// This module takes in an axi_stream without packet boundaries (i.e.,
|
||||||
|
// without tlast) and groups the data into packets by adding tlast at the
|
||||||
|
// appropriate time. The size of the packet is controlled by the "size"
|
||||||
|
// input, which is sampled at the beginning of each packet to be output. The
|
||||||
|
// packet_size input indicates the number of i_tdata words to group into a
|
||||||
|
// packet. The i_tlength output indicates the length of the packet being
|
||||||
|
// output.
|
||||||
|
//
|
||||||
|
// The gate input causes data transfers to be stopped at the end of the
|
||||||
|
// current packet when the gate input is asserted. It is not legal to
|
||||||
|
// deassert tvalid once it has been asserted until the next transfer is
|
||||||
|
// completed, so this module monitors the state of the AXI-Stream protocol
|
||||||
|
// so that no protocol violations occur.
|
||||||
|
//
|
||||||
|
// Note that the current transfer may still complete after gate has been
|
||||||
|
// asserted, so the downstream logic must be able to account for at least
|
||||||
|
// one more transfer.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
//
|
||||||
|
// DATA_W : Width of the tdata signals.
|
||||||
|
// SIZE_W : The width of the packet size port. This dictates the
|
||||||
|
// maximum packet size.
|
||||||
|
// FLUSH : Controls whether or not the input should be stalled or
|
||||||
|
// flushed. That is, when FLUSH=0, the input data is stalled
|
||||||
|
// whenever the gate is on (i_tready becomes 0). When
|
||||||
|
// FLUSH=1, the input data is dropped whenever the gate is on
|
||||||
|
// (i_tready becomes 1).
|
||||||
|
// DEFAULT_SIZE : The default packet size to use, if it doesn't need to be
|
||||||
|
// changed at run time.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module axis_packetize #(
|
||||||
|
parameter DATA_W = 32,
|
||||||
|
parameter SIZE_W = 16,
|
||||||
|
parameter FLUSH = 0,
|
||||||
|
parameter DEFAULT_SIZE = 2**SIZE_W-1
|
||||||
|
) (
|
||||||
|
input wire clk,
|
||||||
|
input wire rst,
|
||||||
|
|
||||||
|
input wire gate, // Stop or "gate" packet output
|
||||||
|
input wire [SIZE_W-1:0] size, // Size to use for the next packet
|
||||||
|
|
||||||
|
// Input data stream
|
||||||
|
input wire [DATA_W-1:0] i_tdata,
|
||||||
|
input wire i_tvalid,
|
||||||
|
output wire i_tready,
|
||||||
|
|
||||||
|
// Output data stream
|
||||||
|
output wire [DATA_W-1:0] o_tdata,
|
||||||
|
output reg o_tlast,
|
||||||
|
output wire o_tvalid,
|
||||||
|
input wire o_tready,
|
||||||
|
output wire [SIZE_W-1:0] o_tuser // Current packet's size
|
||||||
|
);
|
||||||
|
|
||||||
|
reg start_of_packet = 1; // Next sample is start of a packet
|
||||||
|
reg [SIZE_W-1:0] word_count = 0; // Count of output words
|
||||||
|
reg [SIZE_W-1:0] current_size = DEFAULT_SIZE; // Current packet size
|
||||||
|
|
||||||
|
reg gating = 1'b1; // Indicate if output is blocked
|
||||||
|
reg mid_packet = 1'b0; // Indicate if we're in the middle of a packet
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Packet Size Logic
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
assign o_tuser = current_size;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
start_of_packet <= 1;
|
||||||
|
word_count <= 0;
|
||||||
|
current_size <= DEFAULT_SIZE;
|
||||||
|
o_tlast <= 0;
|
||||||
|
end else begin
|
||||||
|
if (gating) begin
|
||||||
|
// Wait until we're enabled. Setup for the start of the next packet.
|
||||||
|
start_of_packet <= 1;
|
||||||
|
current_size <= size;
|
||||||
|
word_count <= 0;
|
||||||
|
o_tlast <= (size == 1);
|
||||||
|
end else if (o_tvalid && o_tready) begin
|
||||||
|
start_of_packet <= 1'b0;
|
||||||
|
word_count <= word_count + 1;
|
||||||
|
if (o_tlast) begin
|
||||||
|
// This is the last sample, so restart everything for a new packet.
|
||||||
|
o_tlast <= (size == 1);
|
||||||
|
current_size <= size;
|
||||||
|
word_count <= 0;
|
||||||
|
start_of_packet <= 1'b1;
|
||||||
|
end else if (word_count == current_size-2) begin
|
||||||
|
// This is the second to last sample, so we assert tlast for the
|
||||||
|
// last sample.
|
||||||
|
o_tlast <= 1'b1;
|
||||||
|
end
|
||||||
|
end else if (start_of_packet) begin
|
||||||
|
// We're waiting for the start of the next packet. Keep checking the
|
||||||
|
// size input until the next packet starts.
|
||||||
|
current_size <= size;
|
||||||
|
word_count <= 0;
|
||||||
|
o_tlast <= (size == 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Handshake Monitor
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// We start out gated to allow a clock cycle for the length to be loaded.
|
||||||
|
|
||||||
|
// Monitor the state of the handshake so we know when it's OK to
|
||||||
|
// enable/disable data transfer.
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
gating = 1'b1;
|
||||||
|
mid_packet = 1'b0;
|
||||||
|
end else begin
|
||||||
|
// Keep track of if we are in the middle of a packet or not. Note that
|
||||||
|
// mid_packet will be 0 for the first transfer of a packet.
|
||||||
|
if (o_tvalid && o_tready) begin
|
||||||
|
if (o_tlast) begin
|
||||||
|
mid_packet = 1'b0;
|
||||||
|
end else begin
|
||||||
|
mid_packet = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (gating) begin
|
||||||
|
// We can stop gating any time
|
||||||
|
if (!gate) gating <= 0;
|
||||||
|
end else begin
|
||||||
|
// Only start gating between packets or at the end of a packet
|
||||||
|
if ((mid_packet && !o_tvalid) || (o_tvalid && o_tready && o_tlast)) begin
|
||||||
|
gating <= gate;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Data Pass-Through
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
assign o_tdata = i_tdata;
|
||||||
|
assign o_tvalid = i_tvalid && !gating;
|
||||||
|
assign i_tready = FLUSH ? (o_tready || gating) : (o_tready && !gating);
|
||||||
|
|
||||||
|
endmodule
|
||||||
Reference in New Issue
Block a user