aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/fifo
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2020-01-23 16:10:22 -0800
committerMartin Braun <martin.braun@ettus.com>2020-01-28 09:35:36 -0800
commitbafa9d95453387814ef25e6b6256ba8db2df612f (patch)
tree39ba24b5b67072d354775272e687796bb511848d /fpga/usrp3/lib/fifo
parent3075b981503002df3115d5f1d0b97d2619ba30f2 (diff)
downloaduhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz
uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2
uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip
Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce the size of the repository. However, over the last half-decade, the split between the repositories has proven more burdensome than it has been helpful. By merging the FPGA code back, it will be possible to create atomic commits that touch both FPGA and UHD codebases. Continuous integration testing is also simplified by merging the repositories, because it was previously difficult to automatically derive the correct UHD branch when testing a feature branch on the FPGA repository. This commit also updates the license files and paths therein. We are therefore merging the repositories again. Future development for FPGA code will happen in the same repository as the UHD host code and MPM code. == Original Codebase and Rebasing == The original FPGA repository will be hosted for the foreseeable future at its original local location: https://github.com/EttusResearch/fpga/ It can be used for bisecting, reference, and a more detailed history. The final commit from said repository to be merged here is 05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as v4.0.0.0-pre-uhd-merge. If you have changes in the FPGA repository that you want to rebase onto the UHD repository, simply run the following commands: - Create a directory to store patches (this should be an empty directory): mkdir ~/patches - Now make sure that your FPGA codebase is based on the same state as the code that was merged: cd src/fpga # Or wherever your FPGA code is stored git rebase v4.0.0.0-pre-uhd-merge Note: The rebase command may look slightly different depending on what exactly you're trying to rebase. - Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge: git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches Note: Make sure that only patches are stored in your output directory. It should otherwise be empty. Make sure that you picked the correct range of commits, and only commits you wanted to rebase were exported as patch files. - Go to the UHD repository and apply the patches: cd src/uhd # Or wherever your UHD repository is stored git am --directory fpga ~/patches/* rm -rf ~/patches # This is for cleanup == Contributors == The following people have contributed mainly to these files (this list is not complete): Co-authored-by: Alex Williams <alex.williams@ni.com> Co-authored-by: Andrej Rode <andrej.rode@ettus.com> Co-authored-by: Ashish Chaudhari <ashish@ettus.com> Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com> Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com> Co-authored-by: Daniel Jepson <daniel.jepson@ni.com> Co-authored-by: Derek Kozel <derek.kozel@ettus.com> Co-authored-by: EJ Kreinar <ej@he360.com> Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com> Co-authored-by: Ian Buckley <ian.buckley@gmail.com> Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com> Co-authored-by: Jon Kiser <jon.kiser@ni.com> Co-authored-by: Josh Blum <josh@joshknows.com> Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com> Co-authored-by: Martin Braun <martin.braun@ettus.com> Co-authored-by: Matt Ettus <matt@ettus.com> Co-authored-by: Michael West <michael.west@ettus.com> Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com> Co-authored-by: Nick Foster <nick@ettus.com> Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com> Co-authored-by: Paul Butler <paul.butler@ni.com> Co-authored-by: Paul David <paul.david@ettus.com> Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com> Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com> Co-authored-by: Sylvain Munaut <tnt@246tNt.com> Co-authored-by: Trung Tran <trung.tran@ettus.com> Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com> Co-authored-by: Wade Fife <wade.fife@ettus.com>
Diffstat (limited to 'fpga/usrp3/lib/fifo')
-rw-r--r--fpga/usrp3/lib/fifo/Makefile.srcs37
-rw-r--r--fpga/usrp3/lib/fifo/axi_demux.v75
-rw-r--r--fpga/usrp3/lib/fifo/axi_demux4.v80
-rw-r--r--fpga/usrp3/lib/fifo/axi_demux8.v63
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo.v71
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo16_to_fifo32.v43
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo32_to_fifo16.v36
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo32_to_fifo64.v44
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo64_to_fifo32.v37
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_2clk.v184
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_32_64_tb.v119
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_bram.v174
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_cascade.v48
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_flop.v43
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_flop2.v59
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_short.v113
-rw-r--r--fpga/usrp3/lib/fifo/axi_fifo_tb.v328
-rw-r--r--fpga/usrp3/lib/fifo/axi_filter_mux4.v158
-rw-r--r--fpga/usrp3/lib/fifo/axi_loopback.v75
-rw-r--r--fpga/usrp3/lib/fifo/axi_mux.v110
-rw-r--r--fpga/usrp3/lib/fifo/axi_mux4.v115
-rw-r--r--fpga/usrp3/lib/fifo/axi_mux8.v59
-rw-r--r--fpga/usrp3/lib/fifo/axi_mux_select.v104
-rw-r--r--fpga/usrp3/lib/fifo/axi_packet_gate.v229
-rw-r--r--fpga/usrp3/lib/fifo/axis_fifo_monitor.v66
-rw-r--r--fpga/usrp3/lib/fifo/axis_strm_monitor.v110
-rw-r--r--fpga/usrp3/lib/fifo/fifo64_to_axi4lite.v140
-rw-r--r--fpga/usrp3/lib/fifo/shortfifo.v95
28 files changed, 2815 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/fifo/Makefile.srcs b/fpga/usrp3/lib/fifo/Makefile.srcs
new file mode 100644
index 000000000..8b48f6586
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/Makefile.srcs
@@ -0,0 +1,37 @@
+#
+# Copyright 2012-2013 Ettus Research LLC
+# Copyright 2016 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+
+##################################################
+# FIFO Sources
+##################################################
+FIFO_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/fifo/, \
+axi_demux4.v \
+axi_demux8.v \
+axi_demux.v \
+axi_fifo_2clk.v \
+axi_fifo32_to_fifo64.v \
+axi_fifo64_to_fifo32.v \
+axi_fifo32_to_fifo16.v \
+axi_fifo16_to_fifo32.v \
+axi_fifo_bram.v \
+axi_fifo_cascade.v \
+axi_fifo_flop2.v \
+axi_fifo_flop.v \
+axi_fifo_short.v \
+axi_fifo.v \
+axi_filter_mux4.v \
+axi_loopback.v \
+axi_mux4.v \
+axi_mux8.v \
+axi_mux_select.v \
+axi_mux.v \
+axi_packet_gate.v \
+fifo64_to_axi4lite.v \
+shortfifo.v \
+axis_fifo_monitor.v \
+axis_strm_monitor.v \
+))
diff --git a/fpga/usrp3/lib/fifo/axi_demux.v b/fpga/usrp3/lib/fifo/axi_demux.v
new file mode 100644
index 000000000..965fb95f0
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_demux.v
@@ -0,0 +1,75 @@
+
+// Copyright 2012 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// axi_demux -- takes 1 AXI stream, demuxes to up to 16 output streams
+// One bubble cycle between each packet
+
+module axi_demux
+ #(parameter WIDTH=64,
+ parameter SIZE=4,
+ parameter PRE_FIFO_SIZE=0,
+ parameter POST_FIFO_SIZE=0)
+ (input clk, input reset, input clear,
+ output [WIDTH-1:0] header, input [$clog2(SIZE)-1:0] dest,
+ input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
+ output [(WIDTH*SIZE)-1:0] o_tdata, output [SIZE-1:0] o_tlast, output [SIZE-1:0] o_tvalid, input [SIZE-1:0] o_tready);
+
+ wire i_tlast_int, i_tready_int, i_tvalid_int;
+ wire [WIDTH-1:0] i_tdata_int;
+ generate
+ if (PRE_FIFO_SIZE == 0) begin
+ assign i_tlast_int = i_tlast;
+ assign i_tdata_int = i_tdata;
+ assign i_tvalid_int = i_tvalid;
+ assign i_tready = i_tready_int;
+ end else begin
+ axi_fifo #(.WIDTH(WIDTH+1),.SIZE(PRE_FIFO_SIZE)) axi_fifo (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata({i_tlast_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int),
+ .space(), .occupied());
+ end
+ endgenerate
+
+ reg [SIZE-1:0] st;
+
+ assign header = i_tdata_int;
+
+ always @(posedge clk)
+ if(reset | clear)
+ st <= {SIZE{1'b0}};
+ else
+ if(st == 0)
+ if(i_tvalid_int)
+ st[dest] <= 1'b1;
+ else
+ ;
+ else
+ if(i_tready_int & i_tvalid_int & i_tlast_int)
+ st <= {SIZE{1'b0}};
+
+ wire [SIZE-1:0] o_tlast_int, o_tready_int, o_tvalid_int;
+ wire [WIDTH-1:0] o_tdata_int[0:SIZE-1];
+ genvar n;
+ generate
+ if (POST_FIFO_SIZE == 0) begin
+ assign o_tdata = {SIZE{i_tdata_int}};
+ assign o_tlast = {SIZE{i_tlast_int}};
+ assign o_tvalid = {SIZE{i_tvalid_int}} & st;
+ assign i_tready_int = |(o_tready & st);
+ end else begin
+ wire [SIZE-1:0] o_tready_fifo;
+ assign i_tready_int = |(o_tready_fifo & st);
+ for (n = 0; n < SIZE; n = n + 1) begin
+ axi_fifo #(.WIDTH(WIDTH+1),.SIZE(POST_FIFO_SIZE)) axi_fifo (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({i_tlast_int,i_tdata_int}), .i_tvalid(i_tvalid_int & st[n]), .i_tready(o_tready_fifo[n]),
+ .o_tdata({o_tlast[n],o_tdata[WIDTH*(n+1)-1:WIDTH*n]}), .o_tvalid(o_tvalid[n]), .o_tready(o_tready[n]),
+ .space(), .occupied());
+ end
+ end
+ endgenerate
+
+endmodule // axi_demux
diff --git a/fpga/usrp3/lib/fifo/axi_demux4.v b/fpga/usrp3/lib/fifo/axi_demux4.v
new file mode 100644
index 000000000..09f017dd1
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_demux4.v
@@ -0,0 +1,80 @@
+
+// Copyright 2012 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// axi_demux -- takes one AXI stream, sends to one of 4 output channels
+// Choice of output channel is by external logic based on first line of packet ("header" port)
+// If compressed vita data, this line contains vita header and streamid.
+
+module axi_demux4
+ #(parameter ACTIVE_CHAN = 4'b1111, // ACTIVE_CHAN is a map of connected outputs
+ parameter WIDTH = 64,
+ parameter BUFFER=0)
+ (input clk, input reset, input clear,
+ output [WIDTH-1:0] header, input [1:0] dest,
+ input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
+ output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
+ output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
+ output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
+ output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready);
+
+ wire [WIDTH-1:0] i_tdata_int;
+ wire i_tlast_int, i_tvalid_int, i_tready_int;
+
+ generate
+ if(BUFFER == 0)
+ begin
+ assign i_tdata_int = i_tdata;
+ assign i_tlast_int = i_tlast;
+ assign i_tvalid_int = i_tvalid;
+ assign i_tready = i_tready_int;
+ end
+ else
+ axi_fifo_flop2 #(.WIDTH(WIDTH+1)) axi_fifo_flop2
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata({i_tlast_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int),
+ .space(), .occupied());
+ endgenerate
+
+ reg [3:0] dm_state;
+ localparam DM_IDLE = 4'b0000;
+ localparam DM_0 = 4'b0001;
+ localparam DM_1 = 4'b0010;
+ localparam DM_2 = 4'b0100;
+ localparam DM_3 = 4'b1000;
+
+ assign header = i_tdata_int;
+
+ always @(posedge clk)
+ if(reset | clear)
+ dm_state <= DM_IDLE;
+ else
+ case (dm_state)
+ DM_IDLE :
+ if(i_tvalid_int)
+ case(dest)
+ 2'b00 : dm_state <= DM_0;
+ 2'b01 : dm_state <= DM_1;
+ 2'b10 : dm_state <= DM_2;
+ 2'b11 : dm_state <= DM_3;
+ endcase // case (i_tdata[1:0])
+
+ DM_0, DM_1, DM_2, DM_3 :
+ if(i_tvalid_int & i_tready_int & i_tlast_int)
+ dm_state <= DM_IDLE;
+
+ default :
+ dm_state <= DM_IDLE;
+ endcase // case (dm_state)
+
+ assign {o3_tvalid, o2_tvalid, o1_tvalid, o0_tvalid} = dm_state & {4{i_tvalid_int}};
+ assign i_tready_int = |(dm_state & ({o3_tready, o2_tready, o1_tready, o0_tready} | ~ACTIVE_CHAN));
+
+ assign {o0_tlast, o0_tdata} = {i_tlast_int, i_tdata_int};
+ assign {o1_tlast, o1_tdata} = {i_tlast_int, i_tdata_int};
+ assign {o2_tlast, o2_tdata} = {i_tlast_int, i_tdata_int};
+ assign {o3_tlast, o3_tdata} = {i_tlast_int, i_tdata_int};
+
+endmodule // axi_demux4
diff --git a/fpga/usrp3/lib/fifo/axi_demux8.v b/fpga/usrp3/lib/fifo/axi_demux8.v
new file mode 100644
index 000000000..2ee18040b
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_demux8.v
@@ -0,0 +1,63 @@
+
+// Copyright 2012 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// axi_demux -- takes one AXI stream, sends to one of 8 output channels
+// Choice of output channel is by external logic based on first line of packet ("header" port)
+// If compressed vita data, this line contains vita header and streamid.
+
+module axi_demux8 #(
+ parameter ACTIVE_CHAN = 8'b11111111, // ACTIVE_CHAN is a map of connected outputs
+ parameter WIDTH = 64,
+ parameter BUFFER=0
+) (
+ input clk, input reset, input clear,
+ output [WIDTH-1:0] header, input [2:0] dest,
+ input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
+ output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
+ output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
+ output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
+ output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready,
+ output [WIDTH-1:0] o4_tdata, output o4_tlast, output o4_tvalid, input o4_tready,
+ output [WIDTH-1:0] o5_tdata, output o5_tlast, output o5_tvalid, input o5_tready,
+ output [WIDTH-1:0] o6_tdata, output o6_tlast, output o6_tvalid, input o6_tready,
+ output [WIDTH-1:0] o7_tdata, output o7_tlast, output o7_tvalid, input o7_tready
+);
+
+ wire [WIDTH-1:0] i_tdata_int0, i_tdata_int1;
+ wire i_tlast_int0, i_tlast_int1;
+ wire i_tvalid_int0, i_tvalid_int1;
+ wire i_tready_int0, i_tready_int1;
+
+ axi_demux4 #(.ACTIVE_CHAN({2'b00, (|(ACTIVE_CHAN[7:4])), (|(ACTIVE_CHAN[3:0]))}), .WIDTH(WIDTH), .BUFFER(BUFFER)) demux2 (
+ .clk(clk), .reset(reset), .clear(clear),
+ .header(header), .dest({1'b0, dest[2]}),
+ .i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o0_tdata(i_tdata_int0), .o0_tlast(i_tlast_int0), .o0_tvalid(i_tvalid_int0), .o0_tready(i_tready_int0),
+ .o1_tdata(i_tdata_int1), .o1_tlast(i_tlast_int1), .o1_tvalid(i_tvalid_int1), .o1_tready(i_tready_int1),
+ .o2_tdata(), .o2_tlast(), .o2_tvalid(), .o2_tready(1'b0),
+ .o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b0)
+ );
+
+ axi_demux4 #(.ACTIVE_CHAN(ACTIVE_CHAN[3:0]), .WIDTH(WIDTH), .BUFFER(0)) demux4_int0 (
+ .clk(clk), .reset(reset), .clear(clear),
+ .header(), .dest(dest[1:0]),
+ .i_tdata(i_tdata_int0), .i_tlast(i_tlast_int0), .i_tvalid(i_tvalid_int0), .i_tready(i_tready_int0),
+ .o0_tdata(o0_tdata), .o0_tlast(o0_tlast), .o0_tvalid(o0_tvalid), .o0_tready(o0_tready),
+ .o1_tdata(o1_tdata), .o1_tlast(o1_tlast), .o1_tvalid(o1_tvalid), .o1_tready(o1_tready),
+ .o2_tdata(o2_tdata), .o2_tlast(o2_tlast), .o2_tvalid(o2_tvalid), .o2_tready(o2_tready),
+ .o3_tdata(o3_tdata), .o3_tlast(o3_tlast), .o3_tvalid(o3_tvalid), .o3_tready(o3_tready)
+ );
+
+ axi_demux4 #(.ACTIVE_CHAN(ACTIVE_CHAN[7:4]), .WIDTH(WIDTH), .BUFFER(0)) demux4_int1 (
+ .clk(clk), .reset(reset), .clear(clear),
+ .header(), .dest(dest[1:0]),
+ .i_tdata(i_tdata_int1), .i_tlast(i_tlast_int1), .i_tvalid(i_tvalid_int1), .i_tready(i_tready_int1),
+ .o0_tdata(o4_tdata), .o0_tlast(o4_tlast), .o0_tvalid(o4_tvalid), .o0_tready(o4_tready),
+ .o1_tdata(o5_tdata), .o1_tlast(o5_tlast), .o1_tvalid(o5_tvalid), .o1_tready(o5_tready),
+ .o2_tdata(o6_tdata), .o2_tlast(o6_tlast), .o2_tvalid(o6_tvalid), .o2_tready(o6_tready),
+ .o3_tdata(o7_tdata), .o3_tlast(o7_tlast), .o3_tvalid(o7_tvalid), .o3_tready(o7_tready)
+ );
+
+endmodule // axi_demux4
diff --git a/fpga/usrp3/lib/fifo/axi_fifo.v b/fpga/usrp3/lib/fifo/axi_fifo.v
new file mode 100644
index 000000000..3a99c4c31
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo.v
@@ -0,0 +1,71 @@
+//
+// Copyright 2012-2014 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+// General FIFO block
+// Size == 0: Uses a single stage flop (axi_fifo_flop).
+// Size == 1: Uses a two stage flop (axi_fifo_flop2). Best choice for single stage pipelining.
+// Breaks combinatorial paths on the AXI stream data / control lines at the cost of
+// additional registers. Maps to SLICELs (i.e. does not use distributed RAM).
+// Size <= 5: Uses SRL32 to efficient maps a 32 deep FIFO to SLICEMs (axi_fifo_short). Not
+// recommended for pipelining as most devices have twice as many SLICELs as SLICEMs.
+// Size > 5: Uses BRAM fifo (axi_fifo_bram)
+
+module axi_fifo
+ #(parameter WIDTH=32, SIZE=5)
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] i_tdata,
+ input i_tvalid,
+ output i_tready,
+ output [WIDTH-1:0] o_tdata,
+ output o_tvalid,
+ input o_tready,
+
+ output [15:0] space,
+ output [15:0] occupied);
+
+ generate
+ if(SIZE==0)
+ begin
+ axi_fifo_flop #(.WIDTH(WIDTH)) fifo_flop
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(space[0]), .occupied(occupied[0]));
+ assign space[15:1] = 15'd0;
+ assign occupied[15:1] = 15'd0;
+ end
+ else if(SIZE==1)
+ begin
+ axi_fifo_flop2 #(.WIDTH(WIDTH)) fifo_flop2
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(space[1:0]), .occupied(occupied[1:0]));
+ assign space[15:2] = 14'd0;
+ assign occupied[15:2] = 14'd0;
+ end
+ else if(SIZE<=5)
+ begin
+ axi_fifo_short #(.WIDTH(WIDTH)) fifo_short
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(space[5:0]), .occupied(occupied[5:0]));
+ assign space[15:6] = 10'd0;
+ assign occupied[15:6] = 10'd0;
+ end
+ else
+ begin
+ axi_fifo_bram #(.WIDTH(WIDTH), .SIZE(SIZE)) fifo_bram
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(space), .occupied(occupied));
+ end
+ endgenerate
+
+endmodule // axi_fifo
diff --git a/fpga/usrp3/lib/fifo/axi_fifo16_to_fifo32.v b/fpga/usrp3/lib/fifo/axi_fifo16_to_fifo32.v
new file mode 100644
index 000000000..d22c825c5
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo16_to_fifo32.v
@@ -0,0 +1,43 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+module axi_fifo16_to_fifo32
+ (input clk, input reset, input clear,
+ input [15:0] i_tdata, input [1:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
+ output [31:0] o_tdata, output [2:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
+ );
+
+ reg [15:0] holding;
+
+ reg state;
+
+ always @(posedge clk)
+ if(reset | clear)
+ state <= 0;
+ else
+ if(i_tvalid & i_tready)
+ case(state)
+ 0 : if(~i_tlast) state <= 1'b1;
+ 1 : state <= 1'b0;
+ default : state <= 1'b0;
+ endcase // case (state)
+
+ always @(posedge clk)
+ if(i_tvalid & i_tready)
+ holding <= i_tdata;
+
+ assign i_tready = (state == 0 && !i_tlast)? 1'b1 : o_tready;
+ assign o_tvalid = (state == 0 && !i_tlast)? 1'b0 : i_tvalid;
+
+ assign o_tdata = (state == 0) ? {i_tdata, 16'h0} : { holding, i_tdata };
+ assign o_tlast = i_tlast;
+
+ wire [2:0] occ_in = (i_tuser == 0) ? 3'd4 : {1'b0, i_tuser};
+ wire [2:0] occ_out = (state == 0) ? occ_in : (occ_in + 3'd4);
+
+ assign o_tuser = ~o_tlast ? 3'd0 : occ_out;
+
+endmodule // axi_fifo32_to_fifo64
diff --git a/fpga/usrp3/lib/fifo/axi_fifo32_to_fifo16.v b/fpga/usrp3/lib/fifo/axi_fifo32_to_fifo16.v
new file mode 100644
index 000000000..b4e7ec618
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo32_to_fifo16.v
@@ -0,0 +1,36 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+module axi_fifo32_to_fifo16
+ (input clk, input reset, input clear,
+ input [31:0] i_tdata, input [2:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
+ output [15:0] o_tdata, output [1:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
+ );
+
+ wire short_last = i_tlast & ((i_tuser == 3'd1) | (i_tuser == 3'd2) | (i_tuser == 3'd3) | (i_tuser == 3'd4));
+
+ reg state;
+ always @(posedge clk)
+ if(reset | clear)
+ state <= 1'b0;
+ else
+ if(i_tvalid & o_tready)
+ case(state)
+ 1'b0 :
+ if(~short_last)
+ state <= 1'b1;
+ 1'b1 :
+ state <= 1'b0;
+ endcase // case (state)
+
+ assign o_tdata = (state == 0) ? i_tdata[31:16] : i_tdata[15:0];
+ assign o_tuser = o_tlast ? i_tuser[1:0] : 2'd0;
+ assign o_tlast = i_tlast & ((state == 1'b1) | short_last);
+
+ assign o_tvalid = i_tvalid;
+ assign i_tready = o_tready & ((state == 1'b1) | short_last);
+
+endmodule // axi_fifo64_to_fifo32
diff --git a/fpga/usrp3/lib/fifo/axi_fifo32_to_fifo64.v b/fpga/usrp3/lib/fifo/axi_fifo32_to_fifo64.v
new file mode 100644
index 000000000..1f168420d
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo32_to_fifo64.v
@@ -0,0 +1,44 @@
+//
+// Copyright 2014 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+module axi_fifo32_to_fifo64
+ (input clk, input reset, input clear,
+ input [31:0] i_tdata, input [1:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
+ output [63:0] o_tdata, output [2:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
+ );
+
+ reg [31:0] holding;
+
+ reg state;
+
+ always @(posedge clk)
+ if(reset | clear)
+ state <= 0;
+ else
+ if(i_tvalid & i_tready)
+ case(state)
+ 0 : if(~i_tlast) state <= 1'b1;
+ 1 : state <= 1'b0;
+ default : state <= 1'b0;
+ endcase // case (state)
+
+ always @(posedge clk)
+ if(i_tvalid & i_tready)
+ holding <= i_tdata;
+
+ assign i_tready = (state == 0 && !i_tlast)? 1'b1 : o_tready;
+ assign o_tvalid = (state == 0 && !i_tlast)? 1'b0 : i_tvalid;
+
+ assign o_tdata = (state == 0) ? {i_tdata, 32'h0} : { holding, i_tdata };
+ assign o_tlast = i_tlast;
+
+ wire [2:0] occ_in = (i_tuser == 0) ? 3'd4 : {1'b0, i_tuser};
+ wire [2:0] occ_out = (state == 0) ? occ_in : (occ_in + 3'd4);
+
+ assign o_tuser = ~o_tlast ? 3'd0 : occ_out;
+
+endmodule // axi_fifo32_to_fifo64
diff --git a/fpga/usrp3/lib/fifo/axi_fifo64_to_fifo32.v b/fpga/usrp3/lib/fifo/axi_fifo64_to_fifo32.v
new file mode 100644
index 000000000..f9c12ef33
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo64_to_fifo32.v
@@ -0,0 +1,37 @@
+//
+// Copyright 2014 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+module axi_fifo64_to_fifo32
+ (input clk, input reset, input clear,
+ input [63:0] i_tdata, input [2:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
+ output [31:0] o_tdata, output [1:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
+ );
+
+ wire short_last = i_tlast & ((i_tuser == 3'd1) | (i_tuser == 3'd2) | (i_tuser == 3'd3) | (i_tuser == 3'd4));
+
+ reg state;
+ always @(posedge clk)
+ if(reset | clear)
+ state <= 1'b0;
+ else
+ if(i_tvalid & o_tready)
+ case(state)
+ 1'b0 :
+ if(~short_last)
+ state <= 1'b1;
+ 1'b1 :
+ state <= 1'b0;
+ endcase // case (state)
+
+ assign o_tdata = (state == 0) ? i_tdata[63:32] : i_tdata[31:0];
+ assign o_tuser = o_tlast ? i_tuser[1:0] : 2'd0;
+ assign o_tlast = i_tlast & ((state == 1'b1) | short_last);
+
+ assign o_tvalid = i_tvalid;
+ assign i_tready = o_tready & ((state == 1'b1) | short_last);
+
+endmodule // axi_fifo64_to_fifo32
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_2clk.v b/fpga/usrp3/lib/fifo/axi_fifo_2clk.v
new file mode 100644
index 000000000..1f3eee924
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_2clk.v
@@ -0,0 +1,184 @@
+/////////////////////////////////////////////////////////////////////
+//
+// Copyright 2017 Ettus Research, A National Instruments Company
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: axi_fifo_2clk.v
+//
+// Purpose:
+// An asynchronous clock crossing for AXI-Stream buses
+// The width (WIDTH) and depth (SIZE) of the FIFO is configurable
+// For depths less than the technology's SRL threshold, an SRL
+// will be instantiated. For depths less the minimum RAM block
+// depth (that corresponds to the max width), a single BRAM block
+// will be instantiated. For other larger depths, a BRAM block
+// plus a regular axi_fifo will be instantiated. The depth of the
+// combined FIFO in that case will be larger than the user request.
+//
+// Requirements:
+// Implementation for fifo_short_2clk, fifo_4k_2clk that infer SRL
+// and BRAM based clock-crossing FIFOs respectively
+//
+//////////////////////////////////////////////////////////////////////
+
+module axi_fifo_2clk #(
+ parameter WIDTH = 69, // Width of input/output data word
+ parameter SIZE = 9, // log2 of the depth of the FIFO
+ parameter PIPELINE = "NONE", // Which ports to pipeline? {NONE, IN, OUT, INOUT}
+ parameter DEVICE = "7SERIES" // FPGA technology identifier (for optimal inference)
+)(
+ input wire reset,
+ input wire i_aclk,
+ input wire [WIDTH-1:0] i_tdata,
+ input wire i_tvalid,
+ output wire i_tready,
+ input wire o_aclk,
+ output wire [WIDTH-1:0] o_tdata,
+ output wire o_tvalid,
+ input wire o_tready
+);
+
+ wire i_arst, o_arst;
+ synchronizer #(.INITIAL_VAL(1'b1)) i_rst_sync_i (
+ .clk(i_aclk), .rst(1'b0), .in(reset), .out(i_arst)
+ );
+ synchronizer #(.INITIAL_VAL(1'b1)) o_rst_sync_i (
+ .clk(o_aclk), .rst(1'b0), .in(reset), .out(o_arst)
+ );
+
+ //----------------------------------------------
+ // Pipeline Logic
+ //----------------------------------------------
+
+ wire [WIDTH-1:0] i_pipe_tdata, o_pipe_tdata;
+ wire i_pipe_tvalid, o_pipe_tvalid;
+ wire i_pipe_tready, o_pipe_tready;
+
+ generate
+ if (PIPELINE == "IN" || PIPELINE == "INOUT") begin
+ axi_fifo_flop2 #(.WIDTH(WIDTH)) in_pipe_i (
+ .clk(i_aclk), .reset(i_arst), .clear(1'b0),
+ .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata(i_pipe_tdata), .o_tvalid(i_pipe_tvalid), .o_tready(i_pipe_tready),
+ .space(), .occupied()
+ );
+ end else begin
+ assign {i_pipe_tdata, i_pipe_tvalid} = {i_tdata, i_tvalid};
+ assign i_tready = i_pipe_tready;
+ end
+
+ if (PIPELINE == "OUT" || PIPELINE == "INOUT") begin
+ axi_fifo_flop2 #(.WIDTH(WIDTH)) out_pipe_i (
+ .clk(o_aclk), .reset(o_arst), .clear(1'b0),
+ .i_tdata(o_pipe_tdata), .i_tvalid(o_pipe_tvalid), .i_tready(o_pipe_tready),
+ .o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied()
+ );
+ end else begin
+ assign {o_tdata, o_tvalid} = {o_pipe_tdata, o_pipe_tvalid};
+ assign o_pipe_tready = o_tready;
+ end
+ endgenerate
+
+ //----------------------------------------------
+ // FIFO Logic
+ //----------------------------------------------
+
+ wire [WIDTH-1:0] o_ext_tdata;
+ wire o_ext_tvalid;
+ wire o_ext_tready;
+
+ // Ideally the following parameters should be technology
+ // specific. For now these values have been optimized for
+ // 7Series FPGAs. They also work for Spartan6 but may not
+ // be optimal. For future generations, make these values
+ // depend on the DEVICE parameter.
+ localparam BASE_WIDTH = 72;
+ localparam SRL_THRESHOLD = 5;
+ localparam RAM_THRESHOLD = 9;
+
+ // How many parallel FIFOs to instantiate to fit WIDTH
+ localparam NUM_FIFOS = ((WIDTH-1)/BASE_WIDTH)+1;
+ localparam INT_WIDTH = BASE_WIDTH * NUM_FIFOS;
+
+ wire [INT_WIDTH-1:0] wr_data, rd_data;
+ wire [NUM_FIFOS-1:0] full, empty;
+ wire wr_en, rd_en;
+
+ // Read/write logic for FIFO sections
+ assign wr_data = {{(INT_WIDTH-WIDTH){1'b0}}, i_pipe_tdata};
+ assign wr_en = i_pipe_tready & i_pipe_tvalid;
+ assign i_pipe_tready = &(~full);
+ assign o_ext_tdata = rd_data[WIDTH-1:0];
+ assign o_ext_tvalid = &(~empty);
+ assign rd_en = o_ext_tready & o_ext_tvalid;
+
+ // FIFO IP instantiation
+ genvar i;
+ generate
+ for (i = 0; i < NUM_FIFOS; i = i + 1) begin: fifo_section
+ if (SIZE <= SRL_THRESHOLD) begin
+ fifo_short_2clk impl_srl_i (
+ .rst (i_arst),
+ .wr_clk (i_aclk),
+ .din (wr_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
+ .wr_en (wr_en),
+ .full (full[i]),
+ .wr_data_count(),
+ .rd_clk (o_aclk),
+ .dout (rd_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
+ .rd_en (rd_en),
+ .empty (empty[i]),
+ .rd_data_count()
+ );
+ end else begin
+ fifo_4k_2clk impl_bram_i (
+ .rst (i_arst),
+ .wr_clk (i_aclk),
+ .din (wr_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
+ .wr_en (wr_en),
+ .full (full[i]),
+ .wr_data_count(),
+ .rd_clk (o_aclk),
+ .dout (rd_data[((i+1)*BASE_WIDTH)-1:i*BASE_WIDTH]),
+ .rd_en (rd_en),
+ .empty (empty[i]),
+ .rd_data_count()
+ );
+ end
+ end
+ endgenerate
+
+ //----------------------------------------------
+ // Extension FIFO (for large sizes)
+ //----------------------------------------------
+
+ generate
+ if (SIZE > RAM_THRESHOLD) begin
+ wire [WIDTH-1:0] ext_pipe_tdata;
+ wire ext_pipe_tvalid;
+ wire ext_pipe_tready;
+
+ // Add a register slice between BRAM cascades
+ axi_fifo_flop2 #(.WIDTH(WIDTH)) ext_fifo_pipe_i (
+ .clk(o_aclk), .reset(o_arst), .clear(1'b0),
+ .i_tdata(o_ext_tdata), .i_tvalid(o_ext_tvalid), .i_tready(o_ext_tready),
+ .o_tdata(ext_pipe_tdata), .o_tvalid(ext_pipe_tvalid), .o_tready(ext_pipe_tready),
+ .space(), .occupied()
+ );
+
+ // Bolt on an extension FIFO if the requested depth is larger than the BRAM
+ // 2clk FIFO primitive (IP)
+ axi_fifo_bram #(.WIDTH(WIDTH), .SIZE(SIZE)) ext_fifo_i (
+ .clk(o_aclk), .reset(o_arst), .clear(1'b0),
+ .i_tdata(ext_pipe_tdata), .i_tvalid(ext_pipe_tvalid), .i_tready(ext_pipe_tready),
+ .o_tdata(o_pipe_tdata), .o_tvalid(o_pipe_tvalid), .o_tready(o_pipe_tready),
+ .space(), .occupied()
+ );
+ end else begin
+ assign {o_pipe_tdata, o_pipe_tvalid} = {o_ext_tdata, o_ext_tvalid};
+ assign o_ext_tready = o_pipe_tready;
+ end
+ endgenerate
+
+endmodule
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_32_64_tb.v b/fpga/usrp3/lib/fifo/axi_fifo_32_64_tb.v
new file mode 100644
index 000000000..792538361
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_32_64_tb.v
@@ -0,0 +1,119 @@
+//
+// Copyright 2013 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+`timescale 1ns/1ps
+
+module axi_fifo_32_64_tb();
+
+ reg clk = 0;
+ reg reset = 1;
+
+ always #10 clk = ~clk;
+
+ initial $dumpfile("axi_fifo_32_64_tb.vcd");
+ initial $dumpvars(0,axi_fifo_32_64_tb);
+
+ task send_packet;
+ input [63:0] data_start;
+ input [2:0] user;
+ input [31:0] len;
+
+ begin
+ @(posedge clk);
+ {i_tuser, i_tlast, i_tdata} <= { 3'd0, 1'b0, data_start };
+ repeat(len-1)
+ begin
+ i_tvalid <= 1;
+ @(posedge clk);
+ i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
+ end
+ i_tuser <= user;
+ i_tlast <= 1;
+ @(posedge clk);
+ i_tvalid <= 1'b0;
+ @(posedge clk);
+ end
+ endtask // send_packet
+
+ initial
+ begin
+ #1000 reset = 0;
+ #200000;
+ $finish;
+ end
+
+ reg [63:0] i_tdata;
+ reg [2:0] i_tuser;
+ reg i_tlast;
+ reg i_tvalid;
+ wire i_tready;
+
+ wire [63:0] i_tdata_int;
+ wire [2:0] i_tuser_int;
+ wire i_tlast_int, i_tvalid_int, i_tready_int;
+
+ wire [63:0] o_tdata;
+ wire [31:0] o_tdata_int, o_tdata_int2;
+ wire [2:0] o_tuser;
+ wire [1:0] o_tuser_int, o_tuser_int2;
+ wire o_tlast, o_tlast_int, o_tvalid, o_tvalid_int, o_tready, o_tready_int;
+ wire o_tlast_int2, o_tvalid_int2, o_tready_int2;
+
+ localparam RPT_COUNT = 16;
+
+ initial
+ begin
+ i_tvalid <= 0;
+
+ while(reset)
+ @(posedge clk);
+ @(posedge clk);
+
+ send_packet(64'hA0000000_A0000001, 3'd7, 4);
+ @(posedge clk);
+ end // initial begin
+
+ axi_fifo #(.WIDTH(68), .SIZE(10)) fifo
+ (.clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata({i_tlast,i_tuser,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata({i_tlast_int,i_tuser_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int));
+
+ axi_fifo64_to_fifo32 dut
+ (.clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata(i_tdata_int), .i_tuser(i_tuser_int), .i_tlast(i_tlast_int), .i_tvalid(i_tvalid_int), .i_tready(i_tready_int),
+ .o_tdata(o_tdata_int), .o_tuser(o_tuser_int), .o_tlast(o_tlast_int), .o_tvalid(o_tvalid_int), .o_tready(o_tready_int));
+
+ /*
+ axi_fifo #(.WIDTH(35), .SIZE(10)) fifo_middle
+ (.clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata({o_tlast_int,o_tuser_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
+ .o_tdata({o_tlast_int2,o_tuser_int2,o_tdata_int2}), .o_tvalid(o_tvalid_int2), .o_tready(o_tready_int2));
+*/
+ assign o_tdata_int2 = o_tdata_int;
+ assign o_tlast_int2 = o_tlast_int;
+ assign o_tuser_int2 = o_tuser_int;
+ assign o_tvalid_int2 = o_tvalid_int;
+ assign o_tready_int = o_tready_int2;
+
+ axi_fifo32_to_fifo64 dut2
+ (.clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata(o_tdata_int2), .i_tuser(o_tuser_int2), .i_tlast(o_tlast_int2), .i_tvalid(o_tvalid_int2), .i_tready(o_tready_int2),
+ .o_tdata(o_tdata), .o_tuser(o_tuser), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));
+
+ assign o_tready = 1'b1;
+
+ always @(posedge clk)
+ if(i_tvalid & i_tready)
+ $display("IN: TUSER %x\tTLAST %x\tTDATA %x", i_tuser, i_tlast, i_tdata);
+
+ always @(posedge clk)
+ if(o_tvalid_int & o_tready_int)
+ $display("\t\t\t\t\t\tMIDDLE: TUSER %x\tTLAST %x\tTDATA %x", o_tuser_int, o_tlast_int, o_tdata_int);
+
+ always @(posedge clk)
+ if(o_tvalid & o_tready)
+ $display("\t\t\t\t\t\t\t\t\t\t\tOUT: TUSER %x\tTLAST %x\tTDATA %x", o_tuser, o_tlast, o_tdata);
+
+endmodule // axi_fifo_32_64_tb
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_bram.v b/fpga/usrp3/lib/fifo/axi_fifo_bram.v
new file mode 100644
index 000000000..173468129
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_bram.v
@@ -0,0 +1,174 @@
+//
+// Copyright 2012-2014 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+
+
+// Block RAM AXI fifo
+
+
+module axi_fifo_bram
+ #(parameter WIDTH=32, SIZE=9)
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] i_tdata,
+ input i_tvalid,
+ output i_tready,
+ output reg [WIDTH-1:0] o_tdata = 'd0,
+ output reg o_tvalid = 1'b0,
+ input o_tready,
+
+ output reg [15:0] space,
+ output reg [15:0] occupied);
+
+ wire [WIDTH-1:0] int_tdata;
+ wire int_tready;
+
+ wire full, empty;
+ wire write = i_tvalid & i_tready;
+ // read_int will assert when either a read occurs or the output register is empty (and there is data in the shift register fifo)
+ wire read_int = ~empty & int_tready;
+ // read will only assert when an actual 1read request occurs at the interface
+ wire read = o_tready & o_tvalid;
+
+ assign i_tready = ~full;
+
+ // Read side states
+ localparam ST_EMPTY = 0;
+ localparam PRE_READ = 1;
+ localparam READING = 2;
+
+ reg [SIZE-1:0] wr_addr, rd_addr;
+ reg [1:0] read_state;
+
+ reg empty_reg = 1'b1, full_reg = 1'b0;
+ always @(posedge clk)
+ if(reset)
+ wr_addr <= 0;
+ else if(clear)
+ wr_addr <= 0;
+ else if(write)
+ wr_addr <= wr_addr + 1;
+
+ ram_2port #(.DWIDTH(WIDTH),.AWIDTH(SIZE))
+ ram (.clka(clk),
+ .ena(1'b1),
+ .wea(write),
+ .addra(wr_addr),
+ .dia(i_tdata),
+ .doa(),
+
+ .clkb(clk),
+ .enb((read_state==PRE_READ)|read_int),
+ .web(1'b0),
+ .addrb(rd_addr),
+ .dib({WIDTH{1'b1}}),
+ .dob(int_tdata));
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ read_state <= ST_EMPTY;
+ rd_addr <= 0;
+ empty_reg <= 1;
+ end
+ else
+ if(clear)
+ begin
+ read_state <= ST_EMPTY;
+ rd_addr <= 0;
+ empty_reg <= 1;
+ end
+ else
+ case(read_state)
+ ST_EMPTY :
+ if(write)
+ begin
+ //rd_addr <= wr_addr;
+ read_state <= PRE_READ;
+ end
+ PRE_READ :
+ begin
+ read_state <= READING;
+ empty_reg <= 0;
+ rd_addr <= rd_addr + 1;
+ end
+
+ READING :
+ if(read_int)
+ if(rd_addr == wr_addr)
+ begin
+ empty_reg <= 1;
+ if(write)
+ read_state <= PRE_READ;
+ else
+ read_state <= ST_EMPTY;
+ end
+ else
+ rd_addr <= rd_addr + 1;
+ endcase // case(read_state)
+
+ wire [SIZE-1:0] dont_write_past_me = rd_addr - 2;
+ wire becoming_full = wr_addr == dont_write_past_me;
+
+ always @(posedge clk)
+ if(reset)
+ full_reg <= 0;
+ else if(clear)
+ full_reg <= 0;
+ else if(read_int & ~write)
+ full_reg <= 0;
+ //else if(write & ~read_int & (wr_addr == (rd_addr-3)))
+ else if(write & ~read_int & becoming_full)
+ full_reg <= 1;
+
+ //assign empty = (read_state != READING);
+ assign empty = empty_reg;
+
+ // assign full = ((rd_addr - 1) == wr_addr);
+ assign full = full_reg;
+
+ // Output registered stage
+ always @(posedge clk)
+ begin
+ // Valid flag
+ if (reset | clear)
+ o_tvalid <= 1'b0;
+ else if (int_tready)
+ o_tvalid <= ~empty;
+
+ // Data
+ if (int_tready)
+ o_tdata <= int_tdata;
+ end
+
+ assign int_tready = o_tready | ~o_tvalid;
+
+ //////////////////////////////////////////////
+ // space and occupied are for diagnostics only
+ // not guaranteed exact
+
+ localparam NUMLINES = (1<<SIZE)+1; //Output register increases capacity by 1
+ always @(posedge clk)
+ if(reset)
+ space <= NUMLINES;
+ else if(clear)
+ space <= NUMLINES;
+ else if(read & ~write)
+ space <= space + 16'b1;
+ else if(write & ~read)
+ space <= space - 16'b1;
+
+ always @(posedge clk)
+ if(reset)
+ occupied <= 16'b0;
+ else if(clear)
+ occupied <= 16'b0;
+ else if(read & ~write)
+ occupied <= occupied - 16'b1;
+ else if(write & ~read)
+ occupied <= occupied + 16'b1;
+
+endmodule // fifo_long
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_cascade.v b/fpga/usrp3/lib/fifo/axi_fifo_cascade.v
new file mode 100644
index 000000000..84c009c42
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_cascade.v
@@ -0,0 +1,48 @@
+//
+// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+
+
+// Cascade FIFO : ShortFIFO -> Block RAM fifo -> ShortFIFO for timing and placement help
+
+// Special case SIZE <= 5 uses a short fifo in the middle, which is not too useful in this case
+
+module axi_fifo_cascade
+ #(parameter WIDTH=32, SIZE=9)
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] i_tdata,
+ input i_tvalid,
+ output i_tready,
+ output [WIDTH-1:0] o_tdata,
+ output o_tvalid,
+ input o_tready,
+
+ output [15:0] space,
+ output [15:0] occupied);
+
+ wire [WIDTH-1:0] int1_tdata, int2_tdata;
+ wire int1_tvalid, int1_tready, int2_tvalid, int2_tready;
+
+ axi_fifo_flop2 #(.WIDTH(WIDTH)) pre_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata(int1_tdata), .o_tvalid(int1_tvalid), .o_tready(int1_tready),
+ .space(), .occupied());
+
+ axi_fifo #(.WIDTH(WIDTH), .SIZE(SIZE)) main_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(int1_tdata), .i_tvalid(int1_tvalid), .i_tready(int1_tready),
+ .o_tdata(int2_tdata), .o_tvalid(int2_tvalid), .o_tready(int2_tready),
+ .space(space), .occupied(occupied)); // May change unexpectedly, but are always conservative
+
+ axi_fifo_flop2 #(.WIDTH(WIDTH)) post_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(int2_tdata), .i_tvalid(int2_tvalid), .i_tready(int2_tready),
+ .o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+
+endmodule // axi_fifo_cascade
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_flop.v b/fpga/usrp3/lib/fifo/axi_fifo_flop.v
new file mode 100644
index 000000000..a2e058cc1
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_flop.v
@@ -0,0 +1,43 @@
+//
+// Copyright 2014 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+
+//
+// Single FIFO (register) with AXI4-STREAM interface
+//
+
+module axi_fifo_flop
+ #(parameter WIDTH=32)
+ (input clk,
+ input reset,
+ input clear,
+ input [WIDTH-1:0] i_tdata,
+ input i_tvalid,
+ output i_tready,
+ output reg [WIDTH-1:0] o_tdata = 'd0,
+ output reg o_tvalid = 1'b0,
+ input o_tready,
+ output space,
+ output occupied);
+
+ assign i_tready = ~reset & (~o_tvalid | o_tready);
+
+ always @(posedge clk)
+ if(reset | clear)
+ o_tvalid <= 1'b0;
+ else
+ o_tvalid <= (i_tready & i_tvalid) | (o_tvalid & ~o_tready);
+
+ always @(posedge clk)
+ if(i_tvalid & i_tready)
+ o_tdata <= i_tdata;
+
+ // These aren't terribly useful, but include them for consistency
+ assign space = i_tready;
+ assign occupied = o_tvalid;
+
+endmodule // axi_fifo_flop
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_flop2.v b/fpga/usrp3/lib/fifo/axi_fifo_flop2.v
new file mode 100644
index 000000000..381253e56
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_flop2.v
@@ -0,0 +1,59 @@
+//
+// Copyright 2015 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Single cycle latency, depth of 2 "Flip flop" with no end to end combinatorial paths on
+// AXI control signals (such as i_tready depends on o_tready). Breaking the combinatorial
+// paths requires an additional register stage.
+//
+// Note: Once i_tvalid is asserted, it cannot be deasserted without i_tready having asserted
+// indicating i_tdata has been read. This is an AXI stream requirement.
+
+module axi_fifo_flop2 #(
+ parameter WIDTH = 32
+)(
+ input clk,
+ input reset,
+ input clear,
+ input [WIDTH-1:0] i_tdata,
+ input i_tvalid,
+ output i_tready,
+ output reg [WIDTH-1:0] o_tdata = 'h0,
+ output reg o_tvalid = 1'b0,
+ input o_tready,
+ output [1:0] space,
+ output [1:0] occupied);
+
+ reg [WIDTH-1:0] i_tdata_temp = 'h0;
+ reg i_tvalid_temp = 1'b0;
+
+ assign i_tready = ~i_tvalid_temp;
+
+ always @(posedge clk) begin
+ if (~o_tvalid | o_tready) begin
+ if (i_tvalid_temp) begin
+ o_tvalid <= 1'b1;
+ o_tdata <= i_tdata_temp;
+ end else begin
+ o_tvalid <= i_tvalid;
+ o_tdata <= i_tdata;
+ end
+ i_tvalid_temp <= 1'b0;
+ end else begin
+ if (~i_tvalid_temp) begin
+ i_tvalid_temp <= i_tvalid;
+ i_tdata_temp <= i_tdata;
+ end
+ end
+ if (reset | clear) begin
+ o_tvalid <= 1'b0;
+ i_tvalid_temp <= 1'b0;
+ end
+ end
+
+ assign occupied = i_tvalid_temp + o_tvalid;
+ assign space = 2 - occupied;
+
+endmodule
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_short.v b/fpga/usrp3/lib/fifo/axi_fifo_short.v
new file mode 100644
index 000000000..465be28bb
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_short.v
@@ -0,0 +1,113 @@
+//
+// Copyright 2012 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+
+//
+// 32 word FIFO with AXI4-STREAM interface.
+//
+// NOTE: This module uses the SRLC32E primitive explicitly and as such
+// can only be used with Xilinx technology of the VIRTEX-6/SPARTAN-6/SIERIES-7 or newer.
+//
+
+module axi_fifo_short
+ #(parameter WIDTH=32)
+ (
+ input clk,
+ input reset,
+ input clear,
+ input [WIDTH-1:0] i_tdata,
+ input i_tvalid,
+ output i_tready,
+ output [WIDTH-1:0] o_tdata,
+ output o_tvalid,
+ input o_tready,
+
+ output reg [5:0] space,
+ output reg [5:0] occupied
+ );
+
+ reg full = 1'b0, empty = 1'b1;
+ wire write = i_tvalid & i_tready;
+ wire read = o_tready & o_tvalid;
+
+ assign i_tready = ~full;
+ assign o_tvalid = ~empty;
+
+ reg [4:0] a;
+ genvar i;
+
+ generate
+ for (i=0;i<WIDTH;i=i+1)
+ begin : gen_srlc32e
+ SRLC32E
+ srlc32e(.Q(o_tdata[i]), .Q31(),
+ .A(a), //.A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),.A4(a[4]),
+ .CE(write),.CLK(clk),.D(i_tdata[i]));
+ end
+ endgenerate
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ a <= 0;
+ empty <= 1;
+ full <= 0;
+ end
+ else if(clear)
+ begin
+ a <= 0;
+ empty <= 1;
+ full<= 0;
+ end
+ else if(read & ~write)
+ begin
+ full <= 0;
+ if(a==0)
+ empty <= 1;
+ else
+ a <= a - 1;
+ end
+ else if(write & ~read)
+ begin
+ empty <= 0;
+ if(~empty)
+ a <= a + 1;
+ if(a == 30)
+ full <= 1;
+ end
+
+ // NOTE will fail if you write into a full fifo or read from an empty one
+
+ //////////////////////////////////////////////////////////////
+ // space and occupied are used for diagnostics, not
+ // guaranteed correct
+
+ //assign space = full ? 0 : empty ? 16 : 15-a;
+ //assign occupied = empty ? 0 : full ? 16 : a+1;
+
+ always @(posedge clk)
+ if(reset)
+ space <= 6'd32;
+ else if(clear)
+ space <= 6'd32;
+ else if(read & ~write)
+ space <= space + 6'd1;
+ else if(write & ~read)
+ space <= space - 6'd1;
+
+ always @(posedge clk)
+ if(reset)
+ occupied <= 6'd0;
+ else if(clear)
+ occupied <= 6'd0;
+ else if(read & ~write)
+ occupied <= occupied - 6'd1;
+ else if(write & ~read)
+ occupied <= occupied + 6'd1;
+
+endmodule // axi_fifo_short
+
diff --git a/fpga/usrp3/lib/fifo/axi_fifo_tb.v b/fpga/usrp3/lib/fifo/axi_fifo_tb.v
new file mode 100644
index 000000000..69529c7af
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_fifo_tb.v
@@ -0,0 +1,328 @@
+//
+// Copyright 2015 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+module axi_fifo_tb();
+
+ /*********************************************
+ ** User variables
+ *********************************************/
+ localparam FIFO_SIZE = 1;
+ localparam TEST_VECTOR_SIZE = 10;
+
+ /*********************************************
+ ** Clocks & Reset
+ *********************************************/
+ `define CLOCK_FREQ 200e6
+ `define RESET_TIME 100
+
+ reg clk;
+ initial clk = 1'b0;
+ localparam CLOCK_PERIOD = 1e9/`CLOCK_FREQ;
+ always
+ #(CLOCK_PERIOD) clk = ~clk;
+
+ reg reset;
+ initial begin
+ reset = 1'b1;
+ #(`RESET_TIME);
+ @(posedge clk);
+ reset = 1'b0;
+ end
+
+ /*********************************************
+ ** DUT
+ *********************************************/
+ reg [31:0] i_tdata;
+ reg i_tvalid, o_tready;
+ wire i_tready, o_tvalid;
+ wire [31:0] o_tdata;
+ reg clear;
+
+ axi_fifo #(
+ .SIZE(FIFO_SIZE),
+ .WIDTH(32))
+ dut_axi_fifo (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+
+ /*********************************************
+ ** Testbench
+ *********************************************/
+ reg [TEST_VECTOR_SIZE-1:0] i_tvalid_sequence;
+ reg [TEST_VECTOR_SIZE-1:0] o_tready_sequence;
+ integer i,k,n,i_tready_timeout;
+ reg [31:0] o_tdata_check;
+
+ initial begin
+ i_tdata = {32{1'b1}};
+ i_tvalid = 1'b0;
+ o_tready = 1'b0;
+ i_tready_timeout = 0;
+ clear = 1'b0;
+ @(negedge reset);
+ #(10*CLOCK_PERIOD)
+ @(posedge clk);
+ $display("*****************************************************");
+ $display("** Begin Assertion Tests **");
+ $display("*****************************************************");
+ $display("Test 1 -- Check filling FIFO");
+ // Note, if REG_OUTPUT is enabled, the FIFO has space for 1 extra entry
+ for (i = 0; i < 2**FIFO_SIZE; i = i + 1) begin
+ if (~i_tready) begin
+ $display("Test 1 FAILED!");
+ $error("FIFO size should be %d entries, but detected %d!",2**FIFO_SIZE,i);
+ $stop;
+ end
+ i_tvalid = 1'b1;
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ end
+ i_tvalid = 1'b0;
+ @(posedge clk);
+ if (i_tready) begin
+ $display("Test 1 warning!");
+ $warning("i_tready still asserted after filling FIFO with %d entries! Might be due to output registering.",i);
+ //$stop;
+ end
+ $display("Test 1 Passed!");
+ //////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////
+ $display("Test 2 -- Check emptying FIFO");
+ for (i = 0; i < 2**FIFO_SIZE; i = i + 1) begin
+ if (~o_tvalid) begin
+ $display("Test 2 FAILED!");
+ $error("FIFO o_tvalid not asserted! Occured at entry %d",2**FIFO_SIZE-i+1);
+ $stop;
+ end
+ o_tready = 1'b1;
+ @(posedge clk);
+ end
+ o_tready = 1'b0;
+ @(posedge clk);
+ if (o_tvalid) begin
+ $display("Test 1 FAILED!");
+ $error("o_tvalid still asserted after emptying FIFO!");
+ $stop;
+ end
+ $display("Test 2 Passed!");
+ //////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////
+ $display("Test 3 -- Check for o_tready / i_tready dropping unexpectantly");
+ clear = 1'b1;
+ i_tdata = {32{1'b1}};
+ i_tvalid = 1'b0;
+ o_tready = 1'b0;
+ @(posedge clk);
+ clear = 1'b0;
+ @(posedge clk);
+ for (i = 0; i < 2**FIFO_SIZE-1; i = i + 1) begin
+ i_tvalid = 1'b1;
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ i_tvalid = 1'b0;
+ // Give some time to propogate
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ if (~i_tready) begin
+ $display("Test 3 FAILED!");
+ $error("i_tready deasserted unexpectantly after writing %d entries!",i+1);
+ $stop;
+ end
+ if (~o_tvalid) begin
+ $display("Test 3 FAILED!");
+ $error("o_tvalid deasserted unexpectantly after writing %d entries!",i+1);
+ $stop;
+ end
+ end
+ // Write final entry
+ i_tvalid = 1'b1;
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ i_tvalid = 1'b0;
+ @(posedge clk);
+ if (i_tready) begin
+ $display("Test 3 warning!");
+ $warning("i_tready still asserted after writing %d entries! Might be due to output registering.",i+1);
+ //$stop;
+ end
+ @(posedge clk);
+ for (i = 0; i < 2**FIFO_SIZE-1; i = i + 1) begin
+ o_tready = 1'b1;
+ @(posedge clk);
+ o_tready = 1'b0;
+ // Give some time to propogate
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ if (~i_tready) begin
+ $display("Test 3 FAILED!");
+ $error("i_tready deasserted unexpectantly after reading %d entries!",i+1);
+ $stop;
+ end
+ if (~o_tvalid) begin
+ $display("Test 3 FAILED!");
+ $error("o_tvalid deasserted unexpectantly after reading %d entries!",i+1);
+ $stop;
+ end
+ end
+ // Read final entry
+ o_tready = 1'b1;
+ @(posedge clk);
+ o_tready = 1'b0;
+ @(posedge clk);
+ if (o_tvalid) begin
+ $display("Test 3 FAILED!");
+ $error("o_tvalid still asserted after reading %d entries!",i+1);
+ $stop;
+ end
+ @(posedge clk);
+ //////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////
+ $display("Test 4 -- Check for bubble states");
+ clear = 1'b1;
+ i_tdata = {32{1'b1}};
+ i_tvalid = 1'b0;
+ o_tready = 1'b0;
+ @(posedge clk);
+ clear = 1'b0;
+ @(posedge clk);
+ // Fill up half way
+ for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
+ i_tvalid = 1'b1;
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ end
+ // Start reading
+ o_tready = 1'b1;
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ // Give a clock cycle for latency, but no bubbles should occur after this
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ // Continue to write and read at full rate
+ for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
+ if (~i_tready) begin
+ $display("Test 4 FAILED!");
+ $error("FIFO bubble state detected when writing & reading at full rate!");
+ $stop;
+ end
+ i_tvalid = 1'b1;
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ end
+ // Read at full, write at half rate
+ for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
+ if (~i_tready | ~o_tvalid) begin
+ $display("Test 4 FAILED!");
+ $error("FIFO bubble state detected when write at half rate, reading at full rate!");
+ $stop;
+ end
+ i_tvalid = ~i_tvalid;
+ if (i_tvalid) i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ end
+ // Read at half rate, write at full rate
+ for (i = 0; i < (2**FIFO_SIZE + 1)/2; i = i + 1) begin
+ if (~i_tready | ~o_tvalid) begin
+ $display("Test 4 FAILED!");
+ $error("FIFO bubble state detected when write at half rate, reading at full rate!");
+ $stop;
+ end
+ o_tready = ~o_tready;
+ i_tvalid = 1'b1;
+ i_tdata = i_tdata + 32'd1;
+ @(posedge clk);
+ end
+ $display("Test 4 Passed!");
+ //////////////////////////////////////////////////////////////////////////////
+ // Tests combinations of i_tvalid / o_tready sequences.
+ // Test space depends on TEST_VECTOR_SIZE.
+ // Example: TEST_VECTOR_SIZE = 10 => 1024*1024 number of test sequences,
+ // which is every possible 10 bit sequence of i_tvalid / o_tready.
+ $display("Test 5 -- Check combinations of i_tvalid / o_tready");
+ clear = 1'b1;
+ i_tdata = {32{1'b1}};
+ i_tvalid = 1'b0;
+ o_tready = 1'b0;
+ i_tready_timeout = 0;
+ i_tvalid_sequence = {TEST_VECTOR_SIZE{1'd0}};
+ o_tready_sequence = {TEST_VECTOR_SIZE{1'd0}};
+ @(posedge clk);
+ clear = 1'b0;
+ @(posedge clk);
+ for (i = 0; i < 2**TEST_VECTOR_SIZE; i = i + 1) begin
+ i_tvalid_sequence = i_tvalid_sequence + 1;
+ for (k = 0; k < 2**TEST_VECTOR_SIZE; k = k + 1) begin
+ o_tready_sequence = o_tready_sequence + 1;
+ for (n = 0; n < TEST_VECTOR_SIZE; n = n + 1) begin
+ if (o_tready_sequence[n]) begin
+ o_tready = 1'b1;
+ end else begin
+ o_tready = 1'b0;
+ end
+ // Special Case: If i_tready timed out, then i_tvalid is still asserted and we cannot
+ // deassert i_tvalid until we see a corresponding i_tready. This is a basic
+ // AXI stream requirement, so we will continue to assert i_tvalid regardless
+ // of what i_tvalid_sequence would have set i_tvalid for this loop.
+ if (i_tvalid_sequence[n] | (i_tready_timeout == TEST_VECTOR_SIZE)) begin
+ i_tvalid = 1'b1;
+ if (i_tready_timeout < TEST_VECTOR_SIZE) begin
+ i_tdata = i_tdata + 32'd1;
+ end
+ @(posedge clk);
+ i_tready_timeout = 0;
+ // Wait for i_tready until timeout. Timeouts may occur when o_tready_sequence
+ // has o_tready not asserted for several clock cycles.
+ while(~i_tready & (i_tready_timeout < TEST_VECTOR_SIZE)) begin
+ @(posedge clk)
+ i_tready_timeout = i_tready_timeout + 1;
+ end
+ end else begin
+ i_tvalid = 1'b0;
+ @(posedge clk);
+ end
+ end
+ end
+ // Reset starting conditions for the test sequences
+ clear = 1'b1;
+ i_tdata = {32{1'b1}};
+ i_tvalid = 1'b0;
+ o_tready = 1'b0;
+ i_tready_timeout = 0;
+ @(posedge clk);
+ clear = 1'b0;
+ @(posedge clk);
+ end
+ $display("Test 5 Passed!");
+ $display("All tests PASSED!");
+ $stop;
+ end
+
+ // Check the input counting sequence independent of
+ // i_tvalid / o_tready sequences.
+ always @(posedge clk) begin
+ if (reset) begin
+ o_tdata_check <= 32'd0;
+ end else begin
+ if (clear) begin
+ o_tdata_check <= 32'd0;
+ end
+ if (o_tready & o_tvalid) begin
+ o_tdata_check <= o_tdata_check + 32'd1;
+ if (o_tdata != o_tdata_check) begin
+ $display("Test FAILED!");
+ $error("Incorrect output!");
+ $stop;
+ end
+ end
+ end
+ end
+
+endmodule
diff --git a/fpga/usrp3/lib/fifo/axi_filter_mux4.v b/fpga/usrp3/lib/fifo/axi_filter_mux4.v
new file mode 100644
index 000000000..4c9d76003
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_filter_mux4.v
@@ -0,0 +1,158 @@
+//
+// Copyright 2014 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// axi_filter_mux -- takes 4 64-bit AXI stream of CHDR data, merges them to 1 output channel
+// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
+// Bubble cycles are inserted after each packet in PRIO mode, or on wraparound in Round Robin mode.
+// Filter forces specific destination SID to pass per port, else dump data to /dev/null
+
+module axi_filter_mux4
+ #(parameter PRIO=0,
+ parameter WIDTH=64,
+ parameter BUFFER=0,
+ parameter FILTER0 =0,
+ parameter FILTER1 =0,
+ parameter FILTER2 =0,
+ parameter FILTER3 =0
+ )
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
+ input [WIDTH-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
+ input [WIDTH-1:0] i2_tdata, input i2_tlast, input i2_tvalid, output i2_tready,
+ input [WIDTH-1:0] i3_tdata, input i3_tlast, input i3_tvalid, output i3_tready,
+ output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
+
+ wire [WIDTH-1:0] o_tdata_int;
+ wire o_tlast_int, o_tvalid_int, o_tready_int;
+
+ reg [3:0] mx_state;
+ reg filter_packet;
+
+ localparam MX_IDLE = 4'b0000;
+ localparam MX_0 = 4'b0001;
+ localparam MX_1 = 4'b0010;
+ localparam MX_2 = 4'b0100;
+ localparam MX_3 = 4'b1000;
+
+
+ assign good0 = i0_tdata[15:0]==FILTER0;
+ assign good1 = i1_tdata[15:0]==FILTER1;
+ assign good2 = i2_tdata[15:0]==FILTER2;
+ assign good3 = i3_tdata[15:0]==FILTER3;
+
+ always @(posedge clk)
+ if(reset | clear)
+ mx_state <= MX_IDLE;
+ else
+ case (mx_state)
+ MX_IDLE :
+ if(i0_tvalid) begin
+ mx_state <= MX_0;
+ filter_packet <= !good0;
+ end
+ else if(i1_tvalid) begin
+ mx_state <= MX_1;
+ filter_packet <= !good1;
+ end
+ else if(i2_tvalid) begin
+ mx_state <= MX_2;
+ filter_packet <= !good2;
+ end
+ else if(i3_tvalid) begin
+ mx_state <= MX_3;
+ filter_packet <= !good3;
+ end
+
+ MX_0 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ if(PRIO)
+ mx_state <= MX_IDLE;
+ else if(i1_tvalid) begin
+ mx_state <= MX_1;
+ filter_packet <= !good1;
+ end
+ else if(i2_tvalid) begin
+ mx_state <= MX_2;
+ filter_packet <= !good2;
+ end
+ else if(i3_tvalid) begin
+ mx_state <= MX_3;
+ filter_packet <= !good3;
+ end
+ else begin
+ mx_state <= MX_IDLE;
+ filter_packet <= 0;
+ end
+
+ MX_1 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ if(PRIO)
+ mx_state <= MX_IDLE;
+ else if(i2_tvalid) begin
+ mx_state <= MX_2;
+ filter_packet <= !good2;
+ end
+ else if(i3_tvalid) begin
+ mx_state <= MX_3;
+ filter_packet <= !good3;
+ end
+ else begin
+ mx_state <= MX_IDLE;
+ filter_packet <= 0;
+ end
+ MX_2 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ if(PRIO)
+ mx_state <= MX_IDLE;
+ else if(i3_tvalid) begin
+ mx_state <= MX_3;
+ filter_packet <= !good3;
+ end
+ else begin
+ mx_state <= MX_IDLE;
+ filter_packet <= 0;
+ end
+ MX_3 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ begin
+ mx_state <= MX_IDLE;
+ filter_packet <= 0;
+ end
+
+ default :
+ mx_state <= MX_IDLE;
+ endcase // case (mx_state)
+
+ assign {i3_tready, i2_tready, i1_tready, i0_tready} = mx_state & {4{o_tready_int}};
+
+ assign o_tvalid_int = |(mx_state & ({i3_tvalid, i2_tvalid, i1_tvalid, i0_tvalid}));
+
+ assign {o_tlast_int, o_tdata_int} = mx_state[3] ? {i3_tlast, i3_tdata} :
+ mx_state[2] ? {i2_tlast, i2_tdata} :
+ mx_state[1] ? {i1_tlast, i1_tdata} :
+ {i0_tlast, i0_tdata};
+
+ generate
+ if(BUFFER == 0)
+ begin
+ assign o_tdata = o_tdata_int;
+ assign o_tlast = o_tlast_int;
+ assign o_tvalid = o_tvalid_int & !filter_packet;
+ assign o_tready_int = o_tready | filter_packet;
+ end
+ else
+ begin
+ wire o_tready_int_fifo;
+ assign o_tready_int = o_tready_int_fifo | filter_packet;
+
+ axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int & !filter_packet), .i_tready(o_tready_int_fifo),
+ .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+ end
+ endgenerate
+
+endmodule // axi__mux4
diff --git a/fpga/usrp3/lib/fifo/axi_loopback.v b/fpga/usrp3/lib/fifo/axi_loopback.v
new file mode 100644
index 000000000..f80288a73
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_loopback.v
@@ -0,0 +1,75 @@
+//
+// Copyright 2012 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+//
+// axi_loopback.v
+//
+// Loopback all data assuming it's in CHDR format, and swap SRC/DST in the SID in the process
+// thus reflecting it back to it's origin...in theory!
+//
+
+module axi_loopback
+ #(
+ parameter WIDTH = 64
+ )
+ (
+ input clk,
+ input reset,
+ // Input AXIS
+ input [WIDTH-1:0] i_tdata,
+ input i_tlast,
+ input i_tvalid,
+ output i_tready,
+ // Output AXIS
+ output [WIDTH-1:0] o_tdata,
+ output o_tlast,
+ output o_tvalid,
+ input o_tready
+ );
+
+ wire [WIDTH-1:0] fifoin_tdata,fifoout_tdata,dmux_tdata;
+ wire fifoin_tlast,dmux_tlast;
+ wire fifoin_tvalid,dmux_tvalid;
+ wire fifoin_tready,dmux_tready;
+
+ // Since most real endpoints go via Demux4 place one in here to look for bugs.
+ axi_demux4 #(.ACTIVE_CHAN(4'b0001), .WIDTH(WIDTH)) demux
+ (.clk(clk), .reset(reset), .clear(1'b0),
+ .header(), .dest(2'b00),
+ .i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
+ .o0_tdata(dmux_tdata), .o0_tlast(dmux_tlast), .o0_tvalid(dmux_tvalid), .o0_tready(dmux_tready),
+ .o1_tdata(), .o1_tlast(), .o1_tvalid(), .o1_tready(1'b1),
+ .o2_tdata(), .o2_tlast(), .o2_tvalid(), .o2_tready(1'b1),
+ .o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b1));
+
+ axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short1
+ (.clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata({dmux_tlast,dmux_tdata}), .i_tvalid(dmux_tvalid), .i_tready(dmux_tready),
+ .o_tdata({fifoin_tlast,fifoin_tdata}), .o_tvalid(fifoin_tvalid), .o_tready(fifoin_tready),
+ .space(), .occupied());
+
+ reg header;
+ always @(posedge clk) begin
+ if(reset) begin
+ header <= 1'b1;
+ end else if (header) begin
+ if(fifoin_tvalid & fifoin_tready & ~fifoin_tlast) header <= 1'b0;
+ end else begin
+ if(fifoin_tvalid & fifoin_tready & fifoin_tlast) header <= 1'b1;
+ end
+ end
+
+ assign fifoout_tdata = header ?
+ {fifoin_tdata[63:32] ,fifoin_tdata[15:0],fifoin_tdata[31:16]} :
+ fifoin_tdata;
+
+ axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short2
+ (.clk(clk), .reset(reset), .clear(1'b0),
+ .i_tdata({fifoin_tlast,fifoout_tdata}), .i_tvalid(fifoin_tvalid), .i_tready(fifoin_tready),
+ .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+
+endmodule // axi_loopback
diff --git a/fpga/usrp3/lib/fifo/axi_mux.v b/fpga/usrp3/lib/fifo/axi_mux.v
new file mode 100644
index 000000000..72a771348
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_mux.v
@@ -0,0 +1,110 @@
+
+// Copyright 2016 Ettus Research
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+// axi_mux -- takes arbitrary number of AXI stream, merges them to 1 output channel
+// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
+// Bubble cycles are inserted after each packet
+
+module axi_mux
+ #(parameter PRIO=0,
+ parameter WIDTH=64,
+ parameter PRE_FIFO_SIZE=0,
+ parameter POST_FIFO_SIZE=0,
+ parameter SIZE=4)
+ (input clk, input reset, input clear,
+ input [(WIDTH*SIZE)-1:0] i_tdata, input [SIZE-1:0] i_tlast, input [SIZE-1:0] i_tvalid, output [SIZE-1:0] i_tready,
+ output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
+
+ wire [WIDTH*SIZE-1:0] i_tdata_int;
+ wire [SIZE-1:0] i_tlast_int, i_tvalid_int, i_tready_int;
+
+ wire [WIDTH-1:0] o_tdata_int;
+ wire o_tlast_int, o_tvalid_int, o_tready_int;
+
+ reg [$clog2(SIZE)-1:0] st_port;
+ reg st_active;
+
+ genvar n;
+ generate
+ if (PRE_FIFO_SIZE == 0) begin
+ assign i_tdata_int = i_tdata;
+ assign i_tlast_int = i_tlast;
+ assign i_tvalid_int = i_tvalid;
+ assign i_tready = i_tready_int;
+ end else begin
+ for (n = 0; n < SIZE; n = n + 1) begin
+ axi_fifo #(.WIDTH(WIDTH+1), .SIZE(PRE_FIFO_SIZE)) axi_fifo (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({i_tlast[n],i_tdata[WIDTH*(n+1)-1:WIDTH*n]}), .i_tvalid(i_tvalid[n]), .i_tready(i_tready[n]),
+ .o_tdata({i_tlast_int[n],i_tdata_int[WIDTH*(n+1)-1:WIDTH*n]}), .o_tvalid(i_tvalid_int[n]), .o_tready(i_tready_int[n]),
+ .space(), .occupied());
+ end
+ end
+ endgenerate
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ st_port <= 0;
+ st_active <= 1'b0;
+ end
+ else
+ if(st_active)
+ begin
+ if(o_tlast_int & o_tvalid_int & o_tready_int)
+ begin
+ st_active <= 1'b0;
+ if((PRIO != 0) | (st_port == (SIZE-1)))
+ st_port <= 0;
+ else
+ st_port <= st_port + 1;
+ end
+ end // if (st_active)
+ else
+ if(i_tvalid_int[st_port])
+ st_active <= 1'b1;
+ else
+ if(st_port == (SIZE-1))
+ st_port <= 0;
+ else
+ st_port <= st_port + 1;
+
+ genvar i;
+ generate
+ for(i=0;i<SIZE;i=i+1)
+ begin : gen1
+ assign i_tready_int[i] = st_active & o_tready_int & (st_port == i);
+ end
+ endgenerate
+
+ assign o_tvalid_int = st_active & i_tvalid_int[st_port];
+ assign o_tlast_int = i_tlast_int[st_port];
+
+ genvar j;
+ generate
+ for (j=0;j<WIDTH;j=j+1)
+ begin : gen2
+ assign o_tdata_int[j] = i_tdata_int[st_port*WIDTH+j];
+ end
+ endgenerate
+
+ generate
+ if(POST_FIFO_SIZE == 0)
+ begin
+ assign o_tdata = o_tdata_int;
+ assign o_tlast = o_tlast_int;
+ assign o_tvalid = o_tvalid_int;
+ assign o_tready_int = o_tready;
+ end
+ else
+ axi_fifo #(.WIDTH(WIDTH+1),.SIZE(POST_FIFO_SIZE)) axi_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
+ .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+ endgenerate
+
+endmodule // axi__mux
diff --git a/fpga/usrp3/lib/fifo/axi_mux4.v b/fpga/usrp3/lib/fifo/axi_mux4.v
new file mode 100644
index 000000000..1bc603e90
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_mux4.v
@@ -0,0 +1,115 @@
+
+// Copyright 2012 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// axi_mux -- takes 4 64-bit AXI stream, merges them to 1 output channel
+// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
+// Bubble cycles are inserted after each packet in PRIO mode, or on wraparound in Round Robin mode
+
+module axi_mux4
+ #(parameter PRIO=0,
+ parameter WIDTH=64,
+ parameter BUFFER=0)
+ (input clk, input reset, input clear,
+ input [WIDTH-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
+ input [WIDTH-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
+ input [WIDTH-1:0] i2_tdata, input i2_tlast, input i2_tvalid, output i2_tready,
+ input [WIDTH-1:0] i3_tdata, input i3_tlast, input i3_tvalid, output i3_tready,
+ output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
+
+ wire [WIDTH-1:0] o_tdata_int;
+ wire o_tlast_int, o_tvalid_int, o_tready_int;
+
+ reg [3:0] mx_state;
+ localparam MX_IDLE = 4'b0000;
+ localparam MX_0 = 4'b0001;
+ localparam MX_1 = 4'b0010;
+ localparam MX_2 = 4'b0100;
+ localparam MX_3 = 4'b1000;
+
+ always @(posedge clk)
+ if(reset | clear)
+ mx_state <= MX_IDLE;
+ else
+ case (mx_state)
+ MX_IDLE :
+ if(i0_tvalid)
+ mx_state <= MX_0;
+ else if(i1_tvalid)
+ mx_state <= MX_1;
+ else if(i2_tvalid)
+ mx_state <= MX_2;
+ else if(i3_tvalid)
+ mx_state <= MX_3;
+
+ MX_0 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ if(PRIO)
+ mx_state <= MX_IDLE;
+ else if(i1_tvalid)
+ mx_state <= MX_1;
+ else if(i2_tvalid)
+ mx_state <= MX_2;
+ else if(i3_tvalid)
+ mx_state <= MX_3;
+ else
+ mx_state <= MX_IDLE;
+
+ MX_1 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ if(PRIO)
+ mx_state <= MX_IDLE;
+ else if(i2_tvalid)
+ mx_state <= MX_2;
+ else if(i3_tvalid)
+ mx_state <= MX_3;
+ else
+ mx_state <= MX_IDLE;
+
+ MX_2 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ if(PRIO)
+ mx_state <= MX_IDLE;
+ else if(i3_tvalid)
+ mx_state <= MX_3;
+ else
+ mx_state <= MX_IDLE;
+
+ MX_3 :
+ if(o_tready_int & o_tvalid_int & o_tlast_int)
+ if(PRIO)
+ mx_state <= MX_IDLE;
+ else
+ mx_state <= MX_IDLE;
+
+ default :
+ mx_state <= MX_IDLE;
+ endcase // case (mx_state)
+
+ assign {i3_tready, i2_tready, i1_tready, i0_tready} = mx_state & {4{o_tready_int}};
+
+ assign o_tvalid_int = |(mx_state & ({i3_tvalid, i2_tvalid, i1_tvalid, i0_tvalid}));
+
+ assign {o_tlast_int, o_tdata_int} = mx_state[3] ? {i3_tlast, i3_tdata} :
+ mx_state[2] ? {i2_tlast, i2_tdata} :
+ mx_state[1] ? {i1_tlast, i1_tdata} :
+ {i0_tlast, i0_tdata};
+
+ generate
+ if(BUFFER == 0)
+ begin
+ assign o_tdata = o_tdata_int;
+ assign o_tlast = o_tlast_int;
+ assign o_tvalid = o_tvalid_int;
+ assign o_tready_int = o_tready;
+ end
+ else
+ axi_fifo_flop2 #(.WIDTH(WIDTH+1)) axi_fifo_flop2
+ (.clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
+ .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+ endgenerate
+
+endmodule // axi__mux4
diff --git a/fpga/usrp3/lib/fifo/axi_mux8.v b/fpga/usrp3/lib/fifo/axi_mux8.v
new file mode 100644
index 000000000..cfcce6f8f
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_mux8.v
@@ -0,0 +1,59 @@
+
+// Copyright 2012 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// axi_mux -- takes 8 64-bit AXI stream, merges them to 1 output channel
+// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
+// Bubble cycles are inserted after each packet in PRIO mode, or on wraparound in Round Robin mode
+
+module axi_mux8 #(
+ parameter PRIO=0,
+ parameter WIDTH=64,
+ parameter BUFFER=0
+) (
+ input clk, input reset, input clear,
+ input [WIDTH-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
+ input [WIDTH-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
+ input [WIDTH-1:0] i2_tdata, input i2_tlast, input i2_tvalid, output i2_tready,
+ input [WIDTH-1:0] i3_tdata, input i3_tlast, input i3_tvalid, output i3_tready,
+ input [WIDTH-1:0] i4_tdata, input i4_tlast, input i4_tvalid, output i4_tready,
+ input [WIDTH-1:0] i5_tdata, input i5_tlast, input i5_tvalid, output i5_tready,
+ input [WIDTH-1:0] i6_tdata, input i6_tlast, input i6_tvalid, output i6_tready,
+ input [WIDTH-1:0] i7_tdata, input i7_tlast, input i7_tvalid, output i7_tready,
+ output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
+);
+
+ wire [WIDTH-1:0] o_tdata_int0, o_tdata_int1;
+ wire o_tlast_int0, o_tlast_int1;
+ wire o_tvalid_int0, o_tvalid_int1;
+ wire o_tready_int0, o_tready_int1;
+
+ axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(0)) mux4_int0 (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i0_tdata(i0_tdata), .i0_tlast(i0_tlast), .i0_tvalid(i0_tvalid), .i0_tready(i0_tready),
+ .i1_tdata(i1_tdata), .i1_tlast(i1_tlast), .i1_tvalid(i1_tvalid), .i1_tready(i1_tready),
+ .i2_tdata(i2_tdata), .i2_tlast(i2_tlast), .i2_tvalid(i2_tvalid), .i2_tready(i2_tready),
+ .i3_tdata(i3_tdata), .i3_tlast(i3_tlast), .i3_tvalid(i3_tvalid), .i3_tready(i3_tready),
+ .o_tdata(o_tdata_int0), .o_tlast(o_tlast_int0), .o_tvalid(o_tvalid_int0), .o_tready(o_tready_int0)
+ );
+
+ axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(0)) mux4_int1 (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i0_tdata(i4_tdata), .i0_tlast(i4_tlast), .i0_tvalid(i4_tvalid), .i0_tready(i4_tready),
+ .i1_tdata(i5_tdata), .i1_tlast(i5_tlast), .i1_tvalid(i5_tvalid), .i1_tready(i5_tready),
+ .i2_tdata(i6_tdata), .i2_tlast(i6_tlast), .i2_tvalid(i6_tvalid), .i2_tready(i6_tready),
+ .i3_tdata(i7_tdata), .i3_tlast(i7_tlast), .i3_tvalid(i7_tvalid), .i3_tready(i7_tready),
+ .o_tdata(o_tdata_int1), .o_tlast(o_tlast_int1), .o_tvalid(o_tvalid_int1), .o_tready(o_tready_int1)
+ );
+
+ axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(BUFFER)) mux2 (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i0_tdata(o_tdata_int0), .i0_tlast(o_tlast_int0), .i0_tvalid(o_tvalid_int0), .i0_tready(o_tready_int0),
+ .i1_tdata(o_tdata_int1), .i1_tlast(o_tlast_int1), .i1_tvalid(o_tvalid_int1), .i1_tready(o_tready_int1),
+ .i2_tdata(0), .i2_tlast(1'b0), .i2_tvalid(1'b0), .i2_tready(),
+ .i3_tdata(0), .i3_tlast(1'b0), .i3_tvalid(1'b0), .i3_tready(),
+ .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
+ );
+
+endmodule // axi_mux8
diff --git a/fpga/usrp3/lib/fifo/axi_mux_select.v b/fpga/usrp3/lib/fifo/axi_mux_select.v
new file mode 100644
index 000000000..d3c38ba30
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_mux_select.v
@@ -0,0 +1,104 @@
+//
+// Copyright 2016 Ettus Research
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// AXI-Stream multipler with select line
+//
+
+module axi_mux_select #(
+ parameter WIDTH = 32,
+ parameter PRE_FIFO_SIZE = 0,
+ parameter POST_FIFO_SIZE = 0,
+ parameter SWITCH_ON_LAST = 0, // Wait until tlast is asserted before updating
+ parameter SIZE = 4)
+(
+ input clk, input reset, input clear,
+ input [$clog2(SIZE)-1:0] select,
+ input [SIZE*WIDTH-1:0] i_tdata, input [SIZE-1:0] i_tlast, input [SIZE-1:0] i_tvalid, output [SIZE-1:0] i_tready,
+ output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
+);
+
+ wire [WIDTH*SIZE-1:0] i_tdata_int;
+ wire [WIDTH-1:0] i_tdata_arr[0:SIZE-1];
+ wire [SIZE-1:0] i_tlast_int, i_tvalid_int, i_tready_int;
+
+ wire [WIDTH-1:0] o_tdata_int;
+ wire o_tlast_int, o_tvalid_int, o_tready_int;
+
+ genvar n;
+ generate
+ if (PRE_FIFO_SIZE == 0) begin
+ assign i_tdata_int = i_tdata;
+ assign i_tlast_int = i_tlast;
+ assign i_tvalid_int = i_tvalid;
+ assign i_tready = i_tready_int;
+ end else begin
+ for (n = 0; n < SIZE; n = n + 1) begin
+ axi_fifo #(.WIDTH(WIDTH+1), .SIZE(PRE_FIFO_SIZE)) axi_fifo (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({i_tlast[n],i_tdata[WIDTH*(n+1)-1:WIDTH*n]}), .i_tvalid(i_tvalid[n]), .i_tready(i_tready[n]),
+ .o_tdata({i_tlast_int[n],i_tdata_int[WIDTH*(n+1)-1:WIDTH*n]}), .o_tvalid(i_tvalid_int[n]), .o_tready(i_tready_int[n]),
+ .space(), .occupied());
+ end
+ end
+ endgenerate
+
+ // Make arrays for easier muxing
+ genvar i;
+ generate
+ for (i = 0; i < SIZE; i = i + 1) begin
+ assign i_tdata_arr[i] = i_tdata_int[WIDTH*(i+1)-1:WIDTH*i];
+ end
+ endgenerate
+
+ // Switch select line either immediately or after the last word in a packet
+ reg [$clog2(SIZE)-1:0] select_hold;
+ generate
+ if (SWITCH_ON_LAST) begin
+ reg init;
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ init <= 1'b0;
+ select_hold <= 'd0;
+ end else begin
+ if (|i_tvalid) begin
+ init <= 1'b1;
+ end
+ // Set select any time after reset and before the first packet OR
+ // at the end of a packet
+ if (~init | (o_tlast_int & o_tvalid_int & o_tready_int)) begin
+ select_hold <= select;
+ end
+ end
+ end
+ end else begin
+ always @(*) begin
+ select_hold <= select;
+ end
+ end
+ endgenerate
+
+ // Mux
+ assign o_tdata_int = i_tdata_arr[select_hold];
+ assign o_tlast_int = i_tlast_int[select_hold];
+ assign o_tvalid_int = i_tvalid_int[select_hold];
+ assign i_tready_int = (1'b1 << select_hold) & {SIZE{o_tready_int}};
+
+ generate
+ if(POST_FIFO_SIZE == 0) begin
+ assign o_tdata = o_tdata_int;
+ assign o_tlast = o_tlast_int;
+ assign o_tvalid = o_tvalid_int;
+ assign o_tready_int = o_tready;
+ end else begin
+ axi_fifo #(.WIDTH(WIDTH+1),.SIZE(POST_FIFO_SIZE)) axi_fifo (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
+ .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+ end
+ endgenerate
+
+endmodule \ No newline at end of file
diff --git a/fpga/usrp3/lib/fifo/axi_packet_gate.v b/fpga/usrp3/lib/fifo/axi_packet_gate.v
new file mode 100644
index 000000000..771fb2200
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axi_packet_gate.v
@@ -0,0 +1,229 @@
+//
+// Copyright 2012 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Description:
+// Holds packets in a FIFO until they are complete. This allows buffering
+// slowly-built packets so they don't clog up downstream logic. If o_tready
+// is held high, this module guarantees that o_tvalid will not be deasserted
+// until a full packet is transferred. This module can also optionally drop
+// a packet if the i_terror bit is asserted along with i_tlast. This allows
+// discarding packet, say, if a CRC check fails.
+// NOTE:
+// - The maximum size of a packet that can pass through this module is
+// 2^SIZE lines. If a larger packet is sent, this module will lock up.
+// - Assuming that upstream is valid and downstream is ready, the maximum
+// in to out latency per packet is (2^SIZE + 2) clock cycles.
+// 2^SIZE because this module gates a packet, 1 cycle for the RAM read and
+// 1 more cycle for the output register. This is not guaranteed behavior though.
+// - The USE_AS_BUFF parameter can be used to treat this packet gate as
+// a multi-packet buffer. When USE_AS_BUFF=0, the max number of packets
+// (regardless of size) that the module can store is 2. When USE_AS_BUFF=1,
+// the entire storage of this module can be used to buffer packets but at
+// the cost of some additional RAM. Beware the sequence of (big packet,
+// small packet, small packet), as some outside buffering may be needed
+// to handle this case if USE_AS_BUFF=0.
+
+module axi_packet_gate #(
+ parameter WIDTH = 64, // Width of datapath
+ parameter SIZE = 10, // log2 of the buffer size (must be >= MTU of packet)
+ parameter USE_AS_BUFF = 0, // Allow the packet gate to be used as a buffer (uses more RAM)
+ parameter MIN_PKT_SIZE= 0 // log2 of minimum valid packet size (rounded down, used to reduce addr fifo size)
+) (
+ input wire clk,
+ input wire reset,
+ input wire clear,
+ input wire [WIDTH-1:0] i_tdata,
+ input wire i_tlast,
+ input wire i_terror,
+ input wire i_tvalid,
+ output wire i_tready,
+ output reg [WIDTH-1:0] o_tdata = {WIDTH{1'b0}},
+ output reg o_tlast = 1'b0,
+ output reg o_tvalid = 1'b0,
+ input wire o_tready
+);
+
+ localparam [SIZE-1:0] ADDR_ZERO = {SIZE{1'b0}};
+ localparam [SIZE-1:0] ADDR_ONE = {{(SIZE-1){1'b0}}, 1'b1};
+
+ // -------------------------------------------
+ // RAM block that will hold pkts
+ // -------------------------------------------
+ wire wr_en, rd_en;
+ wire [WIDTH:0] wr_data, rd_data;
+ reg [SIZE-1:0] wr_addr = ADDR_ZERO, rd_addr = ADDR_ZERO;
+
+ // Threshold to explicitly instantiate LUTRAM
+ localparam LUTRAM_THRESH = 5;
+
+ // We need to instantiate a simple dual-port RAM here so
+ // we use the ram_2port module with one read port and one
+ // write port and "NO-CHANGE" mode.
+ ram_2port #(
+ .DWIDTH (WIDTH+1), .AWIDTH(SIZE),
+ .RW_MODE("NO-CHANGE"), .OUT_REG(0),
+ .RAM_TYPE(SIZE <= LUTRAM_THRESH ? "LUTRAM" : "AUTOMATIC")
+ ) ram_i (
+ .clka (clk), .ena(1'b1), .wea(wr_en),
+ .addra(wr_addr), .dia(wr_data), .doa(),
+ .clkb (clk), .enb(rd_en), .web(1'b0),
+ .addrb(rd_addr), .dib({WIDTH{1'b0}}), .dob(rd_data)
+ );
+
+ // FIFO empty/full logic. The condition for both
+ // empty and full is when rd_addr == wr_addr. However,
+ // it matters if we approach that case from the low side
+ // or the high side. So keep track of the almost empty/full
+ // state for determine if the next transaction will cause
+ // the FIFO to be truly empty or full.
+ reg ram_full = 1'b0, ram_empty = 1'b1;
+ wire almost_full = (wr_addr == rd_addr - ADDR_ONE);
+ wire almost_empty = (wr_addr == rd_addr + ADDR_ONE);
+
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ ram_full <= 1'b0;
+ end else begin
+ if (almost_full) begin
+ if (wr_en & ~rd_en)
+ ram_full <= 1'b1;
+ end else begin
+ if (~wr_en & rd_en)
+ ram_full <= 1'b0;
+ end
+ end
+ end
+
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ ram_empty <= 1'b1;
+ end else begin
+ if (almost_empty) begin
+ if (rd_en & ~wr_en)
+ ram_empty <= 1'b1;
+ end else begin
+ if (~rd_en & wr_en)
+ ram_empty <= 1'b0;
+ end
+ end
+ end
+
+ // -------------------------------------------
+ // Address FIFO
+ // -------------------------------------------
+ // The address FIFO will hold the write address
+ // for the last line in a non-errant packet
+
+ wire [SIZE-1:0] afifo_i_tdata, afifo_o_tdata, afifo_p_tdata;
+ wire afifo_i_tvalid, afifo_i_tready;
+ wire afifo_o_tvalid, afifo_o_tready;
+ wire afifo_p_tvalid, afifo_p_tready;
+
+ axi_fifo #(.WIDTH(SIZE), .SIZE(USE_AS_BUFF==1 ? SIZE-MIN_PKT_SIZE : 1)) addr_fifo_i (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(afifo_i_tdata), .i_tvalid(afifo_i_tvalid), .i_tready(afifo_i_tready),
+ .o_tdata(afifo_p_tdata), .o_tvalid(afifo_p_tvalid), .o_tready(afifo_p_tready),
+ .space(), .occupied()
+ );
+
+ axi_fifo #(.WIDTH(SIZE), .SIZE(1)) addr_fifo_pipe_i (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata(afifo_p_tdata), .i_tvalid(afifo_p_tvalid), .i_tready(afifo_p_tready),
+ .o_tdata(afifo_o_tdata), .o_tvalid(afifo_o_tvalid), .o_tready(afifo_o_tready),
+ .space(), .occupied()
+ );
+
+ // -------------------------------------------
+ // Write state machine
+ // -------------------------------------------
+ reg [SIZE-1:0] wr_head_addr = ADDR_ZERO;
+
+ assign i_tready = ~ram_full & afifo_i_tready;
+ assign wr_en = i_tvalid & i_tready;
+ assign wr_data = {i_tlast, i_tdata};
+
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ wr_addr <= ADDR_ZERO;
+ wr_head_addr <= ADDR_ZERO;
+ end else begin
+ if (wr_en) begin
+ if (i_tlast) begin
+ if (i_terror) begin
+ // Incoming packet had an error. Rewind the write
+ // pointer and pretend that a packet never came in.
+ wr_addr <= wr_head_addr;
+ end else begin
+ // Incoming packet had no error, advance wr_addr and
+ // wr_head_addr for the next packet.
+ wr_addr <= wr_addr + ADDR_ONE;
+ wr_head_addr <= wr_addr + ADDR_ONE;
+ end
+ end else begin
+ // Packet is still in progress, only update wr_addr
+ wr_addr <= wr_addr + ADDR_ONE;
+ end
+ end
+ end
+ end
+
+ // Push the write address to the address FIFO if
+ // - It is the last one in the packet
+ // - The packet has no errors
+ assign afifo_i_tdata = wr_addr;
+ assign afifo_i_tvalid = ~ram_full & i_tvalid & i_tlast & ~i_terror;
+
+ // -------------------------------------------
+ // Read state machine
+ // -------------------------------------------
+ reg rd_data_valid = 1'b0;
+ wire update_out_reg;
+ // Data can be read if there is a valid last address in the
+ // address FIFO (signifying the end of an input packet) and
+ // if there is data available in RAM
+ wire ready_to_read = (~ram_empty) & afifo_o_tvalid;
+ // Pop from address FIFO once we have see the end of the pkt
+ assign afifo_o_tready = rd_en & (afifo_o_tdata == rd_addr);
+
+ // Read from RAM if
+ // - A full packet has been written AND
+ // - Output data is not valid OR is currently being transferred
+ assign rd_en = ready_to_read & (update_out_reg | ~rd_data_valid);
+
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ rd_data_valid <= 1'b0;
+ rd_addr <= ADDR_ZERO;
+ end else begin
+ if (update_out_reg | ~rd_data_valid) begin
+ // Output data is not valid OR is currently being transferred
+ if (ready_to_read) begin
+ rd_data_valid <= 1'b1;
+ rd_addr <= rd_addr + ADDR_ONE;
+ end else begin
+ rd_data_valid <= 1'b0; // Don't read
+ end
+ end
+ end
+ end
+
+ // Instantiate an output register to break critical paths starting
+ // at the RAM module. When ram_2port is inferred as BRAM, the tools
+ // should absorb this register into the BRAM block without using
+ // SLICE resources.
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ o_tvalid <= 1'b0;
+ end else if (update_out_reg) begin
+ o_tvalid <= rd_data_valid;
+ {o_tlast, o_tdata} <= rd_data;
+ end
+ end
+ // Update the output reg only *after* the downstream
+ // block has consumed the current value
+ assign update_out_reg = o_tready | ~o_tvalid;
+
+endmodule
diff --git a/fpga/usrp3/lib/fifo/axis_fifo_monitor.v b/fpga/usrp3/lib/fifo/axis_fifo_monitor.v
new file mode 100644
index 000000000..e3bb2c633
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axis_fifo_monitor.v
@@ -0,0 +1,66 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Description:
+// This module is instantiated in parallel with a FIFO with AXI4-STREAM interfaces.
+// It tracks how many complete packets are contained within the FIFO, and also indicates
+// when the first word of a packet is presented on the FIFO outputs.
+
+module axis_fifo_monitor #(
+ parameter COUNT_W = 32
+)(
+ // Clocks and resets
+ input wire clk,
+ input wire reset,
+ // FIFO Input
+ input wire i_tlast,
+ input wire i_tvalid,
+ input wire i_tready,
+ // FIFO Output
+ input wire o_tlast,
+ input wire o_tvalid,
+ input wire o_tready,
+ // FIFO Stats
+ output wire i_sop,
+ output wire i_eop,
+ output wire o_sop,
+ output wire o_eop,
+ output wire [COUNT_W-1:0] occupied,
+ output wire [COUNT_W-1:0] occupied_pkts
+);
+
+ wire [COUNT_W-1:0] i_pkt_count, o_pkt_count;
+ wire [COUNT_W-1:0] i_xfer_count, o_xfer_count;
+
+ axis_strm_monitor #(
+ .WIDTH(1), .COUNT_W(COUNT_W),
+ .PKT_LENGTH_EN(0), .PKT_CHKSUM_EN(0),
+ .PKT_COUNT_EN(1), .XFER_COUNT_EN(1)
+ ) input_monitor (
+ .clk(clk), .reset(reset),
+ .axis_tdata(1'b0), .axis_tlast(i_tlast), .axis_tvalid(i_tvalid), .axis_tready(i_tready),
+ .sop(i_sop), .eop(i_eop),
+ .pkt_length(), .pkt_chksum(),
+ .pkt_count(i_pkt_count), .xfer_count(i_xfer_count)
+ );
+
+ axis_strm_monitor #(
+ .WIDTH(1), .COUNT_W(COUNT_W),
+ .PKT_LENGTH_EN(0), .PKT_CHKSUM_EN(0),
+ .PKT_COUNT_EN(1), .XFER_COUNT_EN(1)
+ ) output_monitor (
+ .clk(clk), .reset(reset),
+ .axis_tdata(1'b0), .axis_tlast(o_tlast), .axis_tvalid(o_tvalid), .axis_tready(o_tready),
+ .sop(o_sop), .eop(o_eop),
+ .pkt_length(), .pkt_chksum(),
+ .pkt_count(o_pkt_count), .xfer_count(o_xfer_count)
+ );
+
+ // Count packets in FIFO.
+ // No protection on counter wrap,
+ assign occupied = (i_xfer_count - o_xfer_count);
+ assign occupied_pkts = (i_pkt_count - o_pkt_count);
+
+ endmodule \ No newline at end of file
diff --git a/fpga/usrp3/lib/fifo/axis_strm_monitor.v b/fpga/usrp3/lib/fifo/axis_strm_monitor.v
new file mode 100644
index 000000000..68e4cf5bf
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/axis_strm_monitor.v
@@ -0,0 +1,110 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Description:
+// A module to monitor a an AXI-Stream link and gather various
+// metric about packets and the stream in general
+
+module axis_strm_monitor #(
+ parameter WIDTH = 64,
+ parameter COUNT_W = 32,
+ parameter PKT_LENGTH_EN = 0,
+ parameter PKT_CHKSUM_EN = 0,
+ parameter PKT_COUNT_EN = 0,
+ parameter XFER_COUNT_EN = 0
+)(
+ // Clocks and resets
+ input wire clk,
+ input wire reset,
+ // Stream to monitor
+ input wire [WIDTH-1:0] axis_tdata,
+ input wire axis_tlast,
+ input wire axis_tvalid,
+ input wire axis_tready,
+ // Packet Stats
+ output wire sop,
+ output wire eop,
+ output reg [15:0] pkt_length = 16'd0,
+ output wire [WIDTH-1:0] pkt_chksum,
+ // Stream Stats
+ output reg [COUNT_W-1:0] pkt_count = {COUNT_W{1'b0}},
+ output reg [COUNT_W-1:0] xfer_count = {COUNT_W{1'b0}}
+);
+
+ //----------------------------
+ // Packet specific
+ //----------------------------
+
+ reg pkt_head = 1'b1;
+ wire xfer = axis_tvalid & axis_tready;
+
+ assign sop = pkt_head & xfer;
+ assign eop = xfer & axis_tlast;
+
+ always @(posedge clk) begin
+ if (reset) begin
+ pkt_head <= 1'b1;
+ end else begin
+ if (pkt_head) begin
+ if (xfer)
+ pkt_head <= ~eop;
+ end else begin
+ if (eop)
+ pkt_head <= 1'b0;
+ end
+ end
+ end
+
+ generate if (PKT_LENGTH_EN == 0) begin
+ // Count the number of lines (transfers) in a packet
+ always @(posedge clk) begin
+ if (reset | eop) begin
+ pkt_length <= 16'd1;
+ end else if (xfer) begin
+ pkt_length <= pkt_length + 1'b1;
+ end
+ end
+ end else begin
+ // Default packet length is 0
+ always @(*) pkt_length <= 16'd0;
+ end endgenerate
+
+ generate if (PKT_LENGTH_EN == 0) begin
+ // Compute the XOR checksum of the lines in a packet
+ reg [WIDTH-1:0] chksum_prev = {WIDTH{1'b0}};
+ always @(posedge clk) begin
+ if (reset) begin
+ chksum_prev <= {WIDTH{1'b0}};
+ end else if (xfer) begin
+ chksum_prev <= pkt_chksum;
+ end
+ end
+ assign pkt_chksum = chksum_prev ^ axis_tdata;
+ end else begin
+ // Default checksum is 0
+ assign pkt_chksum = {WIDTH{1'b0}};
+ end endgenerate
+
+ //----------------------------
+ // Stream specific
+ //----------------------------
+
+ always @(posedge clk) begin
+ if (reset | (PKT_COUNT_EN == 0)) begin
+ pkt_count <= {COUNT_W{1'b0}};
+ end else if (eop) begin
+ pkt_count <= pkt_count + 1'b1;
+ end
+ end
+
+ always @(posedge clk) begin
+ if (reset | (XFER_COUNT_EN == 0)) begin
+ xfer_count <= {COUNT_W{1'b0}};
+ end else if (xfer) begin
+ xfer_count <= xfer_count + 1'b1;
+ end
+ end
+
+ endmodule \ No newline at end of file
diff --git a/fpga/usrp3/lib/fifo/fifo64_to_axi4lite.v b/fpga/usrp3/lib/fifo/fifo64_to_axi4lite.v
new file mode 100644
index 000000000..3ba451a63
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/fifo64_to_axi4lite.v
@@ -0,0 +1,140 @@
+/////////////////////////////////////////////////////////////////////
+//
+// Copyright 2016-2017 Ettus Research
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+//////////////////////////////////////////////////////////////////////
+
+module fifo64_to_axi4lite
+(
+ input s_axi_aclk,
+ input s_axi_areset,
+
+ input [31:0] s_axi_awaddr,
+ input s_axi_awvalid,
+ output s_axi_awready,
+ input [31:0] s_axi_wdata,
+ input [3:0] s_axi_wstrb,
+ input s_axi_wvalid,
+ output s_axi_wready,
+ output [1:0] s_axi_bresp,
+ output s_axi_bvalid,
+ input s_axi_bready,
+ input [31:0] s_axi_araddr,
+ input s_axi_arvalid,
+ output s_axi_arready,
+ output [31:0] s_axi_rdata,
+ output [1:0] s_axi_rresp,
+ output s_axi_rvalid,
+ input s_axi_rready,
+
+ output m_axis_tvalid,
+ output m_axis_tlast,
+ output [63:0] m_axis_tdata,
+ input m_axis_tready,
+ output [3:0] m_axis_tuser,
+
+ input s_axis_tvalid,
+ input s_axis_tlast,
+ input [63:0] s_axis_tdata,
+ output s_axis_tready,
+ input [3:0] s_axis_tuser,
+ output irq
+);
+
+ wire clear_txn;
+ wire [31:0] tx_tdata;
+ wire tx_tlast;
+ wire tx_tvalid;
+ wire tx_tready;
+ wire [3:0] tx_tkeep;
+ wire [1:0] tx_tuser = (tx_tkeep == 4'b1111) ? 2'd0 :
+ (tx_tkeep == 4'b0001) ? 2'd1 :
+ (tx_tkeep == 4'b0011) ? 2'd2 :
+ (tx_tkeep == 4'b0111) ? 2'd3 : 2'd0;
+
+ axi_fifo32_to_fifo64 inst_axi_fifo32_to_fifo64
+ (
+ .clk(s_axi_aclk),
+ .reset(s_axi_areset | ~clear_txn),
+ .i_tdata({tx_tdata[7:0], tx_tdata[15:8], tx_tdata[23:16], tx_tdata[31:24]}), // endian swap
+ .i_tuser(tx_tuser),
+ .i_tlast(tx_tlast),
+ .i_tvalid(tx_tvalid),
+ .i_tready(tx_tready),
+ .o_tdata(m_axis_tdata),
+ .o_tuser(m_axis_tuser),
+ .o_tlast(m_axis_tlast),
+ .o_tvalid(m_axis_tvalid),
+ .o_tready(m_axis_tready)
+ );
+
+
+ wire clear_rxn;
+ wire [31:0] rx_tdata;
+ wire rx_tlast;
+ wire rx_tvalid;
+ wire rx_tready;
+ wire [1:0] rx_tuser;
+
+ axi_fifo64_to_fifo32 inst_axi_fifo64_to_fifo32
+ (
+ .clk(s_axi_aclk),
+ .reset(s_axi_areset || ~clear_rxn),
+ .i_tdata(s_axis_tdata),
+ .i_tuser(s_axis_tuser[2:0]),
+ .i_tlast(s_axis_tlast),
+ .i_tvalid(s_axis_tvalid),
+ .i_tready(s_axis_tready),
+ .o_tdata({rx_tdata[7:0], rx_tdata[15:8], rx_tdata[23:16], rx_tdata[31:24]}), // endian swap
+ .o_tuser(rx_tuser),
+ .o_tlast(rx_tlast),
+ .o_tvalid(rx_tvalid),
+ .o_tready(rx_tready)
+ );
+
+ wire [3:0] rx_tkeep = ~rx_tlast ? 4'b1111 : (rx_tuser == 2'd0) ? 4'b1111 :
+ (rx_tuser == 2'd1) ? 4'b0001 :
+ (rx_tuser == 2'd2) ? 4'b0011 :
+ (rx_tuser == 2'd3) ? 4'b0111 :
+ 4'b1111;
+
+ axis_fifo_to_axi4lite inst_axis_fifo_to_axi4lite0
+ (
+ .interrupt(irq),
+ .s_axi_aclk(s_axi_aclk),
+ .s_axi_aresetn(~s_axi_areset),
+ .s_axi_awaddr({16'h0000, s_axi_awaddr}),
+ .s_axi_awvalid(s_axi_awvalid),
+ .s_axi_awready(s_axi_awready),
+ .s_axi_wdata(s_axi_wdata),
+ .s_axi_wstrb(s_axi_wstrb),
+ .s_axi_wvalid(s_axi_wvalid),
+ .s_axi_wready(s_axi_wready),
+ .s_axi_bresp(s_axi_bresp),
+ .s_axi_bvalid(s_axi_bvalid),
+ .s_axi_bready(s_axi_bready),
+ .s_axi_araddr({16'h0000, s_axi_araddr}),
+ .s_axi_arvalid(s_axi_arvalid),
+ .s_axi_arready(s_axi_arready),
+ .s_axi_rdata(s_axi_rdata),
+ .s_axi_rresp(s_axi_rresp),
+ .s_axi_rvalid(s_axi_rvalid),
+ .s_axi_rready(s_axi_rready),
+ .mm2s_prmry_reset_out_n(clear_txn),
+ .axi_str_txd_tvalid(tx_tvalid),
+ .axi_str_txd_tready(tx_tready),
+ .axi_str_txd_tlast(tx_tlast),
+ .axi_str_txd_tdata(tx_tdata),
+ .axi_str_txd_tkeep(tx_tkeep),
+ .s2mm_prmry_reset_out_n(clear_rxn),
+ .axi_str_rxd_tvalid(rx_tvalid),
+ .axi_str_rxd_tready(rx_tready),
+ .axi_str_rxd_tlast(rx_tlast),
+ .axi_str_rxd_tdata(rx_tdata),
+ .axi_str_rxd_tkeep(rx_tkeep)
+);
+
+endmodule
diff --git a/fpga/usrp3/lib/fifo/shortfifo.v b/fpga/usrp3/lib/fifo/shortfifo.v
new file mode 100644
index 000000000..ca8cc4ae6
--- /dev/null
+++ b/fpga/usrp3/lib/fifo/shortfifo.v
@@ -0,0 +1,95 @@
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+
+
+module shortfifo
+ #(parameter WIDTH=32)
+ (input clk, input rst,
+ input [WIDTH-1:0] datain,
+ output [WIDTH-1:0] dataout,
+ input read,
+ input write,
+ input clear,
+ output reg full,
+ output reg empty,
+ output reg [4:0] space,
+ output reg [4:0] occupied);
+
+ reg [3:0] a;
+ genvar i;
+
+ generate
+ for (i=0;i<WIDTH;i=i+1)
+ begin : gen_srl16
+ SRL16E
+ srl16e(.Q(dataout[i]),
+ .A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),
+ .CE(write),.CLK(clk),.D(datain[i]));
+ end
+ endgenerate
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ a <= 0;
+ empty <= 1;
+ full <= 0;
+ end
+ else if(clear)
+ begin
+ a <= 0;
+ empty <= 1;
+ full<= 0;
+ end
+ else if(read & ~write)
+ begin
+ full <= 0;
+ if(a==0)
+ empty <= 1;
+ else
+ a <= a - 1;
+ end
+ else if(write & ~read)
+ begin
+ empty <= 0;
+ if(~empty)
+ a <= a + 1;
+ if(a == 14)
+ full <= 1;
+ end
+
+ // NOTE will fail if you write into a full fifo or read from an empty one
+
+ //////////////////////////////////////////////////////////////
+ // space and occupied are used for diagnostics, not
+ // guaranteed correct
+
+ //assign space = full ? 0 : empty ? 16 : 15-a;
+ //assign occupied = empty ? 0 : full ? 16 : a+1;
+
+ always @(posedge clk)
+ if(rst)
+ space <= 16;
+ else if(clear)
+ space <= 16;
+ else if(read & ~write)
+ space <= space + 1;
+ else if(write & ~read)
+ space <= space - 1;
+
+ always @(posedge clk)
+ if(rst)
+ occupied <= 0;
+ else if(clear)
+ occupied <= 0;
+ else if(read & ~write)
+ occupied <= occupied - 1;
+ else if(write & ~read)
+ occupied <= occupied + 1;
+
+endmodule // shortfifo