【agent辅助pcb routing coding学习】实践10 CU DR 代码 算法学习
·

Dr. CU 详细布线算法设计
项目概述
Dr. CU是香港中文大学研究团队开发的VLSI详细布线工具。与全局布线不同,详细布线需要处理许多详细的设计规则,并在显著更大的布线网格图上执行。在先进技术节点下,它成为VLSI物理设计流程中最复杂和耗时的阶段。
核心创新点
- 两级稀疏数据结构 - 用于高效存储和查询布线信息
- 最优的正确构造路径搜索 - 确保设计规则满足
- 高效的大规模并行方案 - 支持多线程加速
数据结构设计
1. 几何基元 (GeoPrimitive.h)
1.1 网格点 (GridPoint)
class GridPoint {
public:
int layerIdx; // 金属层索引
int trackIdx; // 走线道索引
int crossPointIdx; // 交叉点索引
};
网格点是详细布线中的基本坐标单元,表示在特定金属层的特定走线道上的特定交叉点位置。
1.2 网格边 (GridEdge)
class GridEdge {
public:
GridPoint u, v; // 两个端点
};
网格边有两种类型:
- 通孔边: 连接不同层的两个网格点
- 线段边: 同一层内连接两个网格点,包括顺线方向和逆线方向
1.3 网格盒 (GridBoxOnLayer)
class GridBoxOnLayer {
public:
int layerIdx; // 金属层索引
utils::IntervalT<int> trackRange; // 走线道范围
utils::IntervalT<int> crossPointRange; // 交叉点范围
};
用于表示布线引导区域和引脚访问区域在网格图中的范围。
2. 布线网格 (RouteGrid.h/cpp)
RouteGrid是整个详细布线器的核心数据结构,采用两级稀疏存储策略:
2.1 金属层信息存储
// 1. 已布线线段存储
// (layerIdx, trackIdx) -> (crossPointRange, netIdxs)
vector<vector<boost::icl::interval_map<int, std::set<int>>>> routedWireMap;
// 2. 不良线段存储 (由于与引脚/障碍物冲突)
// (layerIdx, trackIdx) -> (crossPointRange, netIdx)
vector<vector<boost::icl::interval_map<int, PoorWire>>> poorWireMap;
// 3. 历史违规线段存储
// (layerIdx, trackIdx) -> (crossPointRange, discountedUsage)
vector<vector<boost::icl::interval_map<int, HistWire>>> histWireMap;
这种存储方式利用了Boost库的区间映射 (interval_map) 来高效存储和查询线段信息。
2.2 通孔信息存储
// (layerIdx, trackIdx) -> (crossPointIdx, netIdx)
ViaMapT routedViaMap; // 主版本,由下方网格点记录
ViaMapT routedViaMapUpper; // 由上方网格点记录
NDViaMapT routedNonDefViaMap; // 非默认通孔映射
2.3 固定金属存储
RTrees fixedMetals; // box -> netIdx
使用R-tree空间索引结构存储固定的金属障碍物(如单元引脚、阻挡块)。
3. 网格图拓扑 (GridGraph.h)
class GridGraph {
private:
int edgeCount;
// 顶点属性
std::unordered_map<int, int> vertexToPin; // 顶点索引 -> 引脚索引
vector<vector<int>> pinToVertex; // 引脚索引 -> 顶点索引列表
std::unordered_set<int> fakePins; // 跨层访问点
vector<db::GridPoint> vertexToGridPoint; // 顶点 -> 网格点映射
vector<bool> minAreaFixable; // 是否可修复最小面积违规
// 邻接表
vector<std::array<int, 6>> conn; // 6个方向的连接
vector<db::CostT> vertexCost; // 顶点代价
vector<std::array<db::CostT, 6>> edgeCost; // 边代价
};
网格图是一个稀疏图,每个顶点最多有6个方向的边:
BACKWARD/FORWARD: 顺线方向前后UP/DOWN: 层间上下LEFT/RIGHT: 逆线方向左右
核心算法
1. 布线网格图构建 (GridGraphBuilder.cpp)
1.1 构建流程
run()
├── 1. 为每个网格点分配索引
├── 2. 添加引导-引脚连接
├── 3. 添加引导间连接
├── 4. 添加逆线方向连接
├── 5. 添加引导内连接
└── 6. 设置最小面积标志
1.2 引导内连接
对于每个布线引导盒,添加两种连接:
顺线方向连接:
void connectGuide(int guideIdx) {
// 沿走线道方向连接相邻交叉点
// 计算线段代价 = 线长代价 + 违规代价
// 包括:短路代价、间距代价、历史代价
}
逆线方向连接:
void addRegWrongWayConn(int guideIdx) {
// 沿垂直于走线道方向连接
// 使用更高的代价系数来惩罚逆线布线
int numWrongWayPoint = (cpRange.range() + 1) * wrongWayPointDensity;
db::CostT wrongWayCost = wrongWayPenaltyCoeff * pitch;
}
逆线方向连接是稀疏添加的,通过wrongWayPointDensity参数控制密度,以平衡搜索空间和布线质量。
1.3 引导间连接
void connectTwoGuides(int guideIdx1, int guideIdx2) {
// 处理三种连接情况:
// 1. 同层重叠区域:添加顺线和逆线连接
// 2. 相邻层:通过通孔连接
// 3. 通孔代价计算
}
2. 迷宫布线 (MazeRoute.cpp)
2.1 算法流程
run()
├── 1. 构建网格图
├── 2. 初始化优先队列和代价上界
├── 3. 从起始引脚开始Dijkstra搜索
│ ├── 优先队列排序:cost为主,costUB为辅
│ ├── 剪枝:通过代价上界剪枝
│ └── 最小面积惩罚处理
└── 4. 回溯构建Steiner树
2.2 Dijkstra搜索核心
db::RouteStatus MazeRoute::route(int startPin) {
// 优先队列定义
auto solComp = [](const auto& lhs, const auto& rhs) {
return rhs->cost < lhs->cost ||
(rhs->cost == lhs->cost && rhs->costUB < lhs->costUB);
};
std::priority_queue<..., decltype(solComp)> solQueue(solComp);
// 初始化:从起始引脚的所有访问点开始
for (auto vertex : graph.getVertices(startPin)) {
DBU minLen = graph.isFakePin(vertex) ? 0 :
database.getLayer(...).getMinLen();
updateSol(std::make_shared<Solution>(
graph.getVertexCost(vertex), minLen,
graph.getVertexCost(vertex), vertex, nullptr));
}
// 主循环:依次连接每个引脚
while (nPinToConnect != 0) {
// Dijkstra搜索直到到达下一个未访问引脚
while (!solQueue.empty()) {
auto newSol = solQueue.top();
int u = newSol->vertex;
solQueue.pop();
// 检查是否到达引脚
dstPinIdx = graph.getPinIdx(u);
if (dstPinIdx != -1 && visitedPin.find(dstPinIdx) == visitedPin.end()) {
dstVertex = newSol;
break;
}
// 剪枝:通过上界剪枝
if (vertexCostUBs[u] < newSol->cost) continue;
// 扩展邻居节点
for (auto direction : directions) {
if (!graph.hasEdge(u, direction)) continue;
int v = graph.getEdgeEndPoint(u, direction);
// 计算新代价
db::CostT w = graph.getEdgeCost(u, direction) +
graph.getVertexCost(v);
// 最小面积惩罚
db::CostT penalty = 0;
if (switchLayer(direction) &&
uLayer.hasMinLenVioAcc(newSol->len)) {
if (graph.isMinAreaFixable(u))
penalty = uLayer.getMinLen() - newSol->len;
else
penalty = database.getUnitMinAreaVioCost();
}
db::CostT newCost = w + newSol->cost + penalty;
// 上界剪枝
if (newCost < vertexCostUBs[v]) {
updateSol(std::make_shared<Solution>(...));
}
}
}
}
}
2.3 最小面积捕获路径搜索
这是Dr. CU的核心创新之一。在先进工艺节点中,金属线段有最小长度要求。算法通过以下方式处理:
- 代价上界剪枝: 每个顶点维护一个代价上界
vertexCostUBs[v],只有当新路径代价小于上界时才扩展 - 潜在惩罚计算: 在每个顶点预先计算可能的未来最小面积违规惩罚
- 正确构造: 通过标记可修复节点,确保找到的路径满足设计规则
3. 多网络布线调度 (Router.cpp & Scheduler.cpp)
3.1 撕开重布线 (Rip-up and Reroute, RRR)
void Router::run() {
for (iter = 0; iter < rrrIterLimit; iter++) {
// 1. 获取需要重新布线的网络
vector<int> netsToRoute = getNetsToRoute();
if (iter > 0) {
// 2. 更新历史代价
updateCost(netsToRoute);
// 3. 拆除违规网络
ripup(netsToRoute);
}
// 4. 布线所有网络
route(netsToRoute);
}
// 5. 后处理
finish();
}
3.2 历史代价机制
void Router::updateCost(const vector<int>& netsToRoute) {
database.addHistCost(); // 添加历史代价
database.fadeHistCost(netsToRoute); // 衰减当前重布网络的历史代价
}
历史代价用于避免网络在相同位置重复布线,帮助解决局部最优问题。
3.3 并行调度
void Router::route(const vector<int>& netsToRoute) {
// 1. 初始化单网络布线器
vector<SingleNetRouter> routers;
for (int netIdx : netsToRoute) {
routers.emplace_back(database.nets[netIdx]);
}
// 2. 预布线(可并行)
runJobsMT(netsToRoute.size(), [&](int netIdx) {
routers[netIdx].preRoute();
});
// 3. 调度:将网络分组为可并行执行的批次
Scheduler scheduler(routers);
const vector<vector<int>>& batches = scheduler.schedule();
// 4. 按批次执行迷宫布线和提交
for (const vector<int>& batch : batches) {
// 4.1 迷宫布线(可并行)
runJobsMT(batch.size(), [&](int jobIdx) {
routers[batch[jobIdx]].mazeRoute();
});
// 4.2 提交到数据库(可并行)
runJobsMT(batch.size(), [&](int jobIdx) {
if (db::isSucc(router.status))
router.commitNetToDB();
});
// 4.3 获取通孔类型(可并行)
runJobsMT(batch.size(), [&](int jobIdx) {
if (db::isSucc(router.status))
postRoute.getViaTypes();
});
}
}
调度器原理:
- 使用空间R-tree检测网络之间的冲突
- 将不冲突的网络分到同一批次
- 同一批次内的网络可以安全地并行布线
- 不同批次之间需要同步,确保数据一致性
4. 代价计算
4.1 边代价组成
CostT getEdgeCost(const GridEdge& edge, const int netIdx) const {
// 基础线长代价
CostT cost = unitWireCost * length;
// 违规代价
cost += getEdgeVioCost(edge, netIdx);
return cost;
}
4.2 违规代价检测
CostT getEdgeVioCost(const GridEdge& edge, const int netIdx,
bool histCost = true) const {
// 1. 短路违规检测
auto shortUsages = getShortWireSegmentUsageOnOvlpWire(ts, netIdx);
// 2. 间距违规检测
auto spaceVioCPs = getWireSegmentSpaceVioOnWires(ts, netIdx);
// 3. 历史违规
if (histCost) {
auto histUsages = getShortWireSegmentUsageOnOvlpHistWire(ts, netIdx);
}
// 综合计算违规代价
return unitWireCost * shortLength +
unitShortVioCost[layerIdx] * shortVioCount +
unitSpaceVioCost * spaceVioCount +
histCost;
}
4.3 通孔代价计算
CostT getViaCost(const GridPoint& via, const int netIdx) const {
// 基础通孔代价
CostT cost = unitViaCost;
// 1. 通孔对通孔违规
unsigned viaOnViaUsage = getViaUsageOnVias(via, netIdx);
// 2. 通孔对线段违规
unsigned viaOnWireUsage = getViaUsageOnWires(via, netIdx);
// 3. 历史通孔代价
HistUsageT histUsage = getViaHistUsage(via);
// 4. 不良通孔检测
ViaPoorness poorness = getViaPoorness(via, netIdx);
return cost + violationCost + histCost;
}
算法流程图
主流程
┌─────────────────┐
│ 输入: LEF/ │
│ DEF/GUIDES │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 初始化数据库 │
│ - 标记引脚 │
│ - 标记障碍物 │
│ - 切割引导区 │
└────────┬────────┘
│
▼
┌────────────────────────┐
│ RRR迭代 (rrrIterLimit) │
└────────────┬───────────┘
│
┌────────────────┴────────────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ iter = 0? │ │ iter > 0? │
│ 所有网络 │ ◄────────────│ 违规网络 │
└───────┬───────┘ └───────┬───────┘
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ 直接布线 │ │ 更新历史代价 │
└───────┬───────┘ └───────┬───────┘
│ │
│ ▼
│ ┌───────────────┐
│ │ 拆除违规网络 │
│ └───────┬───────┘
│ │
└────────────┬────────────────────┘
▼
┌───────────────────┐
│ 单网络布线 │
│ - 构建网格图 │
│ - 迷宫搜索 │
│ - 提交结果 │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 后处理 │
│ - 最小面积修复 │
│ - 通孔类型选择 │
│ - 开路修复 │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 输出: DEF │
└───────────────────┘
单网络布线流程
┌───────────────────┐
│ SingleNetRouter │
└─────────┬─────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ preRoute │ │ mazeRoute │ │ commitDB │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ 构建引导 │ │构建网格图 │ │ 更新资源 │
│ 连接图 │ │ Dijkstra │ │ 标记占用 │
│ │ 搜索 │ │ 检测违规 │
└───────────┘ └───────────┘
迷宫布线流程
┌───────────────────┐
│ MazeRoute::run() │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ GridGraphBuilder │
│ 构建局部网格图 │
└─────────┬─────────┘
│
┌─────────┴─────────┐
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ 添加引导内连接 │ │ 添加引导间连接 │
│ - 顺线方向 │ │ - 层间通孔 │
│ - 逆线方向 │ │ - 同层重叠 │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
└───────────┬───────────┘
▼
┌───────────────────┐
│ Dijkstra搜索 │
│ │
│ ┌───────────────┐ │
│ │ 优先队列 │ │
│ │ PQ<Solution> │ │
│ └───────┬───────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ 弹出最小cost │ │
│ └───────┬───────┘ │
│ │ │
│ ┌────┴────┐ │
│ ▼ ▼ │
│ ┌────┐ ┌────┐ │
│ │是引脚? │ │否 │ │
│ └┬───┘ └┬───┘ │
│ │ │ │
│ │ ┌────▼────┐ │
│ │ │扩展邻居 │ │
│ │ │-6个方向 │ │
│ │ │-剪枝 │ │
│ │ │-更新PQ │ │
│ │ └────┬────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ │
│ │ 标记路径为0 │ │
│ │ 继续搜索 │ │
│ └─────────────┘ │
│ │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ getResult() │
│ 回溯构建Steiner树 │
└───────────────────┘
并行调度流程
┌───────────────────┐
│ 所有网络 │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 预布线阶段 │
│ (可完全并行) │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ 调度器分组 │
│ Scheduler │
└─────────┬─────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Batch 0 │ │ Batch 1 │ │ Batch 2 │
│ 网络1,2 │ │ 网络3,4 │ │ 网络5,6 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│迷宫布线 │ │迷宫布线 │ │迷宫布线 │
│ 并行执行│ │ 并行执行│ │ 并行执行│
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│提交DB │ │提交DB │ │提交DB │
│ 并行执行│ │ 并行执行│ │ 并行执行│
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└───────────┼───────────┘
▼
┌───────────────────┐
│ 下一批次 │
└───────────────────┘
关键数据流
1. 网络数据流
原始输入 (LEF/DEF)
│
▼
Rsyn解析
│
▼
Net对象
│
├─→ rsynPins: 引脚信息
├─→ pinAccessBoxes: 引脚访问盒
├─→ routeGuides: 布线引导
└─→ gridTopo: 网格Steiner树
│
▼
LocalNet对象 (单网络布线)
│
├─→ gridRouteGuides: 网格化的引导
├─→ gridPinAccessBoxes: 网格化的访问盒
├─→ guideConn: 引导连接图
└─→ guideAdj: 引领邻接图
│
▼
GridGraph (迷宫搜索)
│
├─→ conn: 邻接表
├─→ vertexCost: 顶点代价
└─→ edgeCost: 边代价
│
▼
GridSteiner树 (布线结果)
│
▼
提交到RouteGrid
│
├─→ routedWireMap: 线段占用
├─→ routedViaMap: 通孔占用
└─→ histWireMap: 历史违规
2. 代价计算流
GridEdge/GridPoint
│
▼
查询RouteGrid
│
├─→ routedWireMap: 已占用线段
├─→ poorWireMap: 不良线段
├─→ histWireMap: 历史代价
├─→ routedViaMap: 已占用通孔
└─→ fixedMetals: 固定障碍
│
▼
检测违规
│
├─→ 短路: 重叠检查
├─→ 间距: 最小间距检查
├─→ 通孔违规: Via-on-Via, Via-on-Wire
└─→ 历史代价: 累加历史违规
│
▼
计算总代价
│
├─→ wireCost = unitWireCost × length
├─→ viaCost = unitViaCost + violationCost
├─→ shortCost = unitShortVioCost × count
├─→ spaceCost = unitSpaceVioCost × count
└─→ histCost = histUsage × coeff
│
▼
返回总CostT
核心算法伪代码
1. 迷宫布线算法
def maze_routing(start_pin, all_pins, grid_graph):
"""
改进的Dijkstra算法,用于连接多个引脚
"""
# 初始化
priority_queue = PriorityQueue()
vertex_cost_ub = {v: infinity for v in grid_graph.vertices}
pin_solutions = {}
visited_pins = {start_pin}
# 从起始引脚的所有访问点开始
for vertex in grid_graph.get_pin_vertices(start_pin):
cost = grid_graph.get_vertex_cost(vertex)
min_len = get_min_length(vertex)
priority_queue.push(Solution(cost, min_len, cost, vertex, None))
vertex_cost_ub[vertex] = cost
# 依次连接每个引脚
while len(visited_pins) < len(all_pins):
dst_vertex = None
dst_pin = None
# Dijkstra主循环
while not priority_queue.empty():
current = priority_queue.pop()
u = current.vertex
# 检查是否到达新引脚
pin_idx = grid_graph.get_pin_index(u)
if pin_idx is not None and pin_idx not in visited_pins:
dst_vertex = current
dst_pin = pin_idx
break
# 上界剪枝
if vertex_cost_ub[u] < current.cost:
continue
# 扩展6个方向的邻居
for direction in [BACKWARD, FORWARD, UP, DOWN, LEFT, RIGHT]:
if not grid_graph.has_edge(u, direction):
continue
v = grid_graph.get_edge_end(u, direction)
# 计算新代价
edge_cost = grid_graph.get_edge_cost(u, direction)
vertex_cost = grid_graph.get_vertex_cost(v)
new_cost = current.cost + edge_cost + vertex_cost
# 最小面积惩罚
penalty = 0
if is_layer_change(direction):
if has_min_area_violation(current.length):
if is_min_area_fixable(u):
penalty = get_min_length() - current.length
else:
penalty = UNIT_MIN_AREA_VIO_COST
new_cost += penalty
# 计算新的长度
new_length = compute_new_length(current, u, v)
# 计算潜在惩罚
potential_penalty = 0
if has_min_area_violation(new_length):
if is_min_area_fixable(v):
potential_penalty = get_min_length() - new_length
else:
potential_penalty = UNIT_MIN_AREA_VIO_COST
cost_upper_bound = new_cost + potential_penalty
# 更新
if new_cost < vertex_cost_ub[v]:
priority_queue.push(
Solution(new_cost, new_length, cost_upper_bound, v, current)
)
vertex_cost_ub[v] = new_cost
# 找到下一个引脚的连接路径
if dst_vertex is None:
return FAIL_DISCONNECTED
pin_solutions[dst_pin] = dst_vertex
# 将路径上的顶点代价设为0(Steiner点)
temp = dst_vertex
while temp is not None and temp.cost != 0:
min_len = get_min_length(temp.vertex)
priority_queue.push(Solution(0, min_len, 0, temp.vertex, temp.prev))
temp = temp.prev
# 标记目标引脚的所有访问点
for vertex in grid_graph.get_pin_vertices(dst_pin):
if vertex != dst_vertex.vertex:
cost = grid_graph.get_vertex_cost(vertex)
min_len = get_min_length(vertex)
priority_queue.push(Solution(cost, min_len, cost, vertex, None))
visited_pins.add(dst_pin)
# 回溯构建Steiner树
return build_steiner_tree(pin_solutions)
2. RRR主流程
def ripup_and_reroute(all_nets, max_iterations=10):
"""
撕开重布线主流程
"""
database = initialize_database(all_nets)
for iteration in range(max_iterations):
print(f"RRR Iteration {iteration}")
# 1. 获取需要布线的网络
if iteration == 0:
nets_to_route = all_nets # 首次迭代:所有网络
else:
# 后续迭代:只处理有违规的网络
nets_to_route = [net for net in all_nets
if check_violation(net)]
if not nets_to_route:
break # 没有违规,完成
# 2. 更新历史代价
if iteration > 0:
database.add_history_cost()
database.fade_history_cost(nets_to_route)
# 3. 拆除违规网络的布线
if iteration > 0:
for net in nets_to_route:
ripup_net(net)
# 4. 重新布线
route_nets(nets_to_route)
# 5. 后处理
post_route(all_nets)
write_def("output.def")
def route_nets(nets):
"""
并行布线多个网络
"""
# 1. 初始化单网络布线器
routers = [SingleNetRouter(net) for net in nets]
# 2. 预布线(可并行)
parallel_execute([router.pre_route for router in routers])
# 3. 调度:分组网络
scheduler = Scheduler(routers)
batches = scheduler.schedule()
# 4. 按批次布线
for batch in batches:
# 4.1 迷宫布线(并行)
parallel_execute([routers[i].maze_route for i in batch])
# 4.2 提交到数据库(并行)
parallel_execute([routers[i].commit for i in batch])
# 4.3 选择通孔类型(并行)
parallel_execute([select_via_types(routers[i].db_net) for i in batch])
3. 调度算法
def schedule_networks(routers):
"""
将网络分组为可并行执行的批次
"""
rtrees = build_spatial_rtrees()
unassigned = set(range(len(routers)))
batches = []
while unassigned:
current_batch = []
for net_idx in list(unassigned):
# 检查与当前批次是否冲突
if not has_conflict(routers[net_idx], current_batch, rtrees):
current_batch.append(net_idx)
unassigned.remove(net_idx)
# 更新空间索引
update_rtree(rtrees, routers[net_idx])
batches.append(current_batch)
return batches
def has_conflict(router, batch, rtrees):
"""
检查网络是否与批次中任何网络冲突
"""
net_boxes = get_network_bounding_boxes(router.db_net)
for net_idx in batch:
batch_boxes = get_bounding_boxes(rtrees, net_idx)
# 检查空间重叠
for box1 in net_boxes:
for box2 in batch_boxes:
if boxes_overlap(box1, box2):
return True # 有冲突,不能并行
return False # 无冲突,可以并行
设计规则处理
1. 最小面积规则
// 检查最小面积违规
bool hasMinLenVioAcc(DBU currentLen) {
return currentLen < getMinLen();
}
// 处理最小面积违规
if (switchLayer(direction) && uLayer.hasMinLenVioAcc(newSol->len)) {
if (graph.isMinAreaFixable(u) || dstPinIdx != -1) {
// 可以修复:添加长度惩罚
penalty = uLayer.getMinLen() - newSol->len;
} else {
// 无法修复:添加巨大的违规代价
penalty = database.getUnitMinAreaVioCost();
}
}
2. 间距规则
// 检测间距违规
vector<int> getWireSegmentSpaceVioOnWires(const TrackSegment& ts, int netIdx) {
vector<int> vioCPs;
// 遍历线段上的每个交叉点
iterateWireSegments(ts, netIdx, [&](const auto& interval, int usage) {
if (usage > 0) {
// 检查间距
if (get_spacing() < min_spacing) {
vioCPs.push_back(interval.low);
vioCPs.push_back(interval.high);
}
}
});
return vioCPs;
}
3. 通孔规则
// 检查通孔违规
int getViaFixedVio(const GridPoint& via, const ViaType& viaType, int netIdx) {
int vio = 0;
// 1. 通孔对固定金属的违规
BoxOnLayer viaBox = get_via_box(via, viaType);
vio += getFixedMetalVio(viaBox.lower, netIdx);
vio += getFixedMetalVio(viaBox.upper, netIdx);
// 2. 通孔对通孔的违规
vio += getViaUsageOnVias(via, netIdx, &viaType);
// 3. 通孔对线段的违规
vio += getViaUsageOnWires(via, netIdx, &viaType);
return vio;
}
性能优化技术
1. 稀疏存储
// 使用区间映射存储线段,只存储有占用位置
vector<vector<boost::icl::interval_map<int, std::set<int>>>> routedWireMap;
// 优势:
// 1. 空间高效:空轨道不占用存储
// 2. 查询快速:O(log n)区间查询
// 3. 合并方便:自动合并相邻区间
2. 上界剪枝
// 每个顶点维护最小代价上界
vector<db::CostT> vertexCostUBs;
// 剪枝条件
if (vertexCostUBs[u] < newSol->cost) {
continue; // 跳过劣质解
}
// 效果:
// - 显著减少搜索空间
// - 加速收敛
3. 并行化
// 使用线程池并行执行独立任务
MTStat runJobsMT(int numJobs, const std::function<void(int)>& handle) {
vector<std::thread> threads;
vector<double> durations(numThreads, 0.0);
for (int t = 0; t < numThreads; ++t) {
threads.emplace_back([&, t]() {
auto t0 = std::chrono::high_resolution_clock::now();
for (int j = t; j < numJobs; j += numThreads) {
handle(j);
}
auto t1 = std::chrono::high_resolution_clock::now();
durations[t] = std::chrono::duration<double>(t1 - t0).count();
});
}
for (auto& th : threads) {
th.join();
}
return MTStat(durations);
}
4. 批处理同步
// 通过批次划分减少同步开销
for (const auto& batch : batches) {
// 批次内并行执行
runJobsMT(batch.size(), [&](int jobIdx) {
// 无锁操作
routers[batch[jobIdx]].mazeRoute();
});
// 批次间同步(较少发生)
#pragma omp barrier
}
总结
Dr. CU详细布线工具的核心设计思想:
-
稀疏化: 通过两级稀疏数据结构和稀疏网格图,大幅降低内存占用和计算复杂度
-
正确构造: 最小面积捕获路径搜索确保生成满足设计规则的布线解
-
迭代优化: RRR框架配合历史代价机制,逐步优化布线质量
-
并行加速: 智能调度器识别可并行网络,最大化多核利用率
这些技术的结合使得Dr. CU能够在先进工艺节点的复杂设计规则下,高效地完成详细布线任务。
更多推荐

所有评论(0)