diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v b/fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v new file mode 100644 index 000000000..700da18d3 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/fosphor/fifo_srl.v @@ -0,0 +1,169 @@ +/* + * fifo_srl.v + * + * Very small/light-weight FIFO using SRL. + * Only for synchronous design. Has a fixed depth of 15 or 31 entries and + * always work in the so-called first-word-fall-thru mode. + * + * Copyright (C) 2014 Ettus Corporation LLC + * Copyright 2018 Ettus Research, a National Instruments Company + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * vim: ts=4 sw=4 + */ + +`ifdef SIM +`default_nettype none +`endif + +module fifo_srl #( + parameter integer WIDTH = 4, + parameter integer LOG2_DEPTH = 5, // 4 or 5 + parameter integer AFULL_LEVEL = -1 // -1 -> No AFULL + +)( + input wire [WIDTH-1:0] di, + input wire wren, + output wire full, + output wire afull, + + output reg [WIDTH-1:0] do, + input wire rden, + output reg empty, + + input wire clk, + input wire rst +); + + genvar i; + + // Signals + wire [WIDTH-1:0] srl_q; + reg [LOG2_DEPTH-1:0] srl_addr; + wire srl_addr_ce; + + wire srl_write; + wire srl_read; + + wire srl_full; + wire srl_afull; + reg srl_empty; + wire srl_aempty; + + // Instanciate the SRLs + generate + if (LOG2_DEPTH == 6) begin + wire [WIDTH-1:0] srl0_q31, srl0_q, srl1_q; + + for (i=0; i<WIDTH; i=i+1) + begin : srl_64 + SRLC32E srl_I0 ( + .Q(srl0_q[i]), + .Q31(srl0_q31[i]), + .A(srl_addr[4:0]), + .CE(srl_write), + .CLK(clk), + .D(di[i]) + ); + + SRLC32E srl_I1 ( + .Q(srl1_q[i]), + .A(srl_addr[4:0]), + .CE(srl_write), + .CLK(clk), + .D(srl0_q31[i]) + ); + + MUXF7 mux_I ( + .O(srl_q[i]), + .I0(srl0_q[i]), + .I1(srl1_q[i]), + .S(srl_addr[5]) + ); + end + end else if (LOG2_DEPTH == 5) begin + for (i=0; i<WIDTH; i=i+1) + SRLC32E srl_I ( + .Q(srl_q[i]), + .A(srl_addr), + .CE(srl_write), + .CLK(clk), + .D(di[i]) + ); + end else if (LOG2_DEPTH == 4) begin + for (i=0; i<WIDTH; i=i+1) + SRL16E srl_I ( + .Q(srl_q[i]), + .A0(srl_addr[0]), + .A1(srl_addr[1]), + .A2(srl_addr[2]), + .A3(srl_addr[3]), + .CE(srl_write), + .CLK(clk), + .D(di[i]) + ); + end + endgenerate + + // Address counter + assign srl_addr_ce = srl_write ^ srl_read; + + always @(posedge clk) + begin + if (rst) + srl_addr <= {LOG2_DEPTH{1'b1}}; + else if (srl_addr_ce) begin + if (srl_write) + srl_addr <= srl_addr + 1; + else + srl_addr <= srl_addr - 1; + end + end + + // SRL status + assign srl_full = srl_addr == {{(LOG2_DEPTH-1){1'b1}}, 1'b0}; + + generate + if (AFULL_LEVEL != -1) begin + assign srl_afull = (srl_addr >= AFULL_LEVEL) && ~&(srl_addr); + end else begin + assign srl_afull = 1'b0; + end + endgenerate + + assign srl_aempty = &(~srl_addr); + + always @(posedge clk) + begin + if (rst) + srl_empty <= 1'b1; + else if (srl_addr_ce) + srl_empty <= srl_aempty & srl_read; + end + + // Output register (to capture whatever comes out from SRL) + always @(posedge clk) + begin + if (srl_read) + do <= srl_q; + end + + // Control and flag generation + // Write/Full is easy + assign srl_write = wren; + assign full = srl_full; + assign afull = srl_afull; + + // Read/Empty is tricky + always @(posedge clk) + begin + if (rst) + empty <= 1'b1; + else if (rden | srl_read) + empty <= srl_empty; + end + + assign srl_read = (rden | empty) & ~srl_empty; + +endmodule // fifo_srl |