题解 | #异步FIFO#
异步FIFO
https://www.nowcoder.com/practice/40246577a1a04c08b3b7f529f9a268cf
`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
);
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(winc && !wfull) begin
waddr_bin <= waddr_bin + 1'b1;
end
end
always@(posedge rclk or negedge rrstn) begin
if(!rrstn)
raddr_bin <= 'd0;
else if(rinc && !rempty) begin
raddr_bin <= raddr_bin + 1'b1;
end
end
//二进制转格雷码
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)
wptr <= 'd0;
else
wptr <= waddr_gray;
end
always@(posedge rclk or negedge rrstn) begin
if(!rrstn)
rptr <= 'd0;
else
rptr <= raddr_gray;
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 [ADDR_WIDTH : 0]waddr;
wire [ADDR_WIDTH : 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 #(.DEPTH(DEPTH),
.WIDTH(WIDTH))
u_dual_port_RAM(
.wclk(wclk)
,.wenc(wen)
,.waddr(waddr) //深度对2取对数,得到地址的位宽。
,.wdata(wdata) //数据写入
,.rclk(rclk)
,.renc(ren)
,.raddr(raddr) //深度对2取对数,得到地址的位宽。
,.rdata(rdata) //数据输出
);
endmodule