3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-18 13:15:46 +00:00

patch: merge src into existing cells; opt_merge/_inc + onehot + ff.cc use Patch

This commit is contained in:
Emil J. Tywoniak 2026-05-30 19:07:37 +02:00
parent ea41e61a36
commit e583da906d
6 changed files with 122 additions and 52 deletions

View file

@ -21,6 +21,16 @@
USING_YOSYS_NAMESPACE
namespace {
// Pull the FF's src attribute so we can propagate it to intermediate
// cells created during unmap / conversion — otherwise downstream tools
// lose source provenance for the unmapped logic.
std::string ff_src(const FfData &ff) {
auto it = ff.attributes.find(ID::src);
return it == ff.attributes.end() ? std::string() : it->second.decode_string();
}
}
// sorry
template<typename InputType, typename OutputType, typename = std::enable_if_t<std::is_base_of_v<FfTypeData, OutputType>>>
void manufacture_info(InputType flop, OutputType& info, FfInitVals *initvals) {
@ -484,25 +494,26 @@ void FfData::aload_to_sr() {
log_assert(!has_sr);
has_sr = true;
has_aload = false;
std::string src = ff_src(*this);
if (!is_fine) {
pol_clr = false;
pol_set = true;
if (pol_aload) {
sig_clr = module->Mux(NEW_ID, Const(State::S1, width), sig_ad, sig_aload);
sig_set = module->Mux(NEW_ID, Const(State::S0, width), sig_ad, sig_aload);
sig_clr = module->Mux(NEW_ID, Const(State::S1, width), sig_ad, sig_aload, src);
sig_set = module->Mux(NEW_ID, Const(State::S0, width), sig_ad, sig_aload, src);
} else {
sig_clr = module->Mux(NEW_ID, sig_ad, Const(State::S1, width), sig_aload);
sig_set = module->Mux(NEW_ID, sig_ad, Const(State::S0, width), sig_aload);
sig_clr = module->Mux(NEW_ID, sig_ad, Const(State::S1, width), sig_aload, src);
sig_set = module->Mux(NEW_ID, sig_ad, Const(State::S0, width), sig_aload, src);
}
} else {
pol_clr = pol_aload;
pol_set = pol_aload;
if (pol_aload) {
sig_clr = module->AndnotGate(NEW_ID, sig_aload, sig_ad);
sig_set = module->AndGate(NEW_ID, sig_aload, sig_ad);
sig_clr = module->AndnotGate(NEW_ID, sig_aload, sig_ad, src);
sig_set = module->AndGate(NEW_ID, sig_aload, sig_ad, src);
} else {
sig_clr = module->OrGate(NEW_ID, sig_aload, sig_ad);
sig_set = module->OrnotGate(NEW_ID, sig_aload, sig_ad);
sig_clr = module->OrGate(NEW_ID, sig_aload, sig_ad, src);
sig_set = module->OrnotGate(NEW_ID, sig_aload, sig_ad, src);
}
}
}
@ -510,36 +521,37 @@ void FfData::aload_to_sr() {
void FfData::convert_ce_over_srst(bool val) {
if (!has_ce || !has_srst || ce_over_srst == val)
return;
std::string src = ff_src(*this);
if (val) {
// sdffe to sdffce
if (!is_fine) {
if (pol_ce) {
if (pol_srst) {
sig_ce = module->Or(NEW_ID, sig_ce, sig_srst);
sig_ce = module->Or(NEW_ID, sig_ce, sig_srst, false, src);
} else {
SigSpec tmp = module->Not(NEW_ID, sig_srst);
sig_ce = module->Or(NEW_ID, sig_ce, tmp);
SigSpec tmp = module->Not(NEW_ID, sig_srst, false, src);
sig_ce = module->Or(NEW_ID, sig_ce, tmp, false, src);
}
} else {
if (pol_srst) {
SigSpec tmp = module->Not(NEW_ID, sig_srst);
sig_ce = module->And(NEW_ID, sig_ce, tmp);
SigSpec tmp = module->Not(NEW_ID, sig_srst, false, src);
sig_ce = module->And(NEW_ID, sig_ce, tmp, false, src);
} else {
sig_ce = module->And(NEW_ID, sig_ce, sig_srst);
sig_ce = module->And(NEW_ID, sig_ce, sig_srst, false, src);
}
}
} else {
if (pol_ce) {
if (pol_srst) {
sig_ce = module->OrGate(NEW_ID, sig_ce, sig_srst);
sig_ce = module->OrGate(NEW_ID, sig_ce, sig_srst, src);
} else {
sig_ce = module->OrnotGate(NEW_ID, sig_ce, sig_srst);
sig_ce = module->OrnotGate(NEW_ID, sig_ce, sig_srst, src);
}
} else {
if (pol_srst) {
sig_ce = module->AndnotGate(NEW_ID, sig_ce, sig_srst);
sig_ce = module->AndnotGate(NEW_ID, sig_ce, sig_srst, src);
} else {
sig_ce = module->AndGate(NEW_ID, sig_ce, sig_srst);
sig_ce = module->AndGate(NEW_ID, sig_ce, sig_srst, src);
}
}
}
@ -548,31 +560,31 @@ void FfData::convert_ce_over_srst(bool val) {
if (!is_fine) {
if (pol_srst) {
if (pol_ce) {
sig_srst = cell->module->And(NEW_ID, sig_srst, sig_ce);
sig_srst = cell->module->And(NEW_ID, sig_srst, sig_ce, false, src);
} else {
SigSpec tmp = module->Not(NEW_ID, sig_ce);
sig_srst = cell->module->And(NEW_ID, sig_srst, tmp);
SigSpec tmp = module->Not(NEW_ID, sig_ce, false, src);
sig_srst = cell->module->And(NEW_ID, sig_srst, tmp, false, src);
}
} else {
if (pol_ce) {
SigSpec tmp = module->Not(NEW_ID, sig_ce);
sig_srst = cell->module->Or(NEW_ID, sig_srst, tmp);
SigSpec tmp = module->Not(NEW_ID, sig_ce, false, src);
sig_srst = cell->module->Or(NEW_ID, sig_srst, tmp, false, src);
} else {
sig_srst = cell->module->Or(NEW_ID, sig_srst, sig_ce);
sig_srst = cell->module->Or(NEW_ID, sig_srst, sig_ce, false, src);
}
}
} else {
if (pol_srst) {
if (pol_ce) {
sig_srst = cell->module->AndGate(NEW_ID, sig_srst, sig_ce);
sig_srst = cell->module->AndGate(NEW_ID, sig_srst, sig_ce, src);
} else {
sig_srst = cell->module->AndnotGate(NEW_ID, sig_srst, sig_ce);
sig_srst = cell->module->AndnotGate(NEW_ID, sig_srst, sig_ce, src);
}
} else {
if (pol_ce) {
sig_srst = cell->module->OrnotGate(NEW_ID, sig_srst, sig_ce);
sig_srst = cell->module->OrnotGate(NEW_ID, sig_srst, sig_ce, src);
} else {
sig_srst = cell->module->OrGate(NEW_ID, sig_srst, sig_ce);
sig_srst = cell->module->OrGate(NEW_ID, sig_srst, sig_ce, src);
}
}
}
@ -587,16 +599,17 @@ void FfData::unmap_ce() {
if (has_srst && ce_over_srst)
unmap_srst();
std::string src = ff_src(*this);
if (!is_fine) {
if (pol_ce)
sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce);
sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce, src);
else
sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce);
sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce, src);
} else {
if (pol_ce)
sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce);
sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce, src);
else
sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce);
sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce, src);
}
has_ce = false;
}
@ -607,16 +620,17 @@ void FfData::unmap_srst() {
if (has_ce && !ce_over_srst)
unmap_ce();
std::string src = ff_src(*this);
if (!is_fine) {
if (pol_srst)
sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst);
sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst, src);
else
sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst);
sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst, src);
} else {
if (pol_srst)
sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst);
sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst, src);
else
sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst);
sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst, src);
}
has_srst = false;
}

