Routing 模块技术手册
本文面向需要理解、接入或调试 src/routing 的开发者,流程、数据结构和模式选择均以当前模块实现为准。
目录
1. Routing 在完整流程中的位置
Partition 决定逻辑节点属于哪个 FPGA/Die;Routing 在固定划分结果上选择跨分区线网的物理互连;TDM 再在已选共享链路上分配最终复用比例和延迟。
| 主要输出 | 含义 | 用途 |
|---|---|---|
cut_nets | 跨物理分区线网 | 布线、TDM、结果检查 |
cut_timing_paths | 压缩后的物理时序路径 | 关键度排序、WNS 评估 |
route_trees | 每个原始 net 的物理边集合 | TDM 与内部统计 |
route_trees_edges | 带端口和分区信息的布线边 | 结果回写 |
2. 算法总览
2.1 布线闭环
默认时序布线是一个“投影—排序—增量布线—全局评估—拆线重布”的闭环,不是一次固定权重最短路。
等价路径压缩
动态候选选择
离散全局评分
rip-up/reroute
cut_nets, cut_paths = reform_timing_paths()
order = timing_order(zero_load_shortest_distance)
baseline = route_all(common_cost, order)
timingSeed = route_all(timing_externality_cost, order)
current = discrete_score_and_choose(baseline, timingSeed)
repeat:
targets = nets_on_lowest_slack_paths(current)
backup_all_incremental_state()
rip_up(targets)
reroute(targets)
if discrete_global_score() improves: commit
else: rollback; break
2.2 板级与 Die 级布线
| 条件 | 布线节点 | 默认入口 | 建模重点 |
|---|---|---|---|
!has_die | FPGA | Routing::routing() | GIO/MGT 离散方向容量与层次跨度 |
has_die | 展平的 FPGA/Die | Routing::die_routing() | 片内固定边与跨 FPGA TDM 边 |
2.3 多层级拓扑处理
fpga_hierarchy_paths[i] 描述第 i 个 FPGA 从高层容器到本地位置的层级路径。典型结构如下:
Rack
└── Cluster
└── Board
└── FPGA
└── Die
| 处理位置 | 多层级处理方式 |
|---|---|
| 节点表示 | 无 Die 时使用 FPGA ID;有 Die 时先把 {FPGA, Die} 展平为物理节点 ID |
| 范围识别 | delay_scope_for_parts() 比较两个 FPGA 的层级路径,识别 Board、InterBoard、InterCluster 或 InterRack |
| 延迟查询 | 延迟库含分范围模型且平台提供层级路径时,自动启用 use_hierarchy_delay,按范围查询 GIO/MGT ratio、delay 和 slope |
| 候选选择 | estimate_link() 使用对应范围的离散档位与延迟,因此跨越更高层级的连接具有独立物理代价 |
| 全局评价 | 沿最差路径累计 scope_cost;WNS 持平时优先层级跨度较小的候选 |
四级路径可区分 Rack、Cluster、Board;三级路径可区分 Cluster、Board;二级路径可区分 Board。缺少有效层级路径或分范围延迟模型时使用 Default 模型。
有 Die 时,delay_scope_for_parts() 当前按 part / 4 还原 FPGA ID,即层级延迟范围识别假设每个 FPGA 有 4 个 Die。若平台的 dies_per_fpga 不是 4,需要先同步该映射逻辑。
3. 核心数据结构
3.1 cut_net
| 字段 | 说明 |
|---|---|
fpga_nodes | 源分区和去重汇分区 |
net_id | 原始超图 net ID |
route_graph | 当前布线树父节点数组 |
routing_cost | 排序使用的静态代价 |
bypass | 是否要求 bypass 物理边 |
3.2 cut_timing_path
| 字段 | 说明 |
|---|---|
path | 物理节点序列 |
arcs | 相邻割事件的局部 cut-net ID |
slack | 投影前保留的裕量 |
cut_slack | 当前物理布线后的裕量 |
period / clock_domain | 时钟约束 |
operator== 与哈希均比较 path 和 arcs,它们共同定义当前压缩等价类。
3.3 两种布线树
flat_hash_map<int, set<pair<int,int>>> route_trees;
flat_hash_map<int, vector<RouteTreeEdge>> route_trees_edges;
前者服务算法与 TDM;后者带稳定端口名和分区端点,服务结果回写。
4. 割线网提取与时序路径压缩
4.1 割线网提取
reform_timing_paths() 只保留端点跨越两个及以上物理分区的 net。fpga_nodes[0] 为源分区,其余为去重汇分区;net_id 保留原始 net ID,new_net_id 建立它到局部 cut-net ID 的映射。
cut_timing_path::arcs 存局部 cut-net 下标,而 route_trees 使用原始 net_id 作为 key。
4.2 路径投影与折叠
逻辑节点: a0 -> a1 -> b0 -> b1 -> c0
物理分区: A -> A -> B -> B -> C
投影路径: A --------> B --------> C
割线网弧: net_x net_y
连续落在同一物理分区的逻辑节点被折叠,只保留真实割事件。全程同分区、映射无效、没有有效割边或缺失必要时钟信息的路径不会进入时序布线。
4.3 等价类与最坏代表
Routing 以 (path, arcs) 为压缩键。键相同的路径只保留 slack 较小者,并保存其原始路径 ID。
key = (projected_physical_nodes, projected_cut_net_arcs)
if key is new:
representative[key] = path
else if path.slack < representative[key].slack:
representative[key] = path
压缩只减少布线阶段的重复计算;最终签核仍应在完整原始路径集合上进行。
5. 时序路径与线网排序
5.1 零负载延迟预测
统一板级布线先在零负载拓扑上计算最短距离。压缩路径的预测 slack 为原始裕量减去所有割事件的预计物理延迟:
cut_slack 越小,路径越先布线。各算法分支的平局规则略有不同,调试和性能记录应同时保存实际模式参数。
5.2 路径顺序转换为 net 顺序
P0: n3 -> n8 -> n5 (最关键)
P1: n8 -> n2
P2: n7 -> n3
首次出现顺序: n3, n8, n5, n2, n7
扫描路径时,同一 net 只加入一次。没有出现在压缩路径中的剩余割线网按静态 routing_cost 从大到小追加。
d_max:最远汇端距离;d_avg:所有汇端平均距离;γ:routing_cost_factor;η_clock:相应分支启用的多时钟归一化项。
路径压缩决定哪些物理决策不同;路径排序决定谁先获得稀缺资源;线网排序把路径级关键度转换成实际执行序列。
6. 候选边的容量、延迟与时序外部性
对候选有向边 (u,v),布线器检查方向、GIO/MGT 容量、bypass 类型、离散 TDM 档位、候选自身延迟以及它对既有关键流量造成的延迟增长。不可行候选直接设为无穷大。
6.1 异构链路估计
new demand
|-- GIO split q_gio -> ratio r_gio -> delay D_gio
`-- MGT split q_mgt -> ratio r_mgt -> delay D_mgt
check direction / capacity / clock / bypass
choose minimum-delay feasible split
estimate_link 会在离散选择边界附近试探负载拆分。新增一条线网可能让比例从 r 跳到 r+1,从而同时提高已在该边上的连接延迟。
6.2 代价模式
| 模式 | 候选代价重点 |
|---|---|
critical_minmax | 自身平均延迟 + 对已标记关键链路的最坏增量 |
critical_minmax_hop | 上项 + 层次/跳数惩罚 |
total_externality | 自身平均延迟 + 对全部既有流量的总增量 |
total_externality_zero | 关闭 total externality,用于对照实验 |
7. Dijkstra 选择与多汇布线树
统一板级布线从 fpga_nodes[0] 执行一次动态边权 Dijkstra,得到 prev[],随后从每个汇端回溯到源端。共享树干通过 visited 去重,回溯边并集构成布线树。
source S
|\
| `---- X ---- sink B
`------ Y ---- sink A
`----- sink C
7.1 增量状态更新
- 增加有向
route_load[u][v]; - 更新兼容统计使用的
cut_mat; - 登记关键链路使用;
- 立即刷新受影响的
cost_mat。
因此后布线 net 会看到前面 net 已造成的拥塞和 ratio 变化,避免大量线网同时抢占一条静态“便宜边”。
统一板级实现使用源端前驱树后回溯取并集。部分 Die 级和实验分支采用不同的汇端排序或增量连接策略,应以 routingFlow() 实际选择的函数分支为准。
7.2 不可达的常见原因
- 方向容量为零或拓扑断开;
- GIO/MGT 离散选择均不可行;
- bypass 类型与边不匹配;
- 容量矩阵尺寸或节点映射错误。
8. 离散全局评估与初始种子
Dijkstra 使用局部边代价,而最终 TDM 比例由整张布线共同决定。统一布线会执行 dry-run 离散打包,并用同一口径评分 common baseline 和 timing seed。
RouteScore 指标 | 含义 |
|---|---|
min_slack | 所有压缩路径的最差 slack |
worst_path_hops | 最差路径的物理跳数 |
worst_path_scope_cost | 最差路径的层次跨度代价 |
total_route_edges | 全部布线树边数 |
max_utilization | 最拥塞链路利用率 |
feasible | 离散容量和方向约束是否满足 |
Common baseline
偏向跳数与有界利用率,提供稳健的非时序起点。
Timing seed
使用关键路径 externality,争取更好的初始 WNS。
两个初始解都经过离散全局评分后再选优,避免局部时序估计破坏整体可行性。
9. 关键路径拆线重布
9.1 目标选择
板级统一布线执行至多 K 轮重布,候选不再改善时提前结束。每轮选择一组当前 slack 最差的压缩路径,取其 arcs 并集作为目标线网;路径内线网按最差 slack 优先,其余按 routing_cost 排序。K 和关键路径数量目前由对应布线分支内部的迭代上限控制,尚未接入顶层配置参数。
9.2 全状态事务
backup:
route_trees, route_graph, route_load,
cut_mat, cost_mat, critical_link_usage
rip-up -> decrement loads -> refresh costs
reroute -> update loads/costs after each edge
evaluate -> discrete global RouteScore
improved: commit
otherwise: restore every backed-up structure
只恢复布线树而不恢复负载或代价会污染下一轮,因此回滚必须覆盖全部增量状态。
9.3 板级验收
- 候选必须可行;
min_slack改善超过1e-3时提交;- 在
critical_minmax系列中,slack 精确持平时依次比较最差路径跳数、层次跨度、总边数、最大利用率; - 否则回滚并结束本轮重布循环。
9.4 Die 级差异
die_routing() 使用相同的迭代上限与提前终止框架,但每轮围绕单条最差路径。候选需要 slack 改善超过 1e-3,且不能同时让 TDM cut 和 die cut 变坏。
10. 参数速查与流程分支
10.1 顶层开关
| 参数 | 作用 |
|---|---|
route | 布线总开关 |
has_die | 板级或展平 Die 级布线 |
routing_mode | 启用时序代价和关键网重布 |
legacy_non_timing_routing | 非时序场景使用旧板级 Dijkstra |
test | 选择默认算法或实验对照分支 |
10.2 test 分支
| test | 无 Die | 有 Die |
|---|---|---|
| 0 | routing() | die_routing() |
| 1 | 默认流程 | die_routing_old() |
| 2 | 默认流程 | die_routing_direction() |
| 3 | board_routing_huang() | die_routing_huang() |
| 4 | Synergistic 实验布线 | Synergistic 实验布线 |
| 5 | Near-optimal 实验布线 | Near-optimal 实验布线 |
test=1..5 用于实验对照;常规流程建议使用 test=0。
10.3 代价参数
| 参数 | 常见值 | 作用 |
|---|---|---|
routing_cost_factor | 0.5 | externality / 平均距离权重 |
timing_routing_cost_mode | critical_minmax_hop | 时序候选代价模型 |
timing_hop_penalty_multiplier | 0.5 | 层次跳数惩罚倍率 |
gio_channel_grouping_capacity | 23 | 单根 GIO 折算逻辑通道数 |
delay_lib_path | 空 | GIO/MGT ratio-delay JSON |
11. 输入、构造与调用
| 输入 | 用途 |
|---|---|
finest | nets、incident_nodes、net_bypass |
parts / die_parts | 逻辑节点到 FPGA 或 FPGA/Die 的映射 |
fpga | 拓扑、方向容量、GIO/MGT、层次路径 |
SimpleTiming | 路径节点、net、slack、period、clock domain |
DelayLibrary | 离散比例的 GIO/MGT 延迟 |
11.1 流程调用
vector<CutConnection> cutConnections;
routing_flow::routingFlow(
finest, parts, die_parts, fpgas, cutweights,
para, router, pFlow, &delayLib, cutConnections);
if (para.route) {
tdm::executeTDM(router, fpgas, para, delayLib);
}
有 Die 模式必须保证 die_parts.size() == finest.nodes.size(),展平编号为 fpga_id * dies_per_fpga + die_id。
12. 输出检查与调试顺序
routingFlow() 会写出 routing_cut_info.json;其中 top_port_connection 保存参与布线的跨分区端口,route_graph 保存有效父节点图。
- 检查投影:
cut_net.net_id/fpga_nodes与cut_timing_path.path/arcs; - 检查可达:方向容量、GIO/MGT 类型、bypass 限制;
- 检查树:每个汇端是否能沿父节点回到源端;
- 检查负载:每条树边是否只在
route_load/cut_mat计数一次; - 检查离散可行性:ratio 档位、方向超限和延迟库;
- 检查 slack 口径:压缩、多时钟归一化和 TDM 延迟是否一致;
- 检查回滚:失败候选后所有备份结构是否同时恢复。
13. 算法环节与代码位置
| 处理环节 | 当前行为 | 主要代码或状态 |
|---|---|---|
| 路径压缩 | 按 (path, arcs) 分组并保留最坏 slack | reform_timing_paths() |
| 关键优先 | 使用零负载预计延迟更新并排序 cut_slack | cut_timing_paths、线网顺序 |
| 动态选择 | 联合考虑 TDM ratio、方向容量和已有流量 | estimate_link、cost_mat、Dijkstra |
| 异构连接 | 分别检查 GIO/MGT 容量和延迟档位 | 离散类型选择与可行性检查 |
| 时序外部性 | 估算候选对既有关键连接的延迟影响 | critical_minmax、total_externality |
| 拆线重布 | 板级选择最差路径集合,Die 级选择单条最差路径 | backup、rip-up、reroute、rollback |
| 候选验收 | 以最差 slack 为一级目标,再比较物理指标 | RouteScore |
进行性能比较或时序回归时,应固定代码版本、test、routing_mode、代价模式、延迟库和平台拓扑。
14. 常见问题与调优
Q1:只设置 route=true,为什么没有进入无 Die 布线?
无 Die 分支还要求 IO 约束有效且 cutweights 非空。检查平台容量解析和 Partition 是否产生跨 FPGA 线网。
Q2:为什么有空布线树?
可能是投影后仅剩一个物理端点,也可能是方向、类型或离散容量使汇端不可达。先区分“无需布线”和“布线失败”。
Q3:没有延迟库能否运行?
可以退回默认延迟模型,但异构 GIO/MGT 的档位延迟可能不够准确。性能比较和时序回归应固定延迟库版本。
Q4:为什么最短跳数路径没有被选中?
时序模式优化插入后的延迟和对既有关键流量的影响,而不是纯 hop count。TDM 档位跳变或层级范围变化可能让更长路径具有更低全局代价。
Q5:为什么拆线后 slack 没改善就立即回滚?
当前实现采用保守的单调验收,避免用暂时恶化 WNS 的中间状态换取不确定的后续收益。
- 先确认方向、容量、bypass 和时钟约束可行;
- 校验
fpga_hierarchy_paths、分范围延迟库和dies_per_fpga; - 对比
critical_minmax_hop与total_externality; - 再调整
routing_cost_factor和timing_hop_penalty_multiplier; - 同时观察 WNS、最差路径 hop/scope、总布线边数和最大利用率。