diff options
Diffstat (limited to 'fpga/usrp3/lib/extramfifo/ext_fifo.v')
-rw-r--r-- | fpga/usrp3/lib/extramfifo/ext_fifo.v | 166 |
1 files changed, 166 insertions, 0 deletions
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 |