From b0b3849a18e1f2d3cb255a507b01ac5e7a9416a0 Mon Sep 17 00:00:00 2001 From: Wade Fife Date: Thu, 25 Jun 2020 00:24:25 -0500 Subject: 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. --- fpga/usrp3/lib/axi/Makefile.srcs | 1 + fpga/usrp3/lib/axi/axis_packetize.v | 161 ++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 fpga/usrp3/lib/axi/axis_packetize.v (limited to 'fpga/usrp3') diff --git a/fpga/usrp3/lib/axi/Makefile.srcs b/fpga/usrp3/lib/axi/Makefile.srcs index bf8b3dbd2..598af9ef3 100644 --- a/fpga/usrp3/lib/axi/Makefile.srcs +++ b/fpga/usrp3/lib/axi/Makefile.srcs @@ -34,4 +34,5 @@ axis_upsizer.v \ axis_downsizer.v \ axis_width_conv.v \ axis_split.v \ +axis_packetize.v \ )) diff --git a/fpga/usrp3/lib/axi/axis_packetize.v b/fpga/usrp3/lib/axi/axis_packetize.v new file mode 100644 index 000000000..6ee018d9a --- /dev/null +++ b/fpga/usrp3/lib/axi/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 -- cgit v1.2.3