理論知識參考
異步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
覺得還不錯請點贊,有建議請留言^_^