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

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相对来说比较简单。

Read more

人工智能:自然语言处理在教育领域的应用与实战

人工智能:自然语言处理在教育领域的应用与实战

人工智能:自然语言处理在教育领域的应用与实战 学习目标 💡 理解自然语言处理(NLP)在教育领域的应用场景和重要性 💡 掌握教育领域NLP应用的核心技术(如智能问答、作业批改、个性化学习) 💡 学会使用前沿模型(如BERT、GPT-3)进行教育文本分析 💡 理解教育领域的特殊挑战(如多学科知识、学生认知差异、数据隐私) 💡 通过实战项目,开发一个智能问答系统应用 重点内容 * 教育领域NLP应用的主要场景 * 核心技术(智能问答、作业批改、个性化学习) * 前沿模型(BERT、GPT-3)在教育领域的使用 * 教育领域的特殊挑战 * 实战项目:智能问答系统应用开发 一、教育领域NLP应用的主要场景 1.1 智能问答 1.1.1 智能问答的基本概念 智能问答是通过自然语言与用户进行交互,回答用户问题的程序。在教育领域,智能问答的主要应用场景包括: * 课程问答:回答课程相关的问题(如“什么是机器学习”

AI时代人人都是产品经理:落地流程:AI 核心功能,从需求到上线的全流程管控方法

AI时代人人都是产品经理:落地流程:AI 核心功能,从需求到上线的全流程管控方法

AI的普及正在重构产品经理的工作模式——不再依赖传统的跨部门协作瓶颈,AI可以成为产品经理的"全职助手",覆盖需求分析、原型设计、开发协同、测试验证全流程。本文将拆解AI时代产品核心功能从0到1落地的完整管控方法,让你用AI能力提升300%的落地效率。 一、需求阶段:AI辅助的需求挖掘与标准化 需求是产品的起点,AI可以帮你从海量信息中精准定位用户真实需求,避免"伪需求"浪费资源。 1. 需求挖掘:AI辅助用户洞察 传统需求调研依赖问卷、访谈,效率低且样本有限。AI可以通过以下方式快速完成用户洞察: * 结构化处理非结构化数据:用AI分析用户在社交媒体、客服对话、应用评论中的碎片化反馈,自动提炼高频需求点 * 需求优先级排序:基于KANO模型,AI可以自动将需求划分为基础型、期望型、兴奋型、无差异型四类,输出优先级列表 实战工具与示例: 使用GPT-4+Python脚本批量处理应用商店评论: import openai import pandas as

Flutter 三方库 algolia_client_recommend 的鸿蒙化适配指南 - 打造 AI 驱动的个性化推荐引擎、助力鸿蒙端电商与内容应用转化率倍增

Flutter 三方库 algolia_client_recommend 的鸿蒙化适配指南 - 打造 AI 驱动的个性化推荐引擎、助力鸿蒙端电商与内容应用转化率倍增

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 algolia_client_recommend 的鸿蒙化适配指南 - 打造 AI 驱动的个性化推荐引擎、助力鸿蒙端电商与内容应用转化率倍增 前言 在 OpenHarmony 鸿蒙应用全场景连接的商业版图中,“信息找人”已成为提升流量价值的核心逻辑。无论是电商应用的“经常一起购买”,还是内容平台的“相关推荐”,高质量的个性化算法能显著降低用户的决策成本。algolia_client_recommend 作为一个连接 Algolia 顶尖 AI 推荐服务的专业客户端,为开发者提供了一套开箱即用的推荐逻辑封装。本文将详述如何在鸿蒙端利用此库构建“读懂用户”的智能化交互。 一、原原理分析 / 概念介绍 1.1 基础原理 algolia_client_recommend 的核心逻辑是 基于意图建模的异步推荐查询与联合过滤机制

Plottable高级图表制作:从散点图到堆叠面积图的10种实现方法

Plottable高级图表制作:从散点图到堆叠面积图的10种实现方法 【免费下载链接】plottable:bar_chart: A library of modular chart components built on D3 项目地址: https://gitcode.com/gh_mirrors/pl/plottable Plottable是一个基于D3.js构建的模块化图表组件库,为开发者提供了创建灵活、定制化图表的强大工具。这个开源项目专注于"组合优于配置"的理念,让你能够像搭积木一样构建复杂的图表系统。通过Plottable的高级图表制作功能,你可以轻松实现从基础散点图到复杂堆叠面积图的各种数据可视化需求。😊 为什么选择Plottable进行高级图表制作? Plottable不是一个传统的图表库,而是一个图表组件库。这意味着你拥有前所未有的灵活性来创建自定义图表。与直接使用D3相比,Plottable提供了更高层次的抽象,让图表制作变得更加简单快捷;与传统图表库相比,它又提供了无与伦比的定制能力。 核心关键词:Plottable图表制作、D3图表组件、高级数据可