Skip to content

Commit a8dcfe0

Browse files
ODB: parse 3DBlox external arguments as YAML lists (#10078)
Per the 3DBlox v3.0 spec, every argument inside an external block must be a YAML list of strings (with wildcard expansion). Parse the single-cardinality external keys (verilog_file/sdc_file/def_file in .3dbx; DEF_file/verilog_file in .3dbv) through a shared extractSinglePathFromList helper that expands wildcards via resolvePaths and rejects more than one resolved file. Emit these keys as YAML lists on write for round-trip consistency. Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
1 parent 4db8ad9 commit a8dcfe0

7 files changed

Lines changed: 80 additions & 36 deletions

File tree

src/odb/src/3dblox/baseParser.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,35 @@ void BaseParser::resolvePaths(const std::string& path,
172172
}
173173
}
174174

175+
std::string BaseParser::extractSinglePathFromList(const YAML::Node& parent,
176+
const std::string& key,
177+
const std::string& context)
178+
{
179+
if (!parent[key]) {
180+
return "";
181+
}
182+
// The 3DBlox spec requires every external argument to be a YAML list of
183+
// strings; a scalar value triggers a yaml-cpp conversion error here.
184+
std::vector<std::string> entries;
185+
extractValue(parent, key, entries);
186+
187+
// Honor wildcard expansion before checking cardinality: a single entry may
188+
// resolve to multiple files.
189+
std::vector<std::string> resolved;
190+
for (const std::string& entry : entries) {
191+
resolvePaths(entry, resolved);
192+
}
193+
194+
if (resolved.size() > 1) {
195+
logError("Multiple " + key + " entries for " + context
196+
+ " are currently unsupported.");
197+
}
198+
if (resolved.empty()) {
199+
return "";
200+
}
201+
return resolved[0];
202+
}
203+
175204
void BaseParser::logError(const std::string& message)
176205
{
177206
logger_->error(

src/odb/src/3dblox/baseParser.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ class BaseParser
3636
void parseDefines(std::string& content);
3737
std::string resolvePath(const std::string& path);
3838
void resolvePaths(const std::string& path, std::vector<std::string>& paths);
39+
// Extracts a single resolved path from a YAML list-of-strings under
40+
// parent[key], honoring wildcard expansion. Returns "" when the key is
41+
// absent or the (expanded) list is empty. Emits a parser error when the
42+
// expanded set has more than one file (cardinality > 1 is unsupported per
43+
// the 3DBlox external spec). `context` identifies the owning element in the
44+
// error message.
45+
std::string extractSinglePathFromList(const YAML::Node& parent,
46+
const std::string& key,
47+
const std::string& context);
3948

4049
// Utility methods
4150
void logError(const std::string& message);

src/odb/src/3dblox/dbvParser.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -179,18 +179,14 @@ void DbvParser::parseChiplet(ChipletDef& chiplet,
179179
}
180180
}
181181
}
182-
if (chiplet_node["external"]["DEF_file"]) {
183-
extractValue(
184-
chiplet_node["external"], "DEF_file", chiplet.external.def_file);
185-
chiplet.external.def_file = resolvePath(chiplet.external.def_file);
186-
}
187-
if (chiplet_node["external"]["verilog_file"]) {
188-
extractValue(chiplet_node["external"],
189-
"verilog_file",
190-
chiplet.external.verilog_file);
191-
chiplet.external.verilog_file
192-
= resolvePath(chiplet.external.verilog_file);
193-
}
182+
// DEF_file and verilog_file are single-cardinality: the spec still
183+
// requires a YAML list of strings, so parse via the shared helper (which
184+
// rejects more than one resolved file).
185+
const std::string context = "ChipletDef '" + chiplet.name + "'";
186+
chiplet.external.def_file = extractSinglePathFromList(
187+
chiplet_node["external"], "DEF_file", context);
188+
chiplet.external.verilog_file = extractSinglePathFromList(
189+
chiplet_node["external"], "verilog_file", context);
194190
}
195191
}
196192

src/odb/src/3dblox/dbvWriter.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,11 @@ void DbvWriter::writeExternal(YAML::Node& external_node, odb::dbChip* chiplet)
181181
writeDef(external_node, chiplet);
182182
}
183183
if (auto prop = odb::dbStringProperty::find(chiplet, "verilog_file")) {
184-
external_node["verilog_file"] = prop->getValue();
184+
// Per the 3DBlox spec, every external argument is a YAML list of strings.
185+
YAML::Node verilog_node;
186+
verilog_node.SetStyle(YAML::EmitterStyle::Flow);
187+
verilog_node.push_back(prop->getValue());
188+
external_node["verilog_file"] = verilog_node;
185189
}
186190
}
187191
}
@@ -237,7 +241,11 @@ void DbvWriter::writeDef(YAML::Node& external_node, odb::dbChip* chiplet)
237241
odb::DefOut def_writer(logger_);
238242
auto block = chiplet->getBlock();
239243
def_writer.writeBlock(block, def_file_path.c_str());
240-
external_node["DEF_file"] = def_file;
244+
// Per the 3DBlox spec, every external argument is a YAML list of strings.
245+
YAML::Node def_node;
246+
def_node.SetStyle(YAML::EmitterStyle::Flow);
247+
def_node.push_back(def_file);
248+
external_node["DEF_file"] = def_node;
241249
}
242250

