最近在复习异步fifo,看来不少博客写的代码,自己写起来仿真时候发现了不少博客有些错误。
语法上的错误就不说了。
注意到这两处的问题,很多代码是用打了一拍后的empty和full,这样有什么问题?
在主机根据full和empty的信号调整wen,ren时候没有什么问题,但是作为代码健壮性时候需要考虑到主机如果由于逻辑问题,在full信号发出后仍然wen=1时候,这样的代码会出现仍然将地址+1,于是下一个时钟由于地址变化,会误判full信号为0,这样会导致全部逻辑错误,新的数据会覆盖以前的数据。正常的fifo在判满后,当检测到主机仍然将wen=1时候,会停止写入数据。同理,读数据一样的检测方式。
module Asynfifo
#(
parameter Wsize=8,
parameter Dsize=16,//必须为2的幂次方
parameter Addsize=4
)
(
input rstn,
input w_clk,
input wen,
input [Wsize-1:0]Din,
input r_clk,
input ren,
output reg [Wsize-1:0]Dout,
output reg empty,
output reg full
);
reg [Wsize-1:0] RAM [Dsize-1:0];//寄存器组当SRAM
wire [Addsize-1:0] wadd,radd;
wire [Addsize:0] wgray,rgray;
reg [Addsize:0] w2r_d1,w2r_d2;//写时钟格雷码同步到读时钟
reg [Addsize:0] r2w_d1,r2w_d2;//读时钟格雷码同步到写时钟
wire rempty_val,wfull_val;
reg [Addsize:0] wp,rp;//读写指针(比地址多一位,用于判断读/写地址绕圈)
always@(posedge w_clk or negedge rstn)
if(!rstn)begin
wp<={
Addsize{
1'b0}};
end
else if(wen&&(!wfull_val))begin
wp<=wp+1'd1;
RAM[wadd]<=Din;
end
else begin
wp<=wp;
RAM[wadd]<=RAM[wadd];
end
always@(posedge r_clk or negedge rstn)
if(!rstn)begin
rp<={
Addsize{
1'b0}};
Dout<={
Addsize{
1'b0}}