异步FIFO
`timescale 1ns/1ns
/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,
parameter WIDTH = 8)(
input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。
,input [WIDTH-1:0] wdata //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end
always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end
endmodule
/***************************************AFIFO*****************************************/
module asyn_fifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input wclk ,
input rclk ,
input wrstn ,
input rrstn ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output wire wfull ,
output wire rempty ,
output wire [WIDTH-1:0] rdata
);
//地址宽度
localparam ADDR_WIDTH = $clog2(DEPTH);
//***************例化双口RAM******************//
dual_port_RAM #(
.WIDTH(WIDTH),
.DEPTH(DEPTH)
)
u_dual_port_RAM(
.wclk (wclk) ,
.wenc (winc&&!wfull) ,
.waddr (wr_addr_bin[ADDR_WIDTH-1:0]) ,
.wdata (wdata) ,
.rclk (rclk) ,
.renc (rinc&&!rempty) ,
.raddr (rd_addr_bin[ADDR_WIDTH-1:0]) ,
.rdata (rdata)
);
//写地址,长度为ADDR_WIDTH+1
reg [ADDR_WIDTH:0] wr_addr_bin;
//写地址的格雷码以及用于在本地打拍的寄存器
wire [ADDR_WIDTH:0] wr_addr_gray;
reg [ADDR_WIDTH:0] wr_addr_gray_d;
//写地址同步到读时钟的格雷码寄存器
reg [ADDR_WIDTH:0] wr2rd_addr_gray_d1;
reg [ADDR_WIDTH:0] wr2rd_addr_gray_d2;
//读地址,长度为ADDR_WIDTH+1
reg [ADDR_WIDTH:0] rd_addr_bin;
//读地址的格雷码以及用于在本地打拍的寄存器
wire [ADDR_WIDTH:0] rd_addr_gray;
reg [ADDR_WIDTH:0] rd_addr_gray_d;
//读地址同步到写时钟的格雷码寄存器
reg [ADDR_WIDTH:0] rd2wr_addr_gray_d1;
reg [ADDR_WIDTH:0] rd2wr_addr_gray_d2;
//***************读写地址的产生******************//
always @(posedge wclk or negedge wrstn) begin
if(!wrstn)
wr_addr_bin <= 'b0;
else if(winc&&!wfull)
wr_addr_bin <= wr_addr_bin + 1'b1;
else
wr_addr_bin <= wr_addr_bin;
end
always @(posedge rclk or negedge rrstn) begin
if(!rrstn)
rd_addr_bin <= 'b0;
else if(rinc&&!rempty)
rd_addr_bin <= rd_addr_bin + 1'b1;
else
rd_addr_bin <= rd_addr_bin;
end
//***************读写地址转化成格雷码******************//
assign wr_addr_gray = wr_addr_bin^(wr_addr_bin>>1'b1);
assign rd_addr_gray = rd_addr_bin^(rd_addr_bin>>1'b1);
//***************读写地址格雷码本地打拍******************//
always @(posedge wclk or negedge wrstn) begin
if(!wrstn)
wr_addr_gray_d <= 'b0;
else
wr_addr_gray_d <= wr_addr_gray;
end
always @(posedge rclk or negedge rrstn) begin
if(!rrstn)
rd_addr_gray_d <= 'b0;
else
rd_addr_gray_d <= rd_addr_gray;
end
//***************读地址格雷码同步到写时钟域******************//
always @(posedge wclk or negedge wrstn) begin
if(!wrstn) begin
rd2wr_addr_gray_d1 <= 'b0;
rd2wr_addr_gray_d2 <= 'b0;
end
else begin
rd2wr_addr_gray_d1 <= rd_addr_gray_d;
rd2wr_addr_gray_d2 <= rd2wr_addr_gray_d1;
end
end
//***************写地址格雷码同步到读时钟域******************//
always @(posedge rclk or negedge rrstn) begin
if(!rrstn) begin
wr2rd_addr_gray_d1 <= 'b0;
wr2rd_addr_gray_d2 <= 'b0;
end
else begin
wr2rd_addr_gray_d1 <= wr_addr_gray_d;
wr2rd_addr_gray_d2 <= wr2rd_addr_gray_d1;
end
end
//***************空满标志的判断******************//
//此处判断写满信号,如果根据gray码进行判断就应该翻转高两位,如果根据二进制码进行判断就只翻转高一位就行了
assign wfull = (wr_addr_gray_d == {~rd2wr_addr_gray_d2[ADDR_WIDTH:ADDR_WIDTH-1], rd2wr_addr_gray_d2[ADDR_WIDTH-2:0]});
assign rempty = (rd_addr_gray_d == wr2rd_addr_gray_d2);
endmodule