aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/extramfifo
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/extramfifo')
-rw-r--r--fpga/usrp3/lib/extramfifo/.gitignore3
-rw-r--r--fpga/usrp3/lib/extramfifo/Makefile.srcs17
-rw-r--r--fpga/usrp3/lib/extramfifo/ext_fifo.v166
-rw-r--r--fpga/usrp3/lib/extramfifo/ext_fifo_tb.v435
-rw-r--r--fpga/usrp3/lib/extramfifo/nobl_fifo.v117
-rw-r--r--fpga/usrp3/lib/extramfifo/nobl_if.v168
-rw-r--r--fpga/usrp3/lib/extramfifo/refill_randomizer.v86
-rw-r--r--fpga/usrp3/lib/extramfifo/test_sram_if.v195
8 files changed, 1187 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/extramfifo/.gitignore b/fpga/usrp3/lib/extramfifo/.gitignore
new file mode 100644
index 000000000..94bbf6dcc
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/.gitignore
@@ -0,0 +1,3 @@
+fifo_extram36_tb
+fifo_extram_tb
+*.vcd
diff --git a/fpga/usrp3/lib/extramfifo/Makefile.srcs b/fpga/usrp3/lib/extramfifo/Makefile.srcs
new file mode 100644
index 000000000..c0f5e1097
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/Makefile.srcs
@@ -0,0 +1,17 @@
+#
+# Copyright 2010 Ettus Research LLC
+# Copyright 2015 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+#
+
+##################################################
+# Extram Sources
+##################################################
+EXTRAM_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/extramfifo/, \
+ext_fifo.v \
+nobl_if.v \
+nobl_fifo.v \
+refill_randomizer.v \
+))
diff --git a/fpga/usrp3/lib/extramfifo/ext_fifo.v b/fpga/usrp3/lib/extramfifo/ext_fifo.v
new file mode 100644
index 000000000..8ec32b45d
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/ext_fifo.v
@@ -0,0 +1,166 @@
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+//
+// FIFO backed by an off chip ZBT/NoBL SRAM.
+//
+// This module and its sub-hierarchy implment a FIFO capable of sustaining
+// a data throughput rate of at least int_clk/2 * 36bits and bursts of int_clk * 36bits.
+//
+// This has been designed and tested for an int_clk of 100MHz and an ext_clk of 125MHz,
+// your milage may vary with other clock ratio's especially those where int_clk < ext_clk.
+// Testing has also exclusively used a rst signal synchronized to int_clk.
+//
+// Interface operation mimics a Xilinx FIFO configured as "First Word Fall Through",
+// though signal naming differs.
+//
+// For FPGA use registers interfacing directly with signals prefixed "RAM_*" should be
+// packed into the IO ring.
+//
+
+module ext_fifo
+ #(parameter INT_WIDTH=36,EXT_WIDTH=18,RAM_DEPTH=19,FIFO_DEPTH=19)
+ (
+ input int_clk,
+ input ext_clk,
+ input rst,
+ input [EXT_WIDTH-1:0] RAM_D_pi,
+ output [EXT_WIDTH-1:0] RAM_D_po,
+ output RAM_D_poe,
+ output [RAM_DEPTH-1:0] RAM_A,
+ output RAM_WEn,
+ output RAM_CENn,
+ output RAM_LDn,
+ output RAM_OEn,
+ output RAM_CE1n,
+ input [INT_WIDTH-1:0] datain,
+ input src_rdy_i, // WRITE
+ output dst_rdy_o, // not FULL
+ output [INT_WIDTH-1:0] dataout,
+ output src_rdy_o, // not EMPTY
+ input dst_rdy_i // READ
+ );
+
+ wire [EXT_WIDTH-1:0] write_data;
+ wire [EXT_WIDTH-1:0] read_data;
+ wire full1, empty1;
+ wire almost_full2, almost_full2_spread, full2, empty2;
+ wire [FIFO_DEPTH-1:0] capacity;
+ wire space_avail;
+ wire data_avail;
+
+ // These next 2 lines here purely because ICARUS is crap at handling generate statements.
+ // Empirically this has been determined to make simulations work.
+ wire read_input_fifo = space_avail & ~empty1;
+ wire write_output_fifo = data_avail;
+
+ assign src_rdy_o = ~empty2;
+ assign dst_rdy_o = ~full1;
+
+ // External FIFO running at ext clock rate and 18 or 36 bit width.
+ nobl_fifo #(.WIDTH(EXT_WIDTH),.RAM_DEPTH(RAM_DEPTH),.FIFO_DEPTH(FIFO_DEPTH))
+ nobl_fifo_i1
+ (
+ .clk(ext_clk),
+ .rst(rst),
+ .RAM_D_pi(RAM_D_pi),
+ .RAM_D_po(RAM_D_po),
+ .RAM_D_poe(RAM_D_poe),
+ .RAM_A(RAM_A),
+ .RAM_WEn(RAM_WEn),
+ .RAM_CENn(RAM_CENn),
+ .RAM_LDn(RAM_LDn),
+ .RAM_OEn(RAM_OEn),
+ .RAM_CE1n(RAM_CE1n),
+ .write_data(write_data),
+ .write_strobe(~empty1 ),
+ .space_avail(space_avail),
+ .read_data(read_data),
+ .read_strobe(~almost_full2_spread),
+ .data_avail(data_avail),
+ .capacity(capacity)
+ );
+
+ generate
+ if (EXT_WIDTH == 18 && INT_WIDTH == 36) begin: fifo_g1
+ // FIFO buffers data from UDP engine into external FIFO clock domain.
+ fifo_xlnx_512x36_2clk_36to18 fifo_xlnx_512x36_2clk_36to18_i1 (
+ .rst(rst),
+ .wr_clk(int_clk),
+ .rd_clk(ext_clk),
+ .din(datain), // Bus [35 : 0]
+ .wr_en(src_rdy_i),
+ .rd_en(read_input_fifo),
+ .dout(write_data), // Bus [17 : 0]
+ .full(full1),
+ .empty(empty1));
+
+
+ // FIFO buffers data read from external FIFO into DSP clk domain and to TX DSP.
+ fifo_xlnx_512x36_2clk_18to36 fifo_xlnx_512x36_2clk_18to36_i1 (
+ .rst(rst),
+ .wr_clk(ext_clk),
+ .rd_clk(int_clk),
+ .din(read_data), // Bus [17 : 0]
+ .wr_en(write_output_fifo),
+ .rd_en(dst_rdy_i),
+ .dout(dataout), // Bus [35 : 0]
+ .full(full2),
+ .prog_full(almost_full2),
+ .empty(empty2));
+ end // block: fifo_g1
+ else if (EXT_WIDTH == 36 && INT_WIDTH == 36) begin: fifo_g1
+ // FIFO buffers data from UDP engine into external FIFO clock domain.
+ fifo_xlnx_32x36_2clk fifo_xlnx_32x36_2clk_i1 (
+ .rst(rst),
+ .wr_clk(int_clk),
+ .rd_clk(ext_clk),
+ .din(datain), // Bus [35 : 0]
+ .wr_en(src_rdy_i),
+ .rd_en(read_input_fifo),
+ .dout(write_data), // Bus [35 : 0]
+ .full(full1),
+ .empty(empty1));
+
+ // FIFO buffers data read from external FIFO into DSP clk domain and to TX DSP.
+ fifo_xlnx_512x36_2clk_prog_full fifo_xlnx_32x36_2clk_prog_full_i1 (
+ .rst(rst),
+ .wr_clk(ext_clk),
+ .rd_clk(int_clk),
+ .din(read_data), // Bus [35 : 0]
+ .wr_en(write_output_fifo),
+ .rd_en(dst_rdy_i),
+ .dout(dataout), // Bus [35 : 0]
+ .full(full2),
+ .empty(empty2),
+ .prog_full(almost_full2));
+
+ end
+ endgenerate
+
+ refill_randomizer #(.BITS(7))
+ refill_randomizer_i1 (
+ .clk(ext_clk),
+ .rst(rst),
+ .full_in(almost_full2),
+ .full_out(almost_full2_spread)
+ );
+
+endmodule // ext_fifo
diff --git a/fpga/usrp3/lib/extramfifo/ext_fifo_tb.v b/fpga/usrp3/lib/extramfifo/ext_fifo_tb.v
new file mode 100644
index 000000000..a4e5ea164
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/ext_fifo_tb.v
@@ -0,0 +1,435 @@
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+`timescale 1ns / 1ps
+`define USRP2
+//`define USRP2PLUS
+
+`ifdef USRP2
+ `define INT_WIDTH 36
+ `define EXT_WIDTH 18
+ `define RAM_DEPTH 19
+ `define FIFO_DEPTH 8
+ `define DUMP_VCD_FULL
+ `define INT_CLK_PERIOD 5
+ `define EXT_CLK_PERIOD 4
+`elsif USRP2PLUS
+ `define INT_WIDTH 36
+ `define EXT_WIDTH 36
+ `define RAM_DEPTH 18
+ `define FIFO_DEPTH 8
+ `define DUMP_VCD_FULL
+ `define INT_CLK_PERIOD 5
+ `define EXT_CLK_PERIOD 5
+`endif // `ifdef USRP2
+
+
+module ext_fifo_tb();
+
+ reg int_clk;
+ reg ext_clk;
+ reg rst;
+
+ wire [`EXT_WIDTH-1:0] RAM_D_pi;
+ wire [`EXT_WIDTH-1:0] RAM_D_po;
+ wire [`EXT_WIDTH-1:0] RAM_D;
+ wire RAM_D_poe;
+ wire [`RAM_DEPTH-1:0] RAM_A;
+ wire RAM_WEn;
+ wire RAM_CENn;
+ wire RAM_LDn;
+ wire RAM_OEn;
+ wire RAM_CE1n;
+ reg [`INT_WIDTH-1:0] datain;
+ reg src_rdy_i; // WRITE
+ wire dst_rdy_o; // not FULL
+ wire [`INT_WIDTH-1:0] dataout;
+ reg [`INT_WIDTH-1:0] ref_dataout;
+ wire src_rdy_o; // not EMPTY
+ reg dst_rdy_i;
+ integer ether_frame;
+
+ // Clocks
+ // Int clock is 100MHz
+ // Ext clock is 125MHz
+ initial
+ begin
+ int_clk <= 0;
+ ext_clk <= 0;
+ ref_dataout <= 1;
+ src_rdy_i <= 0;
+ dst_rdy_i <= 0;
+ end
+
+ always
+ #(`INT_CLK_PERIOD/2) int_clk <= ~int_clk;
+
+ always
+ #(`EXT_CLK_PERIOD/2) ext_clk <= ~ext_clk;
+
+ initial
+ begin
+ datain <= 0;
+ ether_frame <= 0;
+
+ rst <= 1;
+ repeat (5) @(negedge int_clk);
+ rst <= 0;
+ @(negedge int_clk);
+ while (datain < 10000)
+ begin
+ @(negedge int_clk);
+ datain <= datain + dst_rdy_o;
+ src_rdy_i <= dst_rdy_o;
+ // Simulate inter-frame time
+ if (ether_frame == 1500)
+ begin
+ ether_frame <= 0;
+ repeat(1600)
+ begin
+ @(negedge int_clk);
+ src_rdy_i <= 0;
+ end
+ end
+ else
+ ether_frame <= ether_frame + dst_rdy_o;
+ end
+ end // initial begin
+
+
+ initial
+ begin
+ repeat (5) @(negedge int_clk);
+ dst_rdy_i <= 1;
+
+ while (src_rdy_o !== 1)
+ @(negedge int_clk);
+
+ // Fall through fifo, first output already valid
+ if (dataout !== ref_dataout)
+ $display("Error: Expected %x, got %x @%d",ref_dataout, dataout, $time);
+ ref_dataout <= ref_dataout + src_rdy_o ;
+
+ // Decimate by 16 rate
+ while (ref_dataout < 2000)
+ begin
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + src_rdy_o ;
+ dst_rdy_i <= src_rdy_o;
+ if ((dataout !== ref_dataout) && src_rdy_o)
+ $display("Error: Expected %x, got %x @%d",ref_dataout, dataout, $time);
+ @(negedge int_clk);
+ dst_rdy_i <= 0;
+ repeat(14) @(negedge int_clk);
+ end // while (ref_dataout < 10000)
+ // Decimate by 8 rate
+ while (ref_dataout < 4000)
+ begin
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + src_rdy_o ;
+ dst_rdy_i <= src_rdy_o;
+ if ((dataout !== ref_dataout) && src_rdy_o)
+ $display("Error: Expected %x, got %x @%d",ref_dataout, dataout, $time);
+ @(negedge int_clk);
+ dst_rdy_i <= 0;
+ repeat(6) @(negedge int_clk);
+ end // while (ref_dataout < 10000)
+ // Decimate by 4 rate
+ while (ref_dataout < 6000)
+ begin
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + src_rdy_o ;
+ dst_rdy_i <= src_rdy_o;
+ if ((dataout !== ref_dataout) && src_rdy_o)
+ $display("Error: Expected %x, got %x @%d",ref_dataout, dataout, $time);
+ @(negedge int_clk);
+ dst_rdy_i <= 0;
+ repeat(2) @(negedge int_clk);
+ end // while (ref_dataout < 10000)
+ // Max rate
+ while (ref_dataout < 10000)
+ begin
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + src_rdy_o ;
+ dst_rdy_i <= src_rdy_o;
+ if ((dataout !== ref_dataout) && src_rdy_o)
+ $display("Error: Expected %x, got %x @%d",ref_dataout, dataout, $time);
+
+ end // while (ref_dataout < 10000)
+
+ @(negedge int_clk);
+ $finish;
+
+ end
+
+
+/* -----\/----- EXCLUDED -----\/-----
+
+ initial
+ begin
+ rst <= 1;
+ repeat (5) @(negedge int_clk);
+ rst <= 0;
+ @(negedge int_clk);
+ repeat (4000)
+ begin
+ @(negedge int_clk);
+ datain <= datain + dst_rdy_o;
+ src_rdy_i <= dst_rdy_o;
+// @(negedge int_clk);
+// src_rdy_i <= 0;
+// @(negedge int_clk);
+// dst_rdy_i <= src_rdy_o;
+// @(negedge int_clk);
+// dst_rdy_i <= 0;
+// repeat (2) @(negedge int_clk);
+ end // repeat (1000)
+ // Fall through fifo, first output already valid
+ if (dataout !== ref_dataout)
+ $display("Error: Expected %x, got %x",ref_dataout, dataout);
+ repeat (1000)
+ begin
+ @(negedge int_clk);
+ datain <= datain + dst_rdy_o ;
+ src_rdy_i <= dst_rdy_o;
+ @(negedge int_clk);
+ src_rdy_i <= 0;
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + src_rdy_o ;
+ dst_rdy_i <= src_rdy_o;
+ if ((dataout !== ref_dataout) && src_rdy_o)
+ $display("Error: Expected %x, got %x",ref_dataout, dataout);
+ @(negedge int_clk);
+ dst_rdy_i <= 0;
+// repeat (2) @(negedge int_clk);
+ end // repeat (1000)
+ repeat (1000)
+ begin
+// @(negedge int_clk);
+// datain <= datain + 1;
+// src_rdy_i <= 1;
+// @(negedge int_clk);
+// src_rdy_i <= 0;
+ @(negedge int_clk);
+ ref_dataout <= ref_dataout + src_rdy_o;
+ dst_rdy_i <= src_rdy_o;
+ if ((dataout !== ref_dataout) && src_rdy_o)
+ $display("Error: Expected %x, got %x",ref_dataout, dataout);
+ @(negedge int_clk);
+ dst_rdy_i <= 0;
+// repeat (2) @(negedge int_clk);
+ end // repeat (1000)
+
+ $finish;
+
+ end // initial begin
+
+
+ -----/\----- EXCLUDED -----/\----- */
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Simulation control //
+ ///////////////////////////////////////////////////////////////////////////////////
+ `ifdef DUMP_LX2_TOP
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.lx2");
+ $dumpvars(1,ext_fifo_tb);
+ end
+ `endif
+
+ `ifdef DUMP_LX2_FULL
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.lx2");
+ $dumpvars(0,ext_fifo_tb);
+ end
+ `endif
+
+ `ifdef DUMP_VCD_TOP
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.vcd");
+ $dumpvars(1,ext_fifo_tb);
+ end
+ `endif
+
+ `ifdef DUMP_VCD_TOP_PLUS_NEXT
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.vcd");
+ $dumpvars(2,ext_fifo_tb);
+ end
+ `endif
+
+
+ `ifdef DUMP_VCD_FULL
+ // Set up output files
+ initial begin
+ $dumpfile("ext_fifo_tb.vcd");
+ $dumpvars(0,ext_fifo_tb);
+ end
+ `endif
+
+ // Update display every 10 us
+ always #10000 $monitor("Time in uS ",$time/1000);
+
+ wire [`EXT_WIDTH-1:0] RAM_D_pi_ext;
+ wire [`EXT_WIDTH-1:0] RAM_D_po_ext;
+ wire [`EXT_WIDTH-1:0] RAM_D_ext;
+ wire RAM_D_poe_ext;
+
+ genvar i;
+
+ //
+ // Instantiate IO for Bidirectional bus to SRAM
+ //
+
+ generate
+ for (i=0;i<`EXT_WIDTH;i=i+1)
+ begin : gen_RAM_D_IO
+
+ IOBUF #(
+ .DRIVE(12),
+ .IOSTANDARD("LVCMOS25"),
+ .SLEW("FAST")
+ )
+ RAM_D_i (
+ .O(RAM_D_pi_ext[i]),
+ .I(RAM_D_po_ext[i]),
+ .IO(RAM_D[i]),
+ .T(RAM_D_poe_ext)
+ );
+ end // block: gen_RAM_D_IO
+
+ endgenerate
+
+ wire [`RAM_DEPTH-1:0] RAM_A_ext;
+ wire RAM_WEn_ext,RAM_LDn_ext,RAM_CE1n_ext,RAM_OEn_ext,RAM_CENn_ext;
+
+ assign #1 RAM_D_pi = RAM_D_pi_ext;
+
+ assign #1 RAM_D_po_ext = RAM_D_po;
+
+ assign #1 RAM_D_poe_ext = RAM_D_poe;
+
+ assign #2 RAM_WEn_ext = RAM_WEn;
+
+ assign #2 RAM_LDn_ext = RAM_LDn;
+
+ assign #2 RAM_CE1n_ext = RAM_CE1n;
+
+ assign #2 RAM_OEn_ext = RAM_OEn;
+
+ assign #2 RAM_CENn_ext = RAM_CENn;
+
+ assign #2 RAM_A_ext = RAM_A;
+
+
+ generate
+ if (`EXT_WIDTH==18) begin: ram_tb_g1
+ idt71v65603s150 idt71v65603s150_i1
+ (
+ .A(RAM_A_ext[17:0]),
+ .adv_ld_(RAM_LDn_ext), // advance (high) / load (low)
+ .bw1_(1'b0),
+ .bw2_(1'b0),
+ .bw3_(1'b1),
+ .bw4_(1'b1), // byte write enables (low)
+ .ce1_(RAM_CE1n_ext),
+ .ce2(1'b1),
+ .ce2_(1'b0), // chip enables
+ .cen_(RAM_CENn_ext), // clock enable (low)
+ .clk(ext_clk), // clock
+ .IO({RAM_D[16:9],RAM_D[7:0]}),
+ .IOP({RAM_D[17],RAM_D[8]}), // data bus
+ .lbo_(1'b0), // linear burst order (low)
+ .oe_(RAM_OEn_ext), // output enable (low)
+ .r_w_(RAM_WEn_ext)
+ ); // read (high) / write (low)
+ end // block: ram_tb_g1
+ else if (`EXT_WIDTH==36) begin: ram_tb_g1
+ idt71v65603s150 idt71v65603s150_i1
+ (
+ .A(RAM_A_ext[17:0]),
+ .adv_ld_(RAM_LDn_ext), // advance (high) / load (low)
+ .bw1_(1'b0),
+ .bw2_(1'b0),
+ .bw3_(1'b0),
+ .bw4_(1'b0), // byte write enables (low)
+ .ce1_(RAM_CE1n_ext),
+ .ce2(1'b1),
+ .ce2_(1'b0), // chip enables
+ .cen_(RAM_CENn_ext), // clock enable (low)
+ .clk(ext_clk), // clock
+ .IO(RAM_D[31:0]),
+ .IOP(RAM_D[35:32]), // data bus
+ .lbo_(1'b0), // linear burst order (low)
+ .oe_(RAM_OEn_ext), // output enable (low)
+ .r_w_(RAM_WEn_ext)
+ ); // read (high) / write (low)
+ end // block: ram_tb_g1
+
+ endgenerate
+
+/* -----\/----- EXCLUDED -----\/-----
+
+
+ cy1356 cy1356_i1
+ ( .d(RAM_D),
+ .clk(ext_clk),
+ .a(RAM_A_ext),
+ .bws(2'b00),
+ .we_b(RAM_WEn_ext),
+ .adv_lb(RAM_LDn_ext),
+ .ce1b(RAM_CE1n_ext),
+ .ce2(1'b1),
+ .ce3b(1'b0),
+ .oeb(RAM_OEn_ext),
+ .cenb(RAM_CENn_ext),
+ .mode(1'b0)
+ );
+ -----/\----- EXCLUDED -----/\----- */
+
+
+ ext_fifo
+ #(.INT_WIDTH(`INT_WIDTH),.EXT_WIDTH(`EXT_WIDTH),.RAM_DEPTH(`RAM_DEPTH),.FIFO_DEPTH(`FIFO_DEPTH))
+ ext_fifo_i1
+ (
+ .int_clk(int_clk),
+ .ext_clk(ext_clk),
+ .rst(rst),
+ .RAM_D_pi(RAM_D_pi),
+ .RAM_D_po(RAM_D_po),
+ .RAM_D_poe(RAM_D_poe),
+ .RAM_A(RAM_A),
+ .RAM_WEn(RAM_WEn),
+ .RAM_CENn(RAM_CENn),
+ .RAM_LDn(RAM_LDn),
+ .RAM_OEn(RAM_OEn),
+ .RAM_CE1n(RAM_CE1n),
+ .datain(datain),
+ .src_rdy_i(src_rdy_i), // WRITE
+ .dst_rdy_o(dst_rdy_o), // not FULL
+ .dataout(dataout),
+ .src_rdy_o(src_rdy_o), // not EMPTY
+ .dst_rdy_i(dst_rdy_i)
+ );
+
+endmodule // ext_fifo_tb
diff --git a/fpga/usrp3/lib/extramfifo/nobl_fifo.v b/fpga/usrp3/lib/extramfifo/nobl_fifo.v
new file mode 100644
index 000000000..e4fa1422e
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/nobl_fifo.v
@@ -0,0 +1,117 @@
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// Since this FIFO uses a ZBT/NoBL SRAM for its storage which is a since port
+// device it can only sustain data throughput at half the RAM clock rate.
+// Fair arbitration to ensure this occurs is included in this logic and
+// requests for transactions that can not be completed are held off.
+// This FIFO requires a an external signal driving read_strobe that assures space for at least 6
+// reads since this the theopretical maximum number in flight due to pipeling.
+
+module nobl_fifo
+ #(parameter WIDTH=18,RAM_DEPTH=19,FIFO_DEPTH=19)
+ (
+ input clk,
+ input rst,
+ input [WIDTH-1:0] RAM_D_pi,
+ output [WIDTH-1:0] RAM_D_po,
+ output RAM_D_poe,
+ output [RAM_DEPTH-1:0] RAM_A,
+ output RAM_WEn,
+ output RAM_CENn,
+ output RAM_LDn,
+ output RAM_OEn,
+ output RAM_CE1n,
+ input [WIDTH-1:0] write_data,
+ input write_strobe,
+ output reg space_avail,
+ output [WIDTH-1:0] read_data,
+ input read_strobe, // Triggers a read, result in approximately 6 cycles.
+ output data_avail, // Qulaifys read data available this cycle on read_data.
+ output reg [FIFO_DEPTH-1:0] capacity
+ );
+
+ //reg [FIFO_DEPTH-1:0] capacity;
+ reg [FIFO_DEPTH-1:0] wr_pointer;
+ reg [FIFO_DEPTH-1:0] rd_pointer;
+ wire [RAM_DEPTH-1:0] address;
+ reg data_avail_int; // Internal not empty flag.
+
+ assign read = read_strobe && data_avail_int;
+ assign write = write_strobe && space_avail;
+
+ // When a read and write collision occur, supress the space_avail flag next cycle
+ // and complete write followed by read over 2 cycles. This forces balanced arbitration
+ // and makes for a simple logic design.
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ capacity <= (1 << FIFO_DEPTH) - 1;
+ wr_pointer <= 0;
+ rd_pointer <= 0;
+ space_avail <= 1;
+ data_avail_int <= 0;
+ end
+ else
+ begin
+ // No space available if:
+ // Capacity is already zero; Capacity is 1 and write is asserted (lookahead); both read and write are asserted (collision)
+ space_avail <= ~((capacity == 0) || (read&&write) || ((capacity == 1) && write) );
+ // Capacity has 1 cycle delay so look ahead here for corner case of read of last item in FIFO.
+ data_avail_int <= ~((capacity == ((1 << FIFO_DEPTH)-1)) || ((capacity == ((1 << FIFO_DEPTH)-2)) && (~write && read)) );
+ wr_pointer <= wr_pointer + write;
+ rd_pointer <= rd_pointer + (~write && read);
+ capacity <= capacity - write + (~write && read) ;
+ end // else: !if(rst)
+
+ assign address = write ? wr_pointer : rd_pointer;
+ assign enable = write || read;
+
+
+ //
+ // Simple NoBL SRAM interface, 4 cycle read latency.
+ // Read/Write arbitration via temprary application of empty/full flags.
+ //
+ nobl_if #(.WIDTH(WIDTH),.DEPTH(RAM_DEPTH))
+ nobl_if_i1
+ (
+ .clk(clk),
+ .rst(rst),
+ .RAM_D_pi(RAM_D_pi),
+ .RAM_D_po(RAM_D_po),
+ .RAM_D_poe(RAM_D_poe),
+ .RAM_A(RAM_A),
+ .RAM_WEn(RAM_WEn),
+ .RAM_CENn(RAM_CENn),
+ .RAM_LDn(RAM_LDn),
+ .RAM_OEn(RAM_OEn),
+ .RAM_CE1n(RAM_CE1n),
+ .address(address),
+ .data_out(write_data),
+ .data_in(read_data),
+ .data_in_valid(data_avail),
+ .write(write),
+ .enable(enable)
+ );
+
+
+
+endmodule // nobl_fifo
diff --git a/fpga/usrp3/lib/extramfifo/nobl_if.v b/fpga/usrp3/lib/extramfifo/nobl_if.v
new file mode 100644
index 000000000..a0126bbe3
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/nobl_if.v
@@ -0,0 +1,168 @@
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// Tested against an IDT 71v65603s150 in simulation and a Cypress 7C1356C in the real world.
+
+module nobl_if
+ #(parameter WIDTH=18,DEPTH=19)
+ (
+ input clk,
+ input rst,
+ input [WIDTH-1:0] RAM_D_pi,
+ output [WIDTH-1:0] RAM_D_po,
+ output reg RAM_D_poe,
+ output [DEPTH-1:0] RAM_A,
+ output reg RAM_WEn,
+ output RAM_CENn,
+ output RAM_LDn,
+ output RAM_OEn,
+ output reg RAM_CE1n,
+ input [DEPTH-1:0] address,
+ input [WIDTH-1:0] data_out,
+ output reg [WIDTH-1:0] data_in,
+ output reg data_in_valid,
+ input write,
+ input enable
+ );
+
+
+ reg enable_pipe1;
+ reg [DEPTH-1:0] address_pipe1;
+ reg write_pipe1;
+ reg [WIDTH-1:0] data_out_pipe1;
+
+ reg enable_pipe2;
+ reg write_pipe2;
+ reg [WIDTH-1:0] data_out_pipe2;
+
+ reg enable_pipe3;
+ reg write_pipe3;
+ reg [WIDTH-1:0] data_out_pipe3;
+
+ assign RAM_LDn = 0;
+ // ZBT/NoBL RAM actually manages its own output enables very well.
+ assign RAM_OEn = 0;
+
+ // gray code the address to reduce EMI
+ wire [DEPTH-1:0] address_gray;
+
+ bin2gray #(.WIDTH(DEPTH)) bin2gray (.bin(address),.gray(address_gray));
+
+
+ //
+ // Pipeline stage 1
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_pipe1 <= 0;
+ address_pipe1 <= 0;
+ write_pipe1 <= 0;
+ data_out_pipe1 <= 0;
+ RAM_WEn <= 1;
+ RAM_CE1n <= 1;
+
+ end
+ else
+ begin
+ enable_pipe1 <= enable;
+ RAM_CE1n <= ~enable; // Creates IOB flop
+ RAM_WEn <= ~write; // Creates IOB flop
+
+ if (enable)
+ begin
+ address_pipe1 <= address_gray;
+ write_pipe1 <= write;
+// RAM_WEn <= ~write; // Creates IOB flop
+
+
+ if (write)
+ data_out_pipe1 <= data_out;
+ end
+ end // always @ (posedge clk)
+
+ // Pipeline 1 drives address, write_enable, chip_select on NoBL SRAM
+ assign RAM_A = address_pipe1;
+ assign RAM_CENn = 1'b0;
+ // assign RAM_WEn = ~write_pipe1;
+// assign RAM_CE1n = ~enable_pipe1;
+
+ //
+ // Pipeline stage2
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_pipe2 <= 0;
+ data_out_pipe2 <= 0;
+ write_pipe2 <= 0;
+ end
+ else
+ begin
+ data_out_pipe2 <= data_out_pipe1;
+ write_pipe2 <= write_pipe1;
+ enable_pipe2 <= enable_pipe1;
+ end
+
+ //
+ // Pipeline stage3
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_pipe3 <= 0;
+ data_out_pipe3 <= 0;
+ write_pipe3 <= 0;
+ RAM_D_poe <= 0;
+ end
+ else
+ begin
+ data_out_pipe3 <= data_out_pipe2;
+ write_pipe3 <= write_pipe2;
+ enable_pipe3 <= enable_pipe2;
+ RAM_D_poe <= ~(write_pipe2 & enable_pipe2); // Active low driver enable in Xilinx.
+ end
+
+ // Pipeline 3 drives write data on NoBL SRAM
+ assign RAM_D_po = data_out_pipe3;
+
+
+ //
+ // Pipeline stage4
+ //
+ always @(posedge clk)
+ if (rst)
+ begin
+ data_in_valid <= 0;
+ data_in <= 0;
+ end
+ else
+ begin
+ data_in <= RAM_D_pi;
+ if (enable_pipe3 & ~write_pipe3)
+ begin
+ // Read data now available to be registered.
+ data_in_valid <= 1'b1;
+ end
+ else
+ data_in_valid <= 1'b0;
+ end // always @ (posedge clk)
+
+endmodule // nobl_if
diff --git a/fpga/usrp3/lib/extramfifo/refill_randomizer.v b/fpga/usrp3/lib/extramfifo/refill_randomizer.v
new file mode 100644
index 000000000..f3208e983
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/refill_randomizer.v
@@ -0,0 +1,86 @@
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+//
+// EMI mitigation.
+// Process FULL flag from FIFO so that de-assertion
+// (FIFO now not FULL) is delayed by a pseudo random
+// value, but assertion is passed straight through.
+//
+
+
+module refill_randomizer
+ #(parameter BITS=7)
+ (
+ input clk,
+ input rst,
+ input full_in,
+ output full_out
+ );
+
+ wire feedback;
+ reg full_last;
+ wire full_deasserts;
+ reg [6:0] shift_reg;
+ reg [6:0] count;
+ reg delayed_fall;
+
+
+ always @(posedge clk)
+ full_last <= full_in;
+
+ assign full_deasserts = full_last & ~full_in;
+
+ // 7 bit LFSR
+ always @(posedge clk)
+ if (rst)
+ shift_reg <= 7'b1;
+ else
+ if (full_deasserts)
+ shift_reg <= {shift_reg[5:0],feedback};
+
+ assign feedback = ^(shift_reg & 7'h41);
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ count <= 1;
+ delayed_fall <= 1;
+ end
+ else if (full_deasserts)
+ begin
+ count <= shift_reg;
+ delayed_fall <= 1;
+ end
+ else if (count == 1)
+ begin
+ count <= 1;
+ delayed_fall <= 0;
+ end
+ else
+ begin
+ count <= count - 1;
+ delayed_fall <= 1;
+ end
+
+ // Full_out goes instantly high if full_in does. However its fall is delayed.
+ assign full_out = (full_in == 1) || (full_last == 1) || delayed_fall;
+
+endmodule \ No newline at end of file
diff --git a/fpga/usrp3/lib/extramfifo/test_sram_if.v b/fpga/usrp3/lib/extramfifo/test_sram_if.v
new file mode 100644
index 000000000..26b805804
--- /dev/null
+++ b/fpga/usrp3/lib/extramfifo/test_sram_if.v
@@ -0,0 +1,195 @@
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// Instantiate this block at the core level to conduct closed
+// loop testing of the AC performance of the USRP2 SRAM interface
+
+
+`define WIDTH 18
+`define DEPTH 19
+
+module test_sram_if
+ (
+ input clk,
+ input rst,
+ input [`WIDTH-1:0] RAM_D_pi,
+ output [`WIDTH-1:0] RAM_D_po,
+ output RAM_D_poe,
+ output [`DEPTH-1:0] RAM_A,
+ output RAM_WEn,
+ output RAM_CENn,
+ output RAM_LDn,
+ output RAM_OEn,
+ output RAM_CE1n,
+ output reg correct
+ );
+
+ reg [`DEPTH-1:0] write_count;
+ reg [`DEPTH-1:0] read_count;
+ reg enable;
+ reg write;
+ reg write_cycle;
+ reg read_cycle;
+ reg enable_reads;
+ reg [18:0] address;
+ reg [17:0] data_out;
+ wire [17:0] data_in;
+ wire data_in_valid;
+
+ reg [17:0] check_data;
+ reg [17:0] check_data_old;
+ reg [17:0] check_data_old2;
+
+ //
+ // Create counter that generates both external modulo 2^19 address and modulo 2^18 data to test RAM.
+ //
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ write_count <= 19'h0;
+ read_count <= 19'h0;
+ end
+ else if (write_cycle) // Write cycle
+ if (write_count == 19'h7FFFF)
+ begin
+ write_count <= 19'h0;
+ end
+ else
+ begin
+ write_count <= write_count + 1'b1;
+ end
+ else if (read_cycle) // Read cycle
+ if (read_count == 19'h7FFFF)
+ begin
+ read_count <= 19'h0;
+ end
+ else
+ begin
+ read_count <= read_count + 1'b1;
+ end
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable_reads <= 0;
+ read_cycle <= 0;
+ write_cycle <= 0;
+ end
+ else
+ begin
+ write_cycle <= ~write_cycle;
+ if (enable_reads)
+ read_cycle <= write_cycle;
+ if (write_count == 15) // Enable reads 15 writes after reset terminates.
+ enable_reads <= 1;
+ end // else: !if(rst)
+
+ always @(posedge clk)
+ if (rst)
+ begin
+ enable <= 0;
+ end
+ else if (write_cycle)
+ begin
+ address <= write_count;
+ data_out <= write_count[17:0];
+ enable <= 1;
+ write <= 1;
+ end
+ else if (read_cycle)
+ begin
+ address <= read_count;
+ check_data <= read_count[17:0];
+ check_data_old <= check_data;
+ check_data_old2 <= check_data_old;
+ enable <= 1;
+ write <= 0;
+ end
+ else
+ enable <= 0;
+
+ always @(posedge clk)
+ if (data_in_valid)
+ begin
+ correct <= (data_in == check_data_old2);
+ end
+
+
+ nobl_if nobl_if_i1
+ (
+ .clk(clk),
+ .rst(rst),
+ .RAM_D_pi(RAM_D_pi),
+ .RAM_D_po(RAM_D_po),
+ .RAM_D_poe(RAM_D_poe),
+ .RAM_A(RAM_A),
+ .RAM_WEn(RAM_WEn),
+ .RAM_CENn(RAM_CENn),
+ .RAM_LDn(RAM_LDn),
+ .RAM_OEn(RAM_OEn),
+ .RAM_CE1n(RAM_CE1n),
+ .address(address),
+ .data_out(data_out),
+ .data_in(data_in),
+ .data_in_valid(data_in_valid),
+ .write(write),
+ .enable(enable)
+ );
+
+
+ wire [35:0] CONTROL0;
+ reg [7:0] data_in_reg, data_out_reg, address_reg;
+ reg data_in_valid_reg,write_reg,enable_reg,correct_reg;
+
+ always @(posedge clk)
+ begin
+ data_in_reg <= data_in[7:0];
+ data_out_reg <= data_out[7:0];
+ data_in_valid_reg <= data_in_valid;
+ write_reg <= write;
+ enable_reg <= enable;
+ correct_reg <= correct;
+ address_reg <= address;
+
+ end
+
+
+ icon icon_i1
+ (
+ .CONTROL0(CONTROL0)
+ );
+
+ ila ila_i1
+ (
+ .CLK(clk),
+ .CONTROL(CONTROL0),
+ // .TRIG0(address_reg),
+ .TRIG0(data_in_reg[7:0]),
+ .TRIG1(data_out_reg[7:0]),
+ .TRIG2(address_reg[7:0]),
+ .TRIG3({data_in_valid_reg,write_reg,enable_reg,correct_reg})
+ );
+
+
+
+endmodule // test_sram_if
+
+ \ No newline at end of file