ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于VU13P FPGA的多卡光纤级联:200Gbps数据汇聚与实时处理实战

基于VU13P FPGA的多卡光纤级联:200Gbps数据汇聚与实时处理实战 1. 项目缘起与整体设计思路1.1 为什么盯上VU13P这块板子第一次拿到VU13P板卡的时候我脑子里想的其实不是“算力有多猛”而是“这玩意儿到底怎么把数据喂饱”。VU13P属于Virtex UltraScale HBM系列逻辑单元规模在数百万级别片上集成了高带宽内存和大量高速收发器单看纸面参数确实漂亮。但做过高速数据采集的人都知道FPGA再强IO喂不进去数据就是空转。所以这个项目的核心命题从一开始就很明确用光纤口把多张VU13P板卡级联起来做200Gbps级别的数据汇聚与实时处理。这个需求在雷达信号处理、大规模图像拼接、分布式高速采集这些场景里非常典型。单卡处理能力有上限但数据源又分散在多个物理位置最合理的做法就是每张卡先做本地预处理然后通过高速光纤链路把结果汇聚到一张主卡上做二次融合。200Gbps这个量级换算成字节就是25GB/s已经远超普通PCIe Gen3 x16的带宽必须走高速串行收发器。1.2 整体架构怎么搭我最终确定的架构是“一主多从”的星型拓扑。主卡负责汇聚和最终处理从卡负责前端采集和预处理。每张从卡通过光纤口把数据送到主卡主卡上的收发器资源被分成多个通道每个通道对应一张从卡。这样做的好处是拓扑清晰主卡的资源分配和时序收敛都比较好控制。具体到VU13P它内部有多个高速收发器Quad每个Quad包含四个通道单通道线速率可以跑到25Gbps以上。如果我用4个通道做一组一组就能提供100Gbps的带宽。要凑够200Gbps至少需要两组也就是8个通道。实际布线时我会留出余量用12个通道来分配其中8个跑数据4个做备份或者控制通道。注意多卡级联最怕的就是时钟域混乱。每张卡都有自己的参考时钟光纤链路两端如果时钟不同源就必须做时钟域转换。我的做法是主卡向下游广播一个参考时钟从卡用CDR恢复出来的时钟去锁本地PLL这样整个系统的时钟是相干的。1.3 方案选型的几个关键取舍在收发器协议选择上我纠结过用Aurora还是自己写轻量级协议。Aurora 64B/66B的好处是Xilinx官方支持完善IP核配置简单但它的帧格式固定开销大约3%。自己写协议可以把开销压到1%以下但调试周期会拉长。考虑到项目时间节点我最终选了Aurora 64B/66B作为底层传输上层再包一层自定义的轻量级帧协议。另一个取舍是数据汇聚方式。一种做法是所有从卡把原始数据直接送到主卡主卡做全部处理另一种是每张从卡先做FFT或者滤波只把特征值送上来。前者对主卡压力大后者对从卡要求高。我选了折中方案从卡做一级预处理把数据量压缩到原来的四分之一再送到主卡。这样主卡的200Gbps带宽里实际有效载荷大约是150Gbps留出了足够的协议开销和重传余量。2. 核心细节解析与实操要点2.1 光纤口物理层配置VU13P的GTY收发器支持的最高线速率跟具体速度等级有关我手上这块是-2等级的单通道跑到25.78125Gbps没有问题。配置的时候有几个参数必须算清楚。首先是参考时钟频率。Aurora 64B/66B要求参考时钟和线速率之间满足特定关系。我用的参考时钟是156.25MHz线速率25.78125Gbps分频比是165。这个分频比在GTY的PLL可配置范围内但需要确认VCO频率落在合适区间。计算过程是这样的线速率除以2得到12.890625GHz这是VCO需要输出的频率。156.25MHz乘以165正好等于25.78125GHz再除以2就是12.890625GHz。VCO频率在GTY的允许范围内配置可以成立。其次是均衡器设置。光纤链路在25Gbps速率下信号衰减比较明显。我一开始用默认的DFE设置误码率在1e-9左右后来把DFE抽头数增加到7误码率降到了1e-12以下。具体配置是在GTY的RX均衡器里把DFE模式打开抽头系数根据实际链路长度调整。短距离链路小于10米用3个抽头就够了长距离建议用7个以上。// GTY收发器关键参数配置示例 GTY_CHANNEL #( .TX_LINE_RATE(25.78125), // 线速率Gbps .TX_REFCLK_FREQ(156.25), // 参考时钟MHz .TX_PLL_DIV(165), // PLL分频比 .RX_DFE_TAPS(7), // DFE抽头数 .RX_CDR_MODE(DFE) // CDR模式 ) gty_inst ( .tx_data(tx_data), .rx_data(rx_data), .tx_clk(tx_clk), .rx_clk(rx_clk) );2.2 多卡同步机制多卡级联最头疼的问题就是同步。每张卡上电时间不同内部复位释放时间也不同如果不做同步处理主卡收到的数据帧会错位。我的做法是在协议层加一个同步头主卡检测到同步头之后才开始计数。具体实现上主卡在每个通道的接收路径上放一个同步状态机。状态机初始处于搜索态检测到连续三个正确的同步头之后进入锁定态开始正常接收数据。如果连续丢失五个同步头就回到搜索态重新同步。同步头我用的是64位的固定序列在Aurora帧的起始位置插入。实操心得同步头的选择有讲究。不要用全0或者全1也不要用太短的序列。我用的是0x5A5AA5A5F0F00F0F这个序列的汉明距离比较大不容易被数据误触发。另外同步头最好加扰避免和有效载荷里的数据模式冲突。2.3 数据帧格式设计自定义帧格式这块我设计了一个固定长度的帧头加可变长度的载荷。帧头包含帧类型、源卡编号、目的卡编号、序列号、载荷长度和CRC校验。载荷长度最大支持4096字节最小64字节。序列号用于检测丢帧和乱序CRC用于检测传输错误。帧头一共16字节具体分配是这样的前2字节是帧起始标志0xEB90接着1字节帧类型1字节源卡编号1字节目的卡编号4字节序列号2字节载荷长度4字节帧头CRC最后1字节保留。载荷部分最大4096字节后面跟4字节的载荷CRC。字段长度说明帧起始2字节固定0xEB90帧类型1字节0x01数据帧0x02控制帧源卡编号1字节0-15目的卡编号1字节0-150xFF为广播序列号4字节递增计数载荷长度2字节64-4096帧头CRC4字节CRC32保留1字节对齐用载荷可变最大4096字节载荷CRC4字节CRC32这个帧格式的开销是20字节帧头加4字节帧尾总共24字节。对于4096字节的载荷来说开销不到0.6%完全可以接受。2.4 流量控制与背压处理200Gbps的汇聚带宽意味着主卡的接收路径压力很大。如果从卡发送速率超过主卡处理速率数据就会堆积。我在协议层加了基于信用的流量控制。主卡定期向从卡发送信用包告诉从卡当前可以发送多少字节。从卡维护一个信用计数器每发一帧就减去相应字节数收到信用包就增加。信用包的发送周期是1微秒每次发送的信用额度根据主卡内部FIFO的空闲空间动态调整。FIFO水位低于25%时全额发放信用25%到75%之间减半发放超过75%就暂停发放。这样可以在不丢帧的前提下平滑流量。注意信用包本身也要走光纤链路会占用带宽。我把信用包做得很小只有8字节而且用独立的控制通道传输不占用数据通道的带宽。3. 实操过程与核心环节实现3.1 硬件连接与上电顺序硬件连接看起来简单但顺序错了会出问题。我的标准流程是这样的先连接光纤确保所有光纤都插到位卡扣扣紧然后给从卡上电等从卡的电源指示灯稳定最后给主卡上电。这个顺序的原因是主卡上电后会立即开始发送同步信号如果从卡还没准备好主卡会一直处于搜索态虽然不会损坏硬件但会延长同步时间。光纤模块我用的是QSFP28封装支持100Gbps聚合。每张从卡插两个QSFP28模块每个模块提供100Gbps带宽。主卡插四个模块其中两个用于接收从卡数据另外两个做级联扩展。光纤跳线用的是多模OM4长度控制在30米以内再长就需要换单模模块了。上电之后先检查GTY的PLL锁定状态。在Vivado的硬件管理器里可以看到每个通道的PLL Lock信号全部为高才说明物理层通了。如果有通道没锁定先检查参考时钟有没有送到再检查光纤模块的供电是否正常。3.2 Aurora IP核配置与例化Aurora 64B/66B IP核的配置界面参数比较多我挑几个关键的说明。Lane Width我设成4也就是四个通道绑定成一组这样一组提供100Gbps。Interface我选Framing因为需要传输自定义帧。Flow Control我关掉了IP核自带的用自己的信用机制。CRC我选的是每帧都校验虽然会增加一点延迟但可靠性更高。例化的时候要注意时钟连接。Aurora IP核需要两个时钟init_clk和gt_refclk。init_clk我用的是100MHz的板载晶振gt_refclk用的是156.25MHz。两个时钟的相位关系不需要严格对齐但频率精度要在正负100ppm以内。aurora_64b66b_0 aurora_inst ( .init_clk(init_clk_100m), .gt_refclk(gt_refclk_156m), .tx_system_reset(tx_reset), .rx_system_reset(rx_reset), .tx_data(tx_data), .tx_valid(tx_valid), .tx_ready(tx_ready), .rx_data(rx_data), .rx_valid(rx_valid), .rx_ready(rx_ready), .lane_up(lane_up), .channel_up(channel_up) );channel_up信号是所有通道都同步之后的指示。这个信号拉高之后才能开始发送数据。我实测下来从上电到channel_up拉高大约需要200毫秒主要时间花在CDR锁定和通道对齐上。3.3 数据汇聚逻辑实现主卡的数据汇聚逻辑是整个项目的核心。我用了两级FIFO结构第一级是每个通道独立的接收FIFO深度设为8192字节第二级是汇聚FIFO深度设为65536字节。每个通道的接收FIFO收到完整帧之后把帧数据推送到汇聚FIFO。汇聚FIFO的输出连接到后级处理模块。汇聚逻辑的状态机有四个状态空闲、接收帧头、接收载荷、校验。空闲态等待帧起始标志检测到0xEB90之后进入接收帧头态收满16字节帧头后计算CRCCRC正确就进入接收载荷态根据载荷长度字段接收相应字节数最后校验载荷CRC。如果任何一步出错状态机回到空闲态并丢弃当前帧。// 汇聚状态机核心逻辑 always (posedge clk) begin case(state) IDLE: begin if (rx_data[15:0] 16hEB90) begin state HEADER; byte_cnt 0; end end HEADER: begin header[byte_cnt*8 : 8] rx_data[7:0]; byte_cnt byte_cnt 1; if (byte_cnt 15) begin if (crc32(header) rx_crc) begin state PAYLOAD; byte_cnt 0; payload_len header[47:32]; end else begin state IDLE; end end end PAYLOAD: begin payload[byte_cnt*8 : 8] rx_data[7:0]; byte_cnt byte_cnt 1; if (byte_cnt payload_len - 1) begin state CHECK; end end CHECK: begin if (crc32(payload) rx_crc) begin // 推送到汇聚FIFO fifo_wr_en 1b1; end state IDLE; end endcase end实操心得状态机的位宽要算清楚。payload_len是16位最大4096byte_cnt需要13位才能表示0到4095。我一开始用12位结果4096的帧会溢出调试了半天才发现。这种位宽问题在高速逻辑里很常见建议所有计数器都留一位余量。3.4 时序收敛与布局约束VU13P的规模虽然大但200Gbps的数据路径对时序要求很高。我在实现的时候遇到了几个典型的时序问题。第一个是跨时钟域路径GTY的恢复时钟和系统时钟之间的路径需要做异步处理。我用的是双触发器同步器加握手信号对于数据路径则用异步FIFO。第二个是高速数据路径的布线延迟。Vivado的默认布局会把相关逻辑放得比较散导致布线延迟过大。我加了Pblock约束把每个通道的接收逻辑约束在对应的GTY Quad附近。这样布线延迟从原来的3纳秒降到了1.2纳秒时序余量从负0.5纳秒变成了正0.8纳秒。# Pblock约束示例 create_pblock pblock_gt0 add_cells_to_pblock pblock_gt0 [get_cells -hierarchical -filter {NAME ~ *gt0_rx*}] resize_pblock pblock_gt0 -add {SLICE_X0Y0:SLICE_X50Y100}第三个是时钟树的问题。多个GTY通道的恢复时钟如果走全局时钟树会有比较大的偏斜。我把每个通道的恢复时钟约束在区域时钟树上偏斜从200皮秒降到了50皮秒以内。3.5 实测数据与性能分析系统跑起来之后我用ILA抓了实际的数据流。在满负荷情况下主卡汇聚FIFO的写入速率稳定在24.8GB/s左右对应198.4Gbps接近200Gbps的理论上限。误码率方面连续跑24小时没有出现CRC错误说明链路稳定性没问题。延迟方面从从卡采集到主卡输出端到端延迟大约是1.2微秒。这个延迟主要来自三个方面从卡的预处理延迟约300纳秒光纤传输延迟约100纳秒30米光纤主卡的汇聚和校验延迟约800纳秒。对于大多数实时处理场景来说这个延迟是可以接受的。指标实测值理论值说明汇聚带宽198.4Gbps200Gbps含协议开销端到端延迟1.2微秒-从采集到输出误码率1e-12-24小时无错同步时间200毫秒-上电到channel_up资源占用42% LUT-含所有逻辑4. 常见问题与排查技巧实录4.1 链路无法同步的排查思路链路同步失败是最常见的问题表现是channel_up一直不拉高。我的排查顺序是这样的先看GTY的PLL Lock信号如果不锁定说明参考时钟有问题用示波器量一下参考时钟的频率和幅度如果PLL锁定了但channel_up不拉高检查lane_up信号看是哪个通道没对齐如果lane_up都高了但channel_up不拉高说明通道间的偏斜太大需要调整RX Buffer的延迟。有一次我遇到四个通道里有一个始终不对齐换了光纤模块也不行。后来发现是那个通道的PCB走线长度和其他通道差了5毫米导致偏斜超过了Aurora的容忍范围。解决办法是在Vivado里手动调整那个通道的RX延迟补偿走线差异。注意光纤模块的兼容性问题也很常见。不同厂家的QSFP28模块在CDR参数上可能有差异建议用同一批次的模块。我试过混用两个厂家的模块结果有一个通道的误码率明显偏高换成同厂家之后问题消失。4.2 数据错帧与CRC错误的处理CRC错误说明链路有误码。如果偶尔出现可能是光纤连接器脏了用专用清洁笔擦一下。如果频繁出现先检查DFE均衡器设置把抽头数增加试试。如果还是不行降低线速率看看比如从25Gbps降到20Gbps如果误码消失说明链路裕量不够需要换更好的光纤或者缩短距离。我遇到过一次CRC错误率突然升高的情况排查了半天发现是机房空调故障导致温度升高GTY的工作温度超过了85度误码率就上去了。所以高速链路对温度也很敏感散热要做好。4.3 流量控制失效的应急处理信用机制偶尔会失效表现是从卡一直在等信用包数据发不出去。这种情况通常是信用包丢失导致的。我在协议里加了超时重传机制从卡如果超过10微秒没收到信用包就主动发送一个信用查询包。主卡收到查询包后立即回复当前信用额度。还有一种情况是信用计数器溢出。如果从卡长时间没收到信用包计数器会一直累加超过最大值后回绕。我在代码里加了饱和处理计数器到最大值就不再增加避免回绕导致误判。4.4 常见问题速查表现象可能原因排查方法解决方案channel_up不拉高参考时钟异常示波器量参考时钟检查晶振和时钟分配单通道lane_up不拉高光纤或模块问题换模块换光纤清洁或更换CRC错误率高链路裕量不足看眼图增加DFE抽头或降速数据错帧同步丢失抓ILA看同步状态重新同步或检查同步头流量控制失效信用包丢失抓控制通道数据启用超时重传时序不收敛布局不合理看时序报告加Pblock约束温度过高散热不良读GTY温度改善散热4.5 几个容易忽略的细节第一个是复位信号的亚稳态问题。GTY的复位信号如果来自异步时钟域必须做同步处理。我一开始直接用了外部按键复位结果偶尔出现复位不彻底的情况。后来加了复位同步器问题解决。第二个是电源纹波。GTY对电源纹波很敏感特别是1.0V的模拟电源。我用示波器量过纹波超过20mV就会影响误码率。建议在电源引脚附近多放几个去耦电容100nF和10uF搭配使用。第三个是PCB走线的阻抗控制。GTY的差分走线要求100欧姆差分阻抗误差控制在正负10%以内。如果阻抗不匹配反射会导致眼图闭合。这个在画板阶段就要注意后期没法改。5. 项目扩展与个人体会这套架构跑通之后我做了几个扩展实验。一个是把从卡数量从4张增加到8张主卡用两组GTY分别接收汇聚带宽提升到400Gbps。另一个是在主卡上加了DSP模块对汇聚后的数据做实时FFT验证了200Gbps数据流下的实时处理能力。我个人在实际操作中的体会是多卡级联项目的难点不在单点技术而在系统集成。每个模块单独测都没问题但连在一起就会出现各种意想不到的交互问题。我的建议是分阶段验证先通物理层再通协议层最后通应用层。每个阶段都要有明确的测试用例和通过标准不要跳步。另外文档和版本管理很重要。GTY的配置参数、Aurora的IP版本、约束文件的内容这些都要记录清楚。我吃过亏换了IP版本之后时序结果完全不一样因为没有记录旧版本的参数重新调了好几天。现在我的做法是每次综合实现之后都把关键参数和时序报告存档方便回溯。最后分享一个小技巧ILA的触发条件可以设成CRC错误这样一旦出现误码就能抓到现场数据。我把ILA的存储深度设成最大触发位置设成中间这样能看到错误前后的完整数据流。这个对排查偶发性错误特别有用。
返回列表