//////////////////////////////////////////////// //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