View file

@ -149,14 +149,25 @@ Cell* Patch::commit_cell(std::unique_ptr<Cell> cell) {
}
void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) {
patch(old_cell, {{old_port, new_sig}});
patch(old_cell, {{old_port, new_sig}}, nullptr);
}
void Patch::patch(Cell* old_cell, const std::vector<std::pair<IdString, SigSpec>> &port_replacements) {
patch(old_cell, port_replacements, nullptr);
}
void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig, Cell* merge_src_into) {
patch(old_cell, {{old_port, new_sig}}, merge_src_into);
}
void Patch::patch(Cell* old_cell, const std::vector<std::pair<IdString, SigSpec>> &port_replacements, Cell* merge_src_into) {
std::vector<SigSpec> old_sigs;
for (auto &[port, new_sig] : port_replacements) {
SigSpec old_sig = old_cell->getPort(port);
log_assert(old_sig.size() == new_sig.size());
if (old_sig.size() != new_sig.size())
log_error("patch size mismatch on cell %s port %s: old %d (%s) vs new %d (%s)\n",
log_id(old_cell->name), log_id(port), old_sig.size(), log_signal(old_sig),
new_sig.size(), log_signal(new_sig));
log_debug("patching %s %s which is %s with %s:\n", old_cell->name, port, log_signal(old_sig), log_signal(new_sig));
old_sigs.push_back(old_sig);
}
@ -164,6 +175,21 @@ void Patch::patch(Cell* old_cell, const std::vector<std::pair<IdString, SigSpec>
SrcCollector collector;
for (auto &old_sig : old_sigs)
collector.collect_src(old_sig);
// The collector should only ever pick up old_cell — the cell whose
// outputs are being patched. If a future change to collect_src ever
// starts walking the fanout or input cone of foreign cells, this
// assertion fires so we notice instead of silently smearing src
// strings across unrelated cells.
for (auto *c : collector.done)
log_assert(c == old_cell);
// For "merge into existing cell" patches (e.g. opt_merge), also pull
// in the keep-cell's pre-existing src so the merged cell carries both
// source locations.
if (merge_src_into)
collector.src.insert(merge_src_into->get_src_attribute());
std::string src_str = AttrObject::strpool_attribute_to_str(collector.src);
// Record leaves (existing wires consumed as inputs by the new cells) so
@ -192,6 +218,9 @@ void Patch::patch(Cell* old_cell, const std::vector<std::pair<IdString, SigSpec>
for (auto& wire: wires_)
commit_wire(std::move(wire));
if (merge_src_into)
merge_src_into->set_src_attribute(src_str);
// Now drop old_cell's drivers so old_sigs are undriven, then merge each
// into its new_sig. connect_incremental updates sigmap and re-normalizes
// fanout consumers in place — no full sigNormalize needed.

View file

@ -35,6 +35,13 @@ public:
void patch(Cell* old_cell, IdString old_port, SigSpec new_sig);
void patch(Cell* old_cell, const std::vector<std::pair<IdString, SigSpec>> &port_replacements);
// Variants for "merge old_cell into an existing keep_cell" (e.g.
// opt_merge): the old_cell's src attribute is collected and combined
// with merge_src_into's existing src, and the result is set on
// merge_src_into. Any new cells in cells_ also receive the combined src.
void patch(Cell* old_cell, IdString old_port, SigSpec new_sig, Cell* merge_src_into);
void patch(Cell* old_cell, const std::vector<std::pair<IdString, SigSpec>> &port_replacements, Cell* merge_src_into);
RTLIL::Wire *addWire(RTLIL::IdString name, int width = 1);
RTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other);