aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/axi_sync.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/axi_sync.v')
-rw-r--r--fpga/usrp3/lib/rfnoc/axi_sync.v101
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