diff --git a/kernel/unstable/patch.cc b/kernel/unstable/patch.cc index fcb81db6f..ea137dcf0 100644 --- a/kernel/unstable/patch.cc +++ b/kernel/unstable/patch.cc @@ -54,24 +54,50 @@ RTLIL::Wire *RTLIL::Patch::addWire(RTLIL::IdString name, const RTLIL::Wire *othe return wire; } -void Patch::collect_src(Cell* old_cell) { - src.insert(old_cell->get_src_attribute()); - log("collect %s\n", old_cell->name); - std::vector inputs = {}; - for (auto [port_name, sig] : old_cell->connections()) { - auto dir = old_cell->port_dir(port_name); - log_assert(dir != PD_UNKNOWN); - if (dir == PD_INPUT || dir == PD_INOUT) { - if (sig.size() && sig.is_wire()) { - Wire* in_wire = sig.as_wire(); - if (!leaves.count(in_wire)) - inputs.push_back(in_wire->driverCell()); + + +struct SrcCollector { + pool to_do; + pool done; + pool src; + + void collect_src(Cell* old_cell) { + if (done.count(old_cell)) + return; + done.insert(old_cell); + + log("collect %s\n", old_cell->name); + src.insert(old_cell->get_src_attribute()); + + std::vector input_cells = {}; + for (auto [port_name, sig] : old_cell->connections()) { + auto dir = old_cell->port_dir(port_name); + log_assert(dir != PD_UNKNOWN); + if (dir == PD_INPUT || dir == PD_INOUT) { + if (sig.size() && sig.is_wire()) { + Wire* in_wire = sig.as_wire(); + if (!in_wire->module) + input_cells.push_back(in_wire->driverCell()); + // if (!leaves.count(in_wire)) + } } } + for (auto input : input_cells) + collect_src(input); } - for (auto input : inputs) - collect_src(input); -} + + void collect_src(SigSpec old_sig) { + log("collect %s\n", log_signal(old_sig)); + for (auto bit : old_sig) { + if (bit.is_wire() && bit.wire->module) { + log_assert(bit.wire->driverCell_); + to_do.insert(bit.wire->driverCell_); + } + } + for (auto cell : to_do) + collect_src(cell); + } +}; void Patch::gc(Cell* old_cell) { log("gc %s\n", old_cell->name); @@ -89,7 +115,9 @@ void Patch::gc(Cell* old_cell) { } if (dir == PD_INPUT || dir == PD_INOUT) { Wire* in_wire = sig.as_wire(); - if (!leaves.count(in_wire)) + log_assert(in_wire); + log_debug("%s\n", in_wire->name); + if (in_wire->known_driver() && !leaves.count(in_wire)) inputs.push_back(in_wire->driverCell()); } } @@ -99,42 +127,45 @@ void Patch::gc(Cell* old_cell) { gc(input); } -void Patch::patch(Cell* old_cell, Cell* new_cell) { - log_assert(!leaves.empty()); - collect_src(old_cell); - std::string src_str = AttrObject::strpool_attribute_to_str(src); - for (auto& wire: wires_) { - wire->module = mod; - Wire* raw = wire.release(); - mod->wires_[raw->name] = raw; - } - log("patching:\n"); - log_cell(old_cell); +Wire* Patch::commit_wire(std::unique_ptr wire) { + Wire* raw = wire.release(); + mod->wires_[raw->name] = raw; + raw->module = mod; + return raw; +} + +Cell* Patch::commit_cell(std::unique_ptr cell) { + Cell* raw = cell.release(); + mod->cells_[raw->name] = raw; + raw->module = mod; + raw->initIndex(); + return raw; +} + +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)); + + 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); + for (auto& cell: cells_) { - log_cell(cell.get()); cell->set_src_attribute(src_str); - Cell* raw = cell.release(); - mod->cells_[raw->name] = raw; - for (auto [port_name, sig] : raw->connections()) { - auto dir = raw->port_dir(port_name); - log_assert(dir != PD_UNKNOWN); - if (dir == PD_OUTPUT || dir == PD_INOUT) { - if (raw == new_cell) { - // RAUW - auto yoink = old_cell->getPort(port_name); - log(">>>> RAUW %s to %s\n", port_name, log_signal(yoink)); - new_cell->setPort(port_name, yoink); - old_cell->setPort(port_name, mod->addWire(NEW_ID, yoink.size())); - } - } - } - raw->module = mod; - raw->initIndex(); - raw->fixup_parameters(); + cell->fixup_parameters(); + commit_cell(std::move(cell)); } - log_module(mod, ""); + + for (auto& wire: wires_) + commit_wire(std::move(wire)); + gc(old_cell); } - YOSYS_NAMESPACE_END \ No newline at end of file diff --git a/kernel/unstable/patch.h b/kernel/unstable/patch.h index badf82cda..c4a3b2fa2 100644 --- a/kernel/unstable/patch.h +++ b/kernel/unstable/patch.h @@ -8,11 +8,7 @@ YOSYS_NAMESPACE_BEGIN struct RTLIL::Patch final : public CellAdderMixin { - Hasher::hash_t hashidx_; - [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } - private: - void collect_src(Cell* old_cell); void gc(Cell* old_cell); protected: @@ -20,22 +16,21 @@ protected: void add(RTLIL::Cell *cell); void add(RTLIL::Process *process); -public: - Module *mod; - // SigMap map; - vector> wires_; - vector> cells_; - Cell* root; - pool leaves; + Cell* commit_cell(std::unique_ptr cell); + Wire* commit_wire(std::unique_ptr wire); - // vector connections_; - pool src; +public: + Module* mod; + SigMap* map; + vector> wires_ = {}; + vector> cells_ = {}; + pool leaves = {}; void connect(const RTLIL::SigSig &conn); void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs); const std::vector &connections() const; - void patch(Cell* old_cell, Cell* new_cell); + void patch(Cell* old_cell, IdString old_port, SigSpec new_sig); RTLIL::Wire *addWire(RTLIL::IdString name, int width = 1); RTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other); diff --git a/passes/cmds/test_patch.cc b/passes/cmds/test_patch.cc index 5effac2cc..f07afb3e5 100644 --- a/passes/cmds/test_patch.cc +++ b/passes/cmds/test_patch.cc @@ -15,6 +15,7 @@ struct TestPatchPass : public Pass { (void) args; design->sigNormalize(); for (auto module : design->selected_modules()) { + SigMap sigmap(module); for (auto cell : module->selected_cells()) { if (cell->type == ID($add)) { Cell* add = cell; @@ -22,17 +23,18 @@ struct TestPatchPass : public Pass { log_assert(add->getPort(ID::B).known_driver()); auto neg = add->getPort(ID::B)[0].wire->driverCell(); log_assert(neg->type == ID($not)); - RTLIL::Patch patcher; - patcher.mod = module; + RTLIL::Patch patcher = {{}, module, nullptr}; + int width = cell->getPort(ID::A).size(); auto sub = patcher.addSub(NEW_ID, neg->getPort(ID::A), add->getPort(ID::A), - patcher.addWire(NEW_ID, cell->getPort(ID::A).size())); - auto new_cell = patcher.addNeg(NEW_ID, sub->getPort(ID::Y), SigSpec()); + patcher.addWire(NEW_ID, width)); + auto new_out_wire = patcher.addWire(NEW_ID, width); + auto new_cell = patcher.addNeg(NEW_ID, sub->getPort(ID::Y), new_out_wire); log_cell(new_cell); patcher.leaves.insert(neg->getPort(ID::A).as_wire()); patcher.leaves.insert(add->getPort(ID::A).as_wire()); - patcher.patch(add, new_cell); + patcher.patch(add, ID::Y, new_out_wire); } } } diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 87ba85785..2b6069309 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -628,12 +628,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (sig_b == State::S0) { replace_cell(assign_map, module, cell, "xor_buffer", ID::Y, sig_a); } else { - RTLIL::Patch patcher; - patcher.mod = module; - Wire* y = patcher.addWire(NEW_ID, cell->type == ID($xor) ? cell->getParam(ID::Y_WIDTH).as_int() : 1); + RTLIL::Patch patcher = {{}, module, &assign_map}; + Wire* y = patcher.addWire(NEW_ID, 1); Cell* new_cell = cell->type == ID($xor) ? patcher.addNot(NEW_ID, sig_a, y) : patcher.addNotGate(NEW_ID, sig_a, y); - patcher.leaves = {cell->getPort(port_a).as_wire()}; - patcher.patch(cell, new_cell); + SigSpec sig_y = y; + int width = cell->type == ID($xor) ? cell->getParam(ID::Y_WIDTH).as_int() : 1; + sig_y.append(RTLIL::Const(State::S0, width-1)); + (void)new_cell; + for (auto chunk : cell->getPort(port_a).chunks()) + if (chunk.wire) + patcher.leaves.insert(chunk.wire); + patcher.patch(cell, ID::Y, sig_y); } goto next_cell; }