Skip to content

Commit 2905ccd

Browse files
committed
gui: add handling of nets with sinks for route guides
Signed-off-by: Peter Gadfort <peter.gadfort@gmail.com>
1 parent c73a6e7 commit 2905ccd

2 files changed

Lines changed: 174 additions & 10 deletions

File tree

src/gui/src/dbDescriptors.cpp

Lines changed: 159 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,32 +1316,131 @@ void DbNetDescriptor::findPath(NodeMap& graph,
13161316
}
13171317
}
13181318

1319-
std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
1319+
void DbNetDescriptor::findPath(PointMap& graph,
1320+
const odb::Point& source,
1321+
const odb::Point& sink,
1322+
std::vector<odb::Point>& path) const
1323+
{
1324+
// find path from source to sink using A*
1325+
// https://en.wikipedia.org/w/index.php?title=A*_search_algorithm&oldid=1050302256
1326+
1327+
auto distance = [](const odb::Point& node0, const odb::Point& node1) -> int {
1328+
return odb::Point::manhattanDistance(node0, node1);
1329+
};
1330+
1331+
std::map<odb::Point, odb::Point> came_from;
1332+
std::map<odb::Point, int> g_score;
1333+
std::map<odb::Point, int> f_score;
1334+
1335+
struct DistNode
1336+
{
1337+
odb::Point node;
1338+
int dist;
1339+
1340+
public:
1341+
// used for priority queue
1342+
bool operator<(const DistNode& other) const { return dist > other.dist; }
1343+
};
1344+
std::priority_queue<DistNode> open_set;
1345+
std::set<odb::Point> open_set_nodes;
1346+
const int source_sink_dist = distance(source, sink);
1347+
open_set.push({source, source_sink_dist});
1348+
open_set_nodes.insert(source);
1349+
1350+
for (const auto& [node, nodes] : graph) {
1351+
g_score[node] = std::numeric_limits<int>::max();
1352+
f_score[node] = std::numeric_limits<int>::max();
1353+
}
1354+
g_score[source] = 0;
1355+
f_score[source] = source_sink_dist;
1356+
1357+
while (!open_set.empty()) {
1358+
auto current = open_set.top().node;
1359+
1360+
open_set.pop();
1361+
open_set_nodes.erase(current);
1362+
1363+
if (current == sink) {
1364+
// build path
1365+
while (current != source) {
1366+
path.emplace_back(current);
1367+
current = came_from[current];
1368+
}
1369+
path.emplace_back(current);
1370+
return;
1371+
}
1372+
1373+
const int current_g_score = g_score[current];
1374+
for (const auto& neighbor : graph[current]) {
1375+
const int possible_g_score
1376+
= current_g_score + distance(current, neighbor);
1377+
if (possible_g_score < g_score[neighbor]) {
1378+
const int new_f_score = possible_g_score + distance(neighbor, sink);
1379+
came_from[neighbor] = current;
1380+
g_score[neighbor] = possible_g_score;
1381+
f_score[neighbor] = new_f_score;
1382+
1383+
if (open_set_nodes.find(neighbor) == open_set_nodes.end()) {
1384+
open_set.push({neighbor, new_f_score});
1385+
open_set_nodes.insert(neighbor);
1386+
}
1387+
}
1388+
}
1389+
}
1390+
}
1391+
1392+
std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(
1393+
odb::dbNet* net,
1394+
DbTargets& sources,
1395+
DbTargets& sinks) const
13201396
{
1397+
sources.clear();
1398+
sinks.clear();
1399+
13211400
auto guides = net->getGuides();
13221401
if (guides.empty()) {
13231402
return {};
13241403
}
13251404

13261405
std::set<odb::Line> lines;
13271406

1407+
struct DbIO
1408+
{
1409+
bool is_sink;
1410+
bool is_source;
1411+
};
1412+
std::map<odb::dbObject*, DbIO> io_map;
1413+
13281414
std::map<odb::dbTechLayer*, std::map<odb::dbObject*, std::set<odb::Rect>>>
13291415
terms;
13301416
for (odb::dbITerm* term : net->getITerms()) {
13311417
if (!term->getInst()->isPlaced()) {
13321418
continue;
13331419
}
1420+
const auto iotype = term->getIoType();
1421+
const bool is_sink
1422+
= iotype == odb::dbIoType::INPUT || iotype == odb::dbIoType::INOUT;
1423+
const bool is_source
1424+
= iotype == odb::dbIoType::OUTPUT || iotype == odb::dbIoType::INOUT;
1425+
io_map[term] = {is_sink, is_source};
13341426
for (const auto& [layer, itermbox] : term->getGeometries()) {
13351427
terms[layer][term].insert(itermbox);
13361428
}
13371429
}
13381430
for (odb::dbBTerm* term : net->getBTerms()) {
1431+
const auto iotype = term->getIoType();
1432+
const bool is_sink
1433+
= iotype == odb::dbIoType::OUTPUT || iotype == odb::dbIoType::INOUT;
1434+
const bool is_source
1435+
= iotype == odb::dbIoType::INPUT || iotype == odb::dbIoType::INOUT;
1436+
io_map[term] = {is_sink, is_source};
1437+
13391438
for (odb::dbBPin* pin : term->getBPins()) {
13401439
if (!pin->getPlacementStatus().isPlaced()) {
13411440
continue;
13421441
}
13431442
for (odb::dbBox* box : pin->getBoxes()) {
1344-
terms[box->getTechLayer()][pin].insert(box->getBox());
1443+
terms[box->getTechLayer()][term].insert(box->getBox());
13451444
}
13461445
}
13471446
}
@@ -1374,7 +1473,9 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
13741473
if (guide->isConnectedToTerm()) {
13751474
std::vector<odb::Point> anchors = {p0, center, p1};
13761475

1377-
auto draw_term_connection = [&anchors, &lines](const odb::Point& term) {
1476+
auto find_term_connection = [&anchors, &lines, &io_map, &sources, &sinks](
1477+
odb::dbObject* dbterm,
1478+
const odb::Point& term) {
13781479
// draw shortest flywire
13791480
std::stable_sort(anchors.begin(),
13801481
anchors.end(),
@@ -1383,6 +1484,12 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
13831484
< odb::Point::manhattanDistance(term, pt1);
13841485
});
13851486
lines.emplace(term, anchors[0]);
1487+
if (io_map[dbterm].is_sink) {
1488+
sinks[dbterm].insert(term);
1489+
}
1490+
if (io_map[dbterm].is_source) {
1491+
sources[dbterm].insert(term);
1492+
}
13861493
};
13871494

13881495
for (const auto& [obj, objbox] : terms[guide->getLayer()]) {
@@ -1392,16 +1499,16 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
13921499
candidates.push_back(&termbox);
13931500
}
13941501
}
1395-
bool drawn = false;
1502+
bool found = false;
13961503
for (const auto* termbox : candidates) {
13971504
if (termbox->overlaps(box)) {
1398-
draw_term_connection(termbox->center());
1399-
drawn = true;
1505+
find_term_connection(obj, termbox->center());
1506+
found = true;
14001507
break;
14011508
}
14021509
}
1403-
if (!drawn && !candidates.empty()) {
1404-
draw_term_connection(candidates[0]->center());
1510+
if (!found && !candidates.empty()) {
1511+
find_term_connection(obj, candidates[0]->center());
14051512
}
14061513
}
14071514
}
@@ -1410,6 +1517,44 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
14101517
return lines;
14111518
}
14121519

