【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,周末空了研究一下。