FPGA教程系列-Vivado AXI4-Stream Data FIFO核解读测试

FPGA教程系列-Vivado AXI4-Stream Data FIFO核解读测试

image

FIFO depth (FIFO 深度): 定义了 FIFO 能存储多少个数据字(Data Words)。

注意:实际占用的存储资源取决于深度乘以数据宽度(TDATA width)。

Memory type (存储器类型): Auto

  • 决定用 FPGA 内部的哪种资源来实现 FIFO。
  • Auto: 让 Vivado 综合工具根据 FIFO 的大小自动选择(通常小 FIFO 用分布式 RAM/LUTRAM,大 FIFO 用块 RAM/BRAM)。
  • Block RAM: 强制使用 BRAM。
  • Distributed RAM: 强制使用 LUT 搭建的 RAM。
  • UltraRAM: 针对 UltraScale+ 系列的特殊大容量 RAM。

Independent clocks (独立时钟): No

  • No (同步 FIFO): 写入侧(Slave)和读取侧(Master)使用同一个时钟信号 (s_axis_aclk)。这消耗资源较少,延迟较低。
  • Yes (异步 FIFO): 启用跨时钟域功能。输入和输出可以使用不同频率的时钟。此时界面左侧的端口图会显示 s_axis_aclk​ (写时钟) 和 m_axis_aclk (读时钟)。

CDC sync stages (跨时钟域同步级数): 3(灰色不可选)

只有当选择了 “Independent clocks: Yes” 时才有效。它定义了用于同步信号的寄存器级数,通常用于防止亚稳态。

Enable packet mode (启用包模式): No

  • No: 普通 FIFO 模式。只要 FIFO 里有数据,Master 端就会尝试输出。
  • Yes: FIFO 会等到接收到一个完整的数据包(即收到 TLAST 信号)后,才开始向 Master 端输出数据。这用于防止数据包在传输中间断流(Underrun),但会增加延迟。

ACLKEN conversion mode: None​,用于控制时钟使能信号的处理方式。通常保持默认 None 即可。

Enable ECC (启用 ECC 校验): No,是否启用错误检查和纠正(Error Correction Code)。启用后会增加逻辑资源,用于检测和修复位翻转错误。


TDATA width (bytes) (数据位宽): 1

  • 定义主要数据总线 TDATA​ 的宽度。设为 1 byte,也就是 8 bits。这意味着每个时钟周期传输 8 位数据。

Enable TSTRB (启用 TSTRB 信号): No,TSTRB (Strobe) 用于指示哪些字节是有效的位置选通信号。对于纯数据流通常不需要。

Enable TKEEP (启用 TKEEP 信号): No,TKEEP (Keep) 用于指示数据流中的哪些字节是有效的(通常用于处理非对齐的数据包尾部)。

Enable TLAST (启用 TLAST 信号): No,TLAST 用于指示一个数据包(Packet)的结束。

设为 No,意味着这个 FIFO 认为数据是无限连续的流,没有“包”的概念。如果需要划分帧或包,必须选 Yes。

TID / TDEST / TUSER width (bits): 0

  • 这些是 AXI-Stream 的边带信号(ID、Destination、User data)。
  • 设为 0 表示不使用这些信号,它们不会出现在 IP 核的端口上,也不会被 FIFO 缓存。

image

Write flags(写入侧标志位)

Enable write data count (启用写入数据计数): Yes​, 勾选后,IP 核会增加一个输出端口 axis_wr_data_count。 这个信号会实时输出 FIFO 中当前存储了多少个数据字(Data Words)。写入侧的逻辑可以读取这个值,精确判断 FIFO 里还有多少空间。

Enable almost full (启用“将满”信号): Yes​, 勾选后,IP 核会增加一个输出端口 almost_full​。当 FIFO 只剩下一个写入位置时,这个信号就会变高。它是一个紧急警告信号,告诉前级电路“再写一个我就满了”,通常比标准的 TREADY 变低(表示已满)提前一个周期提示。

Enable programmable full (启用可编程满信号): No​, 是否启用一个自定义阈值的“满”信号 (prog_full)。

如果选 Yes: 你可以在下方的 Programmable full threshold​ 框中填入一个数字(例如 400)。当 FIFO 里的数据量达到或超过 400 时,prog_full 信号就会变高。这用于需要比“将满”更早进行流控的场景。

Read flags(读取侧标志位)

Enable read data count (启用读取数据计数): Yes​, 勾选后,IP 核会增加一个输出端口 axis_rd_data_count。 实时输出 FIFO 中当前有多少个数据等待被读取。

注意: 如果使用的是独立时钟(异步 FIFO),write data count​ 和 read data count 分别属于写入时钟域和读取时钟域,数值可能略有延迟差异。如果是同步 FIFO,这两个值通常是一样的。

