简析
同步FIFO是指读写数据使用的是同一个时钟,所以不用进行跨时钟域处理。
FIFO的重点和难点是空满状态的判断。本程序设置了统计FIFO内部数据数量的计数器cnt
,并根据计数器的大小判断空满。设FIFO的深度是DEPTH
,如果cnt==0
,说明FIFO内没有数据;如果cnt==DEPTH
,说明FIFO已存满。
计数器根据读写信号自增或者自减。当读写同时进行时,计数器数值不变;当有效写入时计数器减1;当有效读取时,计数器加1。
代码
`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
/**********************************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 [$clog2(DEPTH)-1:0] waddr, raddr;
reg [$clog2(DEPTH) :0] cnt;
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
waddr <= 0;
else
waddr <= winc&~wfull? waddr+1: waddr;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
raddr <= 0;
else
raddr <= rinc&~rempty? raddr+1:raddr;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n)
cnt <= 0;
else if(rinc&~rempty&winc&~wfull)
cnt <= cnt;
else if(winc&~wfull)
cnt <= cnt + 1;
else if(rinc&~rempty)
cnt <= cnt - 1;
else
cnt <= cnt;
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n) begin
wfull = 0;
rempty = 0;
end
else begin
wfull = cnt == DEPTH;
rempty = cnt == 0;
end
end
dual_port_RAM #(
.DEPTH(DEPTH ),
.WIDTH(WIDTH )
)
myRAM(
.wclk (clk ),
.wenc (winc&~wfull ),
.waddr(waddr ),
.wdata(wdata ),
.rclk (clk ),
.renc (rinc&~rempty),
.raddr(raddr ),
.rdata(rdata )
);
endmodule