Skip to content
Open
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
2 changes: 2 additions & 0 deletions src/odb/include/odb/3dblox.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct ChipletInst;
struct Connection;
struct DesignDef;
struct BumpMapEntry;
struct DbxData;

class ThreeDBlox
{
Expand Down Expand Up @@ -59,6 +60,7 @@ class ThreeDBlox
std::vector<dbChipInst*>& path_insts);
void readHeaderIncludes(const std::vector<std::string>& includes);
void calculateSize(dbChip* chip);
void buildChipNetsFromVerilog(dbChip* chip, const DbxData& data);

utl::Logger* logger_ = nullptr;
odb::dbDatabase* db_ = nullptr;
Expand Down
119 changes: 113 additions & 6 deletions src/odb/src/3dblox/3dblox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <cstddef>
#include <filesystem>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
Expand All @@ -29,7 +30,10 @@
#include "odb/geom.h"
#include "odb/lefin.h"
#include "odb/lefout.h"
#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 {
Expand Down Expand Up @@ -78,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<dbChip*, std::map<std::string, dbChipBump*>> 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<sta::NetIterator> 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<sta::NetPinIterator> 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());
Expand All @@ -88,6 +197,9 @@ 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);
}
Expand Down Expand Up @@ -332,12 +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());
}
}

// Read DEF file
if (!chiplet.external.def_file.empty()) {
odb::defin def_reader(db_, logger_, odb::defin::DEFAULT);
Expand Down
79 changes: 77 additions & 2 deletions src/odb/src/3dblox/checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <algorithm>
#include <cstddef>
#include <map>
#include <numeric>
#include <ranges>
#include <string>
Expand Down Expand Up @@ -94,9 +95,9 @@ Checker::Checker(utl::Logger* logger) : logger_(logger)

void Checker::check(dbChip* chip)
{
UnfoldedModel model(logger_, chip);
auto* top_cat = dbMarkerCategory::createOrReplace(chip, "3DBlox");

UnfoldedModel model(logger_, chip);
checkLogicalConnectivity(top_cat, model);
checkFloatingChips(top_cat, model);
checkOverlappingChips(top_cat, model);
checkInternalExtUsage(top_cat, model);
Expand Down Expand Up @@ -288,4 +289,78 @@ void Checker::checkNetConnectivity(dbMarkerCategory* top_cat,
{
}

void Checker::checkLogicalConnectivity(dbMarkerCategory* top_cat,
const UnfoldedModel& model)
{
std::unordered_map<const UnfoldedBump*, const UnfoldedNet*> bump_net_map;
for (const auto& net : model.getNets()) {
for (const auto* bump : net.connected_bumps) {
bump_net_map[bump] = &net;
}
}

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";
};

dbMarkerCategory* cat = nullptr;
for (const auto& conn : model.getConnections()) {
if (!isValid(conn)) {
continue;
}
if (!conn.top_region || !conn.bottom_region) {
continue;
}

std::map<Point, const UnfoldedBump*> bot_bumps;
for (const auto& bump : conn.bottom_region->bumps) {
Point p(bump.global_position.x(), bump.global_position.y());
bot_bumps[p] = &bump;
}

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(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(
"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);
logger_->warn(utl::ODB, 208, msg);
}
}
}
}
}

} // namespace odb
6 changes: 6 additions & 0 deletions src/odb/src/3dblox/checker.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include "odb/unfoldedModel.h"
#include "utl/Logger.h"

namespace sta {
class Sta;
}

namespace odb {
class dbChip;
class dbMarkerCategory;
Expand All @@ -26,6 +30,8 @@ class Checker
void check(dbChip* chip);

private:
void checkLogicalConnectivity(dbMarkerCategory* top_cat,
const UnfoldedModel& model);
void checkFloatingChips(dbMarkerCategory* top_cat,
const UnfoldedModel& model);
void checkOverlappingChips(dbMarkerCategory* top_cat,
Expand Down
2 changes: 1 addition & 1 deletion src/odb/test/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
74 changes: 1 addition & 73 deletions src/odb/test/cpp/Test3DBloxChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,88 +4,16 @@
#include <string>
#include <vector>

#include "Test3DBloxCheckerFixture.h"
#include "gtest/gtest.h"
#include "odb/3dblox.h"
#include "odb/db.h"
#include "odb/dbObject.h"
#include "odb/geom.h"
#include "tst/fixture.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<dbMarker*> 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<dbMarker*> 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");
Expand Down
Loading