Enable almost empty (启用“将空”信号): Yes​, 勾选后,IP 核会增加一个输出端口 almost_empty​。 当 FIFO 只剩下一个数据可读时,这个信号就会变高。提示后级电路数据流即将断档。

Enable programmable empty (启用可编程空信号): No​, 是否启用一个自定义阈值的“空”信号 (prog_empty)。

如果选 Yes: 可以在下方的 Programmable empty threshold 填入数字(例如 10)。当 FIFO 数据量少于等于 10 时,该信号变高。

选项与FIFO很类似,可以参考FIFO的使用。

可以直接打开官方的例程进行仿真:

image

1、写的速度是读的2倍:

这部分主要是因为从的程序:

always @(posedge aclk) begin
    if(areset) ...
    else begin
      s_axis_tready <= ~s_axis_tready; // 核心逻辑:每周期翻转一次
    end
  end

可以看到,s_axis_tready信号在 0 和 1 之间不断跳变。这意味着接收端一会儿说“我满了”,一会儿说“我可以收”。人为制造总线拥塞(Backpressure)。这强迫上游的 FIFO 必须将数据存入内部 RAM,从而验证 FIFO 的缓存功能和满标志逻辑是否正常工作。

2、tlast 一直为 1 是因为:代码逻辑显式地在复位后将其置 1

image

3、快满以后,读跟写的间隔变为一致。

image

自测

可以直接编写一个testbench:

