首页 > 技术 > 内容

FPGA的FIFO实现过程

时间:2026-01-23  作者:Diven  阅读:0

FIFO队列是数据缓冲器,用于数据的缓存。是先入先出的存储器,即最先写入的数据,最先读。FIFO的参数有数据深度和数据宽度。数据宽度是指存储数据的宽度。深度是指存储器可以存储多少个数据。

FIFO队列有两个标志位。一个满和一个空标志位。分别表示FIFO是数据写满,还是数据读空。在数据写满状态下,数据写入是不允许的,因此在这个状态下,写入的数据无效。而数据读空状态下,数据读取是不允许的,因此在这个状态下,读取的数据无效。

FIFO队列有两个位置指示指针。一个是写指针,指向队列的第一个存储单元。一个读指针,指向队列的最后一个存储单元。当有写命令的时候,数据写入写指针指向的存储单元,然后指针加一。当有读命令的时候,读指针加一,在读出读指针指向的存储单元的数据。这里读命令,指针要加一,是定义读数据,是读出读指针的下一个存储单元的数据。

当写指针和读指针的指向存储单元一样时,这时候根据之前是读命令还是写命令来判断队列是空,还是满。在读命令,两个指针值一样时候,则队列空。在写命令,两个指针值一样,则队列满。

以后就开始写代码实现上诉FIFO队列,并进行仿真。

以下,是实现数据宽度为8.深度为2^4的深度的FIFO。。读/写时钟是同一个。

Module fifo_cus

#(

paRAMeter N = 8, //数据宽度

paRAMeter M = 4 //fifo的地址宽度

)

//对队列的参数设置。建议这样写,便于以后代码的移植。

//如果以后要实现数据宽度为16,深度为2^8的FIFO。只需改N =16 M=8即可

(

input clk, //输入时钟

input rst_n, //输入复位信号

input wr, //输入写使能

input[N-1:0] w_data, //输入输入

input rd, //输入读使能

output empty, //输出fifo空标志

output full, //输出fifo满标志

output[N-1:0] r_data //输出读取的数据

);

//寄存器组,用来充当FIFO队列

reg [N-1:0] array_reg [2**M - 1:0];

//定义写指针,指示当前写的位置,下一个状态写的位置,写位置的下一个位置

reg [M-1:0] w_ptr_reg, w_ptr_next,w_ptr_succ;

//定义读指针,指示当前读的位置,下一个状态读的位置,读位置的下一个位置

reg [M-1:0] r_ptr_reg, r_ptr_next,r_ptr_succ;

//定义FIFO满和空的信号

reg full_reg, full_next;

reg empty_reg, empty_next;

wire wr_en;

//数据的写入,在数据的上升沿的时候,有写使能信号,将数据写入。而

always@( posedge clk ) begin

if( wr_en )

array_reg[w_ptr_reg] <= w_data;

else

array_reg[w_ptr_reg] <= array_reg[w_ptr_reg];

end

// 数据的读取。数据读取是一直在读取的,不过读取的是之前的值。

assign r_data = array_reg[r_ptr_reg];

assign wr_en = wr & ~full_reg;

always@( posedge clk ) begin

if( !rst_n )

begin

w_ptr_reg <= 0;

r_ptr_reg <= 0;

full_reg <= 1'b0;

empty_reg <= 1'b1;

end

else

begin

w_ptr_reg <= w_ptr_next;

r_ptr_reg <= r_ptr_next;

full_reg <= full_next;

empty_reg <= empty_next;

end

end

//下一个状态的判定

always@ * begin

w_ptr_next = w_ptr_reg;

r_ptr_next = r_ptr_reg;

full_next = full_reg;

empty_next = empty;

w_ptr_succ = w_ptr_reg + 1'b1;

r_ptr_succ = r_ptr_reg + 1'b1;

case( {wr,rd} )

2'b01:

begin

if( ~empty_reg )

begin

r_ptr_next = r_ptr_succ;

full_next = 0;

if( r_ptr_succ == w_ptr_reg )

empty_next = 1'b1;

else

empty_next = 1'b0;

end

end

2'b10:

begin

if( ~full_reg )

begin

w_ptr_next = w_ptr_succ;

empty_next= 0;

if( w_ptr_succ == r_ptr_reg )

full_next = 1'b1;

else

full_next = 1'b0;

end

end

2'b11:

begin

w_ptr_next = w_ptr_succ;

r_ptr_next = r_ptr_succ;

endcase

end

// 满/空输出信号的赋值。

assign full = full_reg;

assign empty = empty_reg;

endModule

好了,终于搞定FIFO的代码了。下面来仿真看看结果。

以下分析仿真的结果:

写数据:

从下图仿真,可看出。在最开始的时候,队列是空的状态。读指针和写指针都是0。在写使能情况下,在每个时钟的上升沿(蓝色线),数据写入队列array_reg中。写指针加一。而读指针是不变的。

