170 lines
3.1 KiB
Verilog
170 lines
3.1 KiB
Verilog
/*
|
|
* 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 = {WIDTH{1'b0}},
|
|
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
|