异步FIFO代码及仿真结果(Verilog)

👉异步FIFO的分析请看:异步FIFO
注:代码附于文末
注:因为CSDN不支持Verilog高亮,先用截图的代码便于阅读。


1.代码截图

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

2.仿真结果

仿真结果如下:

  • 空满标志生成正常
  • 读写地址指针计数器正常
  • 数据存取正常
  • 格雷码逻辑正常
  • 指针跨时钟域同步正常

https://img-blog.csdnimg.cn/95ba561304f94b65a0e9fb6b26825d44.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1N1bW1lclhSVA==,size_16,color_FFFFFF,t_70

3.代码

代码如下:


module asy_fifo#(
	parameter  WIDTH=8,//FIFO的位宽
	parameter  DEEPTH=32,//FIFO的深度
	parameter  POINTER_WIDTH=5,//读写地址指针,指针向高位扩展一位
	parameter  ADDR_WIDTH=4//读写地址的位宽
	)
	(empty,full,r_data,w_clk,w_rstn,w_en,w_data,r_clk,r_rstn,r_en);

output     empty,full; //FIFO生成的空满信号
output reg [WIDTH-1:0] r_data;//从FIFO中读出的数据
input      w_clk,w_rstn;//读时钟域时钟、读时钟域复位信号
input      w_en;//读操作使能信号 
input      [WIDTH-1:0] w_data;//向FIFO中写入的数据
input      r_clk,r_rstn;//写时钟域时钟、写时钟域复位信号
input      r_en;//写操作使能信号


//定义:FIFO的buffer
reg        [WIDTH-1:0] fifo_mem [0:DEEPTH-1];

//定义:FIFO的读写指针
reg        [POINTER_WIDTH-1:0] w_pointer,r_pointer;
	
//定义:FIFO内数据对应的存取地址
wire       [ADDR_WIDTH-1:0]w_addr,r_addr;
	
//定义:转换为格雷码的指针
wire       [POINTER_WIDTH-1:0] w_gray_pointer;
wire       [POINTER_WIDTH-1:0] r_gray_pointer;

//定义:指针经过两级触发器同步时的指针
reg        [POINTER_WIDTH-1:0] w_pointer_d1,w_pointer_d2;
reg        [POINTER_WIDTH-1:0] r_pointer_d1,r_pointer_d2;

//===========写时钟域========
//写时钟域内,写数据进FIFO,并将写指针加1
assign  w_addr = w_pointer[POINTER_WIDTH-2:0];
always@(posedge w_clk or negedge w_rstn)begin
  if( w_en & (!full) ) begin
    fifo_mem[w_addr] <= w_data;  
  end
end
 //写指针计数器
always@(posedge w_clk or negedge w_rstn) begin
  if(!w_rstn) begin	
	w_pointer <= 0;
  end
  else if(w_en & (!full)) begin
	w_pointer <= w_pointer + 1;  
  end
  else begin
	w_pointer <= w_pointer; 
  end
end
//==========================

//===========读时钟域========
//读时钟域内,把FIFO内的数据取出,并将读指针加1
assign  r_addr = r_pointer[POINTER_WIDTH-2:0];
always@(posedge r_clk or negedge r_rstn)begin
  if(!r_rstn) begin
  	r_data <= 'h0;
  end
  else if( r_en & (!empty) ) begin
    r_data <= fifo_mem[r_addr] ;
  end
end
  //读指针计数器
always@(posedge r_clk or negedge r_rstn)begin
  if(!r_rstn) begin
  	r_pointer <= 0;
  end
  else if( r_en & (!empty) ) begin
    r_pointer <= r_pointer + 1 ;
  end
  else begin
	r_pointer <= r_pointer;  
  end
end
//==========================

//===========指针同步======
//将格雷码写指针同步到读时钟域
  //1.将写指针转换为格雷码的形式
assign w_gray_pointer = w_pointer^(w_pointer >> 1);
  //2.再将转换后的指针经过两级触发器同步
always@(posedge r_clk or negedge r_rstn) begin
  if(!r_rstn)begin
    {w_pointer_d1,w_pointer_d2} <= 0;
  end
  else begin
    {w_pointer_d2,w_pointer_d1} <= {w_pointer_d1,w_gray_pointer};
  end
end

//将格雷码读指针经过两级触发器同步到写时钟域
  //1.将读指针转换为格雷码的形式
assign r_gray_pointer = r_pointer^(r_pointer >> 1);
  //2.再将转换后的指针经过两级触发器同步
always@(posedge w_clk or negedge w_rstn) begin
  if(!w_rstn) begin
    {r_pointer_d1,r_pointer_d2} <= 0;
  end
  else begin
    {r_pointer_d2,r_pointer_d1} <= {r_pointer_d1,r_gray_pointer};
  end
end
//==========================

//判断空满
assign full = (
			    (r_pointer_d2[POINTER_WIDTH-1] != w_gray_pointer[POINTER_WIDTH-1]) && //最高位不同
       	  	    (r_pointer_d2[POINTER_WIDTH-2] != w_gray_pointer[POINTER_WIDTH-2]) && //次高位不同
                (r_pointer_d2[POINTER_WIDTH-3:0] == w_gray_pointer[POINTER_WIDTH-3:0])//其他低位相同
              );
assign empty = (w_pointer_d2 == r_gray_pointer);

endmodule


//==========TESTBENCH=========
`timescale 1ns/10ps
module TB;

parameter  WIDTH=8;
	
wire       empty,full; 
wire       [WIDTH-1:0] r_data;
reg        w_clk,w_rstn;
reg        w_en;  
reg        [WIDTH-1:0] w_data;
reg        r_clk,r_rstn;
reg        r_en;



asy_fifo dut(.empty(empty),
		    .full(full),
		    .r_data(r_data),
		    .w_clk(w_clk),
		    .w_rstn(w_rstn),
		    .w_en(w_en),
		    .w_data(w_data),
		    .r_clk(r_clk),
		    .r_rstn(r_rstn),
		    .r_en(r_en)
			);

//产生写时钟,100MHz
  initial begin 
    w_clk <= 0;
    forever begin
      #5 w_clk <= !w_clk;
    end
  end
  initial begin 
    #10 w_rstn <= 0;
    repeat(10) @(posedge w_clk);
    #1ns;
    w_rstn <= 1;
  end 
  
//产生读时钟,50MHz  
  initial begin 
    r_clk <= 0;
    forever begin
      #5 r_clk <= !r_clk;
    end
  end
  initial begin 
    #10 r_rstn <= 0;
    repeat(10) @(posedge w_clk);
    r_rstn <= 1;
  end 
  
  
initial begin
#10 w_en =  1'b1;
    w_data = #(0.01) $random;
    repeat(5) begin
      @(posedge w_clk);
      w_data = #(0.01) $random;    
    end
    @(posedge w_clk);
    w_en = 1'b0;
    w_data = #(0.01) $random;
   
#20 r_en = #(0.01) 1'b1; 
    repeat(5) begin
      @(posedge r_clk);
    end
    @(posedge r_clk);
    r_en = 1'b0;    

#20 w_en = 1'b1;  
    repeat(20) begin
      @(posedge w_clk);  
      w_data = #(0.01) $random;
    end
    @(posedge w_clk); 
    w_en =  1'b0;
    w_data = #(0.01) $random;
    r_en = #(0.01) 1'b1; 
    repeat(20) begin
      @(posedge r_clk);
    end
#50  $finish();
end

endmodule 
  • 12
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小verifier

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

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

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

打赏作者

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

抵扣说明:

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

余额充值