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
9 changes: 9 additions & 0 deletions src/odb/include/odb/3dblox.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class ThreeDBlox
void createRegion(const ChipletRegion& region, dbChip* chip);
dbChip* createDesignTopChiplet(const DesignDef& design);
void createChipInst(const ChipletInst& chip_inst);
void readDefForChip(dbChip* chip, const std::string& def_file);
void createConnection(const Connection& connection);
void createBump(const BumpMapEntry& entry, dbChipRegion* chip_region);
std::pair<dbInst*, dbBTerm*> createBump(const BumpMapEntry& entry,
Expand All @@ -69,5 +70,13 @@ class ThreeDBlox
std::unordered_set<odb::dbTech*> written_techs_;
std::unordered_set<odb::dbLib*> written_libs_;
std::unordered_set<std::string> read_files_;
// Master chips for which a chiplet instance has already supplied a DEF file.
// Used to reject two instances of the same chiplet that each carry a DEF,
// since they would write design data onto the same shared master block.
std::unordered_set<odb::dbChip*> insts_with_def_;
// Master chips whose design DEF has already been read. The DEF may be given
// by the chiplet definition (3dbv) and/or a chiplet instance (3dbx); it is
// read only once per chip so shared DEF data is not duplicated.
std::unordered_set<odb::dbChip*> chips_with_def_;
};
} // namespace odb
17 changes: 11 additions & 6 deletions src/odb/include/odb/defin.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ class defin
public:
enum MODE
{
DEFAULT, // creates db from scratch (from def)
FLOORPLAN, // update existing COMPONENTS PINS DIEAREA TRACKS ROWS NETS
// SNETS
INCREMENTAL // update existing COMPONENTS PINS
DEFAULT, // creates db from scratch (from def)
FLOORPLAN, // update existing COMPONENTS PINS DIEAREA TRACKS ROWS NETS
// SNETS
INCREMENTAL, // update existing COMPONENTS PINS
THREE_D_BLOX // read DEF onto an existing 3DBlox block (created when the
// chiplet definition was read); find-or-create
// COMPONENTS/PINS/NETS and dedup data shared with the bump
// map
};
defin(dbDatabase* db, utl::Logger* logger, MODE mode = DEFAULT);
~defin();
Expand All @@ -42,8 +46,9 @@ class defin
void continueOnErrors();
void useBlockName(const char* name);

/// Create a new chip
void readChip(std::vector<dbLib*>& search_libs,
/// Read a DEF onto a chip. Returns true on success, false if the DEF file
/// could not be read.
bool readChip(std::vector<dbLib*>& search_libs,
const char* def_file,
dbChip* chip,
bool issue_callback = true);
Expand Down
57 changes: 44 additions & 13 deletions src/odb/src/3dblox/3dblox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,19 +453,6 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet)
db_, tech, chiplet.name, getChipType(chiplet.type, logger_));
}

// Read DEF file
if (!chiplet.external.def_file.empty()) {
odb::defin def_reader(db_, logger_, odb::defin::DEFAULT);
std::vector<odb::dbLib*> search_libs;
for (odb::dbLib* lib : db_->getLibs()) {
search_libs.push_back(lib);
}
// No callbacks here as we are going to give one postRead3Dbx later
def_reader.readChip(search_libs,
chiplet.external.def_file.c_str(),
chip,
/*issue_callback*/ false);
}
const int dbu_per_micron = db_->getDbuPerMicron();
if (chiplet.design_width != -1.0) {
chip->setWidth(std::round(chiplet.design_width * dbu_per_micron));
Expand Down Expand Up @@ -515,6 +502,35 @@ void ThreeDBlox::createChiplet(const ChipletDef& chiplet)
for (const auto& [_, region] : chiplet.regions) {
createRegion(region, chip);
}

// Read the DEF file (if any) onto the block created above. The block and its
// bumps already exist, so the read uses the 3DBlox defin mode, which
// find-or-creates and dedups data shared with the bump map instead of
// erroring because a block is already present.
if (!chiplet.external.def_file.empty()) {
readDefForChip(chip, chiplet.external.def_file);
}
}

void ThreeDBlox::readDefForChip(dbChip* chip, const std::string& def_file)
{
// A chiplet's design DEF only needs to be read once. The DEF may be supplied
// by the chiplet definition (3dbv) and/or by a chiplet instance (3dbx); if it
// was already read onto this chip, skip it so that DEF data not shared with
// the bump map (rows, tracks, ...) is not duplicated.
if (chips_with_def_.contains(chip)) {
return;
}
odb::defin def_reader(db_, logger_, odb::defin::THREE_D_BLOX);
std::vector<odb::dbLib*> search_libs;
search_libs.assign(db_->getLibs().begin(), db_->getLibs().end());
// No callbacks here as we are going to give one postRead3Dbx later. Mark the
// chip only on success so a failed read (e.g. bad path) does not suppress a
// later valid DEF for the same chip.
if (def_reader.readChip(
search_libs, def_file.c_str(), chip, /*issue_callback*/ false)) {
chips_with_def_.insert(chip);
}
}

