xilinx FIFO的使用及各信号的讨论

本文通过实例详细介绍了FIFO的设计与应用,包括FIFO在不同数据宽度和时钟域间的使用,以及如何通过ISE软件生成FIFO并进行信号配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  FIFO的使用非常广泛,一般用于不同时钟域之间的数据传输,比如FIFO的一端是AD数据采集,另一端是计算机的PCI总线,假设其AD采集的速率为16位100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为33*32=1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

  本文就讲通过ISE软件生成一个FIFO,并对其进行一些操作以求更加了解FIFO中各个信号的作用以及控制方法(有些简单步骤将省略不提)。

  在这步中,由于现在做的不是soc工程,选择Native.

Next后,需选择时钟和存储器类型。1,时钟,由FIFO的作用可知大部分都是读写不同步的,这里我们也选择异步模式,即读写的时钟不同。2,存储器类型,这里主要是block RAM和distribute RAM之间的区别。简而言之,block RAM是FPGA中定制的ram资源,而distribute RAM则是由LUT构成的RAM资源。由此区别表明,当FIFO较大时应选择block RAM,当FIFO较小时,选择distribute RAM.另外一个很重要的就是block RAM支持读写不同宽度,而distribute不支持。在这里为了更全面的了解FIFO,选择block RAM以拥有非对称方向速率的特性。

 

  读模式有两种选择,一般选择标准模式,至于First-Word Fall-Fhrough的含义请查看FIFO手册。写数据宽度定义为8位,写深度定义为256.读宽度定义为4位,而读深度将根据以上几个参数自动计算。但我们需要注意的是,在data port parameters处,有actual write depth和actual read depth,他们都比我们设置的要小,其意义以及原因将在例程中说明。

 

  之后便是添加信号,信号越多越难操作,但同时也能让我们更加准确的控制FIFO,这里为了更好的了解FIFO,把所有能选的信号都选上。

 

  接下来是复位信号以及可编程信号的配置。虽然在block RAM和distribute RAM中,复位信号不是必需的,但根据习惯,还是启用rst端口,且配置成同步复位,即整个FIFO共用一个复位信号,而不是读写不同的复位。至于编程信号,看选项就很容易理解了。配置如图,FIFO中数据达到200时,programmable full有效,数据为10时,programmable empty有效。

  之后是写计数和读计数,都使之有效,由于写深度是256,读深度是512.因此写计数器的宽度定义为8,读计数器的狂度定义为9.其实不一定计数器一定要比深度大,当计数器计数最大值小于数据深度时,例如数据深度为512,而计数器大小为256,则每两个数据计数器计数一次。

  最后可以看到我们配置的FIFO信息如下(注意几个关键信息),最后生成IP就好了。

 

  通过点击View HDL Instantiation Template,我们可以看到所有需要例化的信号,以及格式。

  在该FIFO例程中,首先是将1-255写入FIFO中,此时不读取,观察各个信号,然后再从FIFO中读出FIFO中存储的数据,此时不再写入,观察各信号。

代码如下:

module FIFO_top(

input clk,rst,

output  wire [3:0] dout

    );

wire clk_50M_wire;

wire [7:0] din_wire;

wire valid,wr_ack;

wire overflow,underflow;

wire almost_empty,almost_full;

wire [8:0] rd_data_count;

wire [7:0] wr_data_count;

wire prog_full,prog_empty;

wire wr_en,rd_en;

wire full,empty;

///////////////////////////////////////////////////

//二分频电路

//100M为读时钟,50M为写时钟

reg clk_50M;

assign clk_50M_wire = clk_50M ;

 

always @(posedge clk or posedge rst) begin

if (rst) clk_50M<=0;

else clk_50M<=~clk_50M;

end

///////////////////////////////////////////////

 

////////////////////////////////////////////////

reg [2:0] cnt;

 

assign wr_en =(full==0 && rd_en==0 && cnt==5)?1:0 ;//非满时写,且满后就不再写了,即便之后数据被读取导致非满

