同步FIFO和异步FIFO的Verilog实现(代码仿真实现)

同步FIFO和异步FIFO的Verilog实现

一、同步FIFO
1、同步FIFO的Verilog实现

module class_6_fifo#(
    parameter    Width   =     16,
	parameter    Depth   =     4
	)(
    input        wire                              i_clk         ,
	input        wire                              i_rst_n       ,
	input        wire          [Width-1:00]        i_data        ,
	input        wire                              i_wr          ,
	input        wire                              i_rd          ,
	
	output       reg           [Width-1:00]        o_data        ,
	output       wire                              o_empty       ,
	output       wire                              o_full
    );
	
	reg          [Width-1:00]        Memory        [00:2**Depth-1];
	reg          [Depth-1:00]        addr_wr ;
	reg          [Depth-1:00]        addr_rd ;
	reg          [Depth:00]          cnt     ;
	
/*************写信号有效且未写满,数据输入RAM,写地址加1*******************/	
	always@(posedge i_clk or negedge i_rst_n)
	begin
	    if(!i_rst_n)
		   addr_wr <= #1 'd0;
	    else if(i_wr && (!o_full))
		     begin
	            Memory[addr_wr] <= #1 i_data;
				addr_wr <= #1 addr_wr + 1'b1;
			 end
	end
/*************写信号有效且未写满,数据输入RAM,写地址加1*******************/
/*************读信号有效且未读空,RAM输出数据,读地址加1*******************/	
	always@(posedge i_clk or negedge i_rst_n)
	begin
	    if(!i_rst_n)
		   begin
	         o_data <= #1 'd0;
			 addr_rd <= #1 'd0;
		   end
	    else if(i_rd && (!o_empty))
		     begin
	     		o_data <= #1 Memory[addr_rd];
				addr_rd <= #1 addr_rd + 1'b1;
		     end
	end
/*************读信号有效且未读空,RAM输出数据,读地址加1*******************/
/*************读写信号有效,生成cnt计数*******************/	
	always@(posedge i_clk or negedge i_rst_n)
	begin
	    if(!i_rst_n)
	        cnt <= #1 'd0;
		else begin
	         case({i_wr,i_rd})
			    2'b00 : begin                     //读写信号无效,cnt不变
				        cnt <= #1 cnt ;
					 end
		        2'b01 : begin                     //读信号有效且未读空,cnt加1
				      if(!o_empty)
				        cnt <= #1 cnt - 1'b1;
					 end
		        2'b10 : begin                     //写信号有效且未写满,cnt加1
				      if(!o_full)
				        cnt <= #1 cnt + 1'b1;
				     end
		        2'b11 : begin                     //读写信号有效,cnt不变
				        cnt <= #1 cnt ;
					 end
			 endcase
		end
	end
/*************读写信号有效,生成cnt计数*******************/	
	assign  o_empty = (cnt == 0) ? 1'b1 : 1'b0;               //读空标志位
	assign  o_full  = (cnt == 2**Depth ) ? 1'b1 : 1'b0;         //写满标志位	
endmodule

2、同步FIFO的testbench

module tb_fifo#(
    parameter    Width   =     16,
	parameter    Depth   =     4
    );
	
	reg                              i_clk         ;
	reg                              i_rst_n       ;
	reg          [Width-1:00]        i_data        ;
	reg                              i_wr          ;
	reg                              i_rd          ;
    wire          [Width-1:00]       o_data        ;
    wire                             o_empty       ;
    wire                             o_full        ;
	
