同步FIFO

FIFO的原则:
满不能写,空不能读。
设计的思考:如何产生full empty信号?
方法1:计数器cnt,当写一个数据时,cnt加1 ; 反之,减1。
方法2:地址位扩展一位,用最高位进行判断满空。

//写指针  读指针
//状态full   empty 模块用一个fifo_cnt 计数器去控制。  同时这个计数器醉着读写状态的变化自增自减
// 写使能后每个周期写数据
//

module syn_fifo #(

parameter ADDR_width = 2,     
parameter DATA_WIDTH = 8,
parameter depth = 2** ADDR_width    //深度 4
) 
(
input clk,
input rst_n,
//write
input wr_en,
input [DATA_WIDTH - 1: 0] wr_data,
//read
input rd_en,
output [DATA_WIDTH - 1: 0] rd_data,
output wr_full,
output rd_empty
);
//RAM
reg [DATA_WIDTH - 1: 0] mem[0:  depth-1 ];
reg [ADDR_width :0]     fifo_cnt ;          //计数器多计数一位
reg [ADDR_width - 1 :0] wr_pointer ;
reg [ADDR_width - 1 :0] rd_pointer ;

always@(posedge clk)
begin
        if(!rst_n) begin
            fifo_cnt <= 0;
        end
        else begin
            if(wr_en && !rd_en) begin          //写
                fifo_cnt <= fifo_cnt + 'b1;
            end
            else if(rd_en && !wr_en) begin     //读
                fifo_cnt <= fifo_cnt - 'b1;
            end
        end
end       

//write or read pointer : if it arrives to depth,then it comes back to zero
always @(posedge clk or negedge rst_n)
begin
   if(!rst_n)
        wr_pointer <= 0;
   else if(wr_en && !rd_empty)
   begin
        if( wr_pointer == depth - 1)        //full ,then zero  深度和存储的深度一致  才可以正确存放
            wr_pointer <= 'b0;
        else                 //  使能读写
            wr_pointer <= wr_pointer  + 'b1;
   end
end

always @(posedge clk or negedge rst_n)
begin
   if(!rst_n)
        rd_pointer <= 0;
   else if(rd_en && !wr_full)
   begin
        if( rd_pointer == depth - 1)        //full ,then zero  深度和存储的深度一致  才可以正确存放
            rd_pointer <= 'b0;
        else                 //  使能读写
            rd_pointer <= rd_pointer  + 'b1;
   end
end

//data writes into fifo
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        mem[wr_pointer] <= 'b0  ;
    end
    else if(wr_en)
    begin
         mem[wr_pointer] <= wr_data ;    //
    end
end

// use FIFO_CNT to judge full or empty
assign rd_data = mem[rd_pointer];  //  when rd_en is asserted, rd_pointer moves one 
//way one: use counter to judge full or empty 
//way two: use wr_pointer + 1 = rd_pointer to judge full 
assign wr_full = (fifo_cnt == depth) ? 'b1: 'b0;    
assign rd_empty= (fifo_cnt == 0) ? 1:0 ; 
endmodule

module syn_fifo_tb(
    );
parameter ADDR_width = 2;   
parameter DATA_WIDTH = 8;
parameter depth = 2** ADDR_width;    //深度 4    
   
reg   clk          ;
reg   rst_n        ;
reg   wr_en        ;
reg   [DATA_WIDTH - 1: 0] wr_data      ;
reg   rd_en        ;
wire  [DATA_WIDTH - 1: 0] rd_data      ;
wire   wr_full      ;
wire   rd_empty     ;  

always #5 clk = ~clk; 
initial begin
    	clk = 0;
    	rst_n = 0 ;
    	wr_en = 0;
    	rd_en = 0;

    	@(negedge clk) rst_n = 1;     // !   :  negedge 
    	@(negedge clk) wr_en = 1;
    	wr_data = $random;
    	repeat(4) begin
    		@(negedge clk)
    		wr_data = $random;	
    	end
    	
    	@(negedge clk)
    	wr_en = 0;    // only w but not read
    	rd_en = 1;

    	repeat(3) begin
    		@(negedge clk);	
    	end

    	@(negedge clk)
    	rd_en = 0;
    	wr_en = 1;
    	wr_data = $random;

    	repeat(7) begin   		
    		@(negedge clk)
    		wr_data = $random;
    	end
    	#20 $finish;

    end
syn_fifo #(
.ADDR_width ( ADDR_width   ),     
.DATA_WIDTH ( DATA_WIDTH   ),
.depth      ( depth  )    //深度 16
) 
syn_fifo_tb(
. clk          (  clk       )  ,
. rst_n        (  rst_n     )  ,
. wr_en        (  wr_en     )  ,
. wr_data      (  wr_data   )  ,
. rd_en        (  rd_en     )  ,
. rd_data      (  rd_data   )  ,
. wr_full      (  wr_full   )  ,
. rd_empty     (  rd_empty  )
);
endmodule

这种方法:因为增加了计数器, 来产生满和空的条件,这就导师消耗资源,随着深度的增加,也会增加计数器的位宽,这样会降低最高频率。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值