理论知识参考
异步FIFO_Verilog实现_verilog实现异步fifo_Crazzy_M的博客-CSDN博客
代码
/*
位宽8bit, 位深8
*/
module async_fifo#(parameter FIFO_DEPTH = 8,parameter FIFO_WIDTH = 8
)
(input rst_n,input wr_clk,input wr_en,input [FIFO_WIDTH - 1:0] din,input rd_clk,input rd_en,output reg [FIFO_WIDTH - 1:0] dout,output wire full,output wire empty
);reg [FIFO_WIDTH - 1:0] mem [FIFO_DEPTH - 1:0];//地址的位数要满足fifo的位深
wire [2:0] wr_addr;
wire [2:0] rd_addr;//指针的位数和格雷码的位数要比地址位数大1位
reg [3:0] wr_addr_ptr;
reg [3:0] rd_addr_ptr;wire [3:0] wr_gray;
reg [3:0] wr_gray1;
reg [3:0] wr_gray2;wire [3:0] rd_gray;
reg [3:0] rd_gray1;
reg [3:0] rd_gray2;assign wr_addr = wr_addr_ptr;
assign rd_addr = rd_addr_ptr;//二进制转格雷码
assign wr_gray = (wr_addr_ptr >> 1) ^ wr_addr_ptr;
assign rd_gray = (rd_addr_ptr >> 1) ^ rd_addr_ptr;//判断异步FIFO空的条件:读写地址(格雷码)完全相同
assign empty = rd_gray == wr_gray2 ? 1'b1 :1'b0;//判断异步FIFO满的条件:读写地址(格雷码)的高2位不同,其余位均相同
assign full = ((wr_gray[3:2] != rd_gray2[3:2]) && (wr_gray[1:0] == rd_gray2[1:0])) ? 1'b1 : 1'b0;//写
always @(posedge wr_clk) beginif(wr_en && ~full)mem[wr_addr] <= din;else mem[wr_addr] <= mem[wr_addr];
endalways @(posedge wr_clk or negedge rst_n) beginif(!rst_n)wr_addr_ptr <= 0;else if(wr_en && ~full)wr_addr_ptr <= wr_addr_ptr + 1'b1;else wr_addr_ptr <= wr_addr_ptr;
end//读
always@ (posedge rd_clk or negedge rst_n)if(!rst_n)rd_addr_ptr <= 0;else if(rd_en && ~empty)rd_addr_ptr <= rd_addr_ptr + 1'b1;elserd_addr_ptr <= rd_addr_ptr;always@ (posedge rd_clk or negedge rst_n)if(!rst_n)dout <= 11;else if(rd_en && ~empty)dout <= mem[rd_addr];else dout <= 11;//读地址格雷码同步到写时钟域
always @(posedge wr_clk or negedge rst_n)if(!rst_n) beginrd_gray1 <= 0;rd_gray2 <= 0;endelse beginrd_gray1 <= rd_gray;rd_gray2 <= rd_gray1;end//写地址格雷码同步到读时钟域
always@ (posedge rd_clk or negedge rst_n)if(!rst_n) beginwr_gray1 <= 0;wr_gray2 <= 0;endelse beginwr_gray1 <= wr_gray;wr_gray2 <= wr_gray1;endendmodule
testbench
`timescale 1ns/1psmodule fifo_tb ();reg rst_n;reg [7:0] data_in;reg wr_clk;reg rd_clk;reg wr_en;reg rd_en;wire [7:0]data_out;wire full;wire empty;async_fifo fifo(.wr_clk(wr_clk),//写时钟.rd_clk(rd_clk),//读时钟.rst_n(rst_n),//复位信号.wr_en(wr_en),//写使能.rd_en(rd_en),//读使能.din(data_in),//写入的数据.dout(data_out),//读出的数据.empty(empty),//读空信号.full(full)//写满信号);initial wr_clk = 0;//产生写时钟always #10 wr_clk = ~wr_clk;initial rd_clk = 0;//产生读时钟always #30 rd_clk = ~rd_clk;always@(posedge wr_clk or negedge rst_n)//产生写入的数据if(!rst_n)data_in <= 0;else if (wr_en) begindata_in <= data_in + 1'b1;endelsedata_in <= data_in;initial beginrst_n = 0;wr_en = 0;rd_en = 0;#200;rst_n = 1;wr_en = 1;#200;rd_en = 1;#200wr_en = 0;#1100rd_en = 0;#20000;$stop; endendmodule
觉得还不错请点赞,有建议请留言^_^