> 文档中心 > 【Verilog】不用IP,你能写出异步FIFO的verilog代码吗?

【Verilog】不用IP,你能写出异步FIFO的verilog代码吗?

前集回顾:

【Verilog】同步FIFO原理及verilog实现


目录

一、方案设计

 二、Verilog代码

三、仿真


一、方案设计

        异步FIFO使用完全独立的读写时钟,empty由读时钟产生,full由写时钟产生,两者关系完全异步,所以不能采用同步FIFO中的计数器来产生empty和full信号。为了解决这一问题,采用了二进制地址转换为格雷码地址的方法,再由转换后的格雷码地址进行跨时钟域同步处理。

相应的电路图如下

        

 判断空满设计如下:

        

 二、Verilog代码:

moduleasyn_fifo#(parameterDATA_WIDTH=8,parameterADDR_WIDTH=9)(inputfifo_rst,inputrd_clk,inputwr_clk,inputrd_en,inputwr_en,input[DATA_WIDTH-1:0]wr_data,outputreg[DATA_WIDTH-1:0]rd_data,outputregfull,outputregempty);reg[ADDR_WIDTH-1:0]wr_addr_gray;reg[ADDR_WIDTH-1:0]wr_next_gray;reg[ADDR_WIDTH-1:0]rd_addr_gray;reg[ADDR_WIDTH-1:0]rd_next_gray;reg[ADDR_WIDTH-1:0]rd_last_gray;reg[ADDR_WIDTH-1:0]rd_addr;reg[ADDR_WIDTH-1:0]wr_addr;reg[DATA_WIDTH-1:0]ram[ADDR_WIDTH-1:0];wirerd_allow;wirewr_allow ;wireemptyg    ;wirealmost_empty    ;wirefullg    ;wirealmost_full    ;assignrd_allow=(rd_en  && !empty);assignwr_allow=(wr_en  && !full );assignemptyg=(wr_addr_gray  ==  rd_addr_gray);assignalmost_empty=(wr_addr_gray  ==  rd_next_gray);assignfullg=(wr_addr_gray  ==  rd_last_gray);assign almost_full=(wr_next_gray  ==  rd_last_gray);always @ (posedge rd_clk or posedge fifo_rst)beginif(fifo_rst)empty<=1'b1;elseempty<=(emptyg || (almost_empty && rd_en && !empty));endalways @ (posedge rd_clk or posedge fifo_rst)beginif(fifo_rst)full<=1'b1;elsefull<=(fullg || (almost_full && wr_en && !full));end//readalways @ (posedge rd_clk or posedge fifo_rst)beginif(fifo_rst)beginrd_addr<='b0;rd_data<='b0;endelse if(rd_allow)beginrd_addr <= rd_addr + 1'b1;rd_data<=ram[rd_addr];endendalways @ (posedge rd_clk or posedge fifo_rst)beginif(fifo_rst)rd_next_gray<=9'b100_000_000;else if(rd_allow)rd_next_gray <= {rd_addr[8],(rd_addr[8]^rd_addr[7]),(rd_addr[7]^rd_addr[6]),(rd_addr[6]^rd_addr[5]),(rd_addr[5]^rd_addr[4]),(rd_addr[4]^rd_addr[3]),(rd_addr[3]^rd_addr[2]),(rd_addr[2]^rd_addr[1]),(rd_addr[1]^rd_addr[0])};endalways @ (posedge rd_clk or posedge fifo_rst)beginif(fifo_rst)rd_addr_gray<=9'b100_000_001;else if(rd_allow)rd_addr_gray <=rd_next_gray; endalways @ (posedge rd_clk or posedge fifo_rst)beginif(fifo_rst)rd_last_gray<=9'b100_000_011;else if(rd_allow)rd_last_gray <=rd_addr_gray; end//writealways @ (posedge wr_clk or posedge fifo_rst)beginif(fifo_rst)beginwr_addr<='b0;//ram[wr_addr]<='b0;endelse if(wr_allow)beginwr_addr <= wr_addr + 1'b1;ram[wr_addr]<=wr_data;endendalways @ (posedge wr_clk or posedge fifo_rst)beginif(fifo_rst)wr_next_gray<=9'b100_000_000;else if(wr_allow)wr_next_gray<= {wr_addr[8],(wr_addr[8]^wr_addr[7]),(wr_addr[7]^wr_addr[6]),(wr_addr[6]^wr_addr[5]),(wr_addr[5]^wr_addr[4]),(wr_addr[4]^wr_addr[3]),(wr_addr[3]^wr_addr[2]),(wr_addr[2]^wr_addr[1]),(wr_addr[1]^wr_addr[0])};endalways @ (posedge wr_clk or posedge fifo_rst)beginif(fifo_rst)wr_addr_gray<=9'b100_000_001;elsewr_addr_gray<=wr_next_gray;endendmodule

三、仿真

写入:

 写入1-8,读出1-8

读出:

 

PS: 最近比较忙,博客质量有所下降,见谅。

这个是之前看的华为设计,对着笔记来一套,代码貌似还有bug,周末空了研究一下。