-
Notifications
You must be signed in to change notification settings - Fork 738
odb: add 3dbvWriter #8774
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
odb: add 3dbvWriter #8774
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,128 @@ | ||||||
| // SPDX-License-Identifier: BSD-3-Clause | ||||||
| // Copyright (c) 2019-2025, The OpenROAD Authors | ||||||
|
|
||||||
| #include "baseWriter.h" | ||||||
|
|
||||||
| #include <yaml-cpp/emitter.h> | ||||||
| #include <yaml-cpp/emitterstyle.h> | ||||||
| #include <yaml-cpp/node/convert.h> | ||||||
| #include <yaml-cpp/node/detail/impl.h> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: included header convert.h is not used directly [misc-include-cleaner]
Suggested change
|
||||||
| #include <yaml-cpp/node/emit.h> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: included header impl.h is not used directly [misc-include-cleaner]
Suggested change
|
||||||
| #include <yaml-cpp/node/node.h> | ||||||
|
|
||||||
rafaelmoresco marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| #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"] = "3"; | ||||||
| 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"); | ||||||
| } | ||||||
| } | ||||||
|
Comment on lines
+50
to
+98
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couple of comments on this:
|
||||||
|
|
||||||
| 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 | ||||||
| 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); | ||
|
Comment on lines
+29
to
+34
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be moved to dbvWriter as dbxWriter should never handle lef and def. |
||
| 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
| // Copyright (c) 2019-2025, The OpenROAD Authors | ||
|
|
||
| #include "chipletHierarchy.h" | ||
|
|
||
| #include <memory> | ||
| #include <unordered_map> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| #include "odb/db.h" | ||
|
|
||
| namespace odb { | ||
|
|
||
| ChipletNode* ChipletHierarchy::addChip(dbChip* chip) | ||
| { | ||
| if (!chip) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| auto it = nodes_.find(chip); | ||
| if (it == nodes_.end()) { | ||
| auto node = std::make_unique<ChipletNode>(chip); | ||
| ChipletNode* ptr = node.get(); | ||
| nodes_[chip] = std::move(node); | ||
rafaelmoresco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return ptr; | ||
| } | ||
| return it->second.get(); | ||
| } | ||
|
|
||
| void ChipletHierarchy::addDependency(dbChip* parent, dbChip* child) | ||
| { | ||
| if (!parent || !child) { | ||
| return; | ||
| } | ||
|
|
||
| ChipletNode* parent_node = addChip(parent); | ||
| ChipletNode* child_node = addChip(child); | ||
|
|
||
| parent_node->children.push_back(child_node); | ||
| child_node->parents.push_back(parent_node); | ||
| } | ||
|
|
||
| void ChipletHierarchy::buildHierarchy(const std::vector<dbChip*>& all_chips) | ||
| { | ||
| nodes_.clear(); | ||
|
|
||
| for (odb::dbChip* parent : all_chips) { | ||
| ChipletNode* parent_node = addChip(parent); | ||
| if (!parent_node) { | ||
| continue; | ||
| } | ||
|
|
||
| // Iterate instances to find dependencies | ||
| for (dbChipInst* inst : parent->getChipInsts()) { | ||
| // The instance master points to the child chiplets | ||
| odb::dbChip* child = inst->getMasterChip(); | ||
| if (child) { | ||
| addDependency(parent, child); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| std::vector<ChipletNode*> ChipletHierarchy::getRoots() const | ||
| { | ||
| std::vector<ChipletNode*> roots; | ||
| for (auto& [chip, node] : nodes_) { | ||
| if (node->parents.empty()) { | ||
| roots.push_back(node.get()); | ||
| } | ||
| } | ||
| return roots; | ||
| } | ||
|
|
||
| ChipletNode* ChipletHierarchy::findNodeForChip(dbChip* chip) const | ||
| { | ||
| if (!chip) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| auto it = nodes_.find(chip); | ||
| if (it == nodes_.end()) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| return it->second.get(); | ||
| } | ||
|
|
||
| } // namespace odb | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
| // Copyright (c) 2019-2025, The OpenROAD Authors | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <memory> | ||
| #include <unordered_map> | ||
| #include <vector> | ||
|
|
||
| #include "odb/db.h" | ||
|
|
||
| namespace odb { | ||
|
|
||
| struct ChipletNode | ||
| { | ||
| dbChip* chip; | ||
| std::vector<ChipletNode*> children; | ||
| std::vector<ChipletNode*> parents; | ||
| explicit ChipletNode(dbChip* c = nullptr) : chip(c) {} | ||
| }; | ||
|
|
||
| class ChipletHierarchy | ||
| { | ||
| public: | ||
| ChipletHierarchy() = default; | ||
| void buildHierarchy(const std::vector<dbChip*>& all_chips); | ||
| ChipletNode* findNodeForChip(odb::dbChip* chip) const; | ||
|
|
||
| private: | ||
| ChipletNode* addChip(odb::dbChip* chip); | ||
| void addDependency(odb::dbChip* parent, odb::dbChip* child); | ||
| std::vector<ChipletNode*> getRoots() const; | ||
| std::unordered_map<odb::dbChip*, std::unique_ptr<ChipletNode>> nodes_; | ||
| }; | ||
|
|
||
| } // namespace odb |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: included header emitter.h is not used directly [misc-include-cleaner]