在芯片设计中,遇到跨时钟操作时,经常用的哦啊异步FIFO,下面整理了异步FIFO控制代码。
module async_fifo #(
parameter DT_WID =8,
parameter ADR_WID =9
)(
//write port
input wr_rst_n,
input wr_clk,
input wr_en,
input [DT_WID-1:0] wr_dt,
//read port
input rd_rst_n,
input rd_clk,
input rd_en,
output [DT_WID-1:0] rd_dt,
output reg fifo_full,
output reg fifo_empty
);
reg [ADR_WID:0] wptr;
reg [ADR_WID:0] wptr1;
reg [ADR_WID:0] wptr2;
reg [ADR_WID:0] wptr3;
reg [ADR_WID:0] rptr;
reg [ADR_WID:0] rptr1;
reg [ADR_WID:0] rptr2;
reg [ADR_WID:0] rptr3;
reg [ADR_WID:0] raddr_bin;
reg [ADR_WID:0] raddr_gray;
reg [ADR_WID:0] raddr_gray_next;
reg [ADR_WID:0] raddr_bin_next;
reg [ADR_WID:0] waddr_bin;
reg [ADR_WID:0] waddr_gray;
reg [ADR_WID:0] waddr_gray_next;
reg [ADR_WID:0] waddr_bin_next;
//read addr and empyt flag
always @(posedeg rd_clk or negedge rd_rst_n) begin
if(!rd_rst_n) begin
raddr_bin <= 'b0;
raddr_gray <= 'b0;
end
else begin
raddr_bin <= raddr_bin_next;
raddr_gray <= raddr_gray_next;
end
end
always @(posedeg rd_clk or negedge rd_rst_n) begin
if(!rd_rst_n) begin
fifo_empty <= 'b1;
end
else begin
fifo_empty <= (raddr_gray_next == wptr2);
end
end
assign raddr_bin_next = raddr_bin + (rd_en & ~fifo_empty);
assign raddr_gray_next = (raddr_bin_next>>1) ^ raddr_bin_next;
//write addr and full flag
always @(posedeg wr_clk or negedge wr_rst_n) begin
if(!wr_rst_n) begin
waddr_bin <= 'b0;
waddr_gray <= 'b0;
end
else begin
waddr_bin <= waddr_bin_next;
waddr_gray <= waddr_gray_next;
end
end
always @(posedeg wr_clk or negedge wr_rst_n) begin
if(!wr_rst_n) begin
fifo_full <= 'b0;
end
else begin
fifo_full <= (waddr_gray_next == {~rptr2[ADR_WID:ADR_WID-1],rptr2[ADR_WID-2:0]});
end
end
assign waddr_bin_next = waddr_bin + (wr_en & ~fifo_full);
assign waddr_gray_next = (waddr_bin_next>>1) ^ waddr_bin_next;
//sync wprt to rclk domain
always @(posedeg rd_clk or negedge rd_rst_n) begin
if(!rd_rst_n) begin
wptr1 <= 'b0;
wptr2 <= 'b0;
end
else begin
wptr1 <= waddr_gray;
wptr2 <= wptr1 ;
end
end
always @(posedeg wr_clk or negedge wr_rst_n) begin
if(!rd_rst_n) begin
rptr1 <= 'b0;
rptr2 <= 'b0;
end
else begin
rptr1 <= raddr_gray;
rptr2 <= rptr1 ;
end
end
async_ram #(.DT_WID(DT_WID),
.ADR_WID(ADR_WID))
async_ram_u(
.wr_dt(wr_dt),
.wr_addr(waddr_bin[ADR_WID-1:0]),
.wr_clk(wr_clk),
.wr_en (wr_en),
.rd_dt(rd_dt),
.rd_addr(raddr_bin[ADR_WID-1:0]),
.rd_clk(rd_clk),
.rd_en (rd_en)
);
endmodule