从下图发现,在队列满状态下,即使写使能,FIFO也不接受写数据。依旧保持原来的值。

读数据

从下图中看出,最开始,数据读出是有值的。为初始化的读指针指向的存储单元的值。这里为4。

当有读命令时候,在时钟的上升沿(蓝色线),读指针加一。读取的数据随之改变。

在数据读完后,即队列为空状态下。此时对数据的读取是无效的。从图中可看出,读完后,读指针为0.回到存储器的第一个地址。而此时读出的值是无效的。

读写命令:

在同时读同时写的时候。从下图,可看出,结果有问题了。在队列为空的状态下,此时读取的值,应为此时写的数据才对了。但是从图中,可看出,读取的值不是当前写的数据的值。而是之前存储在FIFO中的值。这样的话,读取的值就不是正确的值了。

从上图仿真结果,可知。程序在读写命令时候,编写得不正确。造成结果不对。

返回程序分析。程序不对的地方在于读写命令的时候,处理 得不正确。在空的状态下,数据写入是先写入,然后写指针加一。而读取命令是,指针先加一,然后再读取。而读和写指针的值一样的。这样造成,读取的FIFO的存储单元的值,为写的存储单元的下一个存储单元的值。因此造成读取不正确。

改正的程序如下:

2'b11:

begin

if( ~full_reg && ~empty_reg )

begin

w_ptr_next = w_ptr_succ;

r_ptr_next = r_ptr_succ;

end

else if( full_reg ) //在满的状态,不允许写

begin

r_ptr_next = r_ptr_succ;

full_next = 0;

end

else if( empty_reg ) //在空的状态,不允许写

begin

w_ptr_next = w_ptr_succ;

empty_next = 0;

end

end

只需要规定以下:在满的状态,不允许写,在空的状态下,不允许读。这样就可以了。

然后再进行仿真:

这里只看读写命令的图。从下图中,可看出,此时读取的数据,为刚刚写的数据。这样就正确了。

这样,就完成了FPGA的FIFO了。通过这样一个简单的练习,可看出,仿真,是很重要的,能发现程序中的问题。

以上仿真没有覆盖到所有情况,有兴趣的,可以自己仿真看看仿真图,验证程序写得是否正确。

猜您喜欢


由于在传统的FPGA中增加了处理器,在ASIC中增加了可编程性,使得这些产品的界限越来越模糊了。FPGA与以前的自己相比,现在都是摇滚明星了。不再只是一个查找...
2018-06-21 14:41:00
可调电阻作为调节电路参数的重要元件,有着着不可替代的作用。作为一家专业的电子元件制造商,PHYCOM(飞元)高品质的可调电阻产品受到市场青睐。本文将深入探讨PH...
2012-08-27 04:02:59
电子产品维修或DIY时,常常需要识别电路板上的贴片元器件。贴片电阻、电容、电感是其中最常见的被动元件,快速识别对于电路分析和故障排除很重要。贴片电阻通常体型较小...
2024-11-29 10:26:31
随着现代电力系统的不断发展,电表分流器作为重要的电气设备,应用于电能测量和管理中。了解电表分流器的作用,对于提升电力系统的运行效率和准确性具有重要意义。本文将从...
2025-11-02 17:01:18
电子元器件的性能和规格要求也越来越高。作为电子电路中不可少的基础元件,电阻器在电路的稳定性和性能优化中起着关键作用。金属膜电阻因其优良的温度系数、低噪声和高精度...
2018-01-12 13:19:43
贴片电阻上的「470」代表其阻值为470欧姆。 这是一种简化的标记法,遵循电子元件的常用标识规则。 贴片电阻的阻值与其所能承受的电压并没有直接关系。 电阻的耐压...
2024-11-26 11:29:48
0603贴片电阻是电子电路中常用的元器件,其1%的精度适用于对阻值要求较高的场合。本阻值表提供最新、最全的0603贴片电阻1%阻值系列,方便工程师和电子爱好者快...
2024-11-26 11:29:30
安全验证和加密芯片是现代信息安全的重要组成部分,根据功能和应用场景的不同,可以分为几种主要类型。基于用途的分类,安全芯片可以分为个人身份验证芯片和数据加密芯片。...
2024-06-13 00:00:00
贴片电阻上的「30C」标记并非指摄氏温度,而是代表其阻值。在这个标记中,「30」代表数值,而「C」代表小数点位置和乘数因子。具体来说,「30」代表有效数字30。...
2024-11-26 11:30:00
此项目解释了如何在FPGA上使用resizer IP来调整图像的大小。其中对比了两种图像大小调整的解决方案的运算速度,其中之一为使用Python Image L...
2023-10-13 10:06:00