1520+
void DbNetDescriptor::drawPathSegmentWithGuides(
1521+
const std::set<odb::Line>& lines,
1522+
DbTargets& sources,
1523+
DbTargets& sinks,
1524+
const odb::dbObject* sink,
1525+
Painter& painter) const
1526+
{
1527+
PointMap pointmap;
1528+
for (const auto& line : lines) {
1529+
pointmap[line.pt0()].insert(line.pt1());
1530+
pointmap[line.pt1()].insert(line.pt0());
1531+
}
1532+
1533+
for (const auto& [obj, srcs] : sources) {
1534+
for (const auto& src_pt : srcs) {
1535+
for (const auto& dst_pt : sinks[sink]) {
1536+
std::vector<odb::Point> path;
1537+
findPath(pointmap, src_pt, dst_pt, path);
1538+
1539+
if (!path.empty()) {
1540+
odb::Point prev_pt = path[0];
1541+
for (const auto& pt : path) {
1542+
if (pt == prev_pt) {
1543+
continue;
1544+
}
1545+
1546+
painter.drawLine(prev_pt, pt);
1547+
prev_pt = pt;
1548+
}
1549+
} else {
1550+
// unable to find path so just draw a fly-wire
1551+
painter.drawLine(src_pt, dst_pt);
1552+
}
1553+
}
1554+
}
1555+
}
1556+
}
1557+
14131558
// additional_data is used define the related sink for this net
14141559
// this will limit the fly-wires to just those related to that sink
14151560
// if nullptr, all flywires will be drawn
@@ -1514,8 +1659,13 @@ void DbNetDescriptor::highlight(std::any object, Painter& painter) const
15141659
highlight_color.a = 255;
15151660
painter.setPen(highlight_color, true, 4);
15161661

