树形架构破解FPGA扇出瓶颈
通过构建基于 AXI Stream 协议的树形数据流切换架构包含 N 选 1 仲裁器和 1 分 N 分发器利用多级流水线寄存器打拍技术将原本集中式的大扇出Fanout信号分解为多层级的小扇出网络从而显著降低布线拥塞并提升 FPGA 最高工作频率。核心原理与优势分析树形结构通过将大规模的多路选择或分发任务分解为多个小规模的子任务如 2 选 1 或 N 选 1并在每一级逻辑之间插入寄存器Pipeline Registers实现了物理层面的信号隔离与时序优化。优化维度传统扁平化设计痛点树形结构 寄存器打拍方案优势扇出 (Fanout)单个控制信号需驱动大量负载导致布线延迟大成为时序瓶颈 。将大扇出拆解为多级小扇出每级仅驱动少量下级模块大幅降低单节点负载 。工作频率长组合逻辑路径和高压摆率限制导致 $F_{max}$ 难以提升。寄存器打拍切断了长组合逻辑链将关键路径限制在局部小树节点内显著提升 $F_{max}$ 。地址/通道管理业务模块需自行维护复杂的地址映射和路由逻辑。切换模块自动根据控制位CTL重写通道 ID业务模块无需感知路由细节 。扩展性增加输入/输出端口需重新设计整个多路选择器。支持参数化递归实例化可灵活构建任意规模$N$路的树形网络 。关键技术实现N 选 1 仲裁器 (Tree Arbiter)该模块采用递归生成Generate-Recursion方式构建。当输入端口数大于基数如 $N2$时先并行实例化多个底层仲裁器再将它们的输出作为输入传递给上一级仲裁器形成树状拓扑。关键步骤包含通道 ID 的自动注入与流水线寄存。// 树形 N 选 1 AXI Stream 仲裁器 // 功能将 NUM_IN 路输入汇聚为 1 路输出通过树形结构降低扇出 module tree_packet_arb_n_to_1 # ( parameter DAT_BYTS 8, parameter DAT_BITS DAT_BYTS*8, parameter CTL_BITS 8, parameter NUM_IN 8, // 总输入路数 parameter LOG2_NUM_IN NUM_IN 1 ? 1 : $clog2(NUM_IN), parameter OVR_WRT_BIT CTL_BITS - LOG2_NUM_IN, // 控制位中用于覆盖通道 ID 的起始位 parameter N 2, // 树的分支因子 (如 2 叉树) parameter MAX NUM_IN // 最大路数常量 ) ( input i_clk, i_rst, if_axi_stream.sink i_n_axi [NUM_IN-1:0], // 多路输入接口 if_axi_stream.source o_axi // 单路输出接口 ); localparam MOD_BITS $clog2(DAT_BYTS); localparam NUM_IN_GRP (NUM_INN-1)/N; // 计算本级需要的子模块数量 generate genvar g, h; // 定义内部互联接口 if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) o_axi_int [NUM_IN_GRP-1:0] (i_clk); for (g 0; g NUM_IN_GRP; g) begin: GEN_TREE_LEVEL // 计算当前组实际有效的输入数量 localparam NUM_IN_INT (g1)*N NUM_IN ? N : (NUM_IN % N); if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) i_axi_int [NUM_IN_INT-1:0] (i_clk); // 1. 输入连接与通道 ID 注入 for (h 0; h NUM_IN_INT; h) begin always_comb begin // 复制数据流信号 i_axi_int[h].copy_if_comb(i_n_axi[g*N h].dat, i_n_axi[g*N h].val, i_n_axi[g*N h].sop, i_n_axi[g*N h].eop, i_n_axi[g*N h].err, i_n_axi[g*N h].mod, i_n_axi[g*N h].ctl); // 反压传递 i_n_axi[g*N h].rdy i_axi_int[h].rdy; // 关键优化在入口处自动重写控制位标记数据来源通道 ID if (MAX NUM_IN) i_axi_int[h].ctl[OVR_WRT_BIT : LOG2_NUM_IN] g*N h; end end // 2. 实例化底层仲裁器 (带流水线寄存器 PIPELINE1) packet_arb_bp # ( .DAT_BYTS ( DAT_BYTS ), .DAT_BITS ( DAT_BITS ), .CTL_BITS ( CTL_BITS ), .NUM_IN ( NUM_IN_INT ), .OVR_WRT_BIT ( OVR_WRT_BIT ), .PIPELINE ( 1 ), // 启用寄存器打拍切断组合逻辑提高频率 .PRIORITY_IN ( 0 ), .OVERRIDE_CTL ( 0 ) ) packet_arb_bp_inst ( .i_clk ( i_clk ), .i_rst ( i_rst ), .i_axi ( i_axi_int ), .o_axi ( o_axi_int[g] ) ); end // 3. 递归构建上层树或输出最终结果 if (NUM_IN_GRP 1) begin // 若子模块输出多于 1 路递归调用自身构建上一级树 tree_packet_arb_n_to_1 # ( .DAT_BYTS ( DAT_BYTS ), .DAT_BITS ( DAT_BITS ), .CTL_BITS ( CTL_BITS ), .NUM_IN ( NUM_IN_GRP ), .OVR_WRT_BIT ( OVR_WRT_BIT ), .N ( N ), .MAX ( MAX ) ) tree_upper_level ( .i_clk ( i_clk ), .i_rst ( i_rst ), .i_n_axi ( o_axi_int ), .o_axi ( o_axi ) ); end else begin // 若仅剩一路直接连通 always_comb begin o_axi.copy_if_comb(o_axi_int[0].dat, o_axi_int[0].val, o_axi_int[0].sop, o_axi_int[0].eop, o_axi_int[0].err, o_axi_int[0].mod, o_axi_int[0].ctl); o_axi_int[0].rdy o_axi.rdy; end end endgenerate endmodule关键技术实现1 分 N 分发器 (Tree Distributor)分发器同样采用树形结构依据数据包控制位CTL中的通道 ID 将数据路由至指定输出端口。通过在树的中继节点插入流水线寄存器pipeline_bp_if确保高速时钟下信号能稳定传输至叶子节点。// 树形 1 分 N AXI Stream 分发器 // 功能将 1 路输入根据 CTL 位分发至 NUM_OUT 路输出利用树形结构降低扇出 module tree_packet_arb_1_to_n # ( parameter DAT_BYTS 8, parameter DAT_BITS DAT_BYTS*8, parameter CTL_BITS 8, parameter NUM_OUT 8, parameter LOG2_NUM_OUT NUM_OUT 1 ? 1 : $clog2(NUM_OUT), parameter OVR_WRT_BIT CTL_BITS - LOG2_NUM_OUT, parameter N 2, // 树分支因子 parameter MAX NUM_OUT ) ( input i_clk, i_rst, if_axi_stream.sink i_axi, // 单路输入 if_axi_stream.source o_n_axi[NUM_OUT-1:0] // 多路输出 ); localparam LOG2_MAX MAX 1 ? 1 : $clog2(MAX); localparam NUM_OUT_GRP (NUM_OUTN-1)/N; generate genvar g, h; // 情况 A: 输出数量较少直接进行逻辑判断分发 if (NUM_OUT_GRP 1) begin: FIRST_STAGE_GEN logic [NUM_OUT-1:0] rdy_i; always_comb i_axi.rdy |rdy_i; // 只要有一个输出准备好输入即可发送 for (h 0; h NUM_OUT; h) begin: FINAL_GEN logic in_range_i; // 根据 CTL 位计算目标通道索引 always_comb rdy_i[h] o_n_axi[h].rdy in_range_i; always_comb in_range_i i_axi.ctl[OVR_WRT_BIT : LOG2_MAX] / (MAX/NUM_OUT) h; always_comb begin // 仅当匹配当前通道时拉高 valid 信号 o_n_axi[h].copy_if_comb(i_axi.dat, i_axi.val in_range_i, i_axi.sop, i_axi.eop, i_axi.err, i_axi.mod, i_axi.ctl); end end end else begin // 情况 B: 输出数量多构建多级树形结构 if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) i_pipe [NUM_OUT_GRP-1:0] (i_clk); // 1. 递归调用自身先将数据分发到各个子树组 tree_packet_arb_1_to_n # ( .DAT_BYTS ( DAT_BYTS ), .DAT_BITS ( DAT_BITS ), .CTL_BITS ( CTL_BITS ), .NUM_OUT ( NUM_OUT_GRP ), .OVR_WRT_BIT ( OVR_WRT_BIT ), .N ( N ), .MAX ( MAX ) ) tree_upper_dist ( .i_clk ( i_clk ), .i_rst ( i_rst ), .i_axi ( i_axi ), .o_n_axi ( i_pipe ) ); // 2. 对每个子树组的输入进行流水线打拍并分发到具体端口 for (g 0; g NUM_OUT_GRP; g) begin: GEN_TREE_LEVEL localparam NUM_OUT_INT N; if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) o_pipe (i_clk); logic [NUM_OUT_INT-1:0] rdy_o; always_comb o_pipe.rdy |rdy_o; // 关键优化插入流水线级降低长路径延迟提高频率 pipeline_bp_if #( .DAT_BITS ( DAT_BITS ), .CTL_BITS ( CTL_BITS ), .NUM_STAGES ( 1 ) // 插入1 级寄存器 ) pipeline_stage ( .i_rst ( i_rst ), .i_clk ( i_clk ), .i_if ( i_pipe[g] ), .o_if ( o_pipe ) ); for (h 0; h NUM_OUT_INT; h) begin: FINAL_LEAF_GEN logic in_range_o; // 计算叶子节点的目标范围 always_comb in_range_o o_pipe.ctl[OVR_WRT_BIT : LOG2_MAX] / (MAX/NUM_OUT) g*N h; always_comb begin rdy_o[h] o_n_axi[g*N h].rdy in_range_o; o_n_axi[g*N h].copy_if_comb(o_pipe.dat, o_pipe.val in_range_o, o_pipe.sop, o_pipe.eop, o_pipe.err, o_pipe.mod, o_pipe.ctl); end end end endendgenerate endmodule实施要点总结寄存器打拍Pipeline Register在packet_arb_bp和pipeline_bp_if模块中显式启用流水线模式PIPELINE1或NUM_STAGES1。这是降低 Fanout 和提升频率的核心它将原本跨越整个多路选择器的组合逻辑路径切割为多个短路径 。自动通道管理利用CTL总线的高位动态写入通道 IDi_axi_int[h].ctl[...] g*N h使得下游模块无需硬编码地址逻辑只需解析数据包自带的控制字即可识别来源或去向简化了顶层逻辑 。参数化递归通过NUM_IN_GRP和递归实例化代码可自动适应任意规模的端口数无需手动修改层级结构保证了设计的通用性和可维护性 。参考来源一种Axi stream数据流可自动切换的IP模块一种Axi stream数据流可自动切换的IP模块【信息科学与工程学】计算机科学与自动化——第一百八十九篇 计算机硬件 系列一 微处理器01