class_6_fifo#(
    .Width(Width),
	.Depth(Depth)
	)u_class_6_fifo(
    .i_clk     (i_clk  )    ,
	.i_rst_n   (i_rst_n)    ,
	.i_data    (i_data )    ,
	.i_wr      (i_wr   )    ,
	.i_rd      (i_rd   )    ,	
	.o_data    (o_data )    ,
	.o_empty   (o_empty)    ,
	.o_full    (o_full )
    );

    parameter   clk_period  = 20 ;
	
	initial i_clk = 0;
	always #(clk_period/2) i_clk = ~i_clk;
    
	integer i;
	integer j;
 
 initial begin
 i_rst_n=0;
 i_rd=0;
 i_wr=0;
 i_data=5;
 #(clk_period * 20 + 1);
 i_rst_n = 1 ;
    for(i=0;i<20;i=i+1)
        begin
		@(posedge i_clk);
        i_wr = 1;
        i_data = i + 1;
    	end
	i_wr = 0;	
	#(clk_period * 20 + 1);		
    for(j=0;j<20;j=j+1)
        begin
		@(posedge i_clk);		
        i_rd = 1;
    	end	
	i_rd = 0;
	#(clk_period * 20 + 1);
 end

3、同步FIFO的仿真结果
在这里插入图片描述
写数据
在这里插入图片描述

读数据
在这里插入图片描述
二、异步FIFO
1、异步FIFO的Verilog实现

module class_8_dcfifo#(
       parameter      WIDTH     =    16,
	   parameter      DEPTH     =    4
    )(
	   input                                         i_rst_n      ,
       input                                         i_wr_clk     ,
	   input                                         i_wr         ,
	   input                                         i_rd_clk     ,
	   input                                         i_rd         ,
	   input                     [WIDTH-1:00]        i_data       ,
	   
	   output        reg         [WIDTH-1:00]        o_data       ,
	   output                                        o_full       ,
	   output                                        o_empty
    );	
	   reg         [WIDTH-1:00]         Memory       [00:2**DEPTH-1];
	   wire        [DEPTH-1:00]         wr_addr             ;
       wire        [DEPTH-1:00]         rd_addr             ;
       reg         [DEPTH:00]           wr_addr_ptr         ;
       reg         [DEPTH:00]           rd_addr_ptr         ;
       wire        [DEPTH:00]           wr_addr_ptr_grey    ;
       wire        [DEPTH:00]           rd_addr_ptr_grey    ;	   
       reg         [DEPTH:00]           wr_addr_ptr_grey1   ;
       reg         [DEPTH:00]           wr_addr_ptr_grey2   ;
       reg         [DEPTH:00]           rd_addr_ptr_grey1   ;		   
       reg         [DEPTH:00]           rd_addr_ptr_grey2   ;	
/**********写时钟域下数据输入RAM,写使能且未写满,写指针加1**********/	   
    always@(posedge i_wr_clk or negedge i_rst_n)
	begin
	   if(!i_rst_n)
	       wr_addr_ptr <= #1 'd0;
	   else if(i_wr & (!o_full))
	       begin
		      Memory[wr_addr] <= #1 i_data;
		      wr_addr_ptr <= wr_addr_ptr + 1'b1;
		   end
	end
/**********写时钟域下数据输入RAM,写使能且未写满,写指针加1**********/	
/**********读时钟域下RAM输出数据,读使能且未读空,读指针加1**********/	      			
	always@(posedge i_rd_clk or negedge i_rst_n)
	begin
	   if(!i_rst_n)
	      begin
		    o_data <= #1 'd0;
			rd_addr_ptr <= #1 'd0;
		  end
	   else if(i_rd & (!o_empty))
          begin
            o_data <= #1 Memory[rd_addr];
            rd_addr_ptr <= rd_addr_ptr + 1'b1;
          end		  	
	end
/**********读时钟域下RAM输出数据,读使能且未读空,读指针加1**********/	
/**********读写地址位输出,读写指针除去最高位**********/	
    assign  wr_addr = wr_addr_ptr[DEPTH-1:0];
	assign  rd_addr = rd_addr_ptr[DEPTH-1:0];
/**********读写地址位输出,读写指针除去最高位**********/	
/**********读写指针二进制码转换为格雷码**********/	
    assign  wr_addr_ptr_grey = (wr_addr_ptr >> 1) ^ wr_addr_ptr;
    assign  rd_addr_ptr_grey = (rd_addr_ptr >> 1) ^ rd_addr_ptr;
