Skip to content
Draft
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/include/odb/3dblox.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ThreeDBlox
~ThreeDBlox() = default;
void readDbv(const std::string& dbv_file);
void readDbx(const std::string& dbx_file);
void writeDbx(const std::string& dbx_file);

private:
void createChiplet(const ChipletDef& chiplet);
Expand Down
7 changes: 7 additions & 0 deletions src/odb/src/3dblox/3dblox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "bmapParser.h"
#include "dbvParser.h"
#include "dbxParser.h"
#include "dbxWriter.h"
#include "objects.h"
#include "odb/db.h"
#include "odb/dbTypes.h"
Expand Down Expand Up @@ -83,6 +84,12 @@ void ThreeDBlox::readDbx(const std::string& dbx_file)
db_->triggerPostRead3Dbx(chip);
}

void ThreeDBlox::writeDbx(const std::string& dbx_file)
{
DbxWriter writer(logger_);
writer.writeFile(dbx_file, db_);
}

void ThreeDBlox::calculateSize(dbChip* chip)
{
Rect box;
Expand Down
2 changes: 2 additions & 0 deletions src/odb/src/3dblox/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ add_library(3dblox
bmapParser.cpp
dbvParser.cpp
dbxParser.cpp
baseWriter.cpp
dbxWriter.cpp
3dblox.cpp
)

Expand Down
125 changes: 125 additions & 0 deletions src/odb/src/3dblox/baseWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2019-2025, The OpenROAD Authors

#include "baseWriter.h"

#include <yaml-cpp/emitterstyle.h>
#include <yaml-cpp/node/node.h>
#include <yaml-cpp/yaml.h>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: included header yaml.h is not used directly [misc-include-cleaner]

Suggested change

#include <cstddef>
#include <fstream>
#include <string>

#include "odb/db.h"
#include "odb/defout.h"
#include "odb/lefout.h"
#include "utl/Logger.h"
#include "utl/ScopedTemporaryFile.h"

namespace odb {

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

void BaseWriter::writeHeader(YAML::Node& header_node, odb::dbDatabase* db)
{
header_node["version"] = "2.5"; // TODO: add version to DB
header_node["unit"] = "micron";
header_node["precision"] = db->getDbuPerMicron();
}

void BaseWriter::writeYamlToFile(const std::string& filename,
const YAML::Node& root)
{
std::ofstream out(filename);
if (!out) {
if (logger_ != nullptr) {
logError("cannot open " + filename);
}
return;
}

out << root;
}

void BaseWriter::writeLef(YAML::Node& external_node,
odb::dbDatabase* db,
odb::dbChip* chiplet)
{
auto libs = db->getLibs();
int num_libs = libs.size();
if (num_libs > 0) {
if (num_libs > 1) {
logger_->info(
utl::ODB,
539,
"More than one lib exists, multiple files will be written.");
}
int cnt = 0;
for (auto lib : libs) {
std::string name(std::string(lib->getName()) + ".lef");
if (cnt > 0) {
auto pos = name.rfind('.');
if (pos != std::string::npos) {
name.insert(pos, "_" + std::to_string(cnt));
} else {
name += "_" + std::to_string(cnt);
}
utl::OutStreamHandler stream_handler(name.c_str());
odb::lefout lef_writer(logger_, stream_handler.getStream());
lef_writer.writeLib(lib);
} else {
utl::OutStreamHandler stream_handler(name.c_str());
odb::lefout lef_writer(logger_, stream_handler.getStream());
lef_writer.writeTechAndLib(lib);
}
YAML::Node list_node;
list_node.SetStyle(YAML::EmitterStyle::Flow);
list_node.push_back(name.c_str());
if ((name.find("_tech") != std::string::npos) || (libs.size() == 1)) {
external_node["APR_tech_file"] = list_node;
} else {
external_node["LEF_file"] = list_node;
}
++cnt;
}
} else if (db->getTech()) {
utl::OutStreamHandler stream_handler(
(std::string(chiplet->getName()) + ".lef").c_str());
odb::lefout lef_writer(logger_, stream_handler.getStream());
lef_writer.writeTech(db->getTech());
external_node["APR_tech_file"] = (std::string(chiplet->getName()) + ".lef");
}
}

void BaseWriter::writeDef(YAML::Node& external_node,
odb::dbDatabase* db,
odb::dbChip* chiplet)
{
odb::DefOut def_writer(logger_);
auto block = chiplet->getBlock();
def_writer.writeBlock(block,
(std::string(chiplet->getName()) + ".def").c_str());
external_node["DEF_file"] = std::string(chiplet->getName()) + ".def";
}

void BaseWriter::logError(const std::string& message)
{
if (logger_ != nullptr) {
logger_->error(utl::ODB, 538, "Writer Error: {}", message);
}
}

std::string BaseWriter::trim(const std::string& str)
{
std::size_t first = str.find_first_not_of(' ');
if (first == std::string::npos) {
return "";
}
std::size_t last = str.find_last_not_of(' ');
return str.substr(first, (last - first + 1));
}

} // namespace odb
44 changes: 44 additions & 0 deletions src/odb/src/3dblox/baseWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2019-2025, The OpenROAD Authors

#pragma once

#include <yaml-cpp/node/node.h>

#include <string>

#include "odb/db.h"
#include "odb/dbObject.h"
#include "odb/dbShape.h"
namespace utl {
class Logger;
}

namespace odb {

class BaseWriter
{
public:
BaseWriter(utl::Logger* logger);
virtual ~BaseWriter() = default;
virtual void writeFile(const std::string& filename, odb::dbDatabase* db) = 0;

protected:
// Common YAML content writing
void writeHeader(YAML::Node& header_node, odb::dbDatabase* db);
void writeLef(YAML::Node& external_node,
odb::dbDatabase* db,
odb::dbChip* chiplet);
void writeDef(YAML::Node& external_node,
odb::dbDatabase* db,
odb::dbChip* chiplet);
void logError(const std::string& message);
std::string trim(const std::string& str);
void writeYamlToFile(const std::string& filename, const YAML::Node& root);

// Member variables
utl::Logger* logger_ = nullptr;
std::string current_file_path_;
};

} // namespace odb
150 changes: 150 additions & 0 deletions src/odb/src/3dblox/dbxWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2019-2025, The OpenROAD Authors

#include "dbxWriter.h"

#include <yaml-cpp/emitterstyle.h>
#include <yaml-cpp/node/node.h>
#include <yaml-cpp/yaml.h>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: included header yaml.h is not used directly [misc-include-cleaner]

Suggested change

#include <string>
#include <vector>

#include "baseWriter.h"
#include "odb/db.h"
#include "utl/Logger.h"

namespace odb {

DbxWriter::DbxWriter(utl::Logger* logger) : BaseWriter(logger)
{
}

void DbxWriter::writeFile(const std::string& filename, odb::dbDatabase* db)
{
// TODO: Connect the following
// DbvWriter dbvwriter(logger_);
// dbvwriter.writeChiplet(
// std::string(db->getChip()->getName()) + ".3dbv", db, db->getChip());
YAML::Node root;
writeYamlContent(root, db->getChip());
writeYamlToFile(filename, root);
}

void DbxWriter::writeChiplet(odb::dbChip* chiplet)
{
YAML::Node root;
// TODO: Connect the following
// DbvWriter dbvwriter(logger_);
// dbvwriter.writeChiplet(
// std::string(chiplet->getName()) + ".3dbv", chiplet->getDb(), chiplet);
writeYamlContent(root, chiplet);
writeYamlToFile(std::string(chiplet->getName()), root);
}

void DbxWriter::writeYamlContent(YAML::Node& root, odb::dbChip* chiplet)
{
YAML::Node header_node = root["Header"];
writeHeader(header_node, chiplet->getDb());
YAML::Node includes_node = header_node["include"];
includes_node.push_back(std::string(chiplet->getName()) + ".3dbv");

YAML::Node design_node = root["Design"];
writeDesign(design_node, chiplet);

YAML::Node instances_node = root["ChipletInst"];
writeChipletInsts(instances_node, chiplet);

YAML::Node stack_node = root["Stack"];
writeStack(stack_node, chiplet);

YAML::Node connections_node = root["Connection"];
writeConnections(connections_node, chiplet);
}

void DbxWriter::writeDesign(YAML::Node& design_node, odb::dbChip* chiplet)
{
design_node["name"] = chiplet->getName();
}

void DbxWriter::writeChipletInsts(YAML::Node& instances_node,
odb::dbChip* chiplet)
{
for (auto inst : chiplet->getChipInsts()) {
YAML::Node instance_node = instances_node[std::string(inst->getName())];
writeChipletInst(instance_node, inst);
}
}

void DbxWriter::writeChipletInst(YAML::Node& instance_node,
odb::dbChipInst* inst)
{
auto master_name = inst->getMasterChip()->getName();
instance_node["reference"] = master_name;
}

void DbxWriter::writeStack(YAML::Node& stack_node, odb::dbChip* chiplet)
{
for (auto inst : chiplet->getChipInsts()) {
YAML::Node stack_instance_node = stack_node[std::string(inst->getName())];
writeStackInstance(stack_instance_node, inst);
}
}

void DbxWriter::writeStackInstance(YAML::Node& stack_instance_node,
odb::dbChipInst* inst)
{
const double u = inst->getDb()->getDbuPerMicron();
const double loc_x = inst->getLoc().x() / u;
const double loc_y = inst->getLoc().y() / u;
YAML::Node loc_out;
loc_out.SetStyle(YAML::EmitterStyle::Flow);
loc_out.push_back(loc_x);
loc_out.push_back(loc_y);
stack_instance_node["loc"] = loc_out;
stack_instance_node["z"] = inst->getLoc().z() / u;
stack_instance_node["orient"] = inst->getOrient().getString();
}

void DbxWriter::writeConnections(YAML::Node& connections_node,
odb::dbChip* chiplet)
{
for (auto conn : chiplet->getChipConns()) {
YAML::Node connection_node = connections_node[std::string(conn->getName())];
writeConnection(connection_node, conn);
}
}

void DbxWriter::writeConnection(YAML::Node& connection_node,
odb::dbChipConn* conn)
{
const double u = conn->getDb()->getDbuPerMicron();
connection_node["top"]
= buildPath(conn->getTopRegionPath(), conn->getTopRegion());
connection_node["bot"]
= buildPath(conn->getBottomRegionPath(), conn->getBottomRegion());
connection_node["thicness"] = conn->getThickness() / u;
}

std::string DbxWriter::buildPath(const std::vector<dbChipInst*>& path_insts,
odb::dbChipRegionInst* region)
{
if (region == nullptr) {
return "~";
}

std::string path;
for (auto inst : path_insts) {
if (!path.empty()) {
path += "/";
}
path += inst->getName();
}

if (!path.empty()) {
path += ".regions." + region->getChipRegion()->getName();
}
return path;
}

} // namespace odb
Loading
Loading