Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/odb/src/3dblox/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_library(3dblox
dbvWriter.cpp
dbxWriter.cpp
3dblox.cpp
unfoldedModel.cpp
checker.cpp
)

Expand Down
168 changes: 65 additions & 103 deletions src/odb/src/3dblox/checker.cpp
Original file line number Diff line number Diff line change
@@ -1,133 +1,80 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2023-2026, The OpenROAD Authors

#include "checker.h"

#include <algorithm>
#include <cstddef>
#include <map>
#include <ranges>
#include <string>
#include <utility>
#include <vector>

#include "odb/db.h"
#include "odb/dbTransform.h"
#include "odb/geom.h"
#include "unfoldedModel.h"
#include "utl/Logger.h"
#include "utl/unionFind.h"
namespace odb {

std::string UnfoldedChip::getName() const
{
std::string name;
int index = 0;
for (auto chip_inst : chip_inst_path) {
name += chip_inst->getName();
if (index++ < chip_inst_path.size() - 1) {
name += "/";
}
}
return name;
}
namespace odb {

Checker::Checker(utl::Logger* logger) : logger_(logger)
{
}

void Checker::check(odb::dbChip* chip)
{
for (auto chip_inst : chip->getChipInsts()) {
UnfoldedChip unfolded_chip;
unfoldChip(chip_inst, unfolded_chip);
}
UnfoldedModel model(logger_, chip);

odb::dbMarkerCategory* category
= odb::dbMarkerCategory::createOrReplace(chip, "3DBlox");
checkFloatingChips(category);
checkOverlappingChips(category);
// checkConnectionRegions(chip, category);
checkFloatingChips(model, category);
checkOverlappingChips(model, category);
}

void Checker::unfoldChip(odb::dbChipInst* chip_inst,
UnfoldedChip& unfolded_chip)
{
unfolded_chip.chip_inst_path.push_back(chip_inst);
if (chip_inst->getMasterChip()->getChipType() == dbChip::ChipType::HIER) {
for (auto chip_inst : chip_inst->getMasterChip()->getChipInsts()) {
unfoldChip(chip_inst, unfolded_chip);
}
} else {
// calculate the cuboid of the chip
unfolded_chip.cuboid = chip_inst->getMasterChip()->getCuboid();
for (auto chip_inst : unfolded_chip.chip_inst_path | std::views::reverse) {
chip_inst->getTransform().apply(unfolded_chip.cuboid);
}
debugPrint(
logger_,
utl::ODB,
"3dblox",
1,
"Unfolded chip: {} cuboid: ({}, {}, {}), ({}, {}, {})",
unfolded_chip.getName(),
unfolded_chip.cuboid.xMin() / chip_inst->getDb()->getDbuPerMicron(),
unfolded_chip.cuboid.yMin() / chip_inst->getDb()->getDbuPerMicron(),
unfolded_chip.cuboid.zMin() / chip_inst->getDb()->getDbuPerMicron(),
unfolded_chip.cuboid.xMax() / chip_inst->getDb()->getDbuPerMicron(),
unfolded_chip.cuboid.yMax() / chip_inst->getDb()->getDbuPerMicron(),
unfolded_chip.cuboid.zMax() / chip_inst->getDb()->getDbuPerMicron());
unfolded_chips_.push_back(unfolded_chip);
// Cuboid is overwritten in each leaf - no restoration needed
}
unfolded_chip.chip_inst_path.pop_back();
}
void Checker::checkFloatingChips(odb::dbMarkerCategory* category)
void Checker::checkFloatingChips(const UnfoldedModel& model,
odb::dbMarkerCategory* category)
{
utl::UnionFind uf(unfolded_chips_.size());
const auto& chips = model.getChips();
utl::UnionFind uf(chips.size());

// Check all pairs for intersection and union them
for (size_t i = 0; i < unfolded_chips_.size(); i++) {
auto cuboid_i = unfolded_chips_[i].cuboid;
for (size_t j = i + 1; j < unfolded_chips_.size(); j++) {
auto cuboid_j = unfolded_chips_[j].cuboid;
for (size_t i = 0; i < chips.size(); i++) {
auto cuboid_i = chips[i].cuboid;
for (size_t j = i + 1; j < chips.size(); j++) {
auto cuboid_j = chips[j].cuboid;
if (cuboid_i.intersects(cuboid_j)) {
uf.unite(i, j);
}
}
}

// Group chips by their root parent
std::map<int, std::vector<UnfoldedChip*>> sets;
for (size_t i = 0; i < unfolded_chips_.size(); i++) {
sets[uf.find(i)].push_back(&unfolded_chips_[i]);
std::map<int, std::vector<const UnfoldedChip*>> sets;
for (size_t i = 0; i < chips.size(); i++) {
sets[uf.find(i)].push_back(&chips[i]);
}

if (sets.size() > 1) {
// Convert to vector and sort by size
std::vector<std::vector<UnfoldedChip*>> insts_sets;
std::vector<std::vector<const UnfoldedChip*>> insts_sets;
insts_sets.reserve(sets.size());
for (auto& [root, chips] : sets) {
insts_sets.emplace_back(chips);
for (auto& [root, chips_list] : sets) {
insts_sets.emplace_back(chips_list);
}

std::ranges::sort(insts_sets,
[](const std::vector<UnfoldedChip*>& a,
const std::vector<UnfoldedChip*>& b) {
[](const std::vector<const UnfoldedChip*>& a,
const std::vector<const UnfoldedChip*>& b) {
return a.size() > b.size();
});

odb::dbMarkerCategory* floating_chips_category
= odb::dbMarkerCategory::createOrReplace(category, "Floating chips");
logger_->warn(
utl::ODB, 151, "Found {} floating chip sets", insts_sets.size() - 1);
logger_->warn(utl::ODB,
151,
"Found {} floating chip sets",
(int) insts_sets.size() - 1);

// Create marker for each set except the first one (the biggest one)
for (size_t i = 1; i < insts_sets.size(); i++) {
auto& insts_set = insts_sets[i];
odb::dbMarker* marker = odb::dbMarker::create(floating_chips_category);
for (auto& inst : insts_set) {
debugPrint(logger_,
utl::ODB,
"3dblox",
1,
"Floating chip: {}",
inst->getName());
for (auto* inst : insts_set) {
marker->addShape(Rect(inst->cuboid.xMin(),
inst->cuboid.yMin(),
inst->cuboid.xMax(),
Expand All @@ -138,58 +85,73 @@ void Checker::checkFloatingChips(odb::dbMarkerCategory* category)
}
}

void Checker::checkOverlappingChips(odb::dbMarkerCategory* category)
void Checker::checkOverlappingChips(const UnfoldedModel& model,
odb::dbMarkerCategory* category)
{
std::vector<std::pair<UnfoldedChip*, UnfoldedChip*>> overlaps;
const auto& chips = model.getChips();
std::vector<std::pair<const UnfoldedChip*, const UnfoldedChip*>> overlaps;

// Check all pairs of chip instances for overlaps
for (size_t i = 0; i < unfolded_chips_.size(); i++) {
auto cuboid_i = unfolded_chips_[i].cuboid;
for (size_t j = i + 1; j < unfolded_chips_.size(); j++) {
auto cuboid_j = unfolded_chips_[j].cuboid;
for (size_t i = 0; i < chips.size(); i++) {
auto cuboid_i = chips[i].cuboid;
for (size_t j = i + 1; j < chips.size(); j++) {
auto cuboid_j = chips[j].cuboid;
if (cuboid_i.overlaps(cuboid_j)) {
overlaps.emplace_back(&unfolded_chips_[i], &unfolded_chips_[j]);
overlaps.emplace_back(&chips[i], &chips[j]);
}
}
}

if (!overlaps.empty()) {
odb::dbMarkerCategory* overlapping_chips_category
= odb::dbMarkerCategory::createOrReplace(category, "Overlapping chips");
logger_->warn(utl::ODB, 156, "Found {} overlapping chips", overlaps.size());
logger_->warn(
utl::ODB, 156, "Found {} overlapping chips", (int) overlaps.size());

for (const auto& [inst1, inst2] : overlaps) {
odb::dbMarker* marker = odb::dbMarker::create(overlapping_chips_category);

// Compute the intersection region
auto cuboid1 = inst1->cuboid;
auto cuboid2 = inst2->cuboid;
auto intersection = cuboid1.intersect(cuboid2);

// Add the intersection as a shape (project to 2D for visualization)
odb::Rect bbox(intersection.xMin(),
intersection.yMin(),
intersection.xMax(),
intersection.yMax());
marker->addShape(bbox);

// Add both chip instances as sources
marker->addSource(inst1->chip_inst_path.back());
marker->addSource(inst2->chip_inst_path.back());

// Add a comment describing the overlap
std::string comment = "Chips " + inst1->getName() + " and "
+ inst2->getName() + " overlap";
debugPrint(logger_,
utl::ODB,
"3dblox",
1,
"Overlapping chips: {} and {}",
inst1->getName(),
inst2->getName());
marker->setComment(comment);
}
}
}

void Checker::checkConnectionRegions(const UnfoldedModel& model,
dbChip* chip,
dbMarkerCategory* category)
{
}

void Checker::checkBumpPhysicalAlignment(const UnfoldedModel& model,
dbMarkerCategory* category)
{
}

void Checker::checkNetConnectivity(const UnfoldedModel& model,
dbChip* chip,
dbMarkerCategory* category)
{
}

bool Checker::isOverlapFullyInConnections(const UnfoldedChip* chip1,
const UnfoldedChip* chip2,
const Cuboid& overlap) const
{
return false;
}

} // namespace odb
45 changes: 28 additions & 17 deletions src/odb/src/3dblox/checker.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
#pragma once
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2023-2026, The OpenROAD Authors

#include <string>
#include <vector>
#pragma once

#include "odb/3dblox.h"
#include "odb/db.h"
#include "odb/geom.h"
#include "unfoldedModel.h"
#include "utl/Logger.h"

namespace odb {
class dbChip;
class dbMarkerCategory;
class dbChipInst;
struct UnfoldedChip
{
std::string getName() const;
std::vector<dbChipInst*> chip_inst_path;
Cuboid cuboid;
};

class Checker
{
public:
Expand All @@ -23,10 +20,24 @@ class Checker
void check(odb::dbChip* chip);

private:
void checkFloatingChips(odb::dbMarkerCategory* category);
void checkOverlappingChips(odb::dbMarkerCategory* category);
void unfoldChip(odb::dbChipInst* chip_inst, UnfoldedChip& unfolded_chip);
utl::Logger* logger_ = nullptr;
std::vector<UnfoldedChip> unfolded_chips_;
void checkFloatingChips(const UnfoldedModel& model,
dbMarkerCategory* category);
void checkOverlappingChips(const UnfoldedModel& model,
dbMarkerCategory* category);
void checkConnectionRegions(const UnfoldedModel& model,
dbChip* chip,
dbMarkerCategory* category);
void checkBumpPhysicalAlignment(const UnfoldedModel& model,
dbMarkerCategory* category);
void checkNetConnectivity(const UnfoldedModel& model,
dbChip* chip,
dbMarkerCategory* category);

bool isOverlapFullyInConnections(const UnfoldedChip* chip1,
const UnfoldedChip* chip2,
const Cuboid& overlap) const;

utl::Logger* logger_;
};
} // namespace odb

} // namespace odb
Loading