mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-15 03:35:40 +00:00
rtlil, patch: incremental signorm via connect_incremental, replacing batched sigNormalize in Patch::patch
This commit is contained in:
parent
c3457e2e5c
commit
c264649ae7
3 changed files with 73 additions and 61 deletions
|
|
@ -2666,6 +2666,13 @@ public:
|
|||
const pool<PortBit> &fanout(SigBit bit);
|
||||
const dict<SigBit, pool<PortBit>> &signorm_fanout() const;
|
||||
|
||||
// Equivalent to `connect(lhs, rhs)` followed by `sigNormalize()` for the
|
||||
// merge implied by this single connection: updates the sigmap, promotes
|
||||
// the driven side as canonical, and re-normalizes any existing fanout
|
||||
// consumers of the demoted side. Lets callers in signorm mode merge
|
||||
// signals without the overhead of a full normalize.
|
||||
void connect_incremental(const SigSpec &lhs, const SigSpec &rhs);
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
void cloneInto(RTLIL::Module *new_mod) const;
|
||||
|
|
|
|||
|
|
@ -225,54 +225,56 @@ struct RTLIL::SigNormIndex
|
|||
}
|
||||
}
|
||||
|
||||
void flush_connections() {
|
||||
// Process one (lhs, rhs) connection: apply current sigmap, then for each
|
||||
// bit pair either merge into sigmap (and enqueue the demoted side into
|
||||
// newly_driven) or emit a $connect cell when both sides have drivers.
|
||||
void flush_one_connection(SigSpec lhs, SigSpec rhs) {
|
||||
std::vector<SigBit> connect_lhs;
|
||||
std::vector<SigBit> connect_rhs;
|
||||
|
||||
sigmap.apply(lhs);
|
||||
sigmap.apply(rhs);
|
||||
auto rhs_bits = rhs.bits().begin();
|
||||
|
||||
for (auto l : lhs.bits()) {
|
||||
auto r = *rhs_bits;
|
||||
++rhs_bits;
|
||||
if (l == r)
|
||||
continue;
|
||||
// TODO figure out what should happen with 'z
|
||||
bool l_driven = !l.is_wire() || l.wire->known_driver();
|
||||
bool r_driven = !r.is_wire() || r.wire->known_driver();
|
||||
if (l_driven && r_driven) {
|
||||
connect_lhs.push_back(l);
|
||||
connect_rhs.push_back(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
sigmap.add(l, r);
|
||||
if (l_driven) {
|
||||
sigmap.database.promote(l);
|
||||
newly_driven.insert(r);
|
||||
} else {
|
||||
sigmap.database.promote(r);
|
||||
newly_driven.insert(l);
|
||||
}
|
||||
}
|
||||
|
||||
if (!connect_lhs.empty()) {
|
||||
Cell *cell = module->addCell(NEW_ID, ID($connect));
|
||||
xlog("add connect (1) %s\n", cell->name);
|
||||
cell->setParam(ID::WIDTH, GetSize(connect_lhs));
|
||||
cell->setPort(ID::A, std::move(connect_lhs));
|
||||
cell->setPort(ID::B, std::move(connect_rhs));
|
||||
}
|
||||
}
|
||||
|
||||
void flush_connections() {
|
||||
auto begin = module->connections_.begin() + restored_connections;
|
||||
auto end = module->connections_.end();
|
||||
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
auto &[lhs, rhs] = *it;
|
||||
sigmap.apply(lhs);
|
||||
sigmap.apply(rhs);
|
||||
auto rhs_bits = rhs.bits().begin();
|
||||
|
||||
connect_lhs.clear();
|
||||
connect_rhs.clear();
|
||||
|
||||
for (auto l : lhs.bits()) {
|
||||
auto r = *rhs_bits;
|
||||
++rhs_bits;
|
||||
if (l == r)
|
||||
continue;
|
||||
// TODO figure out what should happen with 'z
|
||||
bool l_driven = !l.is_wire() || l.wire->known_driver();
|
||||
bool r_driven = !r.is_wire() || r.wire->known_driver();
|
||||
if (l_driven && r_driven) {
|
||||
connect_lhs.push_back(l);
|
||||
connect_rhs.push_back(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
sigmap.add(l, r);
|
||||
if (l_driven) {
|
||||
sigmap.database.promote(l);
|
||||
newly_driven.insert(r);
|
||||
} else {
|
||||
sigmap.database.promote(r);
|
||||
newly_driven.insert(l);
|
||||
}
|
||||
}
|
||||
|
||||
if (!connect_lhs.empty()) {
|
||||
Cell *cell = module->addCell(NEW_ID, ID($connect));
|
||||
xlog("add connect (1) %s\n", cell->name);
|
||||
cell->setParam(ID::WIDTH, GetSize(connect_lhs));
|
||||
cell->setPort(ID::A, std::move(connect_lhs));
|
||||
cell->setPort(ID::B, std::move(connect_rhs));
|
||||
}
|
||||
}
|
||||
for (auto it = begin; it != end; ++it)
|
||||
flush_one_connection(it->first, it->second);
|
||||
|
||||
module->connections_.clear();
|
||||
restored_connections = 0;
|
||||
|
|
@ -572,6 +574,14 @@ const dict<RTLIL::SigBit, pool<RTLIL::PortBit>> &RTLIL::Module::signorm_fanout()
|
|||
return sig_norm_index->fanout;
|
||||
}
|
||||
|
||||
void RTLIL::Module::connect_incremental(const SigSpec &lhs, const SigSpec &rhs)
|
||||
{
|
||||
log_assert(sig_norm_index != nullptr);
|
||||
log_assert(GetSize(lhs) == GetSize(rhs));
|
||||
sig_norm_index->flush_one_connection(lhs, rhs);
|
||||
sig_norm_index->flush_newly_driven();
|
||||
}
|
||||
|
||||
void RTLIL::Module::remove(RTLIL::Cell *cell)
|
||||
{
|
||||
while (!cell->connections_.empty())
|
||||
|
|
|
|||
|
|
@ -140,35 +140,29 @@ Cell* Patch::commit_cell(std::unique_ptr<Cell> cell) {
|
|||
void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) {
|
||||
SigSpec old_sig = old_cell->getPort(old_port);
|
||||
log_assert(old_sig.size() == new_sig.size());
|
||||
log("patching %s %s which is %s with %s:\n", old_cell->name, old_port, log_signal(old_sig), log_signal(new_sig));
|
||||
log_debug("patching %s %s which is %s with %s:\n", old_cell->name, old_port, log_signal(old_sig), log_signal(new_sig));
|
||||
|
||||
SrcCollector collector;
|
||||
collector.collect_src(old_sig);
|
||||
std::string src_str = AttrObject::strpool_attribute_to_str(collector.src);
|
||||
|
||||
old_cell->setPort(old_port, SigSpec());
|
||||
mod->connect(old_sig, new_sig);
|
||||
if (map)
|
||||
map->add(old_sig, new_sig);
|
||||
|
||||
// Inefficient
|
||||
// Record leaves (existing wires consumed as inputs by the new cells) so
|
||||
// gc() stops at them. Detected via bit.wire->module being non-null:
|
||||
// uncommitted wires belong to no module yet.
|
||||
for (auto& cell : cells_) {
|
||||
log_debug("cell %s\n", cell->name);
|
||||
for (auto& [port_name, sig] : cell->connections()) {
|
||||
log_debug("port %s\n", port_name);
|
||||
auto dir = cell->port_dir(port_name);
|
||||
if (dir == PD_INPUT || dir == PD_INOUT) {
|
||||
for (auto bit : sig) {
|
||||
log("bit %s\n", log_signal(bit));
|
||||
if (bit.is_wire() && bit.wire->module) {
|
||||
if (bit.is_wire() && bit.wire->module)
|
||||
leaves.insert(bit.wire);
|
||||
log_debug("leaf %s\n", bit.wire->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit new cells/wires first so new_sig becomes a driven signal in the
|
||||
// signorm index before we merge.
|
||||
for (auto& cell: cells_) {
|
||||
cell->set_src_attribute(src_str);
|
||||
cell->fixup_parameters();
|
||||
|
|
@ -178,12 +172,13 @@ void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) {
|
|||
for (auto& wire: wires_)
|
||||
commit_wire(std::move(wire));
|
||||
|
||||
// Flush pending sigmap updates (from the mod->connect above) into the
|
||||
// fanout index so gc() sees the updated fanout for cells whose outputs
|
||||
// were the patched wires. Without this, downstream consumers like the
|
||||
// $output_port / $public sentinels still appear in the OLD wire's fanout
|
||||
// instead of the new representative.
|
||||
mod->sigNormalize();
|
||||
// Now drop old_cell's driver so old_sig is undriven, then merge it into
|
||||
// new_sig. connect_incremental updates sigmap and re-normalizes fanout
|
||||
// consumers in place — no full sigNormalize needed.
|
||||
old_cell->setPort(old_port, SigSpec());
|
||||
if (map)
|
||||
map->add(old_sig, new_sig);
|
||||
mod->connect_incremental(old_sig, new_sig);
|
||||
|
||||
gc(old_cell);
|
||||
cells_.clear();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue