aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/fifo
diff options
context:
space:
mode:
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