手撕代码——异步FIFO
module asynfifo (
input rd_clk,
input wr_clk,
input rst_n,
input rd_en,
input wr_en,
input [7:0] datain,
output reg empty,
output reg full,
output reg [7:0] dataout
);
reg [9:0] rd_addr;
reg [9:0] wr_addr;
wire [9:0] rd_ptr;
wire [9:0] wr_ptr;
wire rd_allow;
wire wr_allow;
assign rd_allow= rd_en && !empty && !rst_n;
assign wr_allow= wr_en && !full && !rst_n;
//DUALRAM
reg [7:0] RAM_DATA[511:0];
always @(posedge wr_clk ) begin
if (wr_allow) begin
RAM_DATA[wr_addr[8:0]] <=datain;
end
end
always @(posedge rd_clk) begin
if (rd_allow) begin
dataout<=RAM_DATA[rd_addr[8:0]];
end
end
//addr change
always @(posedge wr_clk ) begin
if(rst_n) begin
wr_addr<=10'd0;
end
else if(wr_allow)begin
wr_addr<=wr_addr+1'b1;
end
else begin
wr_addr<=wr_addr;
end
end
always @(posedge rd_clk ) begin
if(rst_n) begin
rd_addr<=10'd0;
end
else if(rd_allow) begin
rd_addr<=rd_addr+1'b1;
end
else begin
rd_addr<=rd_addr;
end
end
//指针跨时钟域传递
reg [9:0] rd_ptr_to_wr1;
reg [9:0] rd_ptr_to_wr2;
reg [9:0] wr_ptr_to_rd1;
reg [9:0] wr_ptr_to_rd2;
always @(posedge rd_clk) begin
if(rst_n) begin
wr_ptr_to_rd1<=10'd0;
wr_ptr_to_rd2<=10'd0;
end
else begin
wr_ptr_to_rd1<=wr_ptr;
wr_ptr_to_rd2<=wr_ptr_to_rd1;
end
end
always @(posedge wr_clk) begin
if(rst_n) begin
rd_ptr_to_wr1<=10'd0;
rd_ptr_to_wr2<=10'd0;
end
else begin
rd_ptr_to_wr1<=rd_ptr;
rd_ptr_to_wr2<=rd_ptr_to_wr1;
end
end
//格雷码转换
assign rd_ptr= rd_addr^(rd_addr>>1);
//always@(posedge wr_clk)begin
// if(rst_n) begin
// wr_ptr<=10'b0;
// end
// else begin
assign wr_ptr= wr_addr^(wr_addr>>1);
// end
// end
//空
always @(posedge rd_clk) begin
if(rst_n) begin
empty <=1'b1;
end
else if(rd_ptr==wr_ptr_to_rd2) begin
empty <=1'b1;
end
else begin
empty <=1'b0;
end
end
//满
always @(posedge wr_clk) begin
if(rst_n) begin
full <=1'b1;
end
else if((wr_ptr[9]!=rd_ptr_to_wr2[9])&&(wr_ptr[7:0]==rd_ptr_to_wr2[7:0])&&(wr_ptr[8]!=rd_ptr_to_wr2[8])) begin
full <=1'b1;
end
else begin
full<=1'b0;
end
end
endmodule