题解 | #同步FIFO#
同步FIFO
https://www.nowcoder.com/practice/e5e86054a0ce4355b9dfc08238f25f5f
`timescale 1ns/1ns
/**********************************RAM************************************/
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 [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
/**********************************SFIFO************************************/
module sfifo#(
parameter WIDTH = 8,
parameter DEPTH = 16
)(
input clk ,
input rst_n ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata ,
output reg wfull ,
output reg rempty ,
output wire [WIDTH-1:0] rdata
);
// 写地址
reg [4:0] waddr;
reg [4:0] raddr;
reg [3:0] w_gap;
reg [3:0] r_gap;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
waddr<=0;
else if(winc&~wfull)
waddr<=waddr+1;
else
waddr<=waddr;
end
// 读地址
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
raddr<=0;
else if(rinc&~rempty)
raddr<=raddr+1;
else
raddr<=raddr;
end
// always @(posedge clk or negedge rst_n)begin
// if(!rst_n)
// r_gap<=0;
// else if(waddr[4]==raddr[4])
// r_gap<=waddr[3:0]-raddr[3:0];
// else
// r_gap<=DEPTH-(raddr[3:0]-waddr[3:0]);
// end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
rempty<=0;
else if(waddr==raddr)
rempty<=1;
else
rempty<=0;
end
// always @(posedge clk or negedge rst_n)begin
// if(!rst_n)
// w_gap<=0;
// else if(waddr[4]==1&&raddr[4]==0)
// w_gap<=raddr[3:0]-waddr[3:0];
// else
// w_gap<=DEPTH-(waddr[3:0]-raddr[3:0]);
// end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
wfull<=0;
else if((waddr[4]!=raddr[4])&&(raddr[3:0]==waddr[3:0]))
wfull<=1;
else
wfull<=0;
end
dual_port_RAM uut(
.wclk(clk),
.wenc(winc&~wfull),
.waddr(waddr[3:0]),
.wdata(wdata),
.rclk(clk),
.renc(rinc&~rempty),
.raddr(raddr[3:0]),
.rdata(rdata)
);
endmodule
同步FIFO的好处是读写数据都使用的同一个时钟,可以不用使用格雷码同步。使用时接入了一个双端口的RAM。FIFO full产生的情况:如果地址的最高位都是相同的,那么一定不会写满,因为写地址的指针一定会领先于读指针(不然的话就读空了)吗,而在地址最高位不同的时候,是有可能写满的,有可能写指针追赶上了读指针。在读的时候,读空的情况发生在地址完全相同的时候,如果地址最高位不同,读指针是追赶不上写指针的。只有在地址最高为相同的时候,读指针有追上写指针的可能。