跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

Vivado AXI4-Stream Data FIFO 配置与仿真记录

整理了 Vivado AXI4-Stream Data FIFO 的关键配置项,包括 FIFO 深度、存储器类型、同步/异步时钟、包模式和各类状态信号的开关选择,并结合官方例程和自写 testbench 验证了写入堆积、读取排空以及读写并发时的波形表现。结果显示,在同步 FIFO、8bit 数据宽度、关闭 TLAST/TKEEP/TSTRB 的前提下,Data FIFO 的行为符合预期,`almost_full`、`almost_empty` 和 data count 也能正常反映缓存状态。

星星泡饭发布于 2026/6/300 浏览
Vivado AXI4-Stream Data FIFO 配置与仿真记录

Vivado AXI4-Stream Data FIFO 配置与仿真记录

image

AXI4-Stream Data FIFO 这个核不复杂,真正常踩坑的地方也不是接口本身,而是参数一多,第一次配的时候很容易把几个'看起来差不多'的选项混在一起。下面按实际配置顺一遍,顺手把仿真里能看出来的行为也记下来。

**FIFO depth(FIFO 深度)**定义的是能缓存多少个 data word。

存储资源的消耗不是只看深度,真正的占用还是深度乘上 TDATA 宽度。这个地方经常被忽略:你把深度翻倍,资源不一定只是线性变化,位宽一大,BRAM/LUTRAM 的选择也会跟着变。

**Memory type(存储器类型)**设为 Auto。

  • Auto:交给 Vivado 自动选实现方式。小 FIFO 通常会走分布式 RAM/LUTRAM,大一点就更倾向 BRAM。
  • Block RAM:强制用 BRAM。
  • Distributed RAM:强制用 LUTRAM。
  • UltraRAM:给 UltraScale+ 这类大容量场景用。

**Independent clocks(独立时钟)**设为 No。

也就是同步 FIFO,写端和读端共用 s_axis_aclk。这种配置最省事,资源开销也更小,时序上没那么多额外问题。只有真的跨时钟域,才去开 Yes。

**CDC sync stages(跨时钟域同步级数)**保持默认 3,这项在同步 FIFO 下是灰的,不会起作用。

**Enable packet mode(启用包模式)**设为 No。

普通流模式下,只要 FIFO 里有数据,读端就会尽量往外吐。开了包模式以后,核会等到收到 TLAST 才开始输出整包数据。这个模式的意义很明确:避免包在中途被拆开,但代价就是延迟更高。不是所有场景都值得开。

ACLKEN conversion mode 维持 None。

**Enable ECC(启用 ECC 校验)**设为 No。这个选项主要是给可靠性更敏感的场景留的,开了会多吃一些逻辑资源。


**TDATA width(bytes)**设为 1,也就是 8 bit。

这意味着每个时钟周期传 1 字节。对纯验证 FIFO 行为来说,这个宽度最直观,也方便看波形。

Enable TSTRB 设为 No。

Enable TKEEP 设为 No。

Enable TLAST 也设为 No。

这里的选择其实很朴素:当前只想验证连续数据流,没必要把包边界、字节有效位这些边带信号都打开。如果后面要做帧级处理,再补 TLAST 就行。

TID / TDEST / TUSER width 都设为 0。

这些边带信息不参与当前测试,关掉后端口也会更干净。

image

写入侧我把几个状态信号都打开了,主要是为了看 FIFO 到底什么时候开始吃紧。

Enable write data count 设为 Yes,生成 axis_wr_data_count,它会告诉你当前 FIFO 里已经写进去了多少个 data word。这个信号用来判断剩余空间,比单看 TREADY 更直观。

Enable almost full 设为 Yes,生成 almost_full。它在 FIFO 只剩下一个写入位置时拉高,比真正写满提前一点报警。实际写流控的时候,这种提前量很有用,不然等 TREADY 掉下去再停,前级经常已经多发了一拍。

Enable programmable full 设为 No。

如果项目里需要更早的流控,可以自己设阈值,比如提前几百拍就开始限流。但这次测试没必要把接口再复杂化。

读侧也开了对应的状态信号。

Enable read data count 设为 Yes,生成 axis_rd_data_count。

Enable almost empty 设为 Yes,生成 almost_empty。

Enable programmable empty 设为 No。

如果是独立时钟模式,读写计数值属于各自的时钟域,读起来会有一点延迟和差异;同步模式下就简单得多,两个计数一般是一致的。这个差别在看波形时要有心理预期,不然很容易误以为计数不对。

官方例程可以直接拿来跑。

image

我这里主要看了三件事。

先是写速率比读速率快两倍的情况。例程里把 s_axis_tready 做成了周期性翻转:

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

这段逻辑的作用很直接:人为制造 backpressure。上游一会儿能写,一会儿不能写,FIFO 就只能把多出来的数据先塞进内部存储里。这样最容易看出缓存和满标志是不是按预期工作。

第二个现象是 tlast 一直为 1。原因也不绕,测试代码里复位后就是这么写的,属于显式赋值,不是 FIFO 自己推出来的。

image

第三个点是 FIFO 快满以后,读写节奏会逐渐对齐。这个现象在波形里很明显,说明 FIFO 已经进入正常的流控状态,前后端都开始围着缓冲深度做节拍调整。

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

仿真结果和预期一致。AXI4-Stream 这类接口本质上就是把读写拆成两条握手链路,FIFO 负责中间那段缓冲。逻辑不算花哨,但把 TREADY、计数器和边带信号看明白,后面接别的 IP 会省很多时间。

目录

  1. Vivado AXI4-Stream Data FIFO 配置与仿真记录
  2. 自测
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Web 开发里的 5 种加密算法:原理与代码
  • C++ list 容器的用法与简化实现
  • OpenClaw 飞书机器人部署记录
  • StyleSelectorXL:在 SDXL 里管理 77 种绘画风格
  • Python 3.12.0 的安装、环境配置与实战准备
  • 无人机检测数据集整理:11998 张图像与多格式标注
  • 大模型上下文窗口 200k 到底是什么
  • 鸿蒙金融理财全栈项目:运维监控、性能优化与安全加固
  • 2026 跨端框架怎么选:Flutter、RN、uni-app 与 KMP
  • 2025 年 AI IDE 怎么选:Trae、Copilot、Windsurf、Cursor 实测对比
  • Windows 下升级 Python 3.12 与多版本管理
  • ThinkPad T480 安装 macOS 的实用配置笔记
  • 前缀和解子数组计数:和为 K 与可被 K 整除
  • Ubuntu 24.04 LTS 虚拟机安装与常用配置
  • 麒麟服务器 V10 上搭建 ARM64 Docker 环境
  • Kali Linux 2025.4 发布:Wayland 默认、桌面与工具链更新
  • RAD Studio 13 Florence:Delphi 与 C++ Builder 的新变化
  • Linux 下安装 libwebkit2gtk-4.1-0 的方法与作用
  • CASIC MOTOR 14.8V 无刷减速电机拆解记录
  • 用 Trae Solo 模式做微信小程序:一次 2 小时实战

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online