From dc91432f147f223b1fb7010e4e9edc7f1dc03693 Mon Sep 17 00:00:00 2001 From: "Ahmed R. Mohamed" Date: Thu, 26 Feb 2026 18:49:22 -0800 Subject: [PATCH 1/6] odb: impl 3dblox checker checkLogicalConnectivity Signed-off-by: Ahmed R. Mohamed --- src/odb/include/odb/3dblox.h | 1 + src/odb/src/3dblox/3dblox.cpp | 59 ++++++ src/odb/src/3dblox/checker.cpp | 184 +++++++++++++++++- src/odb/src/3dblox/checker.h | 1 + src/odb/test/cpp/CMakeLists.txt | 2 +- src/odb/test/cpp/Test3DBloxChecker.cpp | 74 +------ src/odb/test/cpp/Test3DBloxCheckerFixture.h | 87 +++++++++ .../test/cpp/Test3DBloxCheckerLogicalConn.cpp | 148 ++++++++++++++ .../test/data/3dblox_logical_check_fail_mod.v | 2 + .../test/data/3dblox_logical_check_fail_net.v | 2 + src/odb/test/data/3dblox_logical_check_pass.v | 2 + src/odb/test/data/3dblox_logical_test.3dbv | 11 ++ src/odb/test/data/3dblox_logical_test.v | 2 + src/odb/test/data/dummy.lef | 14 ++ src/odb/test/temp_test.v | 2 + src/odb/test/test.3dbv | 6 + 16 files changed, 522 insertions(+), 75 deletions(-) create mode 100644 src/odb/test/cpp/Test3DBloxCheckerFixture.h create mode 100644 src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp create mode 100644 src/odb/test/data/3dblox_logical_check_fail_mod.v create mode 100644 src/odb/test/data/3dblox_logical_check_fail_net.v create mode 100644 src/odb/test/data/3dblox_logical_check_pass.v create mode 100644 src/odb/test/data/3dblox_logical_test.3dbv create mode 100644 src/odb/test/data/3dblox_logical_test.v create mode 100644 src/odb/test/data/dummy.lef create mode 100644 src/odb/test/temp_test.v create mode 100644 src/odb/test/test.3dbv diff --git a/src/odb/include/odb/3dblox.h b/src/odb/include/odb/3dblox.h index ab170cd11b..7cf025780f 100644 --- a/src/odb/include/odb/3dblox.h +++ b/src/odb/include/odb/3dblox.h @@ -66,5 +66,6 @@ class ThreeDBlox std::unordered_set written_techs_; std::unordered_set written_libs_; std::unordered_set read_files_; + std::unordered_set read_verilog_files_; }; } // namespace odb diff --git a/src/odb/src/3dblox/3dblox.cpp b/src/odb/src/3dblox/3dblox.cpp index f492dcae4e..f891a8a6e0 100644 --- a/src/odb/src/3dblox/3dblox.cpp +++ b/src/odb/src/3dblox/3dblox.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,8 @@ #include "odb/geom.h" #include "odb/lefin.h" #include "odb/lefout.h" +#include "sta/Network.hh" +#include "sta/NetworkClass.hh" #include "sta/Sta.hh" #include "utl/Logger.h" #include "utl/ScopedTemporaryFile.h" @@ -337,6 +340,62 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet) odb::dbStringProperty::create( chip, "verilog_file", chiplet.external.verilog_file.c_str()); } + if (sta_ != nullptr) { + std::string full_path + = std::filesystem::absolute(chiplet.external.verilog_file).string(); + if (read_verilog_files_.insert(full_path).second) { + if (!sta_->readVerilog(chiplet.external.verilog_file.c_str())) { + logger_->warn(utl::ODB, + 554, + "Failed to read Verilog file {}", + chiplet.external.verilog_file); + } + } + auto* network = sta_->network(); + sta::Cell* cell = nullptr; + { + std::unique_ptr lib_iter( + network->libraryIterator()); + while (lib_iter->hasNext()) { + auto* lib = lib_iter->next(); + cell = network->findCell(lib, chiplet.name.c_str()); + if (cell) { + break; + } + } + } + + if (!cell) { + logger_->warn(utl::ODB, + 555, + "Verilog module {} not found in loaded libraries.", + chiplet.name); + } + + if (cell) { + std::unordered_set existing_nets; + for (auto* net : chip->getChipNets()) { + existing_nets.insert(net->getName()); + } + std::unique_ptr port_iter( + network->portBitIterator(cell)); + while (port_iter->hasNext()) { + auto* port = port_iter->next(); + const char* net_name = network->name(port); + if (!existing_nets.contains(net_name)) { + dbChipNet::create(chip, net_name); + existing_nets.insert(net_name); + debugPrint(logger_, + utl::ODB, + "3dblox", + 1, + "Created dbChipNet {} for chip {} from Verilog", + net_name, + chip->getName()); + } + } + } + } } // Read DEF file if (!chiplet.external.def_file.empty()) { diff --git a/src/odb/src/3dblox/checker.cpp b/src/odb/src/3dblox/checker.cpp index 86a3e63c66..bd466346bd 100644 --- a/src/odb/src/3dblox/checker.cpp +++ b/src/odb/src/3dblox/checker.cpp @@ -5,10 +5,14 @@ #include #include +#include +#include #include #include #include +#include #include +#include #include #include @@ -16,6 +20,10 @@ #include "odb/dbObject.h" #include "odb/geom.h" #include "odb/unfoldedModel.h" +#include "sta/Network.hh" +#include "sta/NetworkClass.hh" +#include "sta/PatternMatch.hh" +#include "sta/Sta.hh" #include "utl/Logger.h" #include "utl/unionFind.h" @@ -86,6 +94,25 @@ bool isValid(const UnfoldedConnection& conn) return (surfaces.top_z - surfaces.bot_z) == conn.connection->getThickness(); } +class StaReportGuard +{ + public: + StaReportGuard() : sta_(std::make_unique()) + { + sta_->makeComponents(); + } + ~StaReportGuard() + { + if (sta_) { + sta_->setReport(nullptr); + } + } + sta::Sta* operator->() const { return sta_.get(); } + + private: + std::unique_ptr sta_; +}; + } // namespace Checker::Checker(utl::Logger* logger) : logger_(logger) @@ -94,8 +121,9 @@ Checker::Checker(utl::Logger* logger) : logger_(logger) void Checker::check(dbChip* chip) { - UnfoldedModel model(logger_, chip); auto* top_cat = dbMarkerCategory::createOrReplace(chip, "3DBlox"); + checkLogicalConnectivity(top_cat, chip); + UnfoldedModel model(logger_, chip); checkFloatingChips(top_cat, model); checkOverlappingChips(top_cat, model); @@ -288,4 +316,158 @@ void Checker::checkNetConnectivity(dbMarkerCategory* top_cat, { } +void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) +{ + StaReportGuard sta; + std::unordered_set loaded_files; + std::unordered_set processed_masters; + + dbMarkerCategory* design_cat = nullptr; + dbMarkerCategory* alignment_cat = nullptr; + + for (auto* inst : chip->getChipInsts()) { + auto* master = inst->getMasterChip(); + if (!master || !processed_masters.insert(master).second) { + continue; + } + + auto* prop = dbProperty::find(master, "verilog_file"); + if (!prop || prop->getType() != dbProperty::STRING_PROP) { + debugPrint(logger_, + utl::ODB, + "3dblox", + 551, + "Missing 'verilog_file' property for master {}", + master->getName()); + continue; + } + + std::string raw_file = static_cast(prop)->getValue(); + std::error_code ec; + std::filesystem::path path + = std::filesystem::weakly_canonical(raw_file, ec); + if (ec) { + path = std::filesystem::absolute(raw_file, ec); + } + std::string file = path.string(); + + if (loaded_files.insert(file).second) { + debugPrint(logger_, + utl::ODB, + "3dblox", + 552, + "Reading Verilog file {} for design {}", + path.filename().string(), + master->getName()); + if (!sta->readVerilog(file.c_str())) { + debugPrint(logger_, + utl::ODB, + "3dblox", + 553, + "Failed to read Verilog file {}", + file); + } + } + + auto* network = sta->network(); + sta::Cell* cell = nullptr; + { + std::unique_ptr lib_iter( + network->libraryIterator()); + while (lib_iter->hasNext()) { + auto* lib = lib_iter->next(); + cell = network->findCell(lib, master->getName()); + if (cell) { + break; + } + } + } + + if (!cell) { + std::vector modules; + std::unique_ptr li(network->libraryIterator()); + sta::PatternMatch all("*"); + while (li->hasNext()) { + auto matches = network->findCellsMatching(li->next(), &all); + for (auto* c : matches) { + modules.emplace_back(network->name(c)); + } + } + std::ranges::sort(modules); + if (modules.size() > 10) { + modules.resize(10); + modules.emplace_back("..."); + } + if (!design_cat) { + design_cat + = dbMarkerCategory::createOrReplace(top_cat, "Design Alignment"); + } + auto* marker = dbMarker::create(design_cat); + std::string msg = fmt::format( + "Design Alignment Violation: Verilog module {} not found in file {}. " + "Available " + "modules: {}", + master->getName(), + file, + modules.empty() ? "None" + : fmt::format("{}", fmt::join(modules, ", "))); + marker->setComment(msg); + marker->addSource(master); + logger_->warn(utl::ODB, 550, msg); + continue; + } + + std::unordered_set verilog_nets; + { + std::unique_ptr port_iter( + network->portBitIterator(cell)); + while (port_iter->hasNext()) { + verilog_nets.insert(network->name(port_iter->next())); + } + } + + for (auto* region : master->getChipRegions()) { + for (auto* bump : region->getChipBumps()) { + auto* net = bump->getNet(); + if (net && !verilog_nets.contains(net->getName())) { + if (!alignment_cat) { + alignment_cat = dbMarkerCategory::createOrReplace( + top_cat, "Logical Alignment"); + } + auto* marker = dbMarker::create(alignment_cat); + std::string bump_name + = bump->getInst() ? bump->getInst()->getName() : "UNKNOWN_BUMP"; + + std::vector available_nets; + available_nets.insert( + available_nets.end(), verilog_nets.begin(), verilog_nets.end()); + std::ranges::sort(available_nets); + if (available_nets.size() > 10) { + available_nets.resize(10); + available_nets.emplace_back("..."); + } + + std::string msg = fmt::format( + "Logical net {} (bump {}) not found in Verilog. Available nets: " + "[{}]", + net->getName(), + bump_name, + fmt::join(available_nets, ", ")); + + marker->setComment(msg); + marker->addSource(bump); + logger_->warn( + utl::ODB, + 560, + "Logical net {} in bmap for chiplet {} (bump {}) not found in " + "Verilog", + net->getName(), + master->getName(), + bump_name); + } + } + } + } +} + } // namespace odb diff --git a/src/odb/src/3dblox/checker.h b/src/odb/src/3dblox/checker.h index 2690b5f981..110d278792 100644 --- a/src/odb/src/3dblox/checker.h +++ b/src/odb/src/3dblox/checker.h @@ -26,6 +26,7 @@ class Checker void check(dbChip* chip); private: + void checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip); void checkFloatingChips(dbMarkerCategory* top_cat, const UnfoldedModel& model); void checkOverlappingChips(dbMarkerCategory* top_cat, diff --git a/src/odb/test/cpp/CMakeLists.txt b/src/odb/test/cpp/CMakeLists.txt index 63bc8ab751..7b510837d9 100644 --- a/src/odb/test/cpp/CMakeLists.txt +++ b/src/odb/test/cpp/CMakeLists.txt @@ -36,7 +36,7 @@ add_executable(TestMaster TestMaster.cpp) add_executable(TestGDSIn TestGDSIn.cpp) add_executable(TestChips TestChips.cpp) add_executable(Test3DBloxParser Test3DBloxParser.cpp) -add_executable(Test3DBloxChecker Test3DBloxChecker.cpp) +add_executable(Test3DBloxChecker Test3DBloxChecker.cpp Test3DBloxCheckerLogicalConn.cpp) add_executable(TestSwapMaster TestSwapMaster.cpp) add_executable(TestSwapMasterUnusedPort TestSwapMasterUnusedPort.cpp) add_executable(TestWriteReadDbHier TestWriteReadDbHier.cpp) diff --git a/src/odb/test/cpp/Test3DBloxChecker.cpp b/src/odb/test/cpp/Test3DBloxChecker.cpp index 46becc8b7c..ef95b70a31 100644 --- a/src/odb/test/cpp/Test3DBloxChecker.cpp +++ b/src/odb/test/cpp/Test3DBloxChecker.cpp @@ -9,83 +9,11 @@ #include "odb/db.h" #include "odb/dbObject.h" #include "odb/geom.h" -#include "tst/fixture.h" +#include "Test3DBloxCheckerFixture.h" namespace odb { namespace { -class CheckerFixture : public tst::Fixture -{ - protected: - CheckerFixture() - { - tech_ = dbTech::create(db_.get(), "tech"); - top_chip_ - = dbChip::create(db_.get(), nullptr, "TopChip", dbChip::ChipType::HIER); - - // Create master chips - chip1_ = dbChip::create(db_.get(), tech_, "Chip1", dbChip::ChipType::DIE); - chip1_->setWidth(2000); - chip1_->setHeight(2000); - chip1_->setThickness(500); - - chip2_ = dbChip::create(db_.get(), tech_, "Chip2", dbChip::ChipType::DIE); - chip2_->setWidth(1500); - chip2_->setHeight(1500); - chip2_->setThickness(500); - - // Create regions on master chips - auto r1_fr = dbChipRegion::create( - chip1_, "r1_fr", dbChipRegion::Side::FRONT, nullptr); - r1_fr->setBox(Rect(0, 0, 2000, 2000)); - - auto r2_bk = dbChipRegion::create( - chip2_, "r2_bk", dbChipRegion::Side::BACK, nullptr); - r2_bk->setBox(Rect(0, 0, 1500, 1500)); - - auto r2_fr = dbChipRegion::create( - chip2_, "r2_fr", dbChipRegion::Side::FRONT, nullptr); - r2_fr->setBox(Rect(0, 0, 1500, 1500)); - } - - void check() - { - db_->setTopChip(top_chip_); - ThreeDBlox three_dblox(&logger_, db_.get()); - three_dblox.check(); - } - - std::vector getMarkers(const char* category_name) - { - auto top_cat = top_chip_->findMarkerCategory("3DBlox"); - if (!top_cat) { - return {}; - } - auto cat = top_cat->findMarkerCategory(category_name); - if (!cat) { - return {}; - } - - std::vector markers; - for (auto* m : cat->getMarkers()) { - markers.push_back(m); - } - return markers; - } - - dbTech* tech_; - dbChip* top_chip_; - dbChip* chip1_; - dbChip* chip2_; - - static constexpr const char* floating_chips_category = "Floating chips"; - static constexpr const char* overlapping_chips_category = "Overlapping chips"; - static constexpr const char* unused_internal_ext_category - = "Unused internal_ext"; - static constexpr const char* connected_regions_category - = "Connection regions"; -}; - TEST_F(CheckerFixture, test_no_violations) { auto inst1 = dbChipInst::create(top_chip_, chip1_, "inst1"); diff --git a/src/odb/test/cpp/Test3DBloxCheckerFixture.h b/src/odb/test/cpp/Test3DBloxCheckerFixture.h new file mode 100644 index 0000000000..3e5ff0e707 --- /dev/null +++ b/src/odb/test/cpp/Test3DBloxCheckerFixture.h @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2023-2026, The OpenROAD Authors + +#pragma once + +#include + +#include "odb/3dblox.h" +#include "odb/db.h" +#include "odb/dbWireCodec.h" +#include "odb/geom.h" +#include "tst/fixture.h" + +namespace odb { +class CheckerFixture : public tst::Fixture +{ + protected: + CheckerFixture() + { + tech_ = dbTech::create(db_.get(), "tech"); + top_chip_ + = dbChip::create(db_.get(), nullptr, "TopChip", dbChip::ChipType::HIER); + + // Create master chips + chip1_ = dbChip::create(db_.get(), tech_, "Chip1", dbChip::ChipType::DIE); + chip1_->setWidth(2000); + chip1_->setHeight(2000); + chip1_->setThickness(500); + + chip2_ = dbChip::create(db_.get(), tech_, "Chip2", dbChip::ChipType::DIE); + chip2_->setWidth(1500); + chip2_->setHeight(1500); + chip2_->setThickness(500); + + // Create regions on master chips + auto r1_fr = dbChipRegion::create( + chip1_, "r1_fr", dbChipRegion::Side::FRONT, nullptr); + r1_fr->setBox(Rect(0, 0, 2000, 2000)); + + auto r2_bk = dbChipRegion::create( + chip2_, "r2_bk", dbChipRegion::Side::BACK, nullptr); + r2_bk->setBox(Rect(0, 0, 1500, 1500)); + + auto r2_fr = dbChipRegion::create( + chip2_, "r2_fr", dbChipRegion::Side::FRONT, nullptr); + r2_fr->setBox(Rect(0, 0, 1500, 1500)); + } + + void check() + { + db_->setTopChip(top_chip_); + ThreeDBlox three_dblox(&logger_, db_.get()); + three_dblox.check(); + } + + std::vector getMarkers(const char* category_name) + { + auto top_cat = top_chip_->findMarkerCategory("3DBlox"); + if (!top_cat) { + return {}; + } + auto cat = top_cat->findMarkerCategory(category_name); + if (!cat) { + return {}; + } + + std::vector markers; + for (auto* m : cat->getMarkers()) { + markers.push_back(m); + } + return markers; + } + + dbTech* tech_; + dbChip* top_chip_; + dbChip* chip1_; + dbChip* chip2_; + + static constexpr const char* floating_chips_category = "Floating chips"; + static constexpr const char* overlapping_chips_category = "Overlapping chips"; + static constexpr const char* unused_internal_ext_category + = "Unused internal_ext"; + static constexpr const char* connected_regions_category + = "Connection regions"; +}; + +} // namespace odb diff --git a/src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp b/src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp new file mode 100644 index 0000000000..3c83501f26 --- /dev/null +++ b/src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp @@ -0,0 +1,148 @@ +#include + +#include + +#include "odb/3dblox.h" +#include "odb/db.h" +#include "tst/fixture.h" + +namespace odb { + +class LogicalConnFixture : public tst::Fixture +{ + protected: + void SetUp() override + { + blox_ = new ThreeDBlox(&logger_, db_.get(), sta_.get()); + } + + void TearDown() override { delete blox_; } + + ThreeDBlox* blox_; +}; + +TEST_F(LogicalConnFixture, TestMissingNetCreation) +{ + std::string dbv_file + = getFilePath("src/odb/test/data/3dblox_logical_test.3dbv"); + + // Run readDbv + blox_->readDbv(dbv_file); + + // Check if chip "top" was created + auto* created_chip = db_->findChip("top"); + ASSERT_NE(created_chip, nullptr); + + // Check if nets "A" and "Z" were created in the chip + bool foundA = false; + bool foundZ = false; + for (auto* net : created_chip->getChipNets()) { + if (net->getName() == "A") { + foundA = true; + } + if (net->getName() == "Z") { + foundZ = true; + } + } + EXPECT_TRUE(foundA); + EXPECT_TRUE(foundZ); +} + +TEST_F(LogicalConnFixture, TestCheckerNoViolations) +{ + auto* tech = dbTech::create(db_.get(), "tech"); + // master chip name matches module name in Verilog "top" + auto* master = dbChip::create(db_.get(), tech, "top", dbChip::ChipType::DIE); + dbChipNet::create(master, "A"); + dbChipNet::create(master, "Z"); + + std::string verilog_file + = getFilePath("src/odb/test/data/3dblox_logical_check_pass.v"); + odb::dbStringProperty::create(master, "verilog_file", verilog_file.c_str()); + + // top chip containing instance of master + auto* design_top = dbChip::create( + db_.get(), nullptr, "design_top", dbChip::ChipType::HIER); + dbChipInst::create(design_top, master, "inst1"); + db_->setTopChip(design_top); + + // Run Checker + blox_->check(); + + // Verify no markers in "Logical Alignment" or "Design Alignment" + auto* top_cat = design_top->findMarkerCategory("3DBlox"); + if (top_cat) { + auto* design_cat = top_cat->findMarkerCategory("Design Alignment"); + if (design_cat) { + EXPECT_EQ(design_cat->getMarkers().size(), 0); + } + auto* align_cat = top_cat->findMarkerCategory("Logical Alignment"); + if (align_cat) { + EXPECT_EQ(align_cat->getMarkers().size(), 0); + } + } +} + +TEST_F(LogicalConnFixture, TestCheckerMissingModule) +{ + auto* tech = dbTech::create(db_.get(), "tech"); + // master chip name "top" but Verilog has "other_module" + auto* master = dbChip::create(db_.get(), tech, "top", dbChip::ChipType::DIE); + + std::string verilog_file + = getFilePath("src/odb/test/data/3dblox_logical_check_fail_mod.v"); + odb::dbStringProperty::create(master, "verilog_file", verilog_file.c_str()); + + auto* design_top = dbChip::create( + db_.get(), nullptr, "design_top", dbChip::ChipType::HIER); + dbChipInst::create(design_top, master, "inst1"); + db_->setTopChip(design_top); + + blox_->check(); + + // Verify "Design Alignment" marker + auto* top_cat = design_top->findMarkerCategory("3DBlox"); + ASSERT_NE(top_cat, nullptr); + auto* design_cat = top_cat->findMarkerCategory("Design Alignment"); + ASSERT_NE(design_cat, nullptr); + EXPECT_GT(design_cat->getMarkers().size(), 0); +} + +TEST_F(LogicalConnFixture, TestCheckerMissingNetInVerilog) +{ + auto* tech = dbTech::create(db_.get(), "tech"); + // master chip name "top" matches module name in Verilog + auto* master = dbChip::create(db_.get(), tech, "top", dbChip::ChipType::DIE); + + // Create a bump connected to a net "EXTRA" that is NOT in Verilog + auto* region + = dbChipRegion::create(master, "r1", dbChipRegion::Side::FRONT, nullptr); + auto* block = dbBlock::create(master, "block"); + auto* lib = dbLib::create(db_.get(), "lib", tech); + auto* bump_master = dbMaster::create(lib, "bump_cell"); + bump_master->setFrozen(); + auto* inst = dbInst::create(block, bump_master, "bump_inst"); + auto* bump = dbChipBump::create(region, inst); + auto* net = dbNet::create(block, "EXTRA"); + bump->setNet(net); + + std::string verilog_file + = getFilePath("src/odb/test/data/3dblox_logical_check_fail_net.v"); + odb::dbStringProperty::create(master, "verilog_file", verilog_file.c_str()); + + auto* design_top = dbChip::create( + db_.get(), nullptr, "design_top", dbChip::ChipType::HIER); + dbChipInst::create(design_top, master, "inst1"); + db_->setTopChip(design_top); + + blox_->check(); + + // Verify "Logical Alignment" marker + auto* top_cat = design_top->findMarkerCategory("3DBlox"); + ASSERT_NE(top_cat, nullptr); + auto* align_cat = top_cat->findMarkerCategory("Logical Alignment"); + ASSERT_NE(align_cat, nullptr); + EXPECT_GT(align_cat->getMarkers().size(), 0); +} + +} // namespace odb diff --git a/src/odb/test/data/3dblox_logical_check_fail_mod.v b/src/odb/test/data/3dblox_logical_check_fail_mod.v new file mode 100644 index 0000000000..131858912c --- /dev/null +++ b/src/odb/test/data/3dblox_logical_check_fail_mod.v @@ -0,0 +1,2 @@ +module other_module ( input A ); +endmodule diff --git a/src/odb/test/data/3dblox_logical_check_fail_net.v b/src/odb/test/data/3dblox_logical_check_fail_net.v new file mode 100644 index 0000000000..aa14a96b57 --- /dev/null +++ b/src/odb/test/data/3dblox_logical_check_fail_net.v @@ -0,0 +1,2 @@ +module top ( input A ); +endmodule diff --git a/src/odb/test/data/3dblox_logical_check_pass.v b/src/odb/test/data/3dblox_logical_check_pass.v new file mode 100644 index 0000000000..7ef36a9cc2 --- /dev/null +++ b/src/odb/test/data/3dblox_logical_check_pass.v @@ -0,0 +1,2 @@ +module top ( input A, output Z ); +endmodule diff --git a/src/odb/test/data/3dblox_logical_test.3dbv b/src/odb/test/data/3dblox_logical_test.3dbv new file mode 100644 index 0000000000..1ed86aeb2f --- /dev/null +++ b/src/odb/test/data/3dblox_logical_test.3dbv @@ -0,0 +1,11 @@ +Header: + version: 2.5 + unit: micron + precision: 1000 + +ChipletDef: + top: + type: die + external: + verilog_file: 3dblox_logical_test.v + APR_tech_file: [dummy.lef] diff --git a/src/odb/test/data/3dblox_logical_test.v b/src/odb/test/data/3dblox_logical_test.v new file mode 100644 index 0000000000..7ef36a9cc2 --- /dev/null +++ b/src/odb/test/data/3dblox_logical_test.v @@ -0,0 +1,2 @@ +module top ( input A, output Z ); +endmodule diff --git a/src/odb/test/data/dummy.lef b/src/odb/test/data/dummy.lef new file mode 100644 index 0000000000..0acd086a8a --- /dev/null +++ b/src/odb/test/data/dummy.lef @@ -0,0 +1,14 @@ +VERSION 5.8 ; +NAMESCASESENSITIVE ON ; +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; + +UNITS + DATABASE MICRONS 1000 ; +END UNITS + +LAYER metal1 + TYPE ROUTING ; +END metal1 + +END LIBRARY diff --git a/src/odb/test/temp_test.v b/src/odb/test/temp_test.v new file mode 100644 index 0000000000..7ef36a9cc2 --- /dev/null +++ b/src/odb/test/temp_test.v @@ -0,0 +1,2 @@ +module top ( input A, output Z ); +endmodule diff --git a/src/odb/test/test.3dbv b/src/odb/test/test.3dbv new file mode 100644 index 0000000000..d5343a806f --- /dev/null +++ b/src/odb/test/test.3dbv @@ -0,0 +1,6 @@ +precision: 1000 +chiplet_defs: + top: + type: die + external: + verilog_file: temp_test.v From e3bb1583f7740df001d9306c0485c1db1e0b10a9 Mon Sep 17 00:00:00 2001 From: "Ahmed R. Mohamed" Date: Sun, 1 Mar 2026 08:48:17 -0800 Subject: [PATCH 2/6] odb: fix 3dblox checker logical conn PR comments Performance imporvments and formatting Signed-off-by: Ahmed R. Mohamed --- src/odb/src/3dblox/3dblox.cpp | 10 ++++++++-- src/odb/src/3dblox/checker.cpp | 18 +++++++++--------- src/odb/test/cpp/Test3DBloxChecker.cpp | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/odb/src/3dblox/3dblox.cpp b/src/odb/src/3dblox/3dblox.cpp index f891a8a6e0..7dd0ca3ad8 100644 --- a/src/odb/src/3dblox/3dblox.cpp +++ b/src/odb/src/3dblox/3dblox.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -341,8 +342,13 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet) chip, "verilog_file", chiplet.external.verilog_file.c_str()); } if (sta_ != nullptr) { - std::string full_path - = std::filesystem::absolute(chiplet.external.verilog_file).string(); + std::error_code ec; + auto path = std::filesystem::weakly_canonical( + chiplet.external.verilog_file, ec); + if (ec) { + path = std::filesystem::absolute(chiplet.external.verilog_file, ec); + } + std::string full_path = path.string(); if (read_verilog_files_.insert(full_path).second) { if (!sta_->readVerilog(chiplet.external.verilog_file.c_str())) { logger_->warn(utl::ODB, diff --git a/src/odb/src/3dblox/checker.cpp b/src/odb/src/3dblox/checker.cpp index bd466346bd..4a8a658c05 100644 --- a/src/odb/src/3dblox/checker.cpp +++ b/src/odb/src/3dblox/checker.cpp @@ -426,6 +426,15 @@ void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) } } + std::vector available_nets; + available_nets.insert( + available_nets.end(), verilog_nets.begin(), verilog_nets.end()); + std::ranges::sort(available_nets); + if (available_nets.size() > 10) { + available_nets.resize(10); + available_nets.emplace_back("..."); + } + for (auto* region : master->getChipRegions()) { for (auto* bump : region->getChipBumps()) { auto* net = bump->getNet(); @@ -438,15 +447,6 @@ void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) std::string bump_name = bump->getInst() ? bump->getInst()->getName() : "UNKNOWN_BUMP"; - std::vector available_nets; - available_nets.insert( - available_nets.end(), verilog_nets.begin(), verilog_nets.end()); - std::ranges::sort(available_nets); - if (available_nets.size() > 10) { - available_nets.resize(10); - available_nets.emplace_back("..."); - } - std::string msg = fmt::format( "Logical net {} (bump {}) not found in Verilog. Available nets: " "[{}]", diff --git a/src/odb/test/cpp/Test3DBloxChecker.cpp b/src/odb/test/cpp/Test3DBloxChecker.cpp index ef95b70a31..88d23aac48 100644 --- a/src/odb/test/cpp/Test3DBloxChecker.cpp +++ b/src/odb/test/cpp/Test3DBloxChecker.cpp @@ -4,12 +4,12 @@ #include #include +#include "Test3DBloxCheckerFixture.h" #include "gtest/gtest.h" #include "odb/3dblox.h" #include "odb/db.h" #include "odb/dbObject.h" #include "odb/geom.h" -#include "Test3DBloxCheckerFixture.h" namespace odb { namespace { From fd22b2e8d773d6bb378e4c204363a04736766ff4 Mon Sep 17 00:00:00 2001 From: "Ahmed R. Mohamed" Date: Sun, 1 Mar 2026 16:23:26 -0800 Subject: [PATCH 3/6] odb: fix 3dblox checker check logical conn PR comments use NetIterator instead of PortBitIterator. Remove redundent code. Signed-off-by: Ahmed R. Mohamed --- src/odb/include/odb/3dblox.h | 1 - src/odb/src/3dblox/3dblox.cpp | 102 +++++++++++++++----------- src/odb/src/3dblox/checker.cpp | 130 ++++++++++++++------------------- src/odb/src/3dblox/checker.h | 10 ++- src/odb/test/data/dummy.lef | 1 - src/odb/test/write_3dbv.3dbvok | 1 + 6 files changed, 123 insertions(+), 122 deletions(-) diff --git a/src/odb/include/odb/3dblox.h b/src/odb/include/odb/3dblox.h index 7cf025780f..ab170cd11b 100644 --- a/src/odb/include/odb/3dblox.h +++ b/src/odb/include/odb/3dblox.h @@ -66,6 +66,5 @@ class ThreeDBlox std::unordered_set written_techs_; std::unordered_set written_libs_; std::unordered_set read_files_; - std::unordered_set read_verilog_files_; }; } // namespace odb diff --git a/src/odb/src/3dblox/3dblox.cpp b/src/odb/src/3dblox/3dblox.cpp index 7dd0ca3ad8..09f1439d27 100644 --- a/src/odb/src/3dblox/3dblox.cpp +++ b/src/odb/src/3dblox/3dblox.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -31,9 +30,10 @@ #include "odb/geom.h" #include "odb/lefin.h" #include "odb/lefout.h" -#include "sta/Network.hh" +#include "sta/ConcreteNetwork.hh" #include "sta/NetworkClass.hh" #include "sta/Sta.hh" +#include "sta/VerilogReader.hh" #include "utl/Logger.h" #include "utl/ScopedTemporaryFile.h" namespace odb { @@ -98,10 +98,37 @@ void ThreeDBlox::readDbx(const std::string& dbx_file) calculateSize(chip); } +namespace { +void readVerilogFiles(dbChip* chip, + sta::Sta* sta, + std::unordered_set& processed) +{ + if (!chip || !processed.insert(chip).second) { + return; + } + auto* prop = dbStringProperty::find(chip, "verilog_file"); + if (prop && sta) { + std::string verilog_file = prop->getValue(); + if (!verilog_file.empty()) { + if (std::filesystem::exists(verilog_file)) { + sta->readVerilog(verilog_file.c_str()); + } + } + } + for (auto* inst : chip->getChipInsts()) { + readVerilogFiles(inst->getMasterChip(), sta, processed); + } +} +} // namespace + void ThreeDBlox::check() { + if (sta_) { + std::unordered_set processed; + readVerilogFiles(db_->getChip(), sta_, processed); + } Checker checker(logger_); - checker.check(db_->getChip()); + checker.check(db_->getChip(), sta_); } namespace { @@ -342,14 +369,8 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet) chip, "verilog_file", chiplet.external.verilog_file.c_str()); } if (sta_ != nullptr) { - std::error_code ec; - auto path = std::filesystem::weakly_canonical( - chiplet.external.verilog_file, ec); - if (ec) { - path = std::filesystem::absolute(chiplet.external.verilog_file, ec); - } - std::string full_path = path.string(); - if (read_verilog_files_.insert(full_path).second) { + if (!chiplet.external.verilog_file.empty() + && std::filesystem::exists(chiplet.external.verilog_file)) { if (!sta_->readVerilog(chiplet.external.verilog_file.c_str())) { logger_->warn(utl::ODB, 554, @@ -357,40 +378,21 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet) chiplet.external.verilog_file); } } - auto* network = sta_->network(); - sta::Cell* cell = nullptr; - { - std::unique_ptr lib_iter( - network->libraryIterator()); - while (lib_iter->hasNext()) { - auto* lib = lib_iter->next(); - cell = network->findCell(lib, chiplet.name.c_str()); - if (cell) { - break; - } - } - } - - if (!cell) { - logger_->warn(utl::ODB, - 555, - "Verilog module {} not found in loaded libraries.", - chiplet.name); - } - - if (cell) { - std::unordered_set existing_nets; - for (auto* net : chip->getChipNets()) { - existing_nets.insert(net->getName()); - } - std::unique_ptr port_iter( - network->portBitIterator(cell)); - while (port_iter->hasNext()) { - auto* port = port_iter->next(); - const char* net_name = network->name(port); - if (!existing_nets.contains(net_name)) { + sta::ConcreteNetwork temp_network; + temp_network.copyState(sta_); + sta::VerilogReader verilog_reader(&temp_network); + if (verilog_reader.read(chiplet.external.verilog_file.c_str())) { + sta::Instance* top_inst + = verilog_reader.linkNetwork(chiplet.name.c_str(), + /*make_black_boxes*/ true, + /*delete_modules*/ false); + if (top_inst) { + std::unique_ptr net_iter( + temp_network.netIterator(top_inst)); + while (net_iter->hasNext()) { + auto* net = net_iter->next(); + const char* net_name = temp_network.name(net); dbChipNet::create(chip, net_name); - existing_nets.insert(net_name); debugPrint(logger_, utl::ODB, "3dblox", @@ -399,6 +401,12 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet) net_name, chip->getName()); } + } else { + logger_->warn(utl::ODB, + 555, + "Verilog module {} not found in Verilog file {}.", + chiplet.name, + chiplet.external.verilog_file); } } } @@ -640,6 +648,12 @@ void ThreeDBlox::createChipInst(const ChipletInst& chip_inst) static_cast(chip_inst.loc.y * db_->getDbuPerMicron()), static_cast(chip_inst.z * db_->getDbuPerMicron()), }); + if (!chip_inst.external.verilog_file.empty()) { + if (odb::dbProperty::find(chip, "verilog_file") == nullptr) { + odb::dbStringProperty::create( + chip, "verilog_file", chip_inst.external.verilog_file.c_str()); + } + } } static std::vector splitPath(const std::string& path) { diff --git a/src/odb/src/3dblox/checker.cpp b/src/odb/src/3dblox/checker.cpp index 4a8a658c05..7eaf92e5a4 100644 --- a/src/odb/src/3dblox/checker.cpp +++ b/src/odb/src/3dblox/checker.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -20,10 +19,12 @@ #include "odb/dbObject.h" #include "odb/geom.h" #include "odb/unfoldedModel.h" +#include "sta/ConcreteNetwork.hh" #include "sta/Network.hh" #include "sta/NetworkClass.hh" #include "sta/PatternMatch.hh" #include "sta/Sta.hh" +#include "sta/VerilogReader.hh" #include "utl/Logger.h" #include "utl/unionFind.h" @@ -94,23 +95,28 @@ bool isValid(const UnfoldedConnection& conn) return (surfaces.top_z - surfaces.bot_z) == conn.connection->getThickness(); } -class StaReportGuard +class StaGuard { public: - StaReportGuard() : sta_(std::make_unique()) + StaGuard(sta::Sta* sta) : sta_ptr_(sta) { - sta_->makeComponents(); + if (!sta_ptr_) { + temp_sta_ = std::make_unique(); + temp_sta_->makeComponents(); + sta_ptr_ = temp_sta_.get(); + } } - ~StaReportGuard() + ~StaGuard() { - if (sta_) { - sta_->setReport(nullptr); + if (temp_sta_) { + temp_sta_->setReport(nullptr); } } - sta::Sta* operator->() const { return sta_.get(); } + sta::Sta* operator->() const { return sta_ptr_; } private: - std::unique_ptr sta_; + std::unique_ptr temp_sta_; + sta::Sta* sta_ptr_; }; } // namespace @@ -119,12 +125,11 @@ Checker::Checker(utl::Logger* logger) : logger_(logger) { } -void Checker::check(dbChip* chip) +void Checker::check(dbChip* chip, sta::Sta* sta) { auto* top_cat = dbMarkerCategory::createOrReplace(chip, "3DBlox"); - checkLogicalConnectivity(top_cat, chip); + checkLogicalConnectivity(top_cat, chip, sta); UnfoldedModel model(logger_, chip); - checkFloatingChips(top_cat, model); checkOverlappingChips(top_cat, model); checkInternalExtUsage(top_cat, model); @@ -316,10 +321,11 @@ void Checker::checkNetConnectivity(dbMarkerCategory* top_cat, { } -void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) +void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, + dbChip* chip, + sta::Sta* sta) { - StaReportGuard sta; - std::unordered_set loaded_files; + StaGuard sta_guard(sta); std::unordered_set processed_masters; dbMarkerCategory* design_cat = nullptr; @@ -331,45 +337,7 @@ void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) continue; } - auto* prop = dbProperty::find(master, "verilog_file"); - if (!prop || prop->getType() != dbProperty::STRING_PROP) { - debugPrint(logger_, - utl::ODB, - "3dblox", - 551, - "Missing 'verilog_file' property for master {}", - master->getName()); - continue; - } - - std::string raw_file = static_cast(prop)->getValue(); - std::error_code ec; - std::filesystem::path path - = std::filesystem::weakly_canonical(raw_file, ec); - if (ec) { - path = std::filesystem::absolute(raw_file, ec); - } - std::string file = path.string(); - - if (loaded_files.insert(file).second) { - debugPrint(logger_, - utl::ODB, - "3dblox", - 552, - "Reading Verilog file {} for design {}", - path.filename().string(), - master->getName()); - if (!sta->readVerilog(file.c_str())) { - debugPrint(logger_, - utl::ODB, - "3dblox", - 553, - "Failed to read Verilog file {}", - file); - } - } - - auto* network = sta->network(); + auto* network = sta_guard->network(); sta::Cell* cell = nullptr; { std::unique_ptr lib_iter( @@ -390,7 +358,10 @@ void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) while (li->hasNext()) { auto matches = network->findCellsMatching(li->next(), &all); for (auto* c : matches) { - modules.emplace_back(network->name(c)); + const char* name = network->name(c); + if (name) { + modules.emplace_back(name); + } } } std::ranges::sort(modules); @@ -404,11 +375,9 @@ void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) } auto* marker = dbMarker::create(design_cat); std::string msg = fmt::format( - "Design Alignment Violation: Verilog module {} not found in file {}. " - "Available " - "modules: {}", + "Design Alignment Violation: Verilog module {} not found. " + "Available modules: {}", master->getName(), - file, modules.empty() ? "None" : fmt::format("{}", fmt::join(modules, ", "))); marker->setComment(msg); @@ -417,28 +386,41 @@ void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) continue; } - std::unordered_set verilog_nets; - { - std::unique_ptr port_iter( - network->portBitIterator(cell)); - while (port_iter->hasNext()) { - verilog_nets.insert(network->name(port_iter->next())); + std::unordered_set nets; + auto* prop = dbStringProperty::find(master, "verilog_file"); + if (prop && sta) { + std::string verilog_file = prop->getValue(); + if (!verilog_file.empty() && std::filesystem::exists(verilog_file)) { + sta::ConcreteNetwork temp_network; + temp_network.copyState(sta); + sta::VerilogReader verilog_reader(&temp_network); + if (verilog_reader.read(verilog_file.c_str())) { + sta::Instance* top_inst + = verilog_reader.linkNetwork(master->getName(), + /*make_black_boxes*/ true, + /*delete_modules*/ false); + if (top_inst) { + std::unique_ptr net_iter( + temp_network.netIterator(top_inst)); + while (net_iter->hasNext()) { + nets.insert(temp_network.name(net_iter->next())); + } + } + } } } - std::vector available_nets; - available_nets.insert( - available_nets.end(), verilog_nets.begin(), verilog_nets.end()); - std::ranges::sort(available_nets); - if (available_nets.size() > 10) { - available_nets.resize(10); - available_nets.emplace_back("..."); + std::vector sorted_nets(nets.begin(), nets.end()); + std::ranges::sort(sorted_nets); + if (sorted_nets.size() > 10) { + sorted_nets.resize(10); + sorted_nets.emplace_back("..."); } for (auto* region : master->getChipRegions()) { for (auto* bump : region->getChipBumps()) { auto* net = bump->getNet(); - if (net && !verilog_nets.contains(net->getName())) { + if (net && !nets.contains(net->getName())) { if (!alignment_cat) { alignment_cat = dbMarkerCategory::createOrReplace( top_cat, "Logical Alignment"); @@ -452,7 +434,7 @@ void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip) "[{}]", net->getName(), bump_name, - fmt::join(available_nets, ", ")); + fmt::join(sorted_nets, ", ")); marker->setComment(msg); marker->addSource(bump); diff --git a/src/odb/src/3dblox/checker.h b/src/odb/src/3dblox/checker.h index 110d278792..a131b3e875 100644 --- a/src/odb/src/3dblox/checker.h +++ b/src/odb/src/3dblox/checker.h @@ -7,6 +7,10 @@ #include "odb/unfoldedModel.h" #include "utl/Logger.h" +namespace sta { +class Sta; +} + namespace odb { class dbChip; class dbMarkerCategory; @@ -23,10 +27,12 @@ class Checker public: Checker(utl::Logger* logger); ~Checker() = default; - void check(dbChip* chip); + void check(dbChip* chip, sta::Sta* sta); private: - void checkLogicalConnectivity(dbMarkerCategory* top_cat, dbChip* chip); + void checkLogicalConnectivity(dbMarkerCategory* top_cat, + dbChip* chip, + sta::Sta* sta); void checkFloatingChips(dbMarkerCategory* top_cat, const UnfoldedModel& model); void checkOverlappingChips(dbMarkerCategory* top_cat, diff --git a/src/odb/test/data/dummy.lef b/src/odb/test/data/dummy.lef index 0acd086a8a..4c394baf9e 100644 --- a/src/odb/test/data/dummy.lef +++ b/src/odb/test/data/dummy.lef @@ -1,5 +1,4 @@ VERSION 5.8 ; -NAMESCASESENSITIVE ON ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; diff --git a/src/odb/test/write_3dbv.3dbvok b/src/odb/test/write_3dbv.3dbvok index 7fff9e07ad..9d49e490e8 100644 --- a/src/odb/test/write_3dbv.3dbvok +++ b/src/odb/test/write_3dbv.3dbvok @@ -16,6 +16,7 @@ ChipletDef: APR_tech_file: [Nangate45_tech.lef] LEF_file: [fake_bumps_lib.lef, fake_macros_lib.lef] DEF_file: SoC.def + verilog_file: data/soc.v regions: back_reg: side: back From 0fa4dd81fcaa1cd4ce6e020f51f5bfd897d95fe8 Mon Sep 17 00:00:00 2001 From: "Ahmed R. Mohamed" Date: Mon, 2 Mar 2026 10:22:50 -0800 Subject: [PATCH 4/6] odb: fix 3dblox checker checkLogical PR comments Remvoe STA dependency from checker. Signed-off-by: Ahmed R. Mohamed --- src/odb/include/odb/3dblox.h | 2 + src/odb/src/3dblox/3dblox.cpp | 192 +++++++------ src/odb/src/3dblox/checker.cpp | 199 ++++--------- src/odb/src/3dblox/checker.h | 5 +- src/odb/test/cpp/Test3DBloxCheckerFixture.h | 2 + .../test/cpp/Test3DBloxCheckerLogicalConn.cpp | 263 ++++++++++-------- .../test/data/3dblox_logical_check_fail_mod.v | 2 - .../test/data/3dblox_logical_check_fail_net.v | 2 - src/odb/test/data/3dblox_logical_check_pass.v | 2 - src/odb/test/data/3dblox_logical_test.3dbv | 11 - src/odb/test/data/3dblox_logical_test.v | 2 - src/odb/test/data/dummy.lef | 13 - src/odb/test/temp_test.v | 2 - src/odb/test/test.3dbv | 6 - src/odb/test/write_3dbv.3dbvok | 1 - 15 files changed, 312 insertions(+), 392 deletions(-) delete mode 100644 src/odb/test/data/3dblox_logical_check_fail_mod.v delete mode 100644 src/odb/test/data/3dblox_logical_check_fail_net.v delete mode 100644 src/odb/test/data/3dblox_logical_check_pass.v delete mode 100644 src/odb/test/data/3dblox_logical_test.3dbv delete mode 100644 src/odb/test/data/3dblox_logical_test.v delete mode 100644 src/odb/test/data/dummy.lef delete mode 100644 src/odb/test/temp_test.v delete mode 100644 src/odb/test/test.3dbv diff --git a/src/odb/include/odb/3dblox.h b/src/odb/include/odb/3dblox.h index ab170cd11b..61873bb8aa 100644 --- a/src/odb/include/odb/3dblox.h +++ b/src/odb/include/odb/3dblox.h @@ -32,6 +32,7 @@ struct ChipletInst; struct Connection; struct DesignDef; struct BumpMapEntry; +struct DbxData; class ThreeDBlox { @@ -59,6 +60,7 @@ class ThreeDBlox std::vector& path_insts); void readHeaderIncludes(const std::vector& includes); void calculateSize(dbChip* chip); + void buildChipNetsFromVerilog(dbChip* chip, const DbxData& data); utl::Logger* logger_ = nullptr; odb::dbDatabase* db_ = nullptr; diff --git a/src/odb/src/3dblox/3dblox.cpp b/src/odb/src/3dblox/3dblox.cpp index 09f1439d27..a5b4753583 100644 --- a/src/odb/src/3dblox/3dblox.cpp +++ b/src/odb/src/3dblox/3dblox.cpp @@ -82,6 +82,111 @@ void ThreeDBlox::readDbv(const std::string& dbv_file) } } +void ThreeDBlox::buildChipNetsFromVerilog(dbChip* chip, const DbxData& data) +{ + // Read Verilog and create nets + if (!sta_ || data.design.external.verilog_file.empty()) { + return; + } + + std::string verilog_file = data.design.external.verilog_file; + if (!std::filesystem::exists(verilog_file)) { + return; + } + + sta::ConcreteNetwork temp_network; + temp_network.copyState(sta_); + sta::VerilogReader verilog_reader(&temp_network); + + if (!verilog_reader.read(verilog_file.c_str())) { + return; + } + + sta::Instance* top_inst + = verilog_reader.linkNetwork(data.design.name.c_str(), true, false); + if (!top_inst) { + logger_->warn(utl::ODB, + 555, + "Verilog module {} not found in Verilog file {}.", + data.design.name, + verilog_file); + return; + } + + // Pre-process master chips to map port names to bumps + std::map> master_bump_map; + for (auto* inst : chip->getChipInsts()) { + dbChip* master = inst->getMasterChip(); + + // Skip if already processed + if (master_bump_map.contains(master)) { + continue; + } + + for (auto* region : master->getChipRegions()) { + for (auto* bump : region->getChipBumps()) { + if (auto* bterm = bump->getBTerm()) { + master_bump_map[master][bterm->getName()] = bump; + } + } + } + } + + // Process nets + std::unique_ptr net_iter( + temp_network.netIterator(top_inst)); + while (net_iter->hasNext()) { + auto* net = net_iter->next(); + const char* net_name = temp_network.name(net); + auto* chip_net = dbChipNet::create(chip, net_name); + + debugPrint(logger_, + utl::ODB, + "3dblox", + 1, + "Created dbChipNet {} for chip {} from Verilog", + net_name, + chip->getName()); + + std::unique_ptr pin_iter( + temp_network.pinIterator(net)); + while (pin_iter->hasNext()) { + const sta::Pin* pin = pin_iter->next(); + const sta::Instance* instance = temp_network.instance(pin); + + if (instance == top_inst) { + continue; + } + + auto* chip_inst = chip->findChipInst(temp_network.name(instance)); + if (!chip_inst) { + continue; + } + + const char* port_name = temp_network.name(temp_network.port(pin)); + dbChip* master = chip_inst->getMasterChip(); + + auto bump_it = master_bump_map[master].find(port_name); + if (bump_it == master_bump_map[master].end()) { + continue; + } + + dbChipBump* bump = bump_it->second; + auto* region_inst = chip_inst->findChipRegionInst(bump->getChipRegion()); + if (!region_inst) { + continue; + } + + for (auto bump_inst : region_inst->getChipBumpInsts()) { + if (bump_inst->getChipBump() == bump) { + chip_net->addBumpInst(bump_inst, {chip_inst}); + break; + } + } + } + } +} + void ThreeDBlox::readDbx(const std::string& dbx_file) { read_files_.insert(std::filesystem::absolute(dbx_file).string()); @@ -92,43 +197,19 @@ void ThreeDBlox::readDbx(const std::string& dbx_file) for (const auto& [_, chip_inst] : data.chiplet_instances) { createChipInst(chip_inst); } + + buildChipNetsFromVerilog(chip, data); + for (const auto& [_, connection] : data.connections) { createConnection(connection); } calculateSize(chip); } -namespace { -void readVerilogFiles(dbChip* chip, - sta::Sta* sta, - std::unordered_set& processed) -{ - if (!chip || !processed.insert(chip).second) { - return; - } - auto* prop = dbStringProperty::find(chip, "verilog_file"); - if (prop && sta) { - std::string verilog_file = prop->getValue(); - if (!verilog_file.empty()) { - if (std::filesystem::exists(verilog_file)) { - sta->readVerilog(verilog_file.c_str()); - } - } - } - for (auto* inst : chip->getChipInsts()) { - readVerilogFiles(inst->getMasterChip(), sta, processed); - } -} -} // namespace - void ThreeDBlox::check() { - if (sta_) { - std::unordered_set processed; - readVerilogFiles(db_->getChip(), sta_, processed); - } Checker checker(logger_); - checker.check(db_->getChip(), sta_); + checker.check(db_->getChip()); } namespace { @@ -363,54 +444,7 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet) chip = dbChip::create( db_, tech, chiplet.name, getChipType(chiplet.type, logger_)); } - if (!chiplet.external.verilog_file.empty()) { - if (odb::dbProperty::find(chip, "verilog_file") == nullptr) { - odb::dbStringProperty::create( - chip, "verilog_file", chiplet.external.verilog_file.c_str()); - } - if (sta_ != nullptr) { - if (!chiplet.external.verilog_file.empty() - && std::filesystem::exists(chiplet.external.verilog_file)) { - if (!sta_->readVerilog(chiplet.external.verilog_file.c_str())) { - logger_->warn(utl::ODB, - 554, - "Failed to read Verilog file {}", - chiplet.external.verilog_file); - } - } - sta::ConcreteNetwork temp_network; - temp_network.copyState(sta_); - sta::VerilogReader verilog_reader(&temp_network); - if (verilog_reader.read(chiplet.external.verilog_file.c_str())) { - sta::Instance* top_inst - = verilog_reader.linkNetwork(chiplet.name.c_str(), - /*make_black_boxes*/ true, - /*delete_modules*/ false); - if (top_inst) { - std::unique_ptr net_iter( - temp_network.netIterator(top_inst)); - while (net_iter->hasNext()) { - auto* net = net_iter->next(); - const char* net_name = temp_network.name(net); - dbChipNet::create(chip, net_name); - debugPrint(logger_, - utl::ODB, - "3dblox", - 1, - "Created dbChipNet {} for chip {} from Verilog", - net_name, - chip->getName()); - } - } else { - logger_->warn(utl::ODB, - 555, - "Verilog module {} not found in Verilog file {}.", - chiplet.name, - chiplet.external.verilog_file); - } - } - } - } + // Read DEF file if (!chiplet.external.def_file.empty()) { odb::defin def_reader(db_, logger_, odb::defin::DEFAULT); @@ -648,12 +682,6 @@ void ThreeDBlox::createChipInst(const ChipletInst& chip_inst) static_cast(chip_inst.loc.y * db_->getDbuPerMicron()), static_cast(chip_inst.z * db_->getDbuPerMicron()), }); - if (!chip_inst.external.verilog_file.empty()) { - if (odb::dbProperty::find(chip, "verilog_file") == nullptr) { - odb::dbStringProperty::create( - chip, "verilog_file", chip_inst.external.verilog_file.c_str()); - } - } } static std::vector splitPath(const std::string& path) { diff --git a/src/odb/src/3dblox/checker.cpp b/src/odb/src/3dblox/checker.cpp index 7eaf92e5a4..cf41866060 100644 --- a/src/odb/src/3dblox/checker.cpp +++ b/src/odb/src/3dblox/checker.cpp @@ -5,13 +5,11 @@ #include #include -#include -#include +#include #include #include #include #include -#include #include #include @@ -19,12 +17,6 @@ #include "odb/dbObject.h" #include "odb/geom.h" #include "odb/unfoldedModel.h" -#include "sta/ConcreteNetwork.hh" -#include "sta/Network.hh" -#include "sta/NetworkClass.hh" -#include "sta/PatternMatch.hh" -#include "sta/Sta.hh" -#include "sta/VerilogReader.hh" #include "utl/Logger.h" #include "utl/unionFind.h" @@ -95,41 +87,17 @@ bool isValid(const UnfoldedConnection& conn) return (surfaces.top_z - surfaces.bot_z) == conn.connection->getThickness(); } -class StaGuard -{ - public: - StaGuard(sta::Sta* sta) : sta_ptr_(sta) - { - if (!sta_ptr_) { - temp_sta_ = std::make_unique(); - temp_sta_->makeComponents(); - sta_ptr_ = temp_sta_.get(); - } - } - ~StaGuard() - { - if (temp_sta_) { - temp_sta_->setReport(nullptr); - } - } - sta::Sta* operator->() const { return sta_ptr_; } - - private: - std::unique_ptr temp_sta_; - sta::Sta* sta_ptr_; -}; - } // namespace Checker::Checker(utl::Logger* logger) : logger_(logger) { } -void Checker::check(dbChip* chip, sta::Sta* sta) +void Checker::check(dbChip* chip) { auto* top_cat = dbMarkerCategory::createOrReplace(chip, "3DBlox"); - checkLogicalConnectivity(top_cat, chip, sta); UnfoldedModel model(logger_, chip); + checkLogicalConnectivity(top_cat, model); checkFloatingChips(top_cat, model); checkOverlappingChips(top_cat, model); checkInternalExtUsage(top_cat, model); @@ -322,130 +290,73 @@ void Checker::checkNetConnectivity(dbMarkerCategory* top_cat, } void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat, - dbChip* chip, - sta::Sta* sta) + const UnfoldedModel& model) { - StaGuard sta_guard(sta); - std::unordered_set processed_masters; - - dbMarkerCategory* design_cat = nullptr; - dbMarkerCategory* alignment_cat = nullptr; - - for (auto* inst : chip->getChipInsts()) { - auto* master = inst->getMasterChip(); - if (!master || !processed_masters.insert(master).second) { - continue; + std::unordered_map bump_net_map; + for (const auto& net : model.getNets()) { + for (const auto* bump : net.connected_bumps) { + bump_net_map[bump] = &net; } + } - auto* network = sta_guard->network(); - sta::Cell* cell = nullptr; - { - std::unique_ptr lib_iter( - network->libraryIterator()); - while (lib_iter->hasNext()) { - auto* lib = lib_iter->next(); - cell = network->findCell(lib, master->getName()); - if (cell) { - break; - } - } + auto get_net_name = [&](const UnfoldedBump* bump) -> std::string { + auto it = bump_net_map.find(bump); + if (it != bump_net_map.end()) { + return it->second->chip_net->getName(); } + return "defines no net"; + }; - if (!cell) { - std::vector modules; - std::unique_ptr li(network->libraryIterator()); - sta::PatternMatch all("*"); - while (li->hasNext()) { - auto matches = network->findCellsMatching(li->next(), &all); - for (auto* c : matches) { - const char* name = network->name(c); - if (name) { - modules.emplace_back(name); - } - } - } - std::ranges::sort(modules); - if (modules.size() > 10) { - modules.resize(10); - modules.emplace_back("..."); - } - if (!design_cat) { - design_cat - = dbMarkerCategory::createOrReplace(top_cat, "Design Alignment"); - } - auto* marker = dbMarker::create(design_cat); - std::string msg = fmt::format( - "Design Alignment Violation: Verilog module {} not found. " - "Available modules: {}", - master->getName(), - modules.empty() ? "None" - : fmt::format("{}", fmt::join(modules, ", "))); - marker->setComment(msg); - marker->addSource(master); - logger_->warn(utl::ODB, 550, msg); + dbMarkerCategory* cat = nullptr; + for (const auto& conn : model.getConnections()) { + if (!isValid(conn)) { continue; } - - std::unordered_set nets; - auto* prop = dbStringProperty::find(master, "verilog_file"); - if (prop && sta) { - std::string verilog_file = prop->getValue(); - if (!verilog_file.empty() && std::filesystem::exists(verilog_file)) { - sta::ConcreteNetwork temp_network; - temp_network.copyState(sta); - sta::VerilogReader verilog_reader(&temp_network); - if (verilog_reader.read(verilog_file.c_str())) { - sta::Instance* top_inst - = verilog_reader.linkNetwork(master->getName(), - /*make_black_boxes*/ true, - /*delete_modules*/ false); - if (top_inst) { - std::unique_ptr net_iter( - temp_network.netIterator(top_inst)); - while (net_iter->hasNext()) { - nets.insert(temp_network.name(net_iter->next())); - } - } - } - } + if (!conn.top_region || !conn.bottom_region) { + continue; } - std::vector sorted_nets(nets.begin(), nets.end()); - std::ranges::sort(sorted_nets); - if (sorted_nets.size() > 10) { - sorted_nets.resize(10); - sorted_nets.emplace_back("..."); + std::map bot_bumps; + for (const auto& bump : conn.bottom_region->bumps) { + Point p(bump.global_position.x(), bump.global_position.y()); + bot_bumps[p] = ≎ } - for (auto* region : master->getChipRegions()) { - for (auto* bump : region->getChipBumps()) { - auto* net = bump->getNet(); - if (net && !nets.contains(net->getName())) { - if (!alignment_cat) { - alignment_cat = dbMarkerCategory::createOrReplace( - top_cat, "Logical Alignment"); + for (const auto& top_bump : conn.top_region->bumps) { + Point p(top_bump.global_position.x(), top_bump.global_position.y()); + auto it = bot_bumps.find(p); + if (it != bot_bumps.end()) { + const UnfoldedBump* bot_bump = it->second; + + // Check logical connectivity + auto top_net_it = bump_net_map.find(&top_bump); + auto bot_net_it = bump_net_map.find(bot_bump); + + const UnfoldedNet* top_net + = top_net_it != bump_net_map.end() ? top_net_it->second : nullptr; + const UnfoldedNet* bot_net + = bot_net_it != bump_net_map.end() ? bot_net_it->second : nullptr; + + if (top_net != bot_net) { + if (!cat) { + cat = dbMarkerCategory::createOrReplace(top_cat, + "Logical Connectivity"); } - auto* marker = dbMarker::create(alignment_cat); - std::string bump_name - = bump->getInst() ? bump->getInst()->getName() : "UNKNOWN_BUMP"; + auto* marker = dbMarker::create(cat); + marker->addSource(top_bump.bump_inst); + marker->addSource(bot_bump->bump_inst); + marker->addShape(conn.top_region->cuboid.intersect( + conn.bottom_region->cuboid)); // Mark overlap region std::string msg = fmt::format( - "Logical net {} (bump {}) not found in Verilog. Available nets: " - "[{}]", - net->getName(), - bump_name, - fmt::join(sorted_nets, ", ")); - + "Bumps at ({}, {}) align physically but logical connectivity " + "mismatch: Top bump {} vs Bottom bump {}", + p.x(), + p.y(), + get_net_name(&top_bump), + get_net_name(bot_bump)); marker->setComment(msg); - marker->addSource(bump); - logger_->warn( - utl::ODB, - 560, - "Logical net {} in bmap for chiplet {} (bump {}) not found in " - "Verilog", - net->getName(), - master->getName(), - bump_name); + logger_->warn(utl::ODB, 208, msg); } } } diff --git a/src/odb/src/3dblox/checker.h b/src/odb/src/3dblox/checker.h index a131b3e875..e37de374d2 100644 --- a/src/odb/src/3dblox/checker.h +++ b/src/odb/src/3dblox/checker.h @@ -27,12 +27,11 @@ class Checker public: Checker(utl::Logger* logger); ~Checker() = default; - void check(dbChip* chip, sta::Sta* sta); + void check(dbChip* chip); private: void checkLogicalConnectivity(dbMarkerCategory* top_cat, - dbChip* chip, - sta::Sta* sta); + const UnfoldedModel& model); void checkFloatingChips(dbMarkerCategory* top_cat, const UnfoldedModel& model); void checkOverlappingChips(dbMarkerCategory* top_cat, diff --git a/src/odb/test/cpp/Test3DBloxCheckerFixture.h b/src/odb/test/cpp/Test3DBloxCheckerFixture.h index 3e5ff0e707..aa6abf3d59 100644 --- a/src/odb/test/cpp/Test3DBloxCheckerFixture.h +++ b/src/odb/test/cpp/Test3DBloxCheckerFixture.h @@ -82,6 +82,8 @@ class CheckerFixture : public tst::Fixture = "Unused internal_ext"; static constexpr const char* connected_regions_category = "Connection regions"; + static constexpr const char* logical_connectivity_category + = "Logical Connectivity"; }; } // namespace odb diff --git a/src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp b/src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp index 3c83501f26..26026e9a4e 100644 --- a/src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp +++ b/src/odb/test/cpp/Test3DBloxCheckerLogicalConn.cpp @@ -1,148 +1,167 @@ -#include +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2023-2026, The OpenROAD Authors #include +#include +#include "Test3DBloxCheckerFixture.h" +#include "gtest/gtest.h" #include "odb/3dblox.h" #include "odb/db.h" -#include "tst/fixture.h" +#include "odb/geom.h" namespace odb { +namespace { -class LogicalConnFixture : public tst::Fixture +class CheckerLogicalConnFixture : public CheckerFixture { protected: - void SetUp() override + CheckerLogicalConnFixture() { - blox_ = new ThreeDBlox(&logger_, db_.get(), sta_.get()); + dbTechLayer::create(tech_, "layer1", dbTechLayerType::ROUTING); + + // DIE chips need blocks (for bump masters/cells) + dbBlock::create(chip1_, "block1"); + dbBlock::create(chip2_, "block2"); + + // Lib + bump master + lib_ = dbLib::create(db_.get(), "bump_lib", tech_, ','); + bump_master_ = dbMaster::create(lib_, "bump_pad"); + bump_master_->setWidth(100); + bump_master_->setHeight(100); + bump_master_->setType(dbMasterType::CORE); + dbMTerm::create(bump_master_, "pin", dbIoType::INOUT, dbSigType::SIGNAL); + bump_master_->setFrozen(); } - void TearDown() override { delete blox_; } + // Create a bump on a chip region. + dbChipBump* createBump(dbChip* chip, + dbChipRegion* region, + const char* bump_name, + int x, + int y) + { + dbBlock* block = chip->getBlock(); + dbTechLayer* layer = tech_->findLayer("layer1"); + + // Physical cell in the block + dbInst* inst = dbInst::create(block, bump_master_, bump_name); + inst->setOrigin(x, y); + inst->setPlacementStatus(dbPlacementStatus::PLACED); + + // Chip-level bump association + dbChipBump* chip_bump = dbChipBump::create(region, inst); + + // Net + BTerm for wire-graph connectivity + std::string net_name = std::string(bump_name) + "_net"; + dbNet* net = block->findNet(net_name.c_str()); + if (!net) { + net = dbNet::create(block, net_name.c_str()); + } + dbBTerm* bterm = dbBTerm::create(net, bump_name); + bterm->setIoType(dbIoType::INOUT); - ThreeDBlox* blox_; -}; + // BPin with box at the bump location + dbBPin* bpin = dbBPin::create(bterm); + bpin->setPlacementStatus(dbPlacementStatus::PLACED); + dbBox::create(bpin, layer, x, y, x + 100, y + 100); -TEST_F(LogicalConnFixture, TestMissingNetCreation) -{ - std::string dbv_file - = getFilePath("src/odb/test/data/3dblox_logical_test.3dbv"); - - // Run readDbv - blox_->readDbv(dbv_file); - - // Check if chip "top" was created - auto* created_chip = db_->findChip("top"); - ASSERT_NE(created_chip, nullptr); - - // Check if nets "A" and "Z" were created in the chip - bool foundA = false; - bool foundZ = false; - for (auto* net : created_chip->getChipNets()) { - if (net->getName() == "A") { - foundA = true; - } - if (net->getName() == "Z") { - foundZ = true; - } + chip_bump->setNet(net); + chip_bump->setBTerm(bterm); + + return chip_bump; } - EXPECT_TRUE(foundA); - EXPECT_TRUE(foundZ); -} -TEST_F(LogicalConnFixture, TestCheckerNoViolations) -{ - auto* tech = dbTech::create(db_.get(), "tech"); - // master chip name matches module name in Verilog "top" - auto* master = dbChip::create(db_.get(), tech, "top", dbChip::ChipType::DIE); - dbChipNet::create(master, "A"); - dbChipNet::create(master, "Z"); - - std::string verilog_file - = getFilePath("src/odb/test/data/3dblox_logical_check_pass.v"); - odb::dbStringProperty::create(master, "verilog_file", verilog_file.c_str()); - - // top chip containing instance of master - auto* design_top = dbChip::create( - db_.get(), nullptr, "design_top", dbChip::ChipType::HIER); - dbChipInst::create(design_top, master, "inst1"); - db_->setTopChip(design_top); - - // Run Checker - blox_->check(); - - // Verify no markers in "Logical Alignment" or "Design Alignment" - auto* top_cat = design_top->findMarkerCategory("3DBlox"); - if (top_cat) { - auto* design_cat = top_cat->findMarkerCategory("Design Alignment"); - if (design_cat) { - EXPECT_EQ(design_cat->getMarkers().size(), 0); - } - auto* align_cat = top_cat->findMarkerCategory("Logical Alignment"); - if (align_cat) { - EXPECT_EQ(align_cat->getMarkers().size(), 0); - } + void check() + { + utl::Logger logger; + ThreeDBlox three_dblox(&logger, db_.get()); + three_dblox.check(); } -} -TEST_F(LogicalConnFixture, TestCheckerMissingModule) + dbLib* lib_; + dbMaster* bump_master_; +}; + +TEST_F(CheckerLogicalConnFixture, test_logical_connectivity_matching_nets) { - auto* tech = dbTech::create(db_.get(), "tech"); - // master chip name "top" but Verilog has "other_module" - auto* master = dbChip::create(db_.get(), tech, "top", dbChip::ChipType::DIE); - - std::string verilog_file - = getFilePath("src/odb/test/data/3dblox_logical_check_fail_mod.v"); - odb::dbStringProperty::create(master, "verilog_file", verilog_file.c_str()); - - auto* design_top = dbChip::create( - db_.get(), nullptr, "design_top", dbChip::ChipType::HIER); - dbChipInst::create(design_top, master, "inst1"); - db_->setTopChip(design_top); - - blox_->check(); - - // Verify "Design Alignment" marker - auto* top_cat = design_top->findMarkerCategory("3DBlox"); - ASSERT_NE(top_cat, nullptr); - auto* design_cat = top_cat->findMarkerCategory("Design Alignment"); - ASSERT_NE(design_cat, nullptr); - EXPECT_GT(design_cat->getMarkers().size(), 0); + auto* r1_fr = chip1_->findChipRegion("r1_fr"); + auto* r2_bk = chip2_->findChipRegion("r2_bk"); + + createBump(chip1_, r1_fr, "bump1", 100, 100); + createBump(chip2_, r2_bk, "bump2", 100, 100); + + auto inst1 = dbChipInst::create(top_chip_, chip1_, "inst1"); + inst1->setLoc(Point3D(0, 0, 0)); + inst1->setOrient(dbOrientType3D(dbOrientType::R0, false)); + + auto inst2 = dbChipInst::create(top_chip_, chip2_, "inst2"); + inst2->setLoc(Point3D(0, 0, 500)); // Stacked on top + inst2->setOrient(dbOrientType3D(dbOrientType::R0, false)); + + auto* ri1 = inst1->findChipRegionInst("r1_fr"); + auto* ri2 = inst2->findChipRegionInst("r2_bk"); + + auto* conn1 = dbChipConn::create("c1", top_chip_, {inst1}, ri1, {inst2}, ri2); + conn1->setThickness(0); + + auto inst1_bump1 = *ri1->getChipBumpInsts().begin(); + auto inst2_bump2 = *ri2->getChipBumpInsts().begin(); + + auto* chip_net = dbChipNet::create(top_chip_, "net1"); + chip_net->addBumpInst(inst1_bump1, {inst1}); + chip_net->addBumpInst(inst2_bump2, {inst2}); + + check(); + + auto markers = getMarkers(logical_connectivity_category); + EXPECT_TRUE(markers.empty()); } -TEST_F(LogicalConnFixture, TestCheckerMissingNetInVerilog) +TEST_F(CheckerLogicalConnFixture, test_logical_connectivity_mismatching_nets) { - auto* tech = dbTech::create(db_.get(), "tech"); - // master chip name "top" matches module name in Verilog - auto* master = dbChip::create(db_.get(), tech, "top", dbChip::ChipType::DIE); - - // Create a bump connected to a net "EXTRA" that is NOT in Verilog - auto* region - = dbChipRegion::create(master, "r1", dbChipRegion::Side::FRONT, nullptr); - auto* block = dbBlock::create(master, "block"); - auto* lib = dbLib::create(db_.get(), "lib", tech); - auto* bump_master = dbMaster::create(lib, "bump_cell"); - bump_master->setFrozen(); - auto* inst = dbInst::create(block, bump_master, "bump_inst"); - auto* bump = dbChipBump::create(region, inst); - auto* net = dbNet::create(block, "EXTRA"); - bump->setNet(net); - - std::string verilog_file - = getFilePath("src/odb/test/data/3dblox_logical_check_fail_net.v"); - odb::dbStringProperty::create(master, "verilog_file", verilog_file.c_str()); - - auto* design_top = dbChip::create( - db_.get(), nullptr, "design_top", dbChip::ChipType::HIER); - dbChipInst::create(design_top, master, "inst1"); - db_->setTopChip(design_top); - - blox_->check(); - - // Verify "Logical Alignment" marker - auto* top_cat = design_top->findMarkerCategory("3DBlox"); - ASSERT_NE(top_cat, nullptr); - auto* align_cat = top_cat->findMarkerCategory("Logical Alignment"); - ASSERT_NE(align_cat, nullptr); - EXPECT_GT(align_cat->getMarkers().size(), 0); + auto* r1_fr = chip1_->findChipRegion("r1_fr"); + auto* r2_bk = chip2_->findChipRegion("r2_bk"); + + createBump(chip1_, r1_fr, "bump1", 200, 200); + createBump(chip2_, r2_bk, "bump2", 200, 200); + + auto inst1 = dbChipInst::create(top_chip_, chip1_, "inst1"); + inst1->setLoc(Point3D(0, 0, 0)); + inst1->setOrient(dbOrientType3D(dbOrientType::R0, false)); + + auto inst2 = dbChipInst::create(top_chip_, chip2_, "inst2"); + inst2->setLoc(Point3D(0, 0, 500)); // Stacked on top + inst2->setOrient(dbOrientType3D(dbOrientType::R0, false)); + + auto* ri1 = inst1->findChipRegionInst("r1_fr"); + auto* ri2 = inst2->findChipRegionInst("r2_bk"); + + auto* conn1 = dbChipConn::create("c1", top_chip_, {inst1}, ri1, {inst2}, ri2); + conn1->setThickness(0); + + auto inst1_bump1 = *ri1->getChipBumpInsts().begin(); + auto inst2_bump2 = *ri2->getChipBumpInsts().begin(); + + auto* chip_net1 = dbChipNet::create(top_chip_, "net1"); + chip_net1->addBumpInst(inst1_bump1, {inst1}); + + auto* chip_net2 = dbChipNet::create(top_chip_, "net2"); + chip_net2->addBumpInst(inst2_bump2, {inst2}); + + check(); + + auto markers = getMarkers(logical_connectivity_category); + EXPECT_EQ(markers.size(), 1); + if (!markers.empty()) { + auto sources = markers[0]->getSources(); + EXPECT_EQ(sources.size(), 2); + + // Check message correctness conceptually + EXPECT_NE(markers[0]->getComment().find("logical connectivity mismatch"), + std::string::npos); + } } +} // namespace } // namespace odb diff --git a/src/odb/test/data/3dblox_logical_check_fail_mod.v b/src/odb/test/data/3dblox_logical_check_fail_mod.v deleted file mode 100644 index 131858912c..0000000000 --- a/src/odb/test/data/3dblox_logical_check_fail_mod.v +++ /dev/null @@ -1,2 +0,0 @@ -module other_module ( input A ); -endmodule diff --git a/src/odb/test/data/3dblox_logical_check_fail_net.v b/src/odb/test/data/3dblox_logical_check_fail_net.v deleted file mode 100644 index aa14a96b57..0000000000 --- a/src/odb/test/data/3dblox_logical_check_fail_net.v +++ /dev/null @@ -1,2 +0,0 @@ -module top ( input A ); -endmodule diff --git a/src/odb/test/data/3dblox_logical_check_pass.v b/src/odb/test/data/3dblox_logical_check_pass.v deleted file mode 100644 index 7ef36a9cc2..0000000000 --- a/src/odb/test/data/3dblox_logical_check_pass.v +++ /dev/null @@ -1,2 +0,0 @@ -module top ( input A, output Z ); -endmodule diff --git a/src/odb/test/data/3dblox_logical_test.3dbv b/src/odb/test/data/3dblox_logical_test.3dbv deleted file mode 100644 index 1ed86aeb2f..0000000000 --- a/src/odb/test/data/3dblox_logical_test.3dbv +++ /dev/null @@ -1,11 +0,0 @@ -Header: - version: 2.5 - unit: micron - precision: 1000 - -ChipletDef: - top: - type: die - external: - verilog_file: 3dblox_logical_test.v - APR_tech_file: [dummy.lef] diff --git a/src/odb/test/data/3dblox_logical_test.v b/src/odb/test/data/3dblox_logical_test.v deleted file mode 100644 index 7ef36a9cc2..0000000000 --- a/src/odb/test/data/3dblox_logical_test.v +++ /dev/null @@ -1,2 +0,0 @@ -module top ( input A, output Z ); -endmodule diff --git a/src/odb/test/data/dummy.lef b/src/odb/test/data/dummy.lef deleted file mode 100644 index 4c394baf9e..0000000000 --- a/src/odb/test/data/dummy.lef +++ /dev/null @@ -1,13 +0,0 @@ -VERSION 5.8 ; -BUSBITCHARS "[]" ; -DIVIDERCHAR "/" ; - -UNITS - DATABASE MICRONS 1000 ; -END UNITS - -LAYER metal1 - TYPE ROUTING ; -END metal1 - -END LIBRARY diff --git a/src/odb/test/temp_test.v b/src/odb/test/temp_test.v deleted file mode 100644 index 7ef36a9cc2..0000000000 --- a/src/odb/test/temp_test.v +++ /dev/null @@ -1,2 +0,0 @@ -module top ( input A, output Z ); -endmodule diff --git a/src/odb/test/test.3dbv b/src/odb/test/test.3dbv deleted file mode 100644 index d5343a806f..0000000000 --- a/src/odb/test/test.3dbv +++ /dev/null @@ -1,6 +0,0 @@ -precision: 1000 -chiplet_defs: - top: - type: die - external: - verilog_file: temp_test.v diff --git a/src/odb/test/write_3dbv.3dbvok b/src/odb/test/write_3dbv.3dbvok index 9d49e490e8..7fff9e07ad 100644 --- a/src/odb/test/write_3dbv.3dbvok +++ b/src/odb/test/write_3dbv.3dbvok @@ -16,7 +16,6 @@ ChipletDef: APR_tech_file: [Nangate45_tech.lef] LEF_file: [fake_bumps_lib.lef, fake_macros_lib.lef] DEF_file: SoC.def - verilog_file: data/soc.v regions: back_reg: side: back From 890b4dd6ec326e88c2ed49196ca959d97f2ebc14 Mon Sep 17 00:00:00 2001 From: "Ahmed R. Mohamed" Date: Wed, 4 Mar 2026 15:02:34 -0800 Subject: [PATCH 5/6] odb: fix 3dblox bazel build Signed-off-by: Ahmed R. Mohamed --- src/odb/test/cpp/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/odb/test/cpp/BUILD b/src/odb/test/cpp/BUILD index 7ff7b24625..d2db344708 100644 --- a/src/odb/test/cpp/BUILD +++ b/src/odb/test/cpp/BUILD @@ -236,7 +236,9 @@ cc_test( cc_test( name = "Test3DBloxChecker", srcs = [ + "Test3DBloxCheckerFixture.h", "Test3DBloxChecker.cpp", + "Test3DBloxCheckerLogicalConn.cpp", ], data = [ "//src/odb/test:regression_resources", From dca928b68e8ddad6316c964a636e6444e1ecc227 Mon Sep 17 00:00:00 2001 From: "Ahmed R. Mohamed" Date: Wed, 4 Mar 2026 15:11:06 -0800 Subject: [PATCH 6/6] odb: fix 3dblox checker bazel build Signed-off-by: Ahmed R. Mohamed --- src/odb/test/cpp/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odb/test/cpp/BUILD b/src/odb/test/cpp/BUILD index d2db344708..b24e24ded3 100644 --- a/src/odb/test/cpp/BUILD +++ b/src/odb/test/cpp/BUILD @@ -236,8 +236,8 @@ cc_test( cc_test( name = "Test3DBloxChecker", srcs = [ - "Test3DBloxCheckerFixture.h", "Test3DBloxChecker.cpp", + "Test3DBloxCheckerFixture.h", "Test3DBloxCheckerLogicalConn.cpp", ], data = [