1517-
std::set<odb::Line> lines = convertGuidesToLines(net);
1662+
DbTargets sources;
1663+
DbTargets sinks;
1664+
std::set<odb::Line> lines = convertGuidesToLines(net, sources, sinks);
1665+
15181666
if (sink_object != nullptr) {
1667+
drawPathSegmentWithGuides(
1668+
lines, sources, sinks, sink_object, painter);
15191669
} else {
15201670
for (const auto& line : lines) {
15211671
painter.drawLine(line);

src/gui/src/dbDescriptors.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,23 @@ class DbNetDescriptor : public BaseDbDescriptor<odb::dbNet>
178178
using Node = odb::dbWireGraph::Node;
179179
using NodeList = std::set<const Node*>;
180180
using NodeMap = std::map<const Node*, NodeList>;
181+
using PointList = std::set<odb::Point>;
182+
using PointMap = std::map<odb::Point, PointList>;
181183
using GraphTarget = std::pair<const odb::Rect, const odb::dbTechLayer*>;
184+
using DbTargets = std::map<const odb::dbObject*, std::set<odb::Point>>;
182185

183-
std::set<odb::Line> convertGuidesToLines(odb::dbNet* net) const;
186+
std::set<odb::Line> convertGuidesToLines(odb::dbNet* net,
187+
DbTargets& sources,
188+
DbTargets& sinks) const;
184189

185190
void drawPathSegmentWithGraph(odb::dbNet* net,
186191
const odb::dbObject* sink,
187192
Painter& painter) const;
193+
void drawPathSegmentWithGuides(const std::set<odb::Line>& lines,
194+
DbTargets& sources,
195+
DbTargets& sinks,
196+
const odb::dbObject* sink,
197+
Painter& painter) const;
188198
void findSourcesAndSinksInGraph(odb::dbNet* net,
189199
const odb::dbObject* sink,
190200
odb::dbWireGraph* graph,
@@ -198,6 +208,10 @@ class DbNetDescriptor : public BaseDbDescriptor<odb::dbNet>
198208
const Node* source,
199209
const Node* sink,
200210
std::vector<odb::Point>& path) const;
211+
void findPath(PointMap& graph,
212+
const odb::Point& source,
213+
const odb::Point& sink,
214+
std::vector<odb::Point>& path) const;
201215

202216
void buildNodeMap(odb::dbWireGraph* graph, NodeMap& node_map) const;
203217

0 commit comments

Comments
 (0)