/**********读写指针二进制码转换为格雷码**********/		
/****读写指针跨时钟域处理,写时钟域下采集读指针,读时钟域下采集写指针******/		
	always@(posedge i_wr_clk)
	begin
	    rd_addr_ptr_grey1 <= rd_addr_ptr_grey;
	    rd_addr_ptr_grey2 <= rd_addr_ptr_grey1;
	end	
    always@(posedge i_rd_clk)
	begin
	    wr_addr_ptr_grey1 <= wr_addr_ptr_grey;
		wr_addr_ptr_grey2 <= wr_addr_ptr_grey1;
	end
/*****读写指针跨时钟域处理,写时钟域下采集读指针,读时钟域下采集写指针*****/		
/**********读空标志 即 读指针格雷码与读时钟域下采集写指针相等**********/		
	assign  o_empty = (rd_addr_ptr_grey == wr_addr_ptr_grey2) ? 1'b1 : 1'b0; 
/**********读空标志 即 读指针格雷码与读时钟域下采集写指针相等**********/	
/***写满标志 即 写指针格雷码与写时钟域下采集读指针,高两位取反相等,其他位相等**/		
	assign  o_full  = (wr_addr_ptr_grey == {(~rd_addr_ptr_grey2[DEPTH:DEPTH-2]),rd_addr_ptr_grey2[DEPTH-3:0]}) ? 1'b1 : 1'b0;
/***写满标志 即 写指针格雷码与写时钟域下采集读指针,高两位取反相等,其他位相等**/		
endmodule

2、异步FIFO的testbench

module tb_defifo#(
       parameter      WIDTH     =    16,
	   parameter      DEPTH     =    4
);

	   reg                                         i_rst_n      ;
       reg                                         i_wr_clk     ;
	   reg                                         i_wr         ;
	   reg                                         i_rd_clk     ;
	   reg                                         i_rd         ;
	   reg                     [WIDTH-1:00]        i_data       ;	   
	   wire                    [WIDTH-1:00]        o_data       ;
	   wire                                        o_full       ;
	   wire                                        o_empty      ;
	
class_8_dcfifo#(
       .WIDTH (WIDTH),
	   .DEPTH (DEPTH)
    )u_class_8_dcfifo(
	   .i_rst_n     (i_rst_n ) ,
       .i_wr_clk    (i_wr_clk) ,
	   .i_wr        (i_wr    ) ,
	   .i_rd_clk    (i_rd_clk) ,
	   .i_rd        (i_rd    ) ,
	   .i_data      (i_data  ) ,	   
	   .o_data      (o_data  ) ,
	   .o_full      (o_full  ) ,
	   .o_empty     (o_empty )
    );	
    
	parameter    wr_clk_period   =   20  ;
	parameter    rd_clk_period   =   50  ;
	
    initial  i_wr_clk = 0;
    always#(wr_clk_period/2) i_wr_clk = ~i_wr_clk;

    initial  i_rd_clk = 0;
    always#(rd_clk_period/2) i_rd_clk = ~i_rd_clk;

	integer i,j;
	
    initial begin
	   i_rst_n = 0;
	   i_wr = 0;
	   i_rd = 0;
	   #100;
	   i_rst_n = 1;
	   i_data = 5;
	   for(i=0;i<16;i=i+1)
	      begin
		      @(posedge  i_wr_clk);
		      i_wr = 1;			  
			  i_data = i_data + 1;
		  end
       i_wr = 0;
	   #(rd_clk_period ** 10000 + 1);	   
	   for(j=0;j<16;j=j+1)
	      begin
		      @(posedge i_rd_clk);
		      i_rd = 1;			  
		  end
	   i_rd = 0;
	   #(rd_clk_period ** 100 + 1);	
	   $finish;
	end	
endmodule

3、异步FIFO的仿真结果
FIFO未写满情况
在这里插入图片描述
FIFO写满的情况
在这里插入图片描述

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小灰灰的FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值