`timescale 1ns / 1ps

module tb_axis_data_fifo();

  //-------------------------------------------------------------------------
  // 1. 信号定义
  //-------------------------------------------------------------------------
  // 时钟与复位
  reg           clk;
  reg           resetn;

  // Slave 接口 (写入端)
  reg           s_axis_tvalid;
  wire          s_axis_tready;
  reg  [7:0]    s_axis_tdata;
  reg           s_axis_tlast;

  // Master 接口 (读取端)
  wire          m_axis_tvalid;
  reg           m_axis_tready;
  wire [7:0]    m_axis_tdata;
  wire          m_axis_tlast;

  // 状态信号
  wire [31:0]   axis_wr_data_count;
  wire [31:0]   axis_rd_data_count;
  wire          almost_empty;
  wire          almost_full;

  //-------------------------------------------------------------------------
  // 2. DUT (Device Under Test) 实例化
  //-------------------------------------------------------------------------
  axis_data_fifo_0 dut (
    .s_axis_aresetn     (resetn),               // input wire s_axis_aresetn
    .s_axis_aclk        (clk),                  // input wire s_axis_aclk
    
    // 写端口 (Slave)
    .s_axis_tvalid      (s_axis_tvalid),        // input wire s_axis_tvalid
    .s_axis_tready      (s_axis_tready),        // output wire s_axis_tready
    .s_axis_tdata       (s_axis_tdata),         // input wire [7 : 0] s_axis_tdata
    .s_axis_tlast       (s_axis_tlast),         // input wire s_axis_tlast
    
    // 读端口 (Master)
    .m_axis_tvalid      (m_axis_tvalid),        // output wire m_axis_tvalid
    .m_axis_tready      (m_axis_tready),        // input wire m_axis_tready
    .m_axis_tdata       (m_axis_tdata),         // output wire [7 : 0] m_axis_tdata
    .m_axis_tlast       (m_axis_tlast),         // output wire m_axis_tlast
    
    // 状态信号
    .axis_wr_data_count (axis_wr_data_count),   // output wire [31 : 0] axis_wr_data_count
    .axis_rd_data_count (axis_rd_data_count),   // output wire [31 : 0] axis_rd_data_count
    .almost_empty       (almost_empty),         // output wire almost_empty
    .almost_full        (almost_full)           // output wire almost_full
  );

  //-------------------------------------------------------------------------
  // 3. 时钟生成 (100MHz)
  //-------------------------------------------------------------------------
  initial begin
    clk = 0;
    forever #5 clk = ~clk; // 周期 10ns
  end

  //-------------------------------------------------------------------------
  // 4. 辅助任务:发送数据包
  //-------------------------------------------------------------------------
  // 参数:发送的数据个数
  task write_packet(input [31:0] length);
    integer i;
    begin
      @(posedge clk); // 同步到时钟沿
      wait(resetn == 1);
      
      $display("[Writer] Start writing packet of length %0d at time %0t", length, $time);

      for (i = 0; i < length; i = i + 1) begin
        s_axis_tvalid <= 1'b1;
        s_axis_tdata  <= i[7:0]; // 数据内容就是简单的 0, 1, 2...
        
        // 如果是最后一个数据,拉高 tlast
        if (i == length - 1)
          s_axis_tlast <= 1'b1;
        else
          s_axis_tlast <= 1'b0;

        // 等待握手成功 (tvalid & tready 均为高)
        do begin
          @(posedge clk);
        end while (s_axis_tready == 1'b0); // 如果 FIFO 满,tready 会拉低,这里会阻塞等待
      end

      // 发送完毕,拉低信号
      s_axis_tvalid <= 1'b0;
      s_axis_tlast  <= 1'b0;
      $display("[Writer] Packet writing finished at time %0t", $time);
    end
  endtask

  //-------------------------------------------------------------------------
  // 5. 主测试激励 (Stimulus)
  //-------------------------------------------------------------------------
  initial begin
    // 初始化信号
    resetn        = 0;
    s_axis_tvalid = 0;
    s_axis_tdata  = 0;
    s_axis_tlast  = 0;
    m_axis_tready = 0; // 初始状态下不读取数据,为了测试 Full 信号

    // 1. 复位序列
    $display("--- Test Start: Reset ---");
    #100;
    resetn = 1;
    #20;

    // 2. 写入测试:在不读取的情况下写入数据
    // 假设 FIFO 深度较小,或者我们只是为了观察 Wr_count 增加
    // 此时 m_axis_tready = 0,数据会堆积在 FIFO 中
    $display("--- Test Phase 1: Write only (Fill FIFO) ---");
    write_packet(16); // 写入 16 个数据

    // 观察一段时间状态
    #50;
    $display("Status Check: WR Count = %0d, RD Count = %0d, Almost Full = %b", 
             axis_wr_data_count, axis_rd_data_count, almost_full);

    // 3. 读取测试:打开读使能,排出数据
    $display("--- Test Phase 2: Enable Read (Drain FIFO) ---");
    @(posedge clk);
    m_axis_tready = 1; // 允许读取

    // 等待数据读完(简单起见,延时等待)
    wait(axis_rd_data_count == 0 && m_axis_tvalid == 0); 
    #100;
    
    // 4. 并发读写测试
    $display("--- Test Phase 3: Concurrent Read & Write ---");
    m_axis_tready = 1; // 保持读取开启
    write_packet(32);  // 再次写入 32 个数据
    
    #200;
    $display("--- Test Finished ---");
    $stop;
  end

  //-------------------------------------------------------------------------
  // 6. 监控模块 (Monitor):打印读出的数据
  //-------------------------------------------------------------------------
  always @(posedge clk) begin
    if (m_axis_tvalid && m_axis_tready) begin
      $display("[Reader] Read Data: %h (Last: %b) at time %0t", 
               m_axis_tdata, m_axis_tlast, $time);
    end
  end

endmodule

仿真结果:

image

符合预期。其实就是两个AXI接口分别负责读和写,stream相对来说比较简单。

内容概要:本文介绍了ENVI Deep Learning V1.0的操作教程,重点讲解了如何利用ENVI软件进行深度学习模型的训练与应用,以实现遥感图像中特定目标(如集装箱)的自动提取。教程涵盖了从数据准备、标签图像创建、模型初始化与训练,到执行分类及结果优化的完整流程,并介绍了精度评价与通过ENVI Modeler实现一键化建模的方法。系统基于TensorFlow框架,采用ENVINet5(U-Net变体)架构,支持通过点、线、面ROI或分类图生成标签数据,适用于多/高光谱影像的单一类别特征提取。; 适合人群:具备遥感图像处理基础,熟悉ENVI软件操作,从事地理信息、测绘、环境监测等相关领域的技术人员或研究人员,尤其是希望将深度学习技术应用于遥感目标识别的初学者与实践者。; 使用场景及目标:①在遥感影像中自动识别和提取特定地物目标(如车辆、建筑、道路、集装箱等);②掌握ENVI环境下深度学习模型的训练流程与关键参数设置(如Patch Size、Epochs、Class Weight等);③通过模型调优与结果反馈提升分类精度,实现高效自动化信息提取。; 阅读建议:建议结合实际遥感项目边学边练,重点关注标签数据制作、模型参数配置与结果后处理环节,充分利用ENVI Modeler进行自动化建模与参数优化,同时注意软硬件环境(特别是NVIDIA GPU)的配置要求以保障训练效率。
内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略与效果评估体系,涵盖当前企业传播面临的预算、资源、内容与效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户和自媒体四类媒体资源的特性、传播优势与发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化与GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理与舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率与ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放与GEO优化,提升品牌在AI搜索中的权威性与可见性;④通过数据驱动评估体系量化品牌影响力与销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析与工具指南进行系统学习,重点关注媒体适配性策略与GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
<think>好的,用户让我详细说明Vivado 2024.2的AXI4-Stream Data FIFO IP中的FIFO Depth参数的作用、配置方法以及如何选择合适的深度。首先,我需要回顾之前关于FIFO Depth的讨论,确保信息准确且不重复。用户可能是在使用FPGA进行数据传输设计,需要合理配置FIFO深度以避免溢出或资源浪费。 用户可能已经了解基本概念,但需要更深入的理解和实际应用指导。我需要详细解释FIFO Depth的作用,比如缓冲数据速率差异、背压控制等。同时,配置方法需要具体步骤,可能包括在Vivado中设置参数的流程。选择深度的部分需要提供计算公式和实际例子,帮助用户应用到具体项目中。 还要注意用户可能的实际应用场景,比如摄像头数据传输到DMA,这时候需要考虑输入输出速率差异和突发数据。此外,用户可能关心如何平衡资源占用和性能,所以需要给出不同场景下的配置建议,比如使用Block RAM还是Distributed RAM,以及如何避免溢出。 需要确保回答结构清晰,分点说明,用示例和公式帮助理解。最后,按照用户要求添加相关问题,确保符合格式要求。检查是否有遗漏或错误,比如参数的最新信息是否准确,是否覆盖了所有用户可能关心的点。 </think>### FIFO Depth参数详解(Vivado 2024.2 AXI4-Stream Data FIFO IP--- #### **作用** 1. **缓冲能力心参数** - 决定FIFO可存储的数据项数量(单位:数据字数) - 直接影响数据缓冲能力、系统延迟和资源占用 - 深度越大,抗突发数据能力越强,但消耗更多BRAM/URAM资源 2. **背压控制基础** - 通过`almost_full`信号触发上游模块暂停发送数据 - 避免因下游模块处理速度不足导致数据丢失 3. **时钟域隔离** - 在独立时钟模式下(Independent Clocks),深度决定跨时钟域数据存储能力 --- #### **配置方法** 1. **Vivado IP Catalog设置** - 打开IP配置界面 → 在`FIFO Configuration`选项卡中设置`FIFO Depth` - 支持范围:4/8/16/32/64/128/256/512/1024/2048/4096 - 示例: ```verilog // 参数化配置(Vivado自动推导) parameter FIFO_DEPTH = 512; ``` 2. **硬件资源映射** - **Block RAM模式**: 深度与BRAM资源直接相关(例如512×32位需1块36KB BRAM) - **Distributed RAM模式**: 深度影响LUT占用量(例如64×16位需约32个LUT6) --- #### **深度选择原则** 1. **基本公式** ``` FIFO深度 ≥ (输入速率 × 突发时间) - 输出速率 × 突发时间 ``` **示例**: - 输入速率:100MB/s,输出速率:60MB/s,突发时间1ms - 计算: ``` (100 - 60) × 1e-3 = 40 → 实际配置深度≥64(留安全余量) ``` 2. **关键场景适配** | 场景类型 | 深度选择策略 | 典型值 | |--------------------|---------------------------------------|--------------| | 高速ADC数据采集 | 输入速率×突发时间 ≥ ADC缓冲需求 | 512~2048 | | 视频流传输 | 行/帧缓冲(如1920像素×2行) | 3840~4096 | | 网络数据包处理 | 包大小×最大并发数(如1500字节×2包) | 3072~4096 | 3. **动态流量控制** - 结合`Almost Full Threshold`参数(建议设为深度的90%) - 示例: ```verilog // 深度512 → 阈值设为480 parameter ALMOST_FULL_THRESHOLD = 480; ``` --- #### **配置示例(摄像头到DDR传输)** ```verilog // 场景:1080p@60Hz摄像头 → AXI DMA → DDR4 // 输入速率:1920×1080×60 ≈ 124.4MB/s // 输出速率(DDR4):400MB/s(突发模式) // 计算深度: // (124.4 × 1e-3) - (400 × 1e-3 × 0.3) ≈ 0.01244 → 实际配置深度=64 ``` **IP配置参数**: | 参数项 | 配置值 | |--------------|-------------| | FIFO Depth | 64 | | Memory Type | Block RAM | | Independent Clocks | Enabled (25MHz → 100MHz) | | Almost Full Threshold | 60 | --- #### **深度选择常见问题** 1. **过小的深度**: - 导致溢出(overflow=1) - 数据丢失(需通过`axis_data_count`监控) 2. **过大的深度**: - 资源浪费(如URAM未充分利用) - 增加延迟(数据读取延迟=深度/输出速率) 3. **动态调整建议**: - 利用`axis_data_count`信号动态调整生产者速率 - 示例: ```verilog wire [15:0] data_count; assign data_count = u_axis_fifo.axis_data_count; // 当data_count > THRESHOLD时降低摄像头帧率 ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值