static dbChipRegion::Side getChipRegionSide(const std::string& side,
Expand Down Expand Up @@ -698,6 +714,21 @@ void ThreeDBlox::createChipInst(const ChipletInst& chip_inst)
static_cast<int>(std::round(chip_inst.loc.y * dbu_per_micron)),
static_cast<int>(std::round(chip_inst.z * dbu_per_micron)),
});

// Per the 3DBlox standard, the DEF file may be associated with the chiplet
// instance (ChipletInst.external) rather than the chiplet definition. Read it
// onto the referenced master chip's block. The DEF is shared design data, so
// two instances of the same chiplet may not each carry their own DEF.
if (!chip_inst.external.def_file.empty()) {
if (!insts_with_def_.insert(chip).second) {
logger_->error(utl::ODB,
547,
"3DBX Parser Error: There can't be 2 instances of the "
"same chiplet {} with a def file each",
chip_inst.reference);
}
readDefForChip(chip, chip_inst.external.def_file);
}
}
static std::vector<std::string> splitPath(const std::string& path)
{
Expand Down
29 changes: 29 additions & 0 deletions src/odb/src/3dblox/baseParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,35 @@ void BaseParser::resolvePaths(const std::string& path,
}
}

std::string BaseParser::extractSinglePathFromList(const YAML::Node& parent,
const std::string& key,
const std::string& context)
{
const YAML::Node node = parent[key];
if (!node) {
return "";
}
std::vector<std::string> values;
try {
if (node.IsSequence()) {
values = node.as<std::vector<std::string>>();
} else {
values.push_back(node.as<std::string>());
}
} catch (const YAML::Exception& e) {
logError("Error parsing " + key + " for " + context + ": "
+ std::string(e.what()));
}
if (values.size() > 1) {
logError("Multiple " + key + " entries for " + context
+ " are currently unsupported.");
}
if (values.empty()) {
return "";
}
return resolvePath(values[0]);
}

void BaseParser::logError(const std::string& message)
{
logger_->error(
Expand Down
8 changes: 8 additions & 0 deletions src/odb/src/3dblox/baseParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ class BaseParser
void parseDefines(std::string& content);
std::string resolvePath(const std::string& path);
void resolvePaths(const std::string& path, std::vector<std::string>& paths);
// Extracts a single resolved path from `parent[key]`, accepting either a
// scalar or a single-element list. Returns "" if the key is absent/empty and
// emits a parser error (terminal) when more than one entry is given, since
// these external fields are single-valued per the 3DBlox spec. `context`
// identifies the owning element in the error message.
std::string extractSinglePathFromList(const YAML::Node& parent,
const std::string& key,
const std::string& context);

// Utility methods
void logError(const std::string& message);
Expand Down
17 changes: 5 additions & 12 deletions src/odb/src/3dblox/dbvParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,11 @@ void DbvParser::parseChiplet(ChipletDef& chiplet,
}
}
}
if (chiplet_node["external"]["DEF_file"]) {
extractValue(
chiplet_node["external"], "DEF_file", chiplet.external.def_file);
chiplet.external.def_file = resolvePath(chiplet.external.def_file);
}
if (chiplet_node["external"]["verilog_file"]) {
extractValue(chiplet_node["external"],
"verilog_file",
chiplet.external.verilog_file);
chiplet.external.verilog_file
= resolvePath(chiplet.external.verilog_file);
}
const std::string context = "ChipletDef '" + chiplet.name + "'";
chiplet.external.def_file = extractSinglePathFromList(
chiplet_node["external"], "DEF_file", context);
chiplet.external.verilog_file = extractSinglePathFromList(
chiplet_node["external"], "verilog_file", context);
}
}

Expand Down
27 changes: 12 additions & 15 deletions src/odb/src/3dblox/dbvWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

#include "dbvWriter.h"

#include <algorithm>
#include <filesystem>
#include <string>
#include <unordered_set>
#include <vector>

