同步fifo的串并_同步FIFO笔记

FIFO简介:First in First out,先进先出的数据结构。只能顺序的读入数据,顺序的读出数据。

使用RAM进行建模。设计相应的控制模块,控制RAM中的数据写入和读取,先写入的数据先读取。

深度为16的FIFO,将读写指针位宽设置为5位,但是取低四位作为读取RAM的地址。原因如下:

当读写指针相等时,可以得出FIFO为空。

当继续读取数据,读指针达到15之后,如果再继续写入数据,写指针最高位第五位会变为1,由于取其第四位作为RAM地址,会返回到第0位写入数据,直到写入到地址2。

继续读取数据,直到读指针为11100,此时读写指针低四位相等,最高位相反,可以得出FIFO为满。

具体代码:

`timescale 1ns / 1ns

module Syn_FIFO #(

parameter DEPTH = 16,//FIFO深度

parameter WIDTH = 8,//FIFO内数据位宽

parameter P_WIDTH = 5//读写指针位宽

)

(

input rst_n

,input clk

,input [WIDTH-1:0] Data_Write //写入的数据值

,input Write_Sig//写入数据使能

,input Read_Sig//读取数据使能

,output wire [WIDTH-1:0] Data_Read //读取的数据值

,output wire Full_Sig//FIFO为空信号

,output wire Empty_Sig//FIFO为满信号

);

reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];

reg [P_WIDTH-1:0] Read_pointer;

reg [P_WIDTH-1:0] Write_pointer;

reg [WIDTH-1:0] rData_Read;

assign Full_Sig = ((Read_pointer[P_WIDTH-2:0]==Write_pointer[P_WIDTH-2:0])

&&(Read_pointer[P_WIDTH-1] != Write_pointer[P_WIDTH-1]))? 1'd1:1'd0;

assign Empty_Sig = (Read_pointer[P_WIDTH-1:0]==Write_pointer[P_WIDTH-1:0])? 1'd1:1'd0;

always @(negedge rst_n or posedge clk) begin

if (!rst_n)

begin

rData_Read <= 0;

Read_pointer <= 0;

Write_pointer <= 0;

end

else begin

if (~Full_Sig && ~Empty_Sig && Read_Sig && Write_Sig ) //非空非满时同时读写

begin

rData_Read <= RAM_MEM[Read_pointer[P_WIDTH-2:0]];

RAM_MEM[Write_pointer[P_WIDTH-2:0]] <= Data_Write;

Read_pointer <= Read_pointer + 1'd1;

Write_pointer <= Write_pointer + 1'd1;

end //

else if (~Empty_Sig && Read_Sig )//非空时读数据

begin

rData_Read <= RAM_MEM[Read_pointer[P_WIDTH-2:0]];

Read_pointer <= Read_pointer + 1'd1;

end

else if (~Full_Sig && Write_Sig)//非满时写数据

begin

RAM_MEM[Write_pointer[P_WIDTH-2:0]] <= Data_Write;

Write_pointer <= Write_pointer + 1'd1;

end

end // else

end // always

assign Data_Read = rData_Read;

endmodule

testbench中的数据读写task如下,完整文件查看源码:

//testbench写数据的task

task Write_Data(input reg Write_en,input reg [7:0] Data_in);

begin

@(posedge clk)

if(Full_Sig) begin //testbench检测到FIFO为满,关闭写使能

Write_Sig <= 1'b0;

Data_Write <= 8'd0;

end

else begin

Write_Sig <= Write_en; //testbench检测到FIFO不满,写入数据

Data_Write <= Data_in;

end

end

endtask

//testbench读数据的task

task Read_Data(input reg Read_en);

begin

@(posedge clk)

if(Empty_Sig)

Read_Sig <= 1'b0;

else Read_Sig <= Read_en;

end

endtask

Testbench通过检测FIFO的Full_Sig和Empty_Sig判断FIFO的空满状态,来判断数据是否写入读取,还是应该关闭读\写的使能。

上图波形图中,考虑连续写入FIFO 16个数据的情形,在1处时钟上升沿,第16个数据192被写入,读指针和写指针相等,在这个时钟上升沿之后,2处Full_Sig被拉高。

但是对于Testbench而言,在1处的时钟上升沿,Testbench检测出Full_Sig还是为0(因为这个时钟上升沿之后,Full_Sig才被拉高),所以Testbench得出的判断是此时FIFO还没满,所以在时钟上升沿之后驱动Write_Sig继续为高,驱动Data_Write为204,计划再写入一个数据进去。

但是在3处时钟上升沿,对于FIFO而言,检测到Full_Sig已经被拉高,所以1处Testbench驱动的数据204并不会被FIFO采集并写入FIFO。

由此错误的判断便导致数据204的丢失,即Testbench以为把数据写入FIFO了,然而其实没有写入,如果Testbench替换为其他设计模块,也会导致这样的问题

对于读FIFO也是如此,从满FIFO中连续读取16个数据,在1处时钟上升沿,第16个数据被读出,即192。在该时钟上升沿之后,Empty_Sig被拉高,2处。

但是对于Testbench而言,在1处时钟上升沿,Testbench检测到Empty_Sig为低,所以驱动Read_Sig继续为高,到3处时钟上升沿之后,Read_Sig才被拉低。

在3处时钟上升沿,由于Read_Sig还是为高,所以对于Testbench而言,他以为自己从FIFO中读取又读取了一个数据192,但实际上是重复读取的FIFO中最后的一个数值。

结论:对于同步FIFO,空满信号时“假的”,并不能给外部读写的其他模块一个准确的判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值