【问题标题】:Read after Write Latency in Asynchronous FIFO?在异步 FIFO 中写入延迟后读取?
【发布时间】:2017-08-07 19:00:37
【问题描述】:

我正在尝试将模块与 Xilinx CORE Generator 生成的异步 FIFO 连接。然而,我观察到在 AFIFO 的输入端口提供的数据(虽然是正确的)在 6-7 个时钟周期的延迟后开始出现在 dout 上。这是可以预料的吗?还是我做错了什么?我正在做的是断言 AFIFO 的 write_enable 引脚,提供输入数据,然后在下一个周期断言 read_enable 引脚。但仍然存在延迟问题。任何帮助表示赞赏。

编辑:我附上了我的代码的一部分。

always @ (posedge clk1, posedge rst)//faster clock domain
begin
    if (rst)
        wr_en<= 1'b 0;

    else
        begin
            if (data_wrt)
                begin
                wr_en<= 1'b 1;                          
                end
            else
                wr_en<= 1'b 0;
        end
end
always @ (negedge clk2, posedge rst)//slower clock domain
    begin
        if (rst)
            rd_en<= 1'b 0;

        else
            begin
                if (wr_en)
                    begin
                    rd_en<= 1'b 1;                              
                    end
                else
                    rd_en<= 1'b 0;              
            end

    end
AFIFO AFIFO1(//AFIFO module instantiation
    .din(data_in),
    .rd_clk(clk2),
    .rd_en(rd_en),
    .rst(reset),
    .wr_clk(clk1),
    .wr_en(wr_en),
    .dout(data_out),
    .empty(empty),
    .full(full)
    );

【问题讨论】:

  • 任何代码片段?
  • 如果您的clk2 比clk1 慢,您的rd_en 触发器可能缺少一些启用信号(在if(wr_en) 块中)。
  • 那我该怎么办?

标签: verilog fpga fifo xilinx-ise


【解决方案1】:

什么是时钟关系?假设您看到 6-7 个 clk1(快速时钟)周期的延迟,这看起来确实像您所期望的,具体取决于时钟关系 clk1/clk2。

也就是说,异步 FIFO 的作用通常是充当从一个时钟域到另一个时钟域的同步器。只要 AFIFO 未满,写时钟域 (clk1) 就会将数据写入 AFIFO。只要 AFIFO 不为空,读取时钟域 (clk2) 就会读取新数据。你在这里做的是打破这种用法。

您正在使用由 clk1 生成的 wr_en 来控制由 clk2 计时的 rd_en。所以现在wr_en在两个时钟域中都使用了,会导致metastability。

简而言之,您没有正确使用 AFIFO。当 AFIFO 为 !empty 时,请尝试让您的 clk2 逻辑始终设置为 rd_en。

【讨论】:

  • 我已经上传了我使用 AFIFO 进行模拟的屏幕截图。
  • 这张图片中有很多东西看起来有点奇怪。首先,我会说您看到的延迟比我预期的要大得多。六个慢时钟周期似乎过多。这可能是 FIFO 生成器中可控的。其次,empty 和data_out 似乎与 clk2 不同步,而是延迟了 1/4 个周期。然而,这可能是模拟延迟,也是 FIFO 生成器的一部分。最后,当您不应该启用 rd_en 时,您仍在启用它。只要empty 很高,rd_en 就永远不会很高。
  • 我也上传了第二张截图,其中 rd_en 在 AFIFO 为 !empty 时被激活。现在我在 data_out 上弄错了第一个值!!当我模拟时出现以下警告:错误:C:/Xilinx/verilog/src/simprims/X_RAMB16_S36_S36.v(2655): $setup(posedge DIA[1] &&& dia_enable:127784 ps,posedge CLKA:127972 ps, 484 ps); # 时间:127972 ps 迭代:3 实例:/tb/uut/\AFIFO1/BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram .r/v2_noinit.ram/dp36x36.ram\
  • 我也上传了第二张截图,其中 rd_en 在 AFIFO 为 !empty 时被激活。现在我在 data_out 上弄错了第一个值!!当我模拟时出现以下警告:错误:C:/Xilinx/verilog/src/simprims/X_RAMB16_S36_S36.v(2655): $setup(posedge DIA[1] &&& dia_enable:127784 ps,posedge CLKA:127972 ps, 484 ps); # 时间:127972 ps 迭代:3 实例:/tb/uut/\AFIFO1/BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram .r/v2_noinit.ram/dp36x36.ram\
  • 不仅rd_en需要在!empty时设置,还必须与clk2同步。您看到的设置错误很可能是由于 rd_en 的异步断言造成的。 $setup 错误与我之前提到的亚稳态有关。我现在看到您的clk2 always 块的时钟是negedge。 AFIFO 可能不支持这一点。请改用posedge。
【解决方案2】:

我认为您想通过异步 FIFO 将一些与 clk1 同步的数据转换为与 clk2 同步的数据。

首先,你不需要直接通过clk2对同步到clk1的信号进行采样。比如用clk1产生的wr_en来控制由clk2计时的rd_en。会导致亚稳态。FIFO总是用来解决亚稳态的问题。所以不需要做第二个总是阻塞的。

那么问题就变成了如何正确使用异步FIFO。 你应该阅读像PG057这样的Xilinx FIFO生成器产品指南。你应该知道FIFO的理论和使用方法。否则你在使用FIFO时会很痛苦。

我的建议如下。 对于写操作,你需要同时使用almost_full和full信号来避免溢出。你可以在PG057图3-2中看到它。你需要使用almost_full,因为如果wr_en是连续的,那么full信号会慢1个时钟以避免溢出。 对于读取操作,您需要同时使用 most_empty 和 empty 信号,原因相同。 然后就可以正确转换时钟区域了。

原谅我的英语。

【讨论】:

    猜你喜欢
    • 2021-09-06
    • 1970-01-01
    • 2021-04-12
    • 2021-01-20
    • 2018-06-04
    • 1970-01-01
    • 2018-07-12
    • 2016-02-02
    • 1970-01-01
    相关资源
    最近更新 更多