理论知识参考
异步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) begin
if(wr_en && ~full)
mem[wr_addr] <= din;
else
mem[wr_addr] <= mem[wr_addr];
end
always @(posedge wr_clk or negedge rst_n) begin
if(!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;
else
rd_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) begin
rd_gray1 <= 0;
rd_gray2 <= 0;
end
else begin
rd_gray1 <= rd_gray;
rd_gray2 <= rd_gray1;
end
//写地址格雷码同步到读时钟域
always@ (posedge rd_clk or negedge rst_n)
if(!rst_n) begin
wr_gray1 <= 0;
wr_gray2 <= 0;
end
else begin
wr_gray1 <= wr_gray;
wr_gray2 <= wr_gray1;
end
endmodule
testbench
`timescale 1ns/1ps
module 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) begin
data_in <= data_in + 1'b1;
end
else
data_in <= data_in;
initial begin
rst_n = 0;
wr_en = 0;
rd_en = 0;
#200;
rst_n = 1;
wr_en = 1;
#200;
rd_en = 1;
#200
wr_en = 0;
#1100
rd_en = 0;
#20000;
$stop;
end
endmodule