diff options
Diffstat (limited to 'fpga/usrp3/lib/extramfifo')
-rw-r--r-- | fpga/usrp3/lib/extramfifo/.gitignore | 3 | ||||
-rw-r--r-- | fpga/usrp3/lib/extramfifo/Makefile.srcs | 17 | ||||
-rw-r--r-- | fpga/usrp3/lib/extramfifo/ext_fifo.v | 166 | ||||
-rw-r--r-- | fpga/usrp3/lib/extramfifo/ext_fifo_tb.v | 435 | ||||
-rw-r--r-- | fpga/usrp3/lib/extramfifo/nobl_fifo.v | 117 | ||||
-rw-r--r-- | fpga/usrp3/lib/extramfifo/nobl_if.v | 168 | ||||
-rw-r--r-- | fpga/usrp3/lib/extramfifo/refill_randomizer.v | 86 | ||||
-rw-r--r-- | fpga/usrp3/lib/extramfifo/test_sram_if.v | 195 |
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 |