#include "baseWriter.h"
#include "odb/db.h"
#include "odb/defout.h"
#include "utl/Logger.h"
#include "yaml-cpp/yaml.h"
namespace odb {
Expand Down Expand Up @@ -177,9 +178,8 @@ void DbvWriter::writeExternal(YAML::Node& external_node, odb::dbChip* chiplet)
{
if (chiplet->getChipType() != odb::dbChip::ChipType::HIER) {
writeLef(external_node, chiplet);
if (chiplet->getBlock() != nullptr) {
writeDef(external_node, chiplet);
}
// Per the 3DBlox standard the DEF file is attached to a chiplet instance,
// so it is emitted in the .3dbx (by the DbxWriter), not here in the .3dbv.
if (auto prop = odb::dbStringProperty::find(chiplet, "verilog_file")) {
external_node["verilog_file"] = prop->getValue();
}
Expand Down Expand Up @@ -223,21 +223,18 @@ void DbvWriter::writeLef(YAML::Node& external_node, odb::dbChip* chiplet)
YAML::Node list_node;
list_node.SetStyle(YAML::EmitterStyle::Flow);
external_node["LEF_file"] = list_node;
// Sort so the output is deterministic regardless of the (unordered) set
// iteration order.
std::vector<std::string> lef_files;
lef_files.reserve(libs.size());
for (auto lib : libs) {
std::string lef_file = std::string(lib->getName()) + "_lib.lef";
lef_files.push_back(std::string(lib->getName()) + "_lib.lef");
}
std::ranges::sort(lef_files);
for (const auto& lef_file : lef_files) {
external_node["LEF_file"].push_back(lef_file);
}
}
}

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

} // namespace odb
1 change: 0 additions & 1 deletion src/odb/src/3dblox/dbvWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class DbvWriter : public BaseWriter
void writeRegion(YAML::Node& region_node, odb::dbChipRegion* region);
void writeExternal(YAML::Node& external_node, odb::dbChip* chiplet);
void writeLef(YAML::Node& external_node, odb::dbChip* chiplet);
void writeDef(YAML::Node& external_node, odb::dbChip* chiplet);
};

} // namespace odb
33 changes: 13 additions & 20 deletions src/odb/src/3dblox/dbxParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,8 @@ void DbxParser::parseDesign(DesignDef& design, const YAML::Node& design_node)
void DbxParser::parseDesignExternal(DesignExternal& external,
const YAML::Node& external_node)
{
if (external_node["verilog_file"]) {
extractValue(external_node, "verilog_file", external.verilog_file);
external.verilog_file = resolvePath(external.verilog_file);
}
external.verilog_file
= extractSinglePathFromList(external_node, "verilog_file", "Design");
}

void DbxParser::parseChipletInsts(std::map<std::string, ChipletInst>& instances,
Expand Down Expand Up @@ -126,27 +124,22 @@ void DbxParser::parseChipletInst(ChipletInst& instance,
extractValue(instance_node, "reference", instance.reference);

if (instance_node["external"]) {
parseChipletInstExternal(instance.external, instance_node["external"]);
parseChipletInstExternal(
instance.external, instance_node["external"], instance.name);
}
}

void DbxParser::parseChipletInstExternal(ChipletInstExternal& external,
const YAML::Node& external_node)
const YAML::Node& external_node,
const std::string& instance_name)
{
if (external_node["verilog_file"]) {
extractValue(external_node, "verilog_file", external.verilog_file);
external.verilog_file = resolvePath(external.verilog_file);
}

if (external_node["sdc_file"]) {
extractValue(external_node, "sdc_file", external.sdc_file);
external.sdc_file = resolvePath(external.sdc_file);
}

if (external_node["def_file"]) {
extractValue(external_node, "def_file", external.def_file);
external.def_file = resolvePath(external.def_file);
}
const std::string context = "ChipletInst '" + instance_name + "'";
external.verilog_file
= extractSinglePathFromList(external_node, "verilog_file", context);
external.sdc_file
= extractSinglePathFromList(external_node, "sdc_file", context);
external.def_file
= extractSinglePathFromList(external_node, "def_file", context);
}

void DbxParser::parseStack(std::map<std::string, ChipletInst>& instances,
Expand Down
3 changes: 2 additions & 1 deletion src/odb/src/3dblox/dbxParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class DbxParser : public BaseParser
const YAML::Node& instances_node);
void parseChipletInst(ChipletInst& instance, const YAML::Node& instance_node);
void parseChipletInstExternal(ChipletInstExternal& external,
const YAML::Node& external_node);
const YAML::Node& external_node,
const std::string& instance_name);
void parseStack(std::map<std::string, ChipletInst>& instances,
const YAML::Node& stack_node);
void parseStackInstance(ChipletInst& instance,
Expand Down
Loading
Loading