mirror of https://github.com/YosysHQ/yosys.git
rtlil_frontend: fix twine ordering
This commit is contained in:
parent
1b7daaae2e
commit
84829cb11d
|
|
@ -65,6 +65,20 @@ struct RTLILFrontendWorker {
|
||||||
dict<size_t, TwineRef> twine_remap;
|
dict<size_t, TwineRef> twine_remap;
|
||||||
std::vector<TwineRef> twine_parser_holds;
|
std::vector<TwineRef> twine_parser_holds;
|
||||||
|
|
||||||
|
// Raw twines-block node descriptors keyed by file-local id. The block may
|
||||||
|
// list a node before its children (the writer emits in pool-index order,
|
||||||
|
// and free-list slot reuse can place a parent at a lower index than a
|
||||||
|
// child), so descriptors are collected first and materialized on demand in
|
||||||
|
// dependency order via materialize_file_twine.
|
||||||
|
struct TwineDesc {
|
||||||
|
enum Kind { Leaf, Suffix, Concat } kind;
|
||||||
|
std::string text;
|
||||||
|
size_t parent = 0;
|
||||||
|
std::vector<size_t> children;
|
||||||
|
bool materializing = false;
|
||||||
|
};
|
||||||
|
dict<size_t, TwineDesc> twine_descs;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void error(FmtString<TypeIdentity<Args>...> fmt, const Args &... args)
|
void error(FmtString<TypeIdentity<Args>...> fmt, const Args &... args)
|
||||||
|
|
@ -570,20 +584,6 @@ struct RTLILFrontendWorker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses a `twines` ... `end` block. Builds twine_remap so subsequent
|
|
||||||
// cell/wire src "@N" references (which use file-local ids) translate
|
|
||||||
// to ids in design->twines. The destination pool may already be
|
|
||||||
// non-empty (multi-file load) — interned/concated nodes are dedup'd
|
|
||||||
// against the existing pool by the pool itself.
|
|
||||||
// Static ids are universal: a file id below STATIC_TWINE_END denotes the
|
|
||||||
// same prepopulated twine in every pool, so it maps to itself and is
|
|
||||||
// never emitted in the `twines` block.
|
|
||||||
// Resolve a numeric content id from the twines block (a node's own id, or
|
|
||||||
// a suffix/concat child). Statics are universal — an id below
|
|
||||||
// STATIC_TWINE_END denotes the same prepopulated twine in every pool;
|
|
||||||
// locals are remapped per file. Publicity (for $pub@/$priv@ handles)
|
|
||||||
// travels separately and is reapplied here. Object-use statics never reach
|
|
||||||
// this path: they are written as escaped names and interned by content.
|
|
||||||
TwineRef resolve_file_twine(size_t id, bool is_public = false)
|
TwineRef resolve_file_twine(size_t id, bool is_public = false)
|
||||||
{
|
{
|
||||||
TwineRef base;
|
TwineRef base;
|
||||||
|
|
@ -592,14 +592,52 @@ struct RTLILFrontendWorker {
|
||||||
} else {
|
} else {
|
||||||
auto it = twine_remap.find(id);
|
auto it = twine_remap.find(id);
|
||||||
if (it == twine_remap.end())
|
if (it == twine_remap.end())
|
||||||
error("Unknown twine reference @%zu at line %d", id, line_num);
|
base = materialize_file_twine(id);
|
||||||
base = it->second;
|
else
|
||||||
|
base = it->second;
|
||||||
}
|
}
|
||||||
return twine_tag(base, is_public);
|
return twine_tag(base, is_public);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a "$pub@N"/"$priv@N" twine handle into a resolved, retagged ref.
|
// Tolerates nodes listed out of dependency order
|
||||||
// Returns nullopt (consuming nothing) if the next token is not a handle.
|
TwineRef materialize_file_twine(size_t id)
|
||||||
|
{
|
||||||
|
if (id < STATIC_TWINE_END)
|
||||||
|
return TwineRef(id);
|
||||||
|
auto rit = twine_remap.find(id);
|
||||||
|
if (rit != twine_remap.end())
|
||||||
|
return rit->second;
|
||||||
|
auto dit = twine_descs.find(id);
|
||||||
|
if (dit == twine_descs.end())
|
||||||
|
error("Unknown twine reference @%zu at line %d", id, line_num);
|
||||||
|
TwineDesc &desc = dit->second;
|
||||||
|
if (desc.materializing)
|
||||||
|
error("Cyclic twine reference @%zu at line %d", id, line_num);
|
||||||
|
desc.materializing = true;
|
||||||
|
TwineRef ref;
|
||||||
|
switch (desc.kind) {
|
||||||
|
case TwineDesc::Leaf:
|
||||||
|
ref = design->twines.add(Twine{desc.text});
|
||||||
|
break;
|
||||||
|
case TwineDesc::Suffix:
|
||||||
|
ref = design->twines.add(Twine{Twine::Suffix{
|
||||||
|
materialize_file_twine(desc.parent), desc.text}});
|
||||||
|
break;
|
||||||
|
case TwineDesc::Concat: {
|
||||||
|
std::vector<TwineRef> children;
|
||||||
|
children.reserve(desc.children.size());
|
||||||
|
for (size_t c : desc.children)
|
||||||
|
children.push_back(materialize_file_twine(c));
|
||||||
|
ref = design->twines.add(Twine{children});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
desc.materializing = false;
|
||||||
|
twine_remap[id] = ref;
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a "$pub@N"/"$priv@N" twine handle into a resolved, retagged ref
|
||||||
std::optional<TwineRef> try_parse_twine_handle()
|
std::optional<TwineRef> try_parse_twine_handle()
|
||||||
{
|
{
|
||||||
bool is_public;
|
bool is_public;
|
||||||
|
|
@ -632,6 +670,10 @@ struct RTLILFrontendWorker {
|
||||||
return *t;
|
return *t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse a `twines` ... `end` block into per-file node descriptors, then
|
||||||
|
// intern them all into design->twines. The destination pool may already
|
||||||
|
// hold twines (multi-file load); it dedups by content. Static ids are
|
||||||
|
// universal and never appear in the block.
|
||||||
void parse_twines()
|
void parse_twines()
|
||||||
{
|
{
|
||||||
expect_eol();
|
expect_eol();
|
||||||
|
|
@ -640,30 +682,35 @@ struct RTLILFrontendWorker {
|
||||||
break;
|
break;
|
||||||
if (try_parse_keyword("leaf")) {
|
if (try_parse_keyword("leaf")) {
|
||||||
size_t file_id = parse_integer();
|
size_t file_id = parse_integer();
|
||||||
std::string text = parse_string();
|
TwineDesc &desc = twine_descs[file_id];
|
||||||
|
desc.kind = TwineDesc::Leaf;
|
||||||
|
desc.text = parse_string();
|
||||||
expect_eol();
|
expect_eol();
|
||||||
twine_remap[file_id] = design->twines.add(Twine{text});
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (try_parse_keyword("suffix")) {
|
if (try_parse_keyword("suffix")) {
|
||||||
size_t file_id = parse_integer();
|
size_t file_id = parse_integer();
|
||||||
size_t file_parent = parse_integer();
|
TwineDesc &desc = twine_descs[file_id];
|
||||||
std::string tail = parse_string();
|
desc.kind = TwineDesc::Suffix;
|
||||||
|
desc.parent = parse_integer();
|
||||||
|
desc.text = parse_string();
|
||||||
expect_eol();
|
expect_eol();
|
||||||
twine_remap[file_id] = design->twines.add(Twine{Twine::Suffix{resolve_file_twine(file_parent), tail}});
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (try_parse_keyword("concat")) {
|
if (try_parse_keyword("concat")) {
|
||||||
size_t file_id = parse_integer();
|
size_t file_id = parse_integer();
|
||||||
std::vector<TwineRef> children;
|
TwineDesc &desc = twine_descs[file_id];
|
||||||
|
desc.kind = TwineDesc::Concat;
|
||||||
while (!try_parse_eol())
|
while (!try_parse_eol())
|
||||||
children.push_back(resolve_file_twine(parse_integer()));
|
desc.children.push_back(parse_integer());
|
||||||
twine_remap[file_id] = design->twines.add(Twine{children});
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
error("Expected `leaf`, `suffix` or `concat` inside twines block, got `%s'.",
|
error("Expected `leaf`, `suffix` or `concat` inside twines block, got `%s'.",
|
||||||
error_token());
|
error_token());
|
||||||
}
|
}
|
||||||
|
for (auto &it : twine_descs)
|
||||||
|
materialize_file_twine(it.first);
|
||||||
|
twine_descs.clear();
|
||||||
expect_eol();
|
expect_eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue