3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-15 03:35:40 +00:00

techmap: efficient twines

This commit is contained in:
Emil J. Tywoniak 2026-06-22 21:54:45 +02:00
parent 7c73fd62e4
commit ba4ea22831

View file

@ -47,32 +47,69 @@ void apply_prefix(IdString prefix, IdString &id)
id = stringf("$techmap%s.%s", prefix, id);
}
TwineRef apply_prefix_ref(IdString prefix, IdString id, RTLIL::Design *design)
// Prefixes a template object's name with an instance's "<cell>." (public) or
// "$techmap<cell>." (private) prefix, for one cell's worth of instantiation.
// A name like "\a.b.c" is stored as nested Suffix nodes
// Suffix{Suffix{"\a.", "b."}, "c"}; recursing the Suffix chain re-prefixes only
// the innermost leaf ("\a." -> "\u.a.") and reuses the rest, so "b.", "c" stay
// shared instead of materialising "a.b.c" as one fresh tail per object.
// Reads the template name from TwinePool src and writes TwinePool dst.
struct PrefixApplier
{
std::string ids = id.str();
std::string shared, tail;
if (!ids.empty() && ids[0] == '\\') {
shared = prefix.str() + ".";
tail = ids.substr(1);
} else {
shared = "$techmap" + prefix.str() + ".";
tail = std::move(ids);
}
TwineRef pref = design->twines.add(std::move(shared));
return design->twines.add(Twine{Twine::Suffix{pref, std::move(tail)}});
}
RTLIL::Design *dst;
RTLIL::Design *src;
TwineRef cell_name;
TwineRef pub_prefix;
TwineRef priv_prefix = Twine::Null;
dict<TwineRef, TwineRef> memo;
void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
vector<SigChunk> chunks = sig;
for (auto &chunk : chunks)
if (chunk.wire != nullptr) {
TwineRef wire_ref = apply_prefix_ref(prefix, chunk.wire->name, module->design);
log_assert(module->wire(wire_ref) != nullptr);
chunk.wire = module->wire(wire_ref);
PrefixApplier(RTLIL::Design *dst, TwineRef prefix, RTLIL::Design *src)
: dst(dst), src(src), cell_name(prefix)
{
pub_prefix = dst->twines.add(Twine{Twine::Suffix{prefix, "."}});
}
// "$techmap<cell>." can't reuse the cell name's nodes (a tail is appended,
// not prepended), so it is the one prefix we materialise -- lazily, since
// many templates have no private wires.
TwineRef techmap_prefix()
{
if (priv_prefix == Twine::Null)
priv_prefix = dst->twines.add("$techmap" + dst->twines.str(cell_name) + ".");
return priv_prefix;
}
TwineRef name(TwineRef obj_ref)
{
if (auto it = memo.find(obj_ref); it != memo.end())
return it->second;
const Twine &node = src->twines[obj_ref];
TwineRef result;
if (node.is_suffix()) {
const Twine::Suffix &sfx = node.suffix();
TwineRef prefix = name(twine_tag(sfx.prefix, obj_ref.is_public()));
result = dst->twines.add(Twine{Twine::Suffix{prefix, sfx.tail}});
} else {
TwineRef prefix = obj_ref.is_public() ? pub_prefix : techmap_prefix();
result = dst->twines.add(Twine{Twine::Suffix{prefix, node.leaf()}});
}
sig = chunks;
}
memo[obj_ref] = result;
return result;
}
void apply(RTLIL::SigSpec &sig, RTLIL::Module *module)
{
vector<SigChunk> chunks = sig;
for (auto &chunk : chunks)
if (chunk.wire != nullptr) {
TwineRef wire_ref = name(chunk.wire->name.ref());
log_assert(module->wire(wire_ref) != nullptr);
chunk.wire = module->wire(wire_ref);
}
sig = chunks;
}
};
struct TechmapWorker
{
@ -185,6 +222,8 @@ struct TechmapWorker
break;
}
PrefixApplier ap(module->design, cell->name.ref(), tpl->design);
dict<IdString, IdString> memory_renames;
for (auto &it : tpl->memories) {
@ -222,7 +261,7 @@ struct TechmapWorker
autopurge_tpl_bits.insert(bit);
}
}
TwineRef w_ref = apply_prefix_ref(cell->name, tpl_w->name, module->design);
TwineRef w_ref = ap.name(tpl_w->name.ref());
RTLIL::Wire *w = module->wire(w_ref);
if (w != nullptr) {
temp_renamed_wires[w] = w->name.ref();
@ -280,18 +319,18 @@ struct TechmapWorker
if (w->port_output && !w->port_input) {
c.first = it.second;
c.second = RTLIL::SigSpec(w);
apply_prefix(cell->name, c.second, module);
ap.apply(c.second, module);
extra_connect.first = c.second;
extra_connect.second = c.first;
} else if (!w->port_output && w->port_input) {
c.first = RTLIL::SigSpec(w);
c.second = it.second;
apply_prefix(cell->name, c.first, module);
ap.apply(c.first, module);
extra_connect.first = c.first;
extra_connect.second = c.second;
} else {
SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second;
apply_prefix(cell->name, sig_tpl_pf, module);
ap.apply(sig_tpl_pf, module);
for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) {
if (tpl_written_bits.count(sig_tpl[i])) {
c.first.append(sig_mod[i]);
@ -350,7 +389,7 @@ struct TechmapWorker
else if (const char *p = strstr(tpl_cell->name.str().c_str(), "_TECHMAP_REPLACE_."))
c_ref = module->design->twines.add(stringf("%s%s", orig_cell_name, p + strlen("_TECHMAP_REPLACE_")));
else
c_ref = apply_prefix_ref(cell->name, tpl_cell->name, module->design);
c_ref = ap.name(tpl_cell->name.ref());
RTLIL::Cell *c = module->addCell(c_ref, tpl_cell);
design->select(module, c);
@ -378,7 +417,7 @@ struct TechmapWorker
autopurge_ports.push_back(conn.first);
} else {
RTLIL::SigSpec new_conn = conn.second;
apply_prefix(cell->name, new_conn, module);
ap.apply(new_conn, module);
port_signal_map.apply(new_conn);
c->setPort(conn.first, std::move(new_conn));
}
@ -410,8 +449,8 @@ struct TechmapWorker
for (auto &it : tpl->connections()) {
RTLIL::SigSig c = it;
apply_prefix(cell->name.str(), c.first, module);
apply_prefix(cell->name.str(), c.second, module);
ap.apply(c.first, module);
ap.apply(c.second, module);
port_signal_map.apply(c.first);
port_signal_map.apply(c.second);
module->connect(c);