FPGA 流式实战 · 03 流控反压与复位恢复

保证停顿期间数据不变,复现输出槽覆盖故障,并明确复位取消在途包的行为。

先修知识完成 FPGA AXI / CDC 进阶课程;掌握同步 FIFO、握手、Gray 编码和时序报告基础。

适用环境Basys 3 / Artix-7;板上写 100 MHz、读 50 MHz;Python 3、Icarus Verilog;Vivado 2024.1 命令参考。

验证状态六场景 RTL 测试、两类故障检出及顶层软件模型已验证;性能表为仿真测量,Vivado 与板上 ILA 尚需实测。

本文目录反压是接口行为,不是异常用不同流控模式激发设计边界故障注入与检查器验收典型故障:输出槽被提前覆盖

反压是接口行为,不是异常

当接收端暂时无法处理数据时,它可以降低 READY,而发送方仍需保留当前有效拍。FIFO 的输出寄存器让这一要求与 RAM 预取解耦:输出被消费时可以同拍替换为下一条,输出被阻塞时则必须停止预取。写端同样只在实际握手后推进源序号,队列满时所有数据字段保持,不能仅暂停其中一部分。

反压沿缓冲容量向上游传播;等待拍本身不得改变。接收端降 READY当前拍尚未消费输出槽保持data / keep / last停止预取fetch=0写满后反压源序号不前进仅在本域 VALID 与 READY 同时为 1 的时钟沿转移数据
反压沿缓冲容量向上游传播;等待拍本身不得改变。(原创示意,非器件引脚图;窄屏可横向滑动)

用不同流控模式激发设计边界

接收检查器提供始终接收、每八拍开放五拍、开始长暂停三种模式。周期模式用于量化长期接收能力,长暂停用于验证容量和反压传播;它们不能替代彼此。软件矩阵还在非空运行期间共同复位,再重新发送完整数据,证明旧 RAM 内容不会凭空成为新一轮有效输出。

设计契约与检查依据
项目工程含义
MODE=0始终 ready,观察源或读时钟带来的瓶颈
MODE=1每 8 个读周期允许 5 个,形成持续反压
MODE=2开始 80 个读周期暂停,强制填满
共同复位源、FIFO 两域和接收器一起重启;丢弃在途包
独立单域复位本实验不支持,需要额外的重新协商设计

可综合接收器;板上默认 MODE=1,实际握手才累计拍数、字节和包尾。

systemverilog
module stream_sink #(parameter N=4096,MODE=0)(input wire clk,rst,
 input wire [31:0] data,input wire [3:0] keep,input wire last,valid,
 output wire ready,output reg [31:0] received,bytes,packets,cycles,
 output reg done,fail);
 wire expected_last=received[2:0]==7;
 wire [3:0] expected_keep=expected_last?4'h3:4'hf;
 wire [31:0] expected_data=32'h60000000+received*17+3;
 assign ready=!rst && !done && (MODE==0 || (MODE==1?cycles[2:0]<5:cycles>=80));
 always @(posedge clk or posedge rst)begin
  if(rst)begin received<=0;bytes<=0;packets<=0;cycles<=0;done<=0;fail<=0;end
  else if(!done)begin
   cycles<=cycles+1'b1;
   if(valid && ready)begin
    if(data!=expected_data || keep!=expected_keep || last!=expected_last)fail<=1;
    received<=received+1'b1;bytes<=bytes+{31'b0,keep[0]}+{31'b0,keep[1]}+{31'b0,keep[2]}+{31'b0,keep[3]};
    if(last)packets<=packets+1'b1;
    if(received==N-1)done<=1;
   end
  end
 end
endmodule

故障注入与检查器验收

故障宏故意忽略输出槽可用条件,让 RAM 只要非空就预取。接收端处于反压时,旧输出尚未被消费就被新数据覆盖,稳定性检查会直接报告问题。另一种故障翻转数据最低位,在第一拍给出确定差异;两个负向测试只有发现规定的失败才算检查器通过,错误 RTL 本身仍然不合格。

  1. 检查源保持

    预期与判定:源 VALID=1、READY=0 后,下一拍全部字段保持。

  2. 检查输出保持

    预期与判定:读端遇反压,VALID 和 37 位记录保持。

  3. 运行两个故障

    预期与判定:稳定性错误和首拍数据错误分别被检出。

  4. 恢复正常与复位

    预期与判定:正常矩阵重跑,确认旧包被取消且重启后结果一致。

在解压后的 fpga-stream 目录执行;软件测试需要 Python 3、iverilog 和 vvp。

bash
python3 flow.py sim --stall-fault
# OUTPUT_UNSTABLE: backpressure overwrote payload
# STREAM_NEGATIVE_PASS
python3 flow.py sim --fault
# STREAM_MISMATCH beat=0,首拍 0x60000003 被改成 0x60000002
# STREAM_NEGATIVE_PASS
python3 flow.py bist --fault
# 软件模型两轮 led=11

典型故障:输出槽被提前覆盖

在吞吐优化时,开发者可能把持续预取误认为更快,删除了输出槽可用条件。这样波形仍在变化,甚至接收计数也在增加,但没有被握手的旧拍已经丢失。排障应先找反压开始后的第一个被改变字段,而不是只看最后的总数;本工程同时验证接口稳定与逐拍数据,避免两种错误互相掩盖。

完成检查

  • 源和接收端均验证反压稳定性。
  • 两类故障能得到确定诊断。
  • 复位取消在途包的边界明确。

延伸阅读与来源

本文为黄河电子原创教学说明。产品命令与支持范围请以实际安装版本的官方文档为准。

继续阅读

FPGA

从 RTL 到板上运行的完整流程

建立约束、实现、下载与观测的最小工程闭环。

10 分钟
FPGA

第一个工程的引脚与时钟约束

区分电气连接与时间要求,避免“能生成位流就算正确”。

11 分钟
FPGA

如何读懂时序报告

从起点、终点、时钟和裕量找出失败路径的原因。

10 分钟