diff --git a/src/odb/src/3dblox/baseParser.cpp b/src/odb/src/3dblox/baseParser.cpp index e4a5076156d..0c7e87ff3e4 100644 --- a/src/odb/src/3dblox/baseParser.cpp +++ b/src/odb/src/3dblox/baseParser.cpp @@ -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) +{ + if (!parent[key]) { + return ""; + } + // The 3DBlox spec requires every external argument to be a YAML list of + // strings; a scalar value triggers a yaml-cpp conversion error here. + std::vector entries; + extractValue(parent, key, entries); + + // Honor wildcard expansion before checking cardinality: a single entry may + // resolve to multiple files. + std::vector resolved; + for (const std::string& entry : entries) { + resolvePaths(entry, resolved); + } + + if (resolved.size() > 1) { + logError("Multiple " + key + " entries for " + context + + " are currently unsupported."); + } + if (resolved.empty()) { + return ""; + } + return resolved[0]; +} + void BaseParser::logError(const std::string& message) { logger_->error( diff --git a/src/odb/src/3dblox/baseParser.h b/src/odb/src/3dblox/baseParser.h index 83344bc0b4f..08ca2b84fb8 100644 --- a/src/odb/src/3dblox/baseParser.h +++ b/src/odb/src/3dblox/baseParser.h @@ -36,6 +36,15 @@ class BaseParser void parseDefines(std::string& content); std::string resolvePath(const std::string& path); void resolvePaths(const std::string& path, std::vector& paths); + // Extracts a single resolved path from a YAML list-of-strings under + // parent[key], honoring wildcard expansion. Returns "" when the key is + // absent or the (expanded) list is empty. Emits a parser error when the + // expanded set has more than one file (cardinality > 1 is unsupported per + // the 3DBlox external 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); diff --git a/src/odb/src/3dblox/dbvParser.cpp b/src/odb/src/3dblox/dbvParser.cpp index 31f6804b261..210a243303f 100644 --- a/src/odb/src/3dblox/dbvParser.cpp +++ b/src/odb/src/3dblox/dbvParser.cpp @@ -179,18 +179,14 @@ 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); - } + // DEF_file and verilog_file are single-cardinality: the spec still + // requires a YAML list of strings, so parse via the shared helper (which + // rejects more than one resolved 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); } } diff --git a/src/odb/src/3dblox/dbvWriter.cpp b/src/odb/src/3dblox/dbvWriter.cpp index 1fc8e224d80..9bcdb868118 100644 --- a/src/odb/src/3dblox/dbvWriter.cpp +++ b/src/odb/src/3dblox/dbvWriter.cpp @@ -181,7 +181,11 @@ void DbvWriter::writeExternal(YAML::Node& external_node, odb::dbChip* chiplet) writeDef(external_node, chiplet); } if (auto prop = odb::dbStringProperty::find(chiplet, "verilog_file")) { - external_node["verilog_file"] = prop->getValue(); + // Per the 3DBlox spec, every external argument is a YAML list of strings. + YAML::Node verilog_node; + verilog_node.SetStyle(YAML::EmitterStyle::Flow); + verilog_node.push_back(prop->getValue()); + external_node["verilog_file"] = verilog_node; } } } @@ -237,7 +241,11 @@ void DbvWriter::writeDef(YAML::Node& external_node, odb::dbChip* chiplet) odb::DefOut def_writer(logger_); auto block = chiplet->getBlock(); def_writer.writeBlock(block, def_file_path.c_str()); - external_node["DEF_file"] = def_file; + // Per the 3DBlox spec, every external argument is a YAML list of strings. + YAML::Node def_node; + def_node.SetStyle(YAML::EmitterStyle::Flow); + def_node.push_back(def_file); + external_node["DEF_file"] = def_node; } } // namespace odb \ No newline at end of file diff --git a/src/odb/src/3dblox/dbxParser.cpp b/src/odb/src/3dblox/dbxParser.cpp index 7fb597048e0..a08327273d3 100644 --- a/src/odb/src/3dblox/dbxParser.cpp +++ b/src/odb/src/3dblox/dbxParser.cpp @@ -89,10 +89,10 @@ 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); - } + // The 3DBlox spec requires every external argument to be a YAML list of + // strings (with wildcard expansion). + external.verilog_file + = extractSinglePathFromList(external_node, "verilog_file", "Design"); } void DbxParser::parseChipletInsts(std::map& instances, @@ -126,27 +126,24 @@ 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); - } + // The 3DBlox spec requires every external argument to be a YAML list of + // strings (with wildcard expansion). + 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& instances, diff --git a/src/odb/src/3dblox/dbxParser.h b/src/odb/src/3dblox/dbxParser.h index 6331e4fc462..42aaa944760 100644 --- a/src/odb/src/3dblox/dbxParser.h +++ b/src/odb/src/3dblox/dbxParser.h @@ -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& instances, const YAML::Node& stack_node); void parseStackInstance(ChipletInst& instance, diff --git a/src/odb/src/3dblox/dbxWriter.cpp b/src/odb/src/3dblox/dbxWriter.cpp index 39684afd5f8..89284c749c7 100644 --- a/src/odb/src/3dblox/dbxWriter.cpp +++ b/src/odb/src/3dblox/dbxWriter.cpp @@ -50,7 +50,11 @@ void DbxWriter::writeDesign(YAML::Node& design_node, odb::dbChip* chiplet) { design_node["name"] = chiplet->getName(); YAML::Node external_node = design_node["external"]; - external_node["verilog_file"] = std::string(chiplet->getName()) + ".v"; + // Per the 3DBlox spec, every external argument is a YAML list of strings. + YAML::Node verilog_node; + verilog_node.SetStyle(YAML::EmitterStyle::Flow); + verilog_node.push_back(std::string(chiplet->getName()) + ".v"); + external_node["verilog_file"] = verilog_node; } void DbxWriter::writeChipletInsts(YAML::Node& instances_node,