Module *module;
SigMap sigmap;
- pool<Cell*> rewritten_mux_cells;
+ pool<Cell*> generated_dlatches;
dict<Cell*, vector<SigBit>> mux_srcbits;
dict<SigBit, pair<Cell*, int>> mux_drivers;
dict<SigBit, int> sigusers;
int n = find_mux_feedback(sig_a[index], needle, set_undef);
if (n != false_node) {
if (set_undef && sig_a[index] == needle) {
- rewritten_mux_cells.insert(cell);
SigSpec sig = cell->getPort("\\A");
sig[index] = State::Sx;
cell->setPort("\\A", sig);
n = find_mux_feedback(sig_b[i*width + index], needle, set_undef);
if (n != false_node) {
if (set_undef && sig_b[i*width + index] == needle) {
- rewritten_mux_cells.insert(cell);
SigSpec sig = cell->getPort("\\B");
sig[i*width + index] = State::Sx;
cell->setPort("\\B", sig);
return and_bits[0];
}
- void fixup_rewritten_muxes()
+ void fixup_mux(Cell *cell)
{
- for (auto cell : rewritten_mux_cells)
- {
- SigSpec sig_a = cell->getPort("\\A");
- SigSpec sig_b = cell->getPort("\\B");
- SigSpec sig_s = cell->getPort("\\S");
- SigSpec sig_any_valid_b;
-
- SigSpec sig_new_b, sig_new_s;
- for (int i = 0; i < GetSize(sig_s); i++) {
- SigSpec b = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
- if (!b.is_fully_undef()) {
- sig_any_valid_b = b;
- sig_new_b.append(b);
- sig_new_s.append(sig_s[i]);
- }
- }
+ SigSpec sig_a = cell->getPort("\\A");
+ SigSpec sig_b = cell->getPort("\\B");
+ SigSpec sig_s = cell->getPort("\\S");
+ SigSpec sig_any_valid_b;
- if (sig_new_s.empty()) {
- sig_new_b = sig_a;
- sig_new_s = State::S0;
+ SigSpec sig_new_b, sig_new_s;
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ SigSpec b = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
+ if (!b.is_fully_undef()) {
+ sig_any_valid_b = b;
+ sig_new_b.append(b);
+ sig_new_s.append(sig_s[i]);
}
+ }
- if (sig_a.is_fully_undef() && !sig_any_valid_b.empty())
- cell->setPort("\\A", sig_any_valid_b);
+ if (sig_new_s.empty()) {
+ sig_new_b = sig_a;
+ sig_new_s = State::S0;
+ }
- if (GetSize(sig_new_s) == 1) {
- cell->type = "$mux";
- cell->unsetParam("\\S_WIDTH");
- } else {
- cell->type = "$pmux";
- cell->setParam("\\S_WIDTH", GetSize(sig_new_s));
+ if (sig_a.is_fully_undef() && !sig_any_valid_b.empty())
+ cell->setPort("\\A", sig_any_valid_b);
+
+ if (GetSize(sig_new_s) == 1) {
+ cell->type = "$mux";
+ cell->unsetParam("\\S_WIDTH");
+ } else {
+ cell->type = "$pmux";
+ cell->setParam("\\S_WIDTH", GetSize(sig_new_s));
+ }
+
+ cell->setPort("\\B", sig_new_b);
+ cell->setPort("\\S", sig_new_s);
+ }
+
+ void fixup_muxes()
+ {
+ pool<Cell*> visited, queue;
+ dict<Cell*, pool<SigBit>> upstream_cell2net;
+ dict<SigBit, pool<Cell*>> upstream_net2cell;
+
+ CellTypes ct;
+ ct.setup_internals();
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections()) {
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ upstream_cell2net[cell].insert(bit);
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ upstream_net2cell[bit].insert(cell);
+ }
+
+ queue = generated_dlatches;
+ while (!queue.empty())
+ {
+ pool<Cell*> next_queue;
+
+ for (auto cell : queue) {
+ if (cell->type.in("$mux", "$pmux"))
+ fixup_mux(cell);
+ for (auto bit : upstream_cell2net[cell])
+ for (auto cell : upstream_net2cell[bit])
+ next_queue.insert(cell);
+ visited.insert(cell);
}
- cell->setPort("\\B", sig_new_b);
- cell->setPort("\\S", sig_new_s);
+ queue.clear();
+ for (auto cell : next_queue) {
+ if (!visited.count(cell) && ct.cell_known(cell->type))
+ queue.insert(cell);
+ }
}
}
};
SigSpec rhs = latches_bits.second.extract(offset, width);
Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n)), rhs, lhs);
+ db.generated_dlatches.insert(cell);
+
log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell));
}
for (auto &proc_it : module->processes)
if (design->selected(module, proc_it.second))
proc_dlatch(db, proc_it.second);
- db.fixup_rewritten_muxes();
+ db.fixup_muxes();
}
}
} ProcDlatchPass;