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 预取解耦:输出被消费时可以同拍替换为下一条,输出被阻塞时则必须停止预取。写端同样只在实际握手后推进源序号,队列满时所有数据字段保持,不能仅暂停其中一部分。
用不同流控模式激发设计边界
接收检查器提供始终接收、每八拍开放五拍、开始长暂停三种模式。周期模式用于量化长期接收能力,长暂停用于验证容量和反压传播;它们不能替代彼此。软件矩阵还在非空运行期间共同复位,再重新发送完整数据,证明旧 RAM 内容不会凭空成为新一轮有效输出。
| 项目 | 工程含义 |
|---|---|
| MODE=0 | 始终 ready,观察源或读时钟带来的瓶颈 |
| MODE=1 | 每 8 个读周期允许 5 个,形成持续反压 |
| MODE=2 | 开始 80 个读周期暂停,强制填满 |
| 共同复位 | 源、FIFO 两域和接收器一起重启;丢弃在途包 |
| 独立单域复位 | 本实验不支持,需要额外的重新协商设计 |
可综合接收器;板上默认 MODE=1,实际握手才累计拍数、字节和包尾。
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 本身仍然不合格。
- 检查源保持
预期与判定:源 VALID=1、READY=0 后,下一拍全部字段保持。
- 检查输出保持
预期与判定:读端遇反压,VALID 和 37 位记录保持。
- 运行两个故障
预期与判定:稳定性错误和首拍数据错误分别被检出。
- 恢复正常与复位
预期与判定:正常矩阵重跑,确认旧包被取消且重启后结果一致。
在解压后的 fpga-stream 目录执行;软件测试需要 Python 3、iverilog 和 vvp。
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典型故障:输出槽被提前覆盖
在吞吐优化时,开发者可能把持续预取误认为更快,删除了输出槽可用条件。这样波形仍在变化,甚至接收计数也在增加,但没有被握手的旧拍已经丢失。排障应先找反压开始后的第一个被改变字段,而不是只看最后的总数;本工程同时验证接口稳定与逐拍数据,避免两种错误互相掩盖。
完成检查
- 源和接收端均验证反压稳定性。
- 两类故障能得到确定诊断。
- 复位取消在途包的边界明确。
延伸阅读与来源
本文为黄河电子原创教学说明。产品命令与支持范围请以实际安装版本的官方文档为准。
- Arm IHI0051A · AXI4-Stream Protocol
握手、字节限定与包尾;本文工程与测试为原创实现。
- AMD UG903 · CDC Constraints
跨域最大延时与总线偏斜约束。
- AMD UG474 · Distributed RAM Timing
分布式 RAM 的写入与异步读取时序特性。
- AMD UG908 · Programming and Debugging
ILA、探针文件与采集流程。
继续阅读
FPGA从 RTL 到板上运行的完整流程
建立约束、实现、下载与观测的最小工程闭环。
第一个工程的引脚与时钟约束
区分电气连接与时间要求,避免“能生成位流就算正确”。
如何读懂时序报告
从起点、终点、时钟和裕量找出失败路径的原因。
黄河电子