异步fifo设计包含以下5步:
-
产生二进制表示的读写地址
-
将二进制地址转换为格雷码形式表达
-
打两拍同步读写指针,将读指针同步到写时钟域,写指针同步到读时钟域
-
空满信号的产生与判断
-
例化RAM
电路图如下:
代码如下:
//设计一个深度为16,宽度为8的异步fifo
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
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 // 读数据
);
//二进制地址的产生//读地址//写地址
parameter ADDR_WIDTH = $clog2(DEPTH);
reg [ADDR_WIDTH:0] waddr_bin;
reg [ADDR_WIDTH:0] raddr_bin;
always@(posedge wclk or negedge wrstn)begin
if(!wrstn)
waddr_bin <= 'd0;
else if(!wfull && winc)
waddr_bin <= waddr_bin + 1'd1;
end
always@(posedge rclk or negedge rrstn)begin
if(!rrstn)
raddr_bin <= 'd0;
else if(!rempty && rinc)
raddr_bin <= raddr_bin + 1'd1;
end
//gray 格雷码地址的产生//读指针//写指针
wire [ADDR_WIDTH:0] waddr_gray;
wire [ADDR_WIDTH:0] raddr_gray;
reg [ADDR_WIDTH:0] wptr;//写指针
reg [ADDR_WIDTH:0] rptr;//读指针
assign waddr_gray = waddr_bin^(waddr_bin>>1);
assign raddr_gray = raddr_bin^(raddr_bin>>1);
always @(posedge wclk or negedge wrstn) begin
if(~wrstn) begin
wptr <= 'd0;
end
else begin
wptr <= waddr_gray;
end
end
always @(posedge rclk or negedge rrstn) begin
if(~rrstn) begin
rptr <= 'd0;
end
else begin
rptr <= raddr_gray;
end
end
//打两拍同步读写指针,将读指针同步到写时钟域,将写指针同步到读时钟域
reg [ADDR_WIDTH:0] wptr_buff;
reg [ADDR_WIDTH:0] wptr_syn;
reg [ADDR_WIDTH:0] rptr_buff;
reg [ADDR_WIDTH:0] rptr_syn;
always @(posedge wclk or negedge wrstn) begin
if(~wrstn) begin
rptr_buff <= 'd0;
rptr_syn <= 'd0;
end
else begin
rptr_buff <= rptr;
rptr_syn <= rptr_buff;
end
end
always @(posedge rclk or negedge rrstn) begin
if(~rrstn) begin
wptr_buff <= 'd0;
wptr_syn <= 'd0;
end
else begin
wptr_buff <= wptr;
wptr_syn <= wptr_buff;
end
end
//空满信号的产生,写满:高两位不同,其余位相同;读空:所有位相同。
assign wfull=(wptr == {~rptr_syn[ADDR_WIDTH:ADDR_WIDTH-1],rptr_syn[ADDR_WIDTH-2:0]});
assign rempty=(rptr == wptr_syn);//读指针等于打两拍之后同步之后的写指针
//例化RAM
wire wen;
wire ren;
wire wren;
wire [ADDR_WIDTH-1:0] waddr;//这里为4位
wire [ADDR_WIDTH-1:0] raddr;
assign wen = winc & !wfull;
assign ren = rinc & !rempty;
assign waddr = waddr_bin[ADDR_WIDTH-1:0];
assign raddr = raddr_bin[ADDR_WIDTH-1:0];
dual_port_RAM dual_port_RAM0(
.wclk(wclk)
,.wenc(wen)
,.waddr(waddr) //深度对2取对数,得到地址的位宽。
,.wdata(wdata) //数据写入
,.rclk(rclk)
,.renc(ren)
,.raddr(raddr) //深度对2取对数,得到地址的位宽。
,.rdata(rdata)
);
endmodule