题解 | #异步FIFO#
异步FIFO
https://www.nowcoder.com/practice/40246577a1a04c08b3b7f529f9a268cf
//async_fifo
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 = $clog2(DEPTH);
reg [ADDR:0] waddr;
reg [ADDR:0] raddr;
always@(posedge wclk or negedge wrstn)begin
if(!wrstn)begin
waddr <= 0;
end
else if(winc&~wfull)begin
waddr <= waddr + 1;
end
end
always@(posedge rclk or negedge rrstn)begin
if(!rrstn)begin
raddr <= 0;
end
else if(rinc&~rempty)begin
raddr <= raddr + 1;
end
end
//双端口RAM例化
dual_port_RAM#(
.DEPTH (16),
.WIDTH (8)
)u_dual_port_RAM(
.wclk (wclk),
.wenc (winc&~wfull),
.waddr (waddr),
.wdata (wdata),
.rclk (rclk),
.renc (rinc&~rempty),
.raddr (raddr),
.rdata (rdata)
);
//读写地址指针格雷码转换
wire [ADDR:0] gray_wptr;
wire [ADDR:0] gray_rptr;
assign gray_wptr = waddr ^ (waddr>>>1);
assign gray_rptr = raddr ^ (raddr>>>1);
reg [ADDR:0] wptr;
reg [ADDR:0] rptr;
always@(posedge wclk or negedge wrstn)begin
if(!wrstn)begin
wptr <= 0;
end
else begin
wptr <= gray_wptr;
end
end
always@(posedge rclk or negedge rrstn)begin
if(!rrstn)begin
rptr <= 0;
end
else begin
rptr <= gray_rptr;
end
end
//同步打拍
reg [ADDR:0] wptr2rclk_r1,wptr2rclk_r2;
reg [ADDR:0] rptr2wclk_r1,rptr2wclk_r2;
always@(posedge rclk or negedge rrstn)begin
if(!rrstn)begin
wptr2rclk_r1 <= 0;
wptr2rclk_r2 <= 0;
end
else begin
wptr2rclk_r1 <= wptr;
wptr2rclk_r2 <= wptr2rclk_r1;
end
end
always@(posedge wclk or negedge wrstn)begin
if(!wrstn)begin
rptr2wclk_r1 <= 0;
rptr2wclk_r2 <= 0;
end
else begin
rptr2wclk_r1 <= rptr;
rptr2wclk_r2 <= rptr2wclk_r1;
end
end
//空满判断
assign wfull = wptr == {~rptr2wclk_r2[ADDR:ADDR-1],rptr2wclk_r2[ADDR-2:0]};
assign rempty = rptr == wptr2rclk_r2;
endmodule
module dual_port_RAM#(
parameter DEPTH = 16,
parameter WIDTH = 8
)(
input wclk ,
input wenc ,
input [$clog2(DEPTH)-1:0] waddr,
input [WIDTH-1:0] wdata,
input rclk ,
input renc ,
input [$clog2(DEPTH)-1:0] raddr,
output reg[WIDTH-1:0] rdata
);
reg [WIDTH-1:0] RAM_MEM [DEPTH-1:0];
always@(posedge wclk)begin
if(wenc)begin
RAM_MEM[waddr] <= wdata;
end
end
always@(posedge rclk)begin
if(renc)begin
rdata <= RAM_MEM[raddr];
end
end
endmodule