243251
} // namespace odb

src/odb/src/3dblox/dbxParser.cpp

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ void DbxParser::parseDesign(DesignDef& design, const YAML::Node& design_node)
8989
void DbxParser::parseDesignExternal(DesignExternal& external,
9090
const YAML::Node& external_node)
9191
{
92-
if (external_node["verilog_file"]) {
93-
extractValue(external_node, "verilog_file", external.verilog_file);
94-
external.verilog_file = resolvePath(external.verilog_file);
95-
}
92+
// The 3DBlox spec requires every external argument to be a YAML list of
93+
// strings (with wildcard expansion).
94+
external.verilog_file
95+
= extractSinglePathFromList(external_node, "verilog_file", "Design");
9696
}
9797

9898
void DbxParser::parseChipletInsts(std::map<std::string, ChipletInst>& instances,
@@ -126,27 +126,24 @@ void DbxParser::parseChipletInst(ChipletInst& instance,
126126
extractValue(instance_node, "reference", instance.reference);
127127

128128
if (instance_node["external"]) {
129-
parseChipletInstExternal(instance.external, instance_node["external"]);
129+
parseChipletInstExternal(
130+
instance.external, instance_node["external"], instance.name);
130131
}
131132
}
132133

133134
void DbxParser::parseChipletInstExternal(ChipletInstExternal& external,
134-
const YAML::Node& external_node)
135+
const YAML::Node& external_node,
136+
const std::string& instance_name)
135137
{
136-
if (external_node["verilog_file"]) {
137-
extractValue(external_node, "verilog_file", external.verilog_file);
138-
external.verilog_file = resolvePath(external.verilog_file);
139-
}
140-
141-
if (external_node["sdc_file"]) {
142-
extractValue(external_node, "sdc_file", external.sdc_file);
143-
external.sdc_file = resolvePath(external.sdc_file);
144-
}
145-
146-
if (external_node["def_file"]) {
147-
extractValue(external_node, "def_file", external.def_file);
148-
external.def_file = resolvePath(external.def_file);
149-
}
138+
// The 3DBlox spec requires every external argument to be a YAML list of
139+
// strings (with wildcard expansion).
140+
const std::string context = "ChipletInst '" + instance_name + "'";
141+
external.verilog_file
142+
= extractSinglePathFromList(external_node, "verilog_file", context);
143+
external.sdc_file
144+
= extractSinglePathFromList(external_node, "sdc_file", context);
145+
external.def_file
146+
= extractSinglePathFromList(external_node, "def_file", context);
150147
}
151148

152149
void DbxParser::parseStack(std::map<std::string, ChipletInst>& instances,

src/odb/src/3dblox/dbxParser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class DbxParser : public BaseParser
3030
const YAML::Node& instances_node);
3131
void parseChipletInst(ChipletInst& instance, const YAML::Node& instance_node);
3232
void parseChipletInstExternal(ChipletInstExternal& external,
33-
const YAML::Node& external_node);
33+
const YAML::Node& external_node,
34+
const std::string& instance_name);
3435
void parseStack(std::map<std::string, ChipletInst>& instances,
3536
const YAML::Node& stack_node);
3637
void parseStackInstance(ChipletInst& instance,

src/odb/src/3dblox/dbxWriter.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ void DbxWriter::writeDesign(YAML::Node& design_node, odb::dbChip* chiplet)
5050
{
5151
design_node["name"] = chiplet->getName();
5252
YAML::Node external_node = design_node["external"];
53-
external_node["verilog_file"] = std::string(chiplet->getName()) + ".v";
53+
// Per the 3DBlox spec, every external argument is a YAML list of strings.
54+
YAML::Node verilog_node;
55+
verilog_node.SetStyle(YAML::EmitterStyle::Flow);
56+
verilog_node.push_back(std::string(chiplet->getName()) + ".v");
57+
external_node["verilog_file"] = verilog_node;
5458
}
5559

5660
void DbxWriter::writeChipletInsts(YAML::Node& instances_node,

0 commit comments

Comments
 (0)