以下内容总结自《深亚微米FPGA结构与CAD设计》- 作为一个读书笔记与大家共享。部分内容为AI补充,不对的地方还请指出。
一、VPR 布局器概述:为"可变结构"而生
VPR(Versatile Place and Route)是一套非常经典的 FPGA CAD 工具,其设计目标就是两个字:通用。
在布局阶段,VPR 做了几件事:
- 把逻辑单元块和 I/O 管脚放到一个二维网格上;
- 支持参数化的 FPGA 结构描述:
- 逻辑块 I/O 引脚数量;
- 每行/每列的 I/O 数目;
- 各布线通道的相对宽度;
- 支持多种成本函数和约束(如是否锁定 I/O 位置)。
VPR 内部采用的是模拟退火(Simulated Annealing) 布局算法,第三章的后半部分重点在于:如何让退火过程足够快,同时布局结果足够好。
二、新型自适应退火表:让退火"聪明一点"
2.1 初始温度设定
借鉴 Huang 等人的方法:
- 随机生成一个布局;
- 对逻辑块和 I/O 做 (N) 次随机交换((N) 为块和 I/O 总数);
- 计算这 (N) 次交换所造成成本变化的均方差 σ;
- 初始温度设为:
这样可以保证退火初期几乎所有移动都被接受,有利于跳出差解。
2.2 每个温度点的移动次数
- 每个温度点进行的移动次数为:
-
(N):块数量;
-
InnerNum:可调参数(默认 10)。
实测:
- 若把 InnerNum 从 10 降到 1,布局质量可能下降 5%--10%,但 CPU 时间直接减少约 10 倍;
- 这为工程实践提供了一个非常直接的"时间 vs 质量"调节旋钮。
2.3 接受率驱动的温度更新策略
新退火表的核心在于:用接受率 α 来调整降温速度。接受率定义为当前温度下,被接受的移动占总移动的比例。
新温度计算为:
直观理解:
- 若当前温度太高(α≈1),说明几乎所有移动都被接受,搜索过于"散漫",就要加速降温;
- 若当前温度过低(α 很小),说明几乎没有移动被接受,系统已经"冻结",也要快速降温以结束退火;
- 当 α≈0.44时,退火过程最有效,此时 γ≈1,维持温度不变,多做几轮探索。
2.4 退火终止条件
退火在以下条件满足时终止:
- Nnets:线网总数;
- ϵ:常数,取 0.005。
含义:当温度相对于每条线网的平均成本已经非常小时,再尝试接受成本上升的移动已经没有意义,继续退火只是在浪费时间。
2.5 与 Huang 退火表的比较
文中对 8 个 MCNC 电路测试,结果大致如下(表 3.3):
- 对 6 个中小电路:
- 新退火表平均快 1.35 倍,成本只略高 0.9% 左右;
- 对 2 个大电路:
- Huang 表在 alu4 上 CPU 时间约为新表的 3.8 倍;
- 在 bigkey 上即便多花 40 倍时间仍未收敛;
- 8 个电路算术平均:
- 新退火表在 CPU 时间上优于 Huang 表约 6.5 倍,
- 最终布局成本还略低 1.5%。
结论很明确:
新退火表不仅平均更快,而且在"最坏情况"上更加可靠,可预测性强,更适合作为通用 CAD 工具的默认方案。
三、线性拥挤成本函数:面向不均匀布线结构的建模
3.1 动机:中心通道更宽怎么办?
许多 FPGA 结构中,不同区域的通道宽度并不相同,例如:
- 芯片中心区域的通道更宽;
- 边缘区域通道相对较窄。
如果仍然使用传统的"边界框"成本函数,只看线网的几何跨度,就无法区分这些资源差异,布局结果也不一定有利于全局布线。
3.2 线性拥挤成本函数定义
文中提出的线性拥挤成本(linear congestion)为:
- bbx(i),bby(i):线网 i 边界框在 x / y 方向的跨度;
- Cav,x(i),Cav,y(i):线网 i 所在边界框内,x / y 方向通道宽度的平均值(可理解为"可用轨道数");
- β:调整对拥挤的惩罚程度,实验发现 β=1 时效果较好。
特点:
- 当所有通道宽度相同时,Cav为常数,线性拥挤成本退化为标准边界框成本;
- 当某个区域通道更窄时,线网边界框若横跨该区域,则会被额外"惩罚",促进布局把高需求线网往宽通道区域倾斜。
3.3 与非线性拥挤成本的比较
非线性拥挤成本的思路是把 FPGA 划分为 M×M个小区域,对每个区域的"布线供需差"进行精细建模,这在经典文献中已有介绍。
文中的对比结果(表 3.4)可以概括如下:
| 成本函数 | 对 36 电路平均布线轨道需求 | CPU 时间 |
|---|---|---|
| 边界框 | 基准 | 1X |
| 线性拥挤 | 轨道数减少约 7% | 1X |
| 非线性拥挤(16 区) | 比线性拥挤再少约 1% | 5X |
| 非线性拥挤(256 区) | 比线性拥挤再少约 3% | 80X |
可见:
- 非线性拥挤在极限情况下可以稍微减少布线轨道(多 1%3% 优势),但 CPU 时间代价惊人(5X80X);
- 而线性拥挤成本函数在几乎不增加时间开销 的情况下,就能在不均匀通道结构上带来5%~10% 的轨道节省。
工程上的结论是:
线性拥挤成本函数是一个在"效果 / 时间"上性价比极高的折中方案,非常适合作为 VPR 这类通用工具的默认成本函数。
四、增量式线网边界框更新:把 O(k) 变成 O(1)
4.1 问题:高扇出线网拖慢一切
在模拟退火布局中,每次尝试交换两个逻辑块,都需要评估"成本变化 ΔCΔC"。其中最费时的是:重新计算与这两个块相关的线网,其边界框及成本变化。
朴素做法:对每根线网重新遍历所有端点,复杂度 (O(k))(k 为线网端点数)。
而高扇出线网(k 几十甚至上百)非常多,导致整体布局时间被严重拖累。
4.2 数据结构设计
为每条线网 (i) 存储如下信息:
objectivec
struct Net {
int xmin, xmax, ymin, ymax; // 边界框坐标
int n_xmin, n_xmax; // 落在 xmin/xmax 边上的端点数
int n_ymin, n_ymax; // 落在 ymin/ymax 边上的端点数
};
这允许我们在端点移动时,用局部信息判断边界框是否需要改变,而不必重新扫描所有端点。
4.3 核心更新伪代码示例
以下为更新 x 方向边界的简化伪代码:
objectivec
void updateBoundingBoxX(int netId, int x_old, int x_new) {
// 情况1:端点在水平方向没有变化
if (x_new == x_old) return;
// 情况2:端点移动到比当前 xmin 更小的位置
if (x_new < xmin[netId]) {
xmin[netId] = x_new;
n_xmin[netId] = 1;
return;
}
// 情况3:端点移动到新的 xmin 边上
if (x_new == xmin[netId]) {
n_xmin[netId]++;
return;
}
// 情况4:端点原本位于 xmin 边界,现在离开
if (x_old == xmin[netId]) {
if (n_xmin[netId] > 1) {
// 仍有其他端点在 xmin 边,无需重算
n_xmin[netId]--;
} else {
// 这是 xmin 边上唯一一个端点,只能暴力重算
bruteForceRecomputeBoundingBox(netId);
}
}
// x_max 类似处理
}
同理可以写出 y 方向的更新函数。
关键观察:
-
只有在"原来边界上的唯一端点被移走"这一种情况下,才需要 (O(k)) 的暴力重算;
-
这一情况出现的概率与 1/k1/k 成正比,因此平均复杂度 为:
4.4 实测提速效果
对 10 个最大 MCNC 基准电路进行测试,结果显示:
- 布局速度平均提升约 5 倍,在某些高扇出电路上甚至可达到 9 倍以上;
- 布局质量不受影响(因为我们只是更快地算同一个成本函数);
- 由于复杂度特性清晰,能更精确地根据电路规模预测布局用时。
五、综合小结:一套完整而实用的布局技术组合
第三章的布局部分,可以概括为 VPR 在三个关键技术点上的进化:
- 自适应退火表 :
用接受率驱动温度更新,统一适配不同电路规模与结构; - 线性拥挤成本函数 :
在几乎零额外时间开销的前提下,对不均匀通道结构给出更合理的布局导向; - 增量式边界框更新 :
从算法层面消除了高扇出线网带来的 O(k) 瓶颈,实现 5X 级别的速度提升。
与前半部分的打包工具(VPack / T‑VPack)结合在一起,第三章完整地构建了一条:
面向 FPGA 的高质量打包 + 布局 CAD 流程。
对于做 FPGA CAD 研究或工具开发的人来说,文中给出的很多设计思路和经验值(如 λ,β,ϵλ,β,ϵ 等取值范围),都可以直接作为工程实现的参考起点。