diff --git a/kernel/unstable/patch.cc b/kernel/unstable/patch.cc index a2cf467ad..edc3081c5 100644 --- a/kernel/unstable/patch.cc +++ b/kernel/unstable/patch.cc @@ -95,7 +95,10 @@ void Patch::gc(Cell* old_cell, bool track) { pool inputs; for (auto [port_name, sig] : old_cell->connections()) { auto dir = old_cell->port_dir(port_name); - log_assert(dir != PD_UNKNOWN); + // Unknown port direction (e.g. user module instance whose interface + // isn't registered): can't decide input vs output, so don't gc it. + if (dir == PD_UNKNOWN) + return; // TODO only running GC through whole connections? log_debug("\tport %s\n", port_name); if (sig.size() && sig.is_wire()) { @@ -144,12 +147,21 @@ Cell* Patch::commit_cell(std::unique_ptr 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_debug("patching %s %s which is %s with %s:\n", old_cell->name, old_port, log_signal(old_sig), log_signal(new_sig)); + patch(old_cell, {{old_port, new_sig}}); +} + +void Patch::patch(Cell* old_cell, const std::vector> &port_replacements) { + std::vector old_sigs; + for (auto &[port, new_sig] : port_replacements) { + SigSpec old_sig = old_cell->getPort(port); + log_assert(old_sig.size() == new_sig.size()); + 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); + } SrcCollector collector; - collector.collect_src(old_sig); + for (auto &old_sig : old_sigs) + collector.collect_src(old_sig); std::string src_str = AttrObject::strpool_attribute_to_str(collector.src); // Record leaves (existing wires consumed as inputs by the new cells) so @@ -178,13 +190,17 @@ void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) { for (auto& wire: wires_) commit_wire(std::move(wire)); - // 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); + // 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. + for (auto &[port, new_sig] : port_replacements) + old_cell->setPort(port, SigSpec()); + for (size_t i = 0; i < port_replacements.size(); i++) { + auto &[port, new_sig] = port_replacements[i]; + if (map) + map->add(old_sigs[i], new_sig); + mod->connect_incremental(old_sigs[i], new_sig); + } gc(old_cell); cells_.clear(); diff --git a/kernel/unstable/patch.h b/kernel/unstable/patch.h index eea9ab685..cc664f511 100644 --- a/kernel/unstable/patch.h +++ b/kernel/unstable/patch.h @@ -34,6 +34,7 @@ public: const std::vector &connections() const; void patch(Cell* old_cell, IdString old_port, SigSpec new_sig); + void patch(Cell* old_cell, const std::vector> &port_replacements); RTLIL::Wire *addWire(RTLIL::IdString name, int width = 1); RTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 74dca953a..200fbf06e 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -143,9 +143,17 @@ struct OptExprPatcher : public RTLIL::Patch { RTLIL::Patch::patch(old_cell, old_port, new_sig); did_something = true; } + void patch(Cell *old_cell, std::vector> ports, const std::string &info) { + for (auto &[port, new_sig] : ports) { + new_sig.extend_u0(old_cell->getPort(port).size(), false); + log_replace_port(mod, old_cell, info, port, new_sig); + } + RTLIL::Patch::patch(old_cell, ports); + did_something = true; + } }; -bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc) +bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc, pool &removed_cells) { IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A; @@ -210,20 +218,23 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", cell->type.unescape(), cell, module); + OptExprPatcher patcher(module, &sigmap, &removed_cells); + + // Replacement bit for each original sig_y bit. + dict bit_map; + for (int i = 0; i < GRP_N; i++) { if (grouped_bits[i].empty()) continue; - RTLIL::SigSpec new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); + int group_size = GetSize(grouped_bits[i]); + RTLIL::SigSpec new_y = patcher.addWire(NEW_ID, group_size); RTLIL::SigSpec new_a, new_b; - RTLIL::SigSig new_conn; for (auto &it : grouped_bits[i]) { - for (auto &bit : it.second) { - new_conn.first.append(bit); - new_conn.second.append(new_y[new_a.size()]); - } + for (auto &bit : it.second) + bit_map[bit] = new_y[new_a.size()]; new_a.append(it.first.first); new_b.append(it.first.second); } @@ -237,8 +248,14 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ else log_abort(); } log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), cell->type.unescape(), log_signal(new_a)); - module->connect(new_y, new_b); - module->connect(new_conn); + // new_y becomes new_b directly: rewrite any bit_map entries pointing at new_y bits. + dict remap; + for (int j = 0; j < group_size; j++) + remap[new_y[j]] = new_b[j]; + for (auto &entry : bit_map) { + auto it = remap.find(entry.second); + if (it != remap.end()) entry.second = it->second; + } continue; } @@ -260,9 +277,9 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ else if (new_a[i] == State::S0 || new_a[i] == State::S1) { undef_a.append(new_a[i]); if (cell->type == ID($xor)) - undef_b.append(new_a[i] == State::S1 ? module->Not(NEW_ID, new_b[i]).as_bit() : new_b[i]); + undef_b.append(new_a[i] == State::S1 ? patcher.Not(NEW_ID, new_b[i]).as_bit() : new_b[i]); else if (cell->type == ID($xnor)) - undef_b.append(new_a[i] == State::S1 ? new_b[i] : module->Not(NEW_ID, new_b[i]).as_bit()); + undef_b.append(new_a[i] == State::S1 ? new_b[i] : patcher.Not(NEW_ID, new_b[i]).as_bit()); else log_abort(); undef_y.append(new_y[i]); } @@ -274,19 +291,22 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ } if (!undef_y.empty()) { log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(undef_b), cell->type.unescape(), log_signal(undef_a)); - module->connect(undef_y, undef_b); - if (def_y.empty()) { - module->connect(new_conn); - continue; + dict remap; + for (int j = 0; j < GetSize(undef_y); j++) + remap[undef_y[j]] = undef_b[j]; + for (auto &entry : bit_map) { + auto it = remap.find(entry.second); + if (it != remap.end()) entry.second = it->second; } + if (def_y.empty()) + continue; } new_a = std::move(def_a); new_b = std::move(def_b); new_y = std::move(def_y); } - - RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); + RTLIL::Cell *c = patcher.addCell(NEW_ID, cell->type); c->setPort(ID::A, new_a); c->parameters[ID::A_WIDTH] = new_a.size(); @@ -300,9 +320,6 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ c->setPort(ID::Y, new_y); c->parameters[ID::Y_WIDTH] = GetSize(new_y); - c->check(); - - module->connect(new_conn); log_debug(" New cell `%s': A=%s", c, log_signal(new_a)); if (b_name == ID::B) @@ -310,8 +327,15 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ log_debug("\n"); } - module->remove(cell); - did_something = true; + // Build replacement SigSpec for cell's Y port. + SigSpec orig_y = cell->getPort(ID::Y); + SigSpec new_sig_y; + for (auto bit : orig_y) { + SigBit canon = sigmap(bit); + auto it = bit_map.find(canon); + new_sig_y.append(it != bit_map.end() ? it->second : bit); + } + patcher.patch(cell, ID::Y, new_sig_y, "group_cell_inputs"); return true; } @@ -708,59 +732,64 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons std::swap(sig_a, sig_b); RTLIL::SigSpec b_group_0, b_group_1, b_group_x; - RTLIL::SigSpec y_group_0, y_group_1, y_group_x; + // Per-i (group, position_in_group); group = -1 means leave as Sx + std::vector> origin(width, {-1, 0}); + + auto group_0 = cell->type == ID($xnor) ? 1 : 0; + auto group_1 = cell->type == ID($xnor) ? 0 : 1; for (int i = 0; i < width; i++) { auto bit_a = sig_a[i].data; - if (bit_a == State::S0) b_group_0.append(sig_b[i]), y_group_0.append(sig_y[i]); - if (bit_a == State::S1) b_group_1.append(sig_b[i]), y_group_1.append(sig_y[i]); - if (bit_a == State::Sx) b_group_x.append(sig_b[i]), y_group_x.append(sig_y[i]); + if (bit_a == State::S0) origin[i] = {group_0, b_group_0.size()}, b_group_0.append(sig_b[i]); + else if (bit_a == State::S1) origin[i] = {group_1, b_group_1.size()}, b_group_1.append(sig_b[i]); + else if (bit_a == State::Sx) origin[i] = {2, b_group_x.size()}, b_group_x.append(sig_b[i]); } - if (cell->type == ID($xnor)) { + if (cell->type == ID($xnor)) std::swap(b_group_0, b_group_1); - std::swap(y_group_0, y_group_1); - } + OptExprPatcher patcher(module, &assign_map, &removed_cells); RTLIL::SigSpec y_new_0, y_new_1, y_new_x; if (cell->type == ID($and)) { - if (!y_group_0.empty()) y_new_0 = Const(State::S0, GetSize(y_group_0)); - if (!y_group_1.empty()) y_new_1 = b_group_1; - if (!y_group_x.empty()) { + if (!b_group_0.empty()) y_new_0 = Const(State::S0, GetSize(b_group_0)); + if (!b_group_1.empty()) y_new_1 = b_group_1; + if (!b_group_x.empty()) { if (keepdc) - y_new_x = module->And(NEW_ID, Const(State::Sx, GetSize(y_group_x)), b_group_x); + y_new_x = patcher.And(NEW_ID, Const(State::Sx, GetSize(b_group_x)), b_group_x); else - y_new_x = Const(State::S0, GetSize(y_group_x)); + y_new_x = Const(State::S0, GetSize(b_group_x)); } } else if (cell->type == ID($or)) { - if (!y_group_0.empty()) y_new_0 = b_group_0; - if (!y_group_1.empty()) y_new_1 = Const(State::S1, GetSize(y_group_1)); - if (!y_group_x.empty()) { + if (!b_group_0.empty()) y_new_0 = b_group_0; + if (!b_group_1.empty()) y_new_1 = Const(State::S1, GetSize(b_group_1)); + if (!b_group_x.empty()) { if (keepdc) - y_new_x = module->Or(NEW_ID, Const(State::Sx, GetSize(y_group_x)), b_group_x); + y_new_x = patcher.Or(NEW_ID, Const(State::Sx, GetSize(b_group_x)), b_group_x); else - y_new_x = Const(State::S1, GetSize(y_group_x)); + y_new_x = Const(State::S1, GetSize(b_group_x)); } } else if (cell->type.in(ID($xor), ID($xnor))) { - if (!y_group_0.empty()) y_new_0 = b_group_0; - if (!y_group_1.empty()) y_new_1 = module->Not(NEW_ID, b_group_1); - if (!y_group_x.empty()) { + if (!b_group_0.empty()) y_new_0 = b_group_0; + if (!b_group_1.empty()) y_new_1 = patcher.Not(NEW_ID, b_group_1); + if (!b_group_x.empty()) { if (keepdc) - y_new_x = module->Xor(NEW_ID, Const(State::Sx, GetSize(y_group_x)), b_group_x); + y_new_x = patcher.Xor(NEW_ID, Const(State::Sx, GetSize(b_group_x)), b_group_x); else // This should be fine even with keepdc, but opt_expr_xor.ys wants to keep the xor - y_new_x = Const(State::Sx, GetSize(y_group_x)); + y_new_x = Const(State::Sx, GetSize(b_group_x)); } } else { log_abort(); } - assign_map.add(y_group_0, y_new_0); module->connect(y_group_0, y_new_0); - assign_map.add(y_group_1, y_new_1); module->connect(y_group_1, y_new_1); - assign_map.add(y_group_x, y_new_x); module->connect(y_group_x, y_new_x); - - module->remove(cell); - did_something = true; + RTLIL::SigSpec new_sig_y(State::Sx, width); + for (int i = 0; i < width; i++) { + if (origin[i].first == 0) new_sig_y[i] = y_new_0[origin[i].second]; + else if (origin[i].first == 1) new_sig_y[i] = y_new_1[origin[i].second]; + else if (origin[i].first == 2) new_sig_y[i] = y_new_x[origin[i].second]; + // else: bit_a was Sz / Sa / etc.; leave as Sx + } + patcher.patch(cell, ID::Y, new_sig_y, "bit_partition"); goto next_cell; } } @@ -775,20 +804,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (sig_s.is_fully_def()) { - RTLIL::SigSpec a_group_0, b_group_1; - RTLIL::SigSpec y_group_0, y_group_1; - for (int i = 0; i < width; i++) { - if (sig_s[i].data == State::S1) - y_group_1.append(sig_y[i]), b_group_1.append(sig_b[i]); - else - y_group_0.append(sig_y[i]), a_group_0.append(sig_a[i]); - } - - assign_map.add(y_group_0, a_group_0); module->connect(y_group_0, a_group_0); - assign_map.add(y_group_1, b_group_1); module->connect(y_group_1, b_group_1); - - module->remove(cell); - did_something = true; + RTLIL::SigSpec new_sig_y(width); + for (int i = 0; i < width; i++) + new_sig_y[i] = sig_s[i].data == State::S1 ? sig_b[i] : sig_a[i]; + OptExprPatcher patcher(module, &assign_map, &removed_cells); + patcher.patch(cell, ID::Y, new_sig_y, "bwmux_const_s"); goto next_cell; } else if (sig_a.is_fully_def() || sig_b.is_fully_def()) @@ -799,29 +819,32 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons RTLIL::SigSpec b_group_0, b_group_1; RTLIL::SigSpec s_group_0, s_group_1; - RTLIL::SigSpec y_group_0, y_group_1; + std::vector> origin(width); for (int i = 0; i < width; i++) { - if (sig_a[i].data == State::S1) - y_group_1.append(sig_y[i]), b_group_1.append(sig_b[i]), s_group_1.append(sig_s[i]); - else - y_group_0.append(sig_y[i]), b_group_0.append(sig_b[i]), s_group_0.append(sig_s[i]); + if (sig_a[i].data == State::S1) { + origin[i] = {1, b_group_1.size()}; + b_group_1.append(sig_b[i]), s_group_1.append(sig_s[i]); + } else { + origin[i] = {0, b_group_0.size()}; + b_group_0.append(sig_b[i]), s_group_0.append(sig_s[i]); + } } + OptExprPatcher patcher(module, &assign_map, &removed_cells); RTLIL::SigSpec y_new_0, y_new_1; if (flip) { - if (!y_group_0.empty()) y_new_0 = module->And(NEW_ID, b_group_0, module->Not(NEW_ID, s_group_0)); - if (!y_group_1.empty()) y_new_1 = module->Or(NEW_ID, b_group_1, s_group_1); + if (!b_group_0.empty()) y_new_0 = patcher.And(NEW_ID, b_group_0, patcher.Not(NEW_ID, s_group_0)); + if (!b_group_1.empty()) y_new_1 = patcher.Or(NEW_ID, b_group_1, s_group_1); } else { - if (!y_group_0.empty()) y_new_0 = module->And(NEW_ID, b_group_0, s_group_0); - if (!y_group_1.empty()) y_new_1 = module->Or(NEW_ID, b_group_1, module->Not(NEW_ID, s_group_1)); + if (!b_group_0.empty()) y_new_0 = patcher.And(NEW_ID, b_group_0, s_group_0); + if (!b_group_1.empty()) y_new_1 = patcher.Or(NEW_ID, b_group_1, patcher.Not(NEW_ID, s_group_1)); } - module->connect(y_group_0, y_new_0); - module->connect(y_group_1, y_new_1); - - module->remove(cell); - did_something = true; + RTLIL::SigSpec new_sig_y(width); + for (int i = 0; i < width; i++) + new_sig_y[i] = origin[i].first == 1 ? y_new_1[origin[i].second] : y_new_0[origin[i].second]; + patcher.patch(cell, ID::Y, new_sig_y, "bwmux_const_ab"); goto next_cell; } } @@ -829,7 +852,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (do_fine) { if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor))) - if (group_cell_inputs(module, cell, true, assign_map, keepdc)) + if (group_cell_inputs(module, cell, true, assign_map, keepdc, removed_cells)) goto next_cell; if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool))) @@ -1362,10 +1385,8 @@ skip_fine_alu: log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", cell->type.unescape(), cell, log_signal(assign_map(cell->getPort(ID::B))), shift_bits, module, log_signal(sig_y)); - module->connect(cell->getPort(ID::Y), sig_y); - module->remove(cell); - - did_something = true; + OptExprPatcher patcher(module, &assign_map, &removed_cells); + patcher.patch(cell, ID::Y, sig_y, "shift_const"); goto next_cell; } @@ -1440,23 +1461,43 @@ skip_fine_alu: bool is_signed = a_signed && b_signed; RTLIL::SigBit sig_ci = assign_map(cell->getPort(ID::CI)); int y_width = GetSize(cell->getPort(ID::Y)); + + OptExprPatcher patcher(module, &assign_map, &removed_cells); + SigSpec new_x, new_co; + SigSpec a_port; + bool a_port_signed; + int a_port_width; if (sig_ci == State::S1) { /* sub, b is 0 */ RTLIL::SigSpec a = cell->getPort(ID::A); a.extend_u0(y_width, is_signed); - module->connect(cell->getPort(ID::X), module->Not(NEW_ID, a)); - module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S1, y_width)); + new_x = patcher.Not(NEW_ID, a); + new_co = RTLIL::Const(State::S1, y_width); + a_port = cell->getPort(ID::A); + a_port_signed = a_signed; + a_port_width = cell->getParam(ID::A_WIDTH).as_int(); } else { /* add */ RTLIL::SigSpec ab = cell->getPort(identity_wrt_a ? ID::A : ID::B); ab.extend_u0(y_width, is_signed); - module->connect(cell->getPort(ID::X), ab); - module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S0, y_width)); + new_x = ab; + new_co = RTLIL::Const(State::S0, y_width); + a_port = cell->getPort(identity_wrt_a ? ID::A : ID::B); + a_port_signed = identity_wrt_a ? a_signed : b_signed; + a_port_width = cell->getParam(identity_wrt_a ? ID::A_WIDTH : ID::B_WIDTH).as_int(); } - cell->unsetPort(ID::BI); - cell->unsetPort(ID::CI); - cell->unsetPort(ID::X); - cell->unsetPort(ID::CO); + + IdString new_type = arith_inverse ? ID($neg) : ID($pos); + SigSpec new_y = patcher.addWire(NEW_ID, y_width); + Cell *new_cell = patcher.addCell(NEW_ID, new_type); + new_cell->setPort(ID::A, a_port); + new_cell->setPort(ID::Y, new_y); + new_cell->setParam(ID::A_WIDTH, a_port_width); + new_cell->setParam(ID::A_SIGNED, a_port_signed); + new_cell->setParam(ID::Y_WIDTH, y_width); + + patcher.patch(cell, {{ID::Y, new_y}, {ID::X, new_x}, {ID::CO, new_co}}, "alu_identity"); + goto next_cell; } if (!identity_wrt_a) { @@ -1746,13 +1787,25 @@ skip_identity: else { log_debug("Replacing pow cell `%s' in module `%s' with multiply and left-shift\n", cell->name.c_str(), module->name.c_str()); - cell->type = ID($mul); - cell->setPort(ID::A, Const(bit_idx, cell->parameters[ID::A_WIDTH].as_int())); + OptExprPatcher patcher(module, &assign_map, &removed_cells); + int a_width = cell->parameters[ID::A_WIDTH].as_int(); - SigSpec y_wire = module->addWire(NEW_ID, y_size); - cell->setPort(ID::Y, y_wire); + SigSpec y_wire = patcher.addWire(NEW_ID, y_size); + Cell *mul = patcher.addCell(NEW_ID, ID($mul)); + mul->setPort(ID::A, Const(bit_idx, a_width)); + mul->setPort(ID::B, cell->getPort(ID::B)); + mul->setPort(ID::Y, y_wire); + mul->parameters[ID::A_WIDTH] = a_width; + mul->parameters[ID::A_SIGNED] = 0; + mul->parameters[ID::B_WIDTH] = cell->parameters[ID::B_WIDTH]; + mul->parameters[ID::B_SIGNED] = cell->parameters[ID::B_SIGNED]; + mul->parameters[ID::Y_WIDTH] = y_size; - module->addShl(NEW_ID, Const(State::S1, 1), y_wire, sig_y); + SigSpec new_y = patcher.addWire(NEW_ID, y_size); + patcher.addShl(NEW_ID, Const(State::S1, 1), y_wire, new_y); + + patcher.patch(cell, ID::Y, new_y, "pow_to_mul_shl"); + goto next_cell; } did_something = true; goto next_cell; @@ -1778,10 +1831,8 @@ skip_identity: log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", cell->name.c_str(), module->name.c_str()); - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - module->remove(cell); - - did_something = true; + OptExprPatcher patcher(module, &assign_map, &removed_cells); + patcher.patch(cell, ID::Y, RTLIL::SigSpec(0, sig_y.size()), "mul_zero"); goto next_cell; } @@ -1825,10 +1876,8 @@ skip_identity: a_zeros, b_zeros, cell->name.c_str(), module->name.c_str()); if (y_zeros >= GetSize(sig_y)) { - module->connect(sig_y, RTLIL::SigSpec(0, GetSize(sig_y))); - module->remove(cell); - - did_something = true; + OptExprPatcher patcher(module, &assign_map, &removed_cells); + patcher.patch(cell, ID::Y, RTLIL::SigSpec(0, GetSize(sig_y)), "mul_low_zeros"); goto next_cell; } @@ -1865,10 +1914,8 @@ skip_identity: log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", cell->name.c_str(), module->name.c_str()); - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); - module->remove(cell); - - did_something = true; + OptExprPatcher patcher(module, &assign_map, &removed_cells); + patcher.patch(cell, ID::Y, RTLIL::SigSpec(State::Sx, sig_y.size()), "div_zero"); goto next_cell; } @@ -1914,15 +1961,18 @@ skip_identity: // the sign bits are those of A (except when R=0) if (is_truncating && a_signed && GetSize(sig_a) != 0 && exp != 0) { - module->remove(cell); + OptExprPatcher patcher(module, &assign_map, &removed_cells); SigSpec truncating = sig_a.extract(0, exp); SigSpec a_sign = sig_a[sig_a.size()-1]; - SigSpec rem_nonzero = module->ReduceOr(NEW_ID, sig_a.extract(0, exp)); - SigSpec extend_bit = module->And(NEW_ID, a_sign, rem_nonzero); + SigSpec rem_nonzero = patcher.ReduceOr(NEW_ID, sig_a.extract(0, exp)); + SigSpec extend_bit = patcher.And(NEW_ID, a_sign, rem_nonzero); truncating.append(extend_bit); - module->addPos(NEW_ID, truncating, sig_y, true); + SigSpec new_y = truncating; + new_y.extend_u0(GetSize(sig_y), true); + patcher.patch(cell, ID::Y, new_y, "mod_truncating"); + goto next_cell; } else { @@ -1997,41 +2047,45 @@ skip_identity: RTLIL::SigSpec sig_ci = assign_map(cell->getPort(ID::CI)); int prev = 0; - RTLIL::SigSpec sig_x = assign_map(cell->getPort(ID::X)); - RTLIL::SigSpec sig_co = assign_map(cell->getPort(ID::CO)); + + OptExprPatcher patcher(module, &assign_map, &removed_cells); + SigSpec new_y, new_x, new_co_concat; for (auto &p : split_points) { int cur = p.first; int sz = cur - prev; bool last = cur == GetSize(sig_y); - RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); + SigSpec slice_y = patcher.addWire(NEW_ID, sz); + SigSpec slice_x = patcher.addWire(NEW_ID, sz); + SigSpec slice_co = patcher.addWire(NEW_ID, sz); + + RTLIL::Cell *c = patcher.addCell(NEW_ID, cell->type); c->setPort(ID::A, sig_a.extract(prev, sz)); c->setPort(ID::B, sig_b.extract(prev, sz)); c->setPort(ID::BI, sig_bi); c->setPort(ID::CI, sig_ci); - c->setPort(ID::Y, sig_y.extract(prev, sz)); - c->setPort(ID::X, sig_x.extract(prev, sz)); - RTLIL::SigSpec new_co = sig_co.extract(prev, sz); - if (p.second != State::Sx) { - module->connect(new_co[sz-1], p.second); - RTLIL::Wire *dummy = module->addWire(NEW_ID); - new_co[sz-1] = dummy; - } - c->setPort(ID::CO, new_co); + c->setPort(ID::Y, slice_y); + c->setPort(ID::X, slice_x); + c->setPort(ID::CO, slice_co); c->parameters[ID::A_WIDTH] = sz; c->parameters[ID::B_WIDTH] = sz; c->parameters[ID::Y_WIDTH] = sz; c->parameters[ID::A_SIGNED] = last ? a_signed : false; c->parameters[ID::B_SIGNED] = last ? b_signed : false; + new_y.append(slice_y); + new_x.append(slice_x); + SigSpec exported_co = slice_co; + if (p.second != State::Sx) + exported_co[sz-1] = p.second; + new_co_concat.append(exported_co); + prev = p.first; sig_ci = p.second; } - module->remove(cell); - - did_something = true; + patcher.patch(cell, {{ID::Y, new_y}, {ID::X, new_x}, {ID::CO, new_co_concat}}, "alu_split"); goto next_cell; } skip_alu_split: @@ -2089,10 +2143,8 @@ skip_alu_split: log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n", cell, module, log_signal(y_value)); - module->connect(y_sig, y_value); - module->remove(cell); - - did_something = true; + OptExprPatcher patcher(module, &assign_map, &removed_cells); + patcher.patch(cell, ID::Y, y_value, "eq_contradiction"); goto next_cell; } @@ -2140,7 +2192,7 @@ skip_alu_split: std::string condition, replacement; SigSpec replace_sig(State::S0, GetSize(cell->getPort(ID::Y))); bool replace = false; - bool remove = false; + OptExprPatcher patcher(module, &assign_map, &removed_cells); if (!is_signed) { /* unsigned */ @@ -2181,15 +2233,15 @@ skip_alu_split: { condition = stringf("unsigned X<%s", log_signal(const_sig)); replacement = stringf("!X[%d:%d]", var_width - 1, const_bit_hot); - module->addLogicNot(NEW_ID, var_high_sig, cell->getPort(ID::Y)); - remove = true; + replace_sig[0] = patcher.LogicNot(NEW_ID, var_high_sig).as_bit(); + replace = true; } if (cmp_type == ID($ge)) { condition = stringf("unsigned X>=%s", log_signal(const_sig)); replacement = stringf("|X[%d:%d]", var_width - 1, const_bit_hot); - module->addReduceOr(NEW_ID, var_high_sig, cell->getPort(ID::Y)); - remove = true; + replace_sig[0] = patcher.ReduceOr(NEW_ID, var_high_sig).as_bit(); + replace = true; } } @@ -2230,19 +2282,16 @@ skip_alu_split: { condition = "signed X>=0"; replacement = stringf("X[%d]", var_width - 1); - module->addLogicNot(NEW_ID, var_sig[var_width - 1], cell->getPort(ID::Y)); - remove = true; + replace_sig[0] = patcher.LogicNot(NEW_ID, var_sig[var_width - 1]).as_bit(); + replace = true; } } - if (replace || remove) + if (replace) { log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n", cell->type.unescape(), cell, condition.c_str(), replacement.c_str()); - if (replace) - module->connect(cell->getPort(ID::Y), replace_sig); - module->remove(cell); - did_something = true; + patcher.patch(cell, ID::Y, replace_sig, condition); goto next_cell; } }