目录
一、设计代码
//async_fifo.v
`timescale 1ns/1ns
module async_fifo #(
parameter DATA_WIDTH = 8,
parameter DATA_DEPTH = 8
)
(
input wr_clk,
input wr_rst_n,
input wr_en,
input signed [DATA_WIDTH - 1:0] data_in,
input rd_clk,
input rd_rst_n,
input rd_en,
output reg signed [DATA_WIDTH - 1:0] data_out,
output empty,
output full
);
reg [DATA_WIDTH - 1:0] fifo_buffer [DATA_DEPTH - 1:0];
reg [$clog2(DATA_DEPTH):0] wr_ptr, rd_ptr;
reg [$clog2(DATA_DEPTH):0] wr_ptr_g_d1, rd_ptr_g_d1;
reg [$clog2(DATA_DEPTH):0] wr_ptr_g_d2, rd_ptr_g_d2;
wire [$clog2(DATA_DEPTH):0] wr_ptr_g, rd_ptr_g;
wire [$clog2(DATA_DEPTH) - 1:0] wr_ptr_true, rd_ptr_true;
assign wr_ptr_g = wr_ptr ^ (wr_ptr >> 1);
assign rd_ptr_g = rd_ptr ^ (rd_ptr >> 1);
assign wr_ptr_true = wr_ptr[$clog2(DATA_DEPTH) - 1:0];
assign rd_ptr_true = rd_ptr[$clog2(DATA_DEPTH) - 1:0];
//写fifo
always @ (posedge wr_clk or negedge wr_rst_n) begin
if (!wr_rst_n)
wr_ptr <= 0;
else if (!full && wr_en) begin
wr_ptr <= wr_ptr + 1;
fifo_buffer[wr_ptr_true] <= data_in;
end
end
//将读指针同步到写时钟域
always @ (posedge wr_clk or negedge wr_rst_n) begin
if (!wr_rst_n) begin
rd_ptr_g_d1 <= 0;
rd_ptr_g_d2 <= 0;
end
else begin
rd_ptr_g_d1 <= rd_ptr_g;
rd_ptr_g_d2 <= rd_ptr_g_d1;
end
end
//读fifo
always @ (posedge rd_clk or negedge rd_rst_n) begin
if (!rd_rst_n) begin
rd_ptr <= 0;
data_out <= 0;
end
else if (!empty && rd_en) begin
rd_ptr <= rd_ptr + 1;
data_out <= fifo_buffer[rd_ptr_true];
end
end
//将写指针同步到读时钟域
always @ (posedge rd_clk or negedge rd_rst_n) begin
if (!rd_rst_n) begin
wr_ptr_g_d1 <= 0;
wr_ptr_g_d2 <= 0;
end
else begin
wr_ptr_g_d1 <= wr_ptr_g;
wr_ptr_g_d2 <= wr_ptr_g_d1;
end
end
//判断读空和写满
assign empty = (wr_ptr_g_d2 == rd_ptr_g) ? 1 : 0;
assign full = (wr_ptr_g == {~(rd_ptr_g_d2[$clog2(DATA_DEPTH) : $clog2(DATA_DEPTH) - 1]),
rd_ptr_g_d2[$clog2(DATA_DEPTH) - 2 : 0]}) ? 1 : 0;
endmodule
二、testbench代码
使用System Verilog实现testbench,以进行随机验证。SV相关基础可参考:System Verilog基础_qq_42922513的博客-CSDN博客https://blog.csdn.net/qq_42922513/article/details/130984574
//async_fifo_tb.sv
`timescale 1ns/1ns
module async_fifo_tb;
parameter DATA_WIDTH = 8;
parameter DATA_DEPTH = 8;
bit wr_clk;
bit wr_rst_n;
bit wr_en;
bit signed [DATA_WIDTH - 1:0] data_in;
bit rd_clk;
bit rd_rst_n;
bit rd_en;
bit signed [DATA_WIDTH - 1:0] data_out;
bit empty;
bit full;
int error_num;
async_fifo #(
.DATA_WIDTH(DATA_WIDTH),
.DATA_DEPTH(DATA_DEPTH)
)
u1(
.wr_clk(wr_clk),
.wr_rst_n(wr_rst_n),
.wr_en(wr_en),
.data_in(data_in),
.rd_clk(rd_clk),
.rd_rst_n(rd_rst_n),
.rd_en(rd_en),
.data_out(data_out),
.empty(empty),
.full(full)
);
bit signed [DATA_WIDTH - 1:0] fifo_reg [DATA_DEPTH - 1:0];
bit [$clog2(DATA_DEPTH) - 1:0] m, n;
bit signed [DATA_WIDTH - 1:0] data_out_tb;
class packet0;
rand bit signed [DATA_WIDTH - 1:0] number;
rand bit wr_en_rand;
constraint c {number <= 2 ** (DATA_WIDTH - 1) - 1;
number >= - ( 2 ** (DATA_WIDTH - 1));
wr_en_rand inside {[0:1]};
}
endclass
class packet1;
rand bit rd_en_rand;
constraint c {rd_en_rand inside {[0:1]};}
endclass
packet0 numb0;
packet1 numb1;
always #15 wr_clk = ~wr_clk;
always #10 rd_clk = ~rd_clk;
initial begin
numb0 = new();
numb1 = new();
rd_clk = 0;
wr_clk = 0;
wr_rst_n = 1;
rd_rst_n = 1;
m = 0;
n = 0;
#3
wr_rst_n = 0;
rd_rst_n = 0;
#20
wr_rst_n = 1;
rd_rst_n = 1;
end
initial begin
repeat (1000) begin
@(negedge wr_clk) begin
assert(numb0.randomize());
data_in <= numb0.number;
wr_en <= numb0.wr_en_rand;
end
@(posedge wr_clk) begin
if (wr_en && !full) begin
fifo_reg[m] = data_in;
m = m + 1;
end
end
end
#200;
$display("-------error_num = %0d -------", error_num);
$stop;
end
initial begin
repeat (1000) begin
@(negedge rd_clk) begin
assert(numb1.randomize());
rd_en <= numb1.rd_en_rand;
end
@(posedge rd_clk) begin
if (rd_en && !empty) begin
data_out_tb <= fifo_reg[n];
if (data_out_tb != data_out) begin
$display("-------ERROR. A mismatch has occurred -------");
$display("data_out_tb = %0d; data_out = %0d;", data_out_tb, data_out);
error_num = error_num + 1;
end
n = n + 1;
end
end
end
end
endmodule
三、仿真结果
工具:Vivado2018.3