1、通过Verilog形式实现异步和同步FIFO,提高代码可移植性。
2、内部可选择调用FPGA板上block、distributed ram资源
3、读写数据位宽一致。FIFO深度为2^n
问题理解:异步fifo读写时钟差距较大会影响FIFO的逻辑功能错误吗?
答案:不会。我们假设读时钟域大于写时钟域,则读时钟域下空信号的判断不会有问题(快时钟采慢时钟)。对于满信号的产生,我们假设读时钟产生地址为7,8,9,10,则写时钟域下同步过来采集到的可能只有7,10。但是写时钟域下写地址正缓慢递增,直到超过采集过来的读地址的一圈后,产生写满信号
代码展示:
module fifo #(
parameter D_WIDTH = 8 , //data width
parameter F_DEPTH = 512 , //fifo depth
parameter DELAY = 1 , //output data delay
parameter F_TYPE ="SYNC" , //fifo type:SYNC(synchronous),ASYNC(asynchronous)
parameter R_TYPE ="block" //ram type:block,distributed
)(
rst_n ,//input , reset low efficiency
clka ,//input , clock a
wr_en ,//input , write enable
w_data ,//input , write data
clkb ,//input , clock b
rd_en ,//input , read enable
r_data ,//output, read data
empty ,//output, siginal empty
full //output, siginal full
);
parameter A_WIDTH = $clog2(F_DEPTH);
input rst_n ;//input , reset low efficiency
input clka ;//input , clock a
input wr_en ;//input , write enable
input [D_WIDTH-1:0] w_data ;//input , write data
input clkb ;//input , clock b
input rd_en ;//input , read enable
output [D_WIDTH-1:0] r_data ;//output, read data
output empty ;//output, siginal empty
output full ;//output, siginal full
generate
if(F_TYPE == "SYNC") begin:SYNC
wire clk = clka;
reg [A_WIDTH:0] w_addr;
reg [A_WIDTH:0] r_addr;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
w_addr <= 'b0;
end
else if(wr_en && !full) begin
w_addr <= w_addr + 1'b1;
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
r_addr <= 'b0;
end
else if(rd_en && !empty) begin
r_addr <= r_addr + 1'b1;
end
end
assign empty = (w_addr == r_addr);
assign full = (w_addr == {!r_addr[A_WIDTH],r_addr[A_WIDTH-1:0]});
simp_dual_ram #(
.A_WIDTH(A_WIDTH),//address width
.R_DEPTH(F_DEPTH),//ram depth
.D_WIDTH(D_WIDTH),//data width
.DELAY (DELAY ),//read data output delay
.TYPE (R_TYPE ) //block,distributed
) u_simp_dual_ram(
//port a
.clka (clk ),//clock a
.ena (wr_en ),//write enable
.w_addr (w_addr[A_WIDTH-1:0]),//write address
.w_data (w_data),//write data
//port b
.clkb (clkb ),//clock b
.enb (rd_en ),//read enable
.r_addr (r_addr[A_WIDTH-1:0]),//read address
.r_data (r_data) //read data
);
end
else begin:ASYNC
reg [A_WIDTH:0] w_addr ;
reg [A_WIDTH:0] r_addr ;
reg [A_WIDTH:0] w_addr_gray2clkb[0:1] ;
reg [A_WIDTH:0] r_addr_gray2clka[0:1] ;
always@(posedge clka or negedge rst_n) begin
if(!rst_n) begin
w_addr <= 'b0;
end
else if(wr_en && !full) begin
w_addr <= w_addr + 1'b1;
end
end
wire [A_WIDTH:0] w_addr_gray = w_addr ^ (w_addr >> 1);
always@(posedge clkb or negedge rst_n) begin
if(!rst_n) begin
r_addr <= 'b0;
end
else if(rd_en && !empty) begin
r_addr <= r_addr + 1'b1;
end
end
wire [A_WIDTH:0] r_addr_gray = r_addr ^ (r_addr >> 1);
always@(posedge clka or negedge rst_n) begin
if(!rst_n) begin
{r_addr_gray2clka[1],r_addr_gray2clka[0]} <= 'b0;
end
else begin
{r_addr_gray2clka[1],r_addr_gray2clka[0]} <= {r_addr_gray2clka[0],r_addr_gray};
end
end
always@(posedge clkb or negedge rst_n) begin
if(!rst_n) begin
{w_addr_gray2clkb[1],w_addr_gray2clkb[0]} <= 'b0;
end
else begin
{w_addr_gray2clkb[1],w_addr_gray2clkb[0]} <= {w_addr_gray2clkb[0],w_addr_gray};
end
end
assign empty = (w_addr_gray2clkb[1] == r_addr_gray);
assign full = ({!w_addr_gray[A_WIDTH-:2],w_addr_gray[A_WIDTH-2:0]} == r_addr_gray2clka[1]);
simp_dual_ram #(
.A_WIDTH(A_WIDTH),//address width
.R_DEPTH(F_DEPTH),//ram depth
.D_WIDTH(D_WIDTH),//data width
.DELAY (DELAY ),//read data output delay
.TYPE (R_TYPE ) //block,distributed
) u_simp_dual_ram(
//port a
.clka (clka ),//clock a
.ena (wr_en ),//write enable
.w_addr (w_addr[A_WIDTH-1:0]),//write address
.w_data (w_data),//write data
//port b
.clkb (clkb ),//clock b
.enb (rd_en ),//read enable
.r_addr (r_addr[A_WIDTH-1:0]),//read address
.r_data (r_data) //read data
);
end
endgenerate
endmodule
测试文件:
`timescale 1ns/1ps
module fifo_tb;
reg clka,wr_en,clkb,rd_en,rst_n;
reg [7:0] w_data;
wire[7:0] r_data;
wire empty,full;
initial begin
clka <= 1'b0;
clkb <= 1'b0;
rst_n <= 1'b0;
#50;
rst_n <= 1'b1;
end
always#5 clka <= !clka;
always#2.5 clkb <= !clkb;
initial begin
wr_en <= 1'b0;
w_data<= 8'd10;
rd_en <= 1'b0 ;
@(posedge rst_n);
@(posedge clka);
wr_en <= 1'b1;
#150;
wr_en <= 1'b0;
rd_en <= 1'b1;
#150;
rd_en <= 1'b0;
#100;
$finish;
end
fifo #(
.D_WIDTH(8 ), //data width
.F_DEPTH(8 ), //fifo depth
.DELAY (1 ), //output data delay
.F_TYPE ("ASYNC" ), //fifo type:SYNC(synchronous),ASYNC(asynchronous)
.R_TYPE ("block") //ram type:block,distributed
)u_fifo(
.rst_n (rst_n ),//input , reset low efficiency
.clka (clka ),//input , clock a
.wr_en (wr_en ),//input , write enable
.w_data (w_data),//input , write data
.clkb (clkb ),//input , clock b
.rd_en (rd_en ),//input , read enable
.r_data (r_data),//output, read data
.empty (empty ),//output, siginal empty
.full (full ) //output, siginal full
);
endmodule