diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/axi_sync.v')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/axi_sync.v | 101 |
1 files changed, 73 insertions, 28 deletions
diff --git a/fpga/usrp3/lib/rfnoc/axi_sync.v b/fpga/usrp3/lib/rfnoc/axi_sync.v index a881a5556..25b43d55b 100644 --- a/fpga/usrp3/lib/rfnoc/axi_sync.v +++ b/fpga/usrp3/lib/rfnoc/axi_sync.v @@ -1,14 +1,32 @@ // -// Copyright 2016 Ettus Research -// Copyright 2018 Ettus Research, a National Instruments Company +// Copyright 2021 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // -// Synchronizes AXI stream buses so data is released on every port simultaneously. +// Module: axi_sync // -// Note: If inputs have inequal bitwidths, use WIDTH_VEC instead of WIDTH to define -// the individual bit widths. Each bit width is defined with 8-bits stuffed -// into a vector of width 8*SIZE. +// Description: +// +// Synchronizes AXI stream buses so data is released on every port +// simultaneously. Multiple inputs/outputs are supported by concatenating the +// bus signals together. The number and size of each input/output bus is +// controlled using parameters. +// +// **WARNING**: This module violates the AXI4-Stream specification by not +// asserting TVALID until it receives TREADY. This will not +// work if downstream logic waits for TVALID before asserting +// TREADY, which is common. Use with care. +// +// Parameters: +// +// SIZE : The number of inputs streams to synchronize. +// WIDTH : The width of TDATA on the input streams, if they are all the +// same width. If they are different widths, then use WIDTH_VEC +// instead. +// WIDTH_VEC : A vector of widths corresponding to each stream's TDATA width. +// Each number in this vector must be 32 bits wide. This defaults +// to WIDTH bits for all inputs. +// FIFO_SIZE : Log2 the size of the FIFO to use internally for each stream. // module axi_sync #( @@ -16,48 +34,75 @@ module axi_sync #( parameter WIDTH = 32, parameter [32*SIZE-1:0] WIDTH_VEC = {SIZE{WIDTH[31:0]}}, parameter FIFO_SIZE = 0 -)( - input clk, input reset, input clear, - input [msb(SIZE,WIDTH_VEC)-1:0] i_tdata, input [SIZE-1:0] i_tlast, input [SIZE-1:0] i_tvalid, output [SIZE-1:0] i_tready, - output [msb(SIZE,WIDTH_VEC)-1:0] o_tdata, output [SIZE-1:0] o_tlast, output [SIZE-1:0] o_tvalid, input [SIZE-1:0] o_tready +) ( + input clk, + input reset, + input clear, + + // Input streams + input [len(SIZE)-1:0] i_tdata, + input [ SIZE-1:0] i_tlast, + input [ SIZE-1:0] i_tvalid, + output [ SIZE-1:0] i_tready, + + // Output streams + output [len(SIZE)-1:0] o_tdata, + output [ SIZE-1:0] o_tlast, + output [ SIZE-1:0] o_tvalid, + input [ SIZE-1:0] o_tready ); - // Helper function to calculate the MSB index based on widths stored in WIDTH_VEC. - // Note: If n is negative, returns 0 - function automatic integer msb(input integer n, input [SIZE*32-1:0] bit_vec); + // Helper function to calculate the combined length of the lower 'n' ports + // based on widths stored in WIDTH_VEC. Note: If n is negative, returns 0. + function automatic integer len(input integer n); integer i, total; begin total = 0; if (n >= 0) begin for (i = 0; i <= n; i = i + 1) begin - total = total + ((bit_vec >> 32*i) & 32'hFF); + total = total + ((WIDTH_VEC >> 32*i) & 32'hFFFF); end end - msb = total; + len = total; end endfunction - wire [msb(SIZE,WIDTH_VEC)-1:0] int_tdata; - wire [SIZE-1:0] int_tlast, int_tvalid, int_tready; + wire [len(SIZE)-1:0] int_tdata; + wire [ SIZE-1:0] int_tlast; + wire [ SIZE-1:0] int_tvalid; + wire [ SIZE-1:0] int_tready; + // Generate a FIFO for each stream genvar i; generate for (i = 0; i < SIZE; i = i + 1) begin - axi_fifo #(.WIDTH(msb(i,WIDTH_VEC)-msb(i-1,WIDTH_VEC)+1), .SIZE(FIFO_SIZE)) axi_fifo ( - .clk(clk), .reset(reset), .clear(clear), - .i_tdata({i_tlast[i],i_tdata[msb(i,WIDTH_VEC)-1:msb(i-1,WIDTH_VEC)]}), - .i_tvalid(i_tvalid[i]), .i_tready(i_tready[i]), - .o_tdata({int_tlast[i],int_tdata[msb(i,WIDTH_VEC)-1:msb(i-1,WIDTH_VEC)]}), - .o_tvalid(int_tvalid[i]), .o_tready(int_tready[i]), - .space(), .occupied()); + axi_fifo #( + .WIDTH (len(i)-len(i-1)+1), + .SIZE (FIFO_SIZE) + ) axi_fifo ( + .clk (clk), + .reset (reset), + .clear (clear), + .i_tdata ({ i_tlast[i], i_tdata[len(i)-1 : len(i-1)] }), + .i_tvalid (i_tvalid[i]), + .i_tready (i_tready[i]), + .o_tdata ({ int_tlast[i], int_tdata[len(i)-1 : len(i-1)] }), + .o_tvalid (int_tvalid[i]), + .o_tready (int_tready[i]), + .space (), + .occupied () + ); end endgenerate - assign o_tdata = int_tdata; - assign o_tlast = int_tlast; - + // We allow a transfer and consume the outputs of the FIFOs when all + // downstream blocks are ready to accept a transfer (o_tready is true for all + // streams) and all FIFOs have data ready (int_tvalid is true for all FIFOs). wire consume = (&int_tvalid) & (&o_tready); + assign int_tready = {SIZE{consume}}; assign o_tvalid = {SIZE{consume}}; + assign o_tdata = int_tdata; + assign o_tlast = int_tlast; -endmodule
\ No newline at end of file +endmodule |