lin-win-share/DA4008_V1.3/rtl/fifo/syn_fwft_fifo.v

204 lines
3.9 KiB
Verilog

////////////////////////////////////////////////
//Engineer: Xiaodong Zhong
//Date: 2019.5.21
//Description: ?????ram
////////////////////////////////////////////////
module syn_fwft_fifo #(
parameter width =16,
parameter depth =1024,
parameter prog_full_thre =512,
parameter prog_empty_thre =16
)(
input clk,
input rst,
input clr,
input wr_en,
input [width-1:0] din,
output full,
output almost_full,
output prog_full,
input rd_en,
output [width-1:0] dout,
output empty,
output almost_empty,
output prog_empty,
output [clog2(depth-1)-1:0] cnt
);
////////////////////////////////////////////////
//log2 function
////////////////////////////////////////////////
function integer clog2(input integer depth);
begin
for(clog2=0;depth>0;clog2=clog2+1)
depth =depth>>1;
end
endfunction
localparam aw = clog2(depth-1);
////////////////////////////////////////////////
//reg & wire
////////////////////////////////////////////////
reg [aw-1:0] wr_p;
reg [aw-1:0] rd_p;
wire [aw-1:0] rd_p_next;
reg [aw:0] i;
reg wr_en_dly;
wire [width-1:0] ram_dout;
wire ram_rden;
////////////////////////////////////////////////
//combinational logic
////////////////////////////////////////////////
//assign cnt = (wr_p >= rd_p) ? wr_p - rd_p : depth-rd_p+wr_p;
assign full = (i>=(depth-1)) ? 1'b1 : 1'b0;
assign almost_full = (i >=(depth-4)) ? 1'b1 : 1'b0;
assign prog_full = (i >= (prog_full_thre-1)) ? 1'b1 :1'b0;
assign empty = (i==1'b0) ? 1'b1 : 1'b0;
assign almost_empty = (i<=1'b1) ? 1'b1 : 1'b0;
assign prog_empty = (i<=prog_empty_thre) ? 1'b1 :1'b0;
assign cnt = i[clog2(depth-1)-1:0];
assign rd_p_next = rd_p + {{(aw-2){1'b0}}, (rd_en & !empty)};
////////////////////////////////////////////////
//timing
////////////////////////////////////////////////
reg wr_clr_r;
reg wr_clr;
//----------------------------------------------
always @(posedge clk or posedge clr)
if(clr)
wr_clr <= 1'b1;
else if(!wr_clr_r)
wr_clr <= 1'b0;// Release Clear
always @(posedge clk or posedge clr)
if(clr)
wr_clr_r <= 1'b1;
else
wr_clr_r <= 1'b0;
//----------------------------------------------
always@(posedge clk or posedge rst)begin
if(rst )begin
wr_en_dly <=1'b0;
end
else begin
wr_en_dly <=wr_en;
end
end
always@(posedge clk or posedge rst)begin
if(rst )begin
wr_p <=0;
end
else if(wr_clr)begin
wr_p <=0;
end
else if(wr_en)begin
if(wr_p == depth-1)begin
wr_p <=0;
end
else begin
wr_p <=wr_p+1;
end
end
else begin
wr_p <=wr_p;
end
end
//----------------------------------------------
always@(posedge clk or posedge rst)begin
if(rst )begin
rd_p <=0;
end
else if(wr_clr)begin
rd_p <=0;
end
else if(rd_en)begin
if(rd_p == depth-1)begin
rd_p <=0;
end
else begin
rd_p <=rd_p+1;
end
end
else begin
rd_p <=rd_p;
end
end
//----------------------------------------------
always@(posedge clk or posedge rst)begin
if(rst)begin
i <=0;
end
else if(wr_clr)begin
i <=0;
end
else begin
case({wr_en_dly,rd_en})
2'b00:begin
i <=i;
end
2'b01:begin
if(i!=0)begin
i <=i-1'b1;
end
else begin
i <=i;
end
end
2'b10:begin
if(i!=depth)begin
i <=i+1'b1;
end
else begin
i <=i;
end
end
2'b11:begin
i <=i;
end
default:begin
i <=i;
end
endcase
end
end
////////////////////////////////////////////////
//SRAM
////////////////////////////////////////////////
spram #(
.width (width ),
.depth (depth )
)spram(
.clka (clk ),
.ena (wr_en ),
.dina (din ),
.addra (wr_p ),
.clkb (clk ),
//.enb (1'b1 ),
.enb (ram_rden ),
.doutb (ram_dout ),
.addrb (rd_p_next )
);
assign ram_rden = wr_p != rd_p_next;
assign dout = empty ? 0 : ram_dout;
endmodule