assign rd_en = (empty==0 && wr_en==0)?1:0 ;//写时不读取,写完再读取

 

reg [7:0] din;

assign din_wire = din ;

 

always @(posedge clk_50M or posedge rst) begin

if (rst) begin

din<=1;

end

else begin

if(wr_en) din<=din+1;

else din<=din;

end

end

 

always @ (posedge clk_50M or posedge rst)

if(rst) cnt<=0;

else begin

if(cnt==3'd5) cnt<=cnt;

else cnt<=cnt+1;

end

 

FIFO FIFO (

  .rst(rst), // input rst

  .wr_clk(clk_50M_wire), // input wr_clk 50M 

  .rd_clk(clk), // input rd_cFIFOlk 100M 

  .din(din_wire), // input [7 : 0] din

  .wr_en(wr_en), // input wr_en

  .rd_en(rd_en), // input rd_en

  .dout(dout), // output [3 : 0] dout

  .full(full), // output full

  .almost_full(almost_full), // output almost_full

  .wr_ack(wr_ack), // output wr_ack

  .overflow(overflow), // output overflow

  .empty(empty), // output empty

  .almost_empty(almost_empty), // output almost_empty

  .valid(valid), // output valid

  .underflow(underflow), // output underflow

  .rd_data_count(rd_data_count), // output [8 : 0] rd_data_count

  .wr_data_count(wr_data_count), // output [7 : 0] wr_data_count

  .prog_full(prog_full), // output prog_full 200

  .prog_empty(prog_empty) // output prog_empty 10

);

endmodule

1,复位信号rst: 由结果可知,其为高电平有效,且复位后其他信号的初始值是可以在产生FIFO中配置的,之前配置为0;很重要的一点是,复位后的几个写周期内(2,3个周期)是无法进行写操作的,所以在本例程中,复位一段时间后再拉高wr_en以确保首先写入的是1.

2,写使能信号wr_en与写响应信号wr_ack:关于该信号,很重要的一点是,写入的值是wr_en拉高时的值;还是说当wr_en拉高后,下一周期才能进行写操作?如果是前者,由波形所示,写入的第一个值应该是1;如果是后者,写入的应该是2。这就需要根据读取的第一个值来判断了。而经查看,读取的第一个值为1,也就是说,只要wr_en拉高,立马就进行写操作。

从下图还能明白wr_ack的工作模式,即写入成功时,wr_ack将在下一周期拉高。也就是说,wr_ack反映的是上一周期的写操作。

3,读使能信号rd_en与读响应信号valid:在读操作中,第一个读取的数据应该是0,第二个是1(原因之后解释)。由波形可知,当rd_en有效的那个上升沿,并没有进行读操作,而是在下一个周期才真正读取了数据,同时valid被拉高,这是与写操作所不同的地方。

4,写计数wr_data_count和rd_data_count:因为写数据会有256个,读数据会有512个,一旦count的大小不够,count从一开始就会失效,成为高阻态,所以应该给wr_data_count设置成8位,rd_data_count设置成9位。当把wr_data_count设置成7位,rd_data_count设置成8位时,结果见图。

正常设置时,即wr_data_count设置成8位,rd_data_count设置成9位。

在写的过程中,可以看到,wr_data_count正常计数,每次加一,但是其值滞后2个周期。而由于读操作是每次4位,写操作是每次8位,即每次写操作都意味着需要读两次才能读出数据,所以每次写操作,rd_data_count都是加2。

在读过程中,rd_data_count是每次减1。同理,wr_data_count则是每2次读操作才减1。

对于这两个信号,也有不太正常的地方。如下图,当进行了读操作的时候,wr_data_count依旧保持在255不变,rd_data_count则在505和504之间切换,且其最大值不是预期的510.

可能的原因在于wr_data_count是属于写时钟域的,读操作进行后需要一段时间才能反映到写时钟域的各个参数,这在之后的empty等信号也可以得出类似结论。

至于rd_data_count应该是受读操作以及full或者wr_data_count等信号的共同影响,导致其在505和504之间不停变换。

官方文档也提到说,wr_data_count以及rd_data_count是大概的,不是非常准确。

5,prog_full;almost_full;full:Prog_full在之前的设置中是200,该值是根据wr_data_count判定的,即当wr_data_count为200时,prog_full置一。但是由于wr_data_count滞后2个周期,所以真正写入到FIFO中的值应该有202个了。

full以及almost_full由图可知,在数据数满足要求后的下一个周期被拉高。而且当读操作进行后,这两个信号并不是立刻被拉低,和之前所提到的一样,这两个信号属于写时钟域,读操作反映到这两个信号上需要一定的时间

6,prog_empty;almost_empty;empty:

Prog_empty之前设置的是10,由波形图知,其信号还是比较准确的。

Almost_empty以及empty则提早了一个周期被拉高

也可以看到,当写操作进行时,empty等信号也不是立刻变低的,其原因也应该是属于不同时钟域。

7,underflow;overflow: 改动程序,使写信号一直有效,可以看到当full变高后的下一周期因为继续进行写操作,使得overflow也被拉高。

再改动程序,写操作一段时间后,读信号一直有效。可以看到当empty有效后,继续读操作,underflow将在下一周期被拉高。

8,关于FIFO实际读写深度的问题:在之前的设置中可以看到,我们原本设置的写深度是256,读深度是512;但是边上显示的实际读写深度分别是255,510.从结果中我们也可以看到:当写到255时(数据是1~255),full被拉高。读数据以及读数据深度是根据写数据和写深度来的,自然也就是510了。也就是说实际写深度会比设置的小1,这是在工程中需要注意的地方。

9,关于读写不对称的问题:所谓的读写不对称,即读写的位大小以及读写速率不一样。在本例程中,写入的数据是8位的,而读出的数据是4位的。那么读操作的时候是怎么样一个读出法呢?在写操作中,我们是顺序写入1~255的。通过观察读数据可知,读出的数据为:0,1,0,2,0,3……这就说明当读写非对称时,是先读取数据的高位的。

10,关于FIFO的深度计算问题:在很多笔试面试中,都会问的FIFO的深度计算问题。因此,了解这方面也是很有必要的。

网上有很多关于这方面的公式,在此就不做讨论了。其实很简单,只要先计算单位时间内读写数据量的差值,然后乘以持续时间,就是FIFO的最小深度了。但是这里还需要注意几点:

1,背靠背问题,假设写数据100个wr_clk内写入80个数据,这时就需要考虑最坏的情况,就是前20个时钟不写入,接着80个时钟写入,再后来的80个时钟继续写入,最后的20个时钟不写入。这样写入数据最集中的情况就有160个时钟写入160个数据了。

2,需要留有深度裕量,即实际的深度会比设置的小,因此应该多设置点FIFO深度,以避免丢失数据。

转载于:https://www.cnblogs.com/flyuea/p/8417280.html

<think>我们正在讨论XilinxFIFO18E1原语中的FULL、ALMOST_FULL、EMPTY、ALMOST_EMPTY信号。这些信号FIFO状态的重要指示信号,用于控制数据流。根据用户需求,我们需要详细解释这些信号的含义以及如何配置它们。一、信号含义:1.FULL:当FIFO的写指针已经到达最后一个地址,并且下一个写操作会覆盖未读数据时,FULL信号变为高电平。此时不应进行写操作,否则会导致数据丢失。2.ALMOST_FULL:这是一个可编程的信号,当FIFO中的数据量达到或超过用户设定的阈值时,该信号变为高电平。这个阈值可以在配置时设置,用于提前警告即将满的状态,以便停止写操作。3.EMPTY:当FIFO的读指针已经到达写指针的位置(即没有数据可读)时,EMPTY信号变为高电平。此时读操作无效。4.ALMOST_EMPTY:同样是一个可编程的信号,当FIFO中剩余的数据量小于或等于用户设定的阈值时,该信号变为高电平。用于提前警告即将空的状态,以便停止读操作。二、配置方法:在FIFO18E1原语中,这些信号的配置主要通过以下参数进行:-ALMOST_FULL_OFFSET:设置ALMOST_FULL信号的触发阈值。它是一个13位的值,表示距离满状态还有多少个写操作。例如,如果设置为16(十六进制13'h0010),那么当FIFO中剩余空间小于等于16时,ALMOST_FULL有效。-ALMOST_EMPTY_OFFSET:设置ALMOST_EMPTY信号的触发阈值。同样是一个13位的值,表示距离空状态还有多少个数据。例如,设置为8(13'h0008)时,当FIFO中数据量小于等于8时,ALMOST_EMPTY有效。在实例化FIFO18E1时,我们可以通过参数来设置这些偏移量。同时,我们还可以选择是否启用这些信号(默认是启用的)。三、注意事项:1.这些阈值偏移量都是相对于满/空状态的偏移量,且使用二进制数表示。2.在异步FIFO中,这些标志信号在各自的时钟域生成,因此在使用时需要注意跨时钟域问题(特别是ALMOST_FULL和ALMOST_EMPTY用于跨时钟域控制时,需要同步)。3.在设置阈值时,需要根据实际应用需求来设定,以避免频繁的启停操作。四、配置示例(Verilog):下面是一个FIFO18E1的实例化示例,其中设置了ALMOST_FULL和ALMOST_EMPTY的偏移量:```verilogFIFO18E1#(.ALMOST_EMPTY_OFFSET(13'h0020),//当数据量<=32时,ALMOST_EMPTY有效.ALMOST_FULL_OFFSET(13'h0100),//当剩余空间<=256时,ALMOST_FULL有效.DATA_WIDTH(36),//使用36位宽(包括4位校验位).DO_REG(1),//启用输出寄存器.EN_SYN("FALSE"),//异步模式.FIRST_WORD_FALL_THROUGH("TRUE")//FWFT模式)fifo_inst(.RST(RST),.WRCLK(WRCLK),.RDCLK(RDCLK),.DI(DI),.DIP(DIP),.WREN(WREN),.RDEN(RDEN),.DO(DO),.DOP(DOP),.FULL(FULL),.ALMOSTFULL(ALMOSTFULL),//注意:端口名是ALMOSTFULL(没有下划线).EMPTY(EMPTY),.ALMOSTEMPTY(ALMOSTEMPTY)//同样没有下划线);```注意:在FIFO18E1中,端口名称是ALMOSTFULL和ALMOSTEMPTY(没有下划线),这与一些文档中的描述可能略有不同。五、相关引用:在配置这些信号时,可以参考Xilinx的官方文档UG473(7SeriesFPGAsMemoryResourcesUserGuide)[^2],其中详细描述了这些信号的时序和配置方法。六、总结:通过合理配置ALMOST_FULL和ALMOST_EMPTY的阈值,可以优化数据流的控制,避免FIFO溢出或下溢,同时提高系统效率。相关问题:1.在异步FIFO中,如何安全地将ALMOST_FULL信号传递到写时钟域?2.如何计算FIFO18E1的深度和宽度以满足特定应用需求?3.FIFO18E1的FWFT(FirstWordFallThrough)模式如何影响空信号的行为?4.FIFO18E1的复位(RST)信号对状态标志有什么影响?</think>### Xilinx FIFO18E1 状态信号详解与配置指南 #### 1. **核心状态信号定义** | 信号名称 | 触发条件 | 功能描述 | |--------------------|-----------------------------------|--------------------------------------------------------------------------| | **FULL** | 写指针 = 读指针 + FIFO深度 | 完全满状态,禁止写入(继续写入会导致数据丢失)[^1] | | **ALMOST_FULL** | 剩余空间 ≤ ALMOST_FULL_OFFSET | 可编程阈值预警,允许提前停止写入(防止突发数据溢出)[^1] | | **EMPTY** | 读指针 = 写指针 | 完全空状态,禁止读取(继续读取会获得无效数据) | | **ALMOST_EMPTY** | 有效数据 ≤ ALMOST_EMPTY_OFFSET | 可编程阈值预警,允许提前停止读取(防止读空操作)[^1] | #### 2. **阈值配置方法** 通过原语参数设置阈值偏移量(二进制补码格式): ```verilog FIFO18E1 #( .ALMOST_FULL_OFFSET(13'h0100), // 剩余256字时触发ALMOST_FULL .ALMOST_EMPTY_OFFSET(13'h0020), // 剩余32字时触发ALMOST_EMPTY .DATA_WIDTH(18), // 数据位宽配置 .FIRST_WORD_FALL_THROUGH("TRUE") // FWFT模式选择 ) fifo_inst ( .ALMOSTFULL(afull_flag), // 输出连接 .ALMOSTEMPTY(aempty_flag) // 输出连接 ); ``` **配置要点**: - 偏移量范围:`13'h0001` 到 `13'h1FFF`(对应深度4K的FIFO) - 阈值计算: - **ALMOST_FULL** 阈值 = FIFO深度 - ALMOST_FULL_OFFSET - **ALMOST_EMPTY** 阈值 = ALMOST_EMPTY_OFFSET 例如:深度4096的FIFO设置`ALMOST_FULL_OFFSET=256`,则当写入数据量 ≥ 3840时触发预警[^2] #### 3. **工作模式影响** | 模式类型 | FULL行为 | EMPTY行为 | 应用场景 | |----------------|-----------------------|-----------------------|------------------------| | **标模式** | 读使能后延迟1周期解除 | 写使能后延迟1周期解除 | 严格同步控制 | | **FWFT模式** | 即时解除 | 数据预取后即时解除 | 低延迟流处理[^2] | #### 4. **跨时钟域处理** 异步FIFO需特殊处理: ```verilog // 异步标志同步化示例(写时钟域→读时钟域) reg [1:0] sync_empty; always @(posedge rdclk) sync_empty <= {sync_empty[0], EMPTY}; wire safe_read = (sync_empty[1] == 1'b0); ``` **设计规则**: - 满/空标志在各自时钟域生成 - 跨时钟域使用需双触发器同步 - ALMOST_*信号同步要求相同[^2] #### 5. **深度扩展配置** 当需求超过18Kb时: ```verilog // 级联实现36Kb FIFO FIFO18E1 fifo_lower (...); FIFO18E1 fifo_upper ( .DI({16'h0, fifo_lower.DO}), // 低位连接 .ALMOST_FULL_OFFSET(13'h0200) // 统一阈值设置 ); ``` 级联时需同步管理状态信号[^2] #### 6. **实战注意事项** 1. **复位要求**:复位脉冲宽度 > 3个最长时钟周期 2. **阈值安全裕量**:ALMOST_FULL_OFFSET > 最大突发数据量 3. **时序约束**:添加`set_false_path`到状态标志同步链 4. **位宽适配**:9/18位宽模式影响实际可用深度 > 📘 **官方文档参考**: > [UG473: 7 Series FPGAs Memory Resources](https://docs.xilinx.com/v/u/en-US/ug473_7Series_Memory_Resources) > - 第4章:FIFO时序与阈值配置细节 > - 附录B:FIFO深度计算工具 --- ### 相关问题 1. 如何计算异步FIFO中ALMOST_FULL_OFFSET的最佳安全值? 2. FWFT模式下EMPTY信号的解除时序有何特殊要求? 3. 级联FIFO18E1时如何统一管理ALMOST_EMPTY信号? 4. FIFO状态信号未同步会导致什么系统级故障? 5. 如何通过Vivado FIFO Generator可视化配置这些参数?[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值