From 09919fe48a1d1f3e318b09ba16294316fd51f149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 14 Mar 2024 22:11:12 +0100 Subject: [PATCH 1/7] abc9: Make the default a non-mapping mode Formerly when you didn't pass any options to `abc9` it would source a LUT library from the current design by considering any module with an `abc9_lut` attribute to be an available mapping primitive. Make the change to condition this behavior on a `-lutlib` option, and instead make `abc9` without any options perform a non-mapping mode in which the netlist is reimported back into Yosys as an and-inverter graph. --- passes/techmap/abc9.cc | 34 ++++++++++++++++--------- passes/techmap/abc9_exe.cc | 7 +++--- passes/techmap/abc9_ops.cc | 51 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 876917e565e..e6775dc9f25 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -151,10 +151,14 @@ struct Abc9Pass : public ScriptPass log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); log(" 2, 3, .. inputs.\n"); log("\n"); + log(" -lutlib\n"); + log(" generate netlist using luts. Use the modules that are loaded into the\n"); + log(" current design and have the (* abc9_lut *) attribute for the library of\n"); + log(" the available lut primitives.\n"); + log("\n"); log(" -maxlut \n"); - log(" when auto-generating the lut library, discard all luts equal to or\n"); - log(" greater than this size (applicable when neither -lut nor -luts is\n"); - log(" specified).\n"); + log(" when sourcing the lut library from the current design (option -lutlib),\n"); + log(" discard all lut primitives with greater than the specified width.\n"); log("\n"); log(" -dff\n"); log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n"); @@ -186,7 +190,7 @@ struct Abc9Pass : public ScriptPass std::stringstream exe_cmd; bool dff_mode, cleanup; - bool lut_mode; + bool lutlib_mode, lut_mode; int maxlut; std::string box_file; @@ -196,6 +200,7 @@ struct Abc9Pass : public ScriptPass exe_cmd << "abc9_exe"; dff_mode = false; cleanup = true; + lutlib_mode = false; lut_mode = false; maxlut = 0; box_file = ""; @@ -223,7 +228,7 @@ struct Abc9Pass : public ScriptPass /*arg == "-box" ||*/ arg == "-W") && argidx+1 < args.size()) { if (arg == "-lut" || arg == "-luts") - lut_mode = true; + lut_mode = false; exe_cmd << " " << arg << " " << args[++argidx]; continue; } @@ -232,6 +237,10 @@ struct Abc9Pass : public ScriptPass exe_cmd << " " << arg; continue; } + if (arg == "-lutlib") { + lutlib_mode = true; + continue; + } if (arg == "-dff") { dff_mode = true; exe_cmd << " " << arg; @@ -261,8 +270,8 @@ struct Abc9Pass : public ScriptPass } extra_args(args, argidx, design); - if (maxlut && lut_mode) - log_cmd_error("abc9 '-maxlut' option only applicable without '-lut' nor '-luts'.\n"); + if (maxlut && !lutlib_mode) + log_cmd_error("abc9 '-maxlut' option only applicable in conjunction with '-lutlib'.\n"); log_assert(design); if (design->selected_modules().empty()) { @@ -359,7 +368,7 @@ struct Abc9Pass : public ScriptPass run("abc9_ops -break_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : "")); if (help_mode) run("abc9_ops -prep_lut ", "(skip if -lut or -luts)"); - else if (!lut_mode) + else if (lutlib_mode) run(stringf("abc9_ops -prep_lut %d", maxlut)); if (help_mode) run("abc9_ops -prep_box", "(skip if -box)"); @@ -386,7 +395,7 @@ struct Abc9Pass : public ScriptPass run(" write_xaiger -map /input.sym [-dff] /input.xaig"); run(" abc9_exe [options] -cwd -lut [/input.lut] -box [/input.box]"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); - run(" abc9_ops -reintegrate [-dff]"); + run(" abc9_ops -reintegrate [-dff] [-lut]"); } else { auto selected_modules = active_design->selected_modules(); @@ -412,7 +421,7 @@ struct Abc9Pass : public ScriptPass tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX"; tempdir_name = make_temp_dir(tempdir_name); - if (!lut_mode) + if (lutlib_mode) run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str())); if (box_file.empty()) run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); @@ -429,7 +438,7 @@ struct Abc9Pass : public ScriptPass if (num_outputs) { std::string abc9_exe_cmd; abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()); - if (!lut_mode) + if (lutlib_mode) abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str()); if (box_file.empty()) abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); @@ -437,7 +446,8 @@ struct Abc9Pass : public ScriptPass abc9_exe_cmd += stringf(" -box %s", box_file.c_str()); run_nocheck(abc9_exe_cmd); run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); - run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : "")); + run_nocheck(stringf("abc9_ops -reintegrate%s%s", dff_mode ? " -dff" : "", + (lutlib_mode || lut_mode) ? " -lut" : "")); } else log("Don't call ABC as there is nothing to map.\n"); diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 8e02e25a4bf..0ba1acc1a0e 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -176,8 +176,6 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); else if (!lut_file.empty()) abc9_script += stringf("read_lut \"%s\"; ", lut_file.c_str()); - else - log_abort(); log_assert(!box_file.empty()); abc9_script += stringf("read_box \"%s\"; ", box_file.c_str()); @@ -197,8 +195,9 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe } else if (!lut_costs.empty() || !lut_file.empty()) { abc9_script += fast_mode ? RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos) : RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos); - } else - log_abort(); + } else { + log_error("Without a target library, a script needs to be provided.\n"); + } for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4eaed1f75dc..9e451276f07 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1137,7 +1137,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) { ofs.close(); } -void reintegrate(RTLIL::Module *module, bool dff_mode) +void reintegrate(RTLIL::Module *module, bool dff_mode, bool lut_mode) { auto design = module->design; log_assert(design); @@ -1248,6 +1248,48 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); + if (!lut_mode && mapped_cell->type.in(ID($_AND_), ID($_NOT_))) { + RTLIL::SigBit a_bit, b_bit, y_bit; + RTLIL::SigBit a_bit_remap, b_bit_remap, y_bit_remap; + + a_bit = a_bit_remap = mapped_cell->getPort(ID::A); + y_bit = y_bit_remap = mapped_cell->getPort(ID::Y); + if (mapped_cell->type == ID($_AND_)) + b_bit = b_bit_remap = mapped_cell->getPort(ID::B); + + for (auto bit : {&a_bit_remap, &b_bit_remap, &y_bit_remap}) + if (bit->wire) + bit->wire = module->wires_.at(remap_name(bit->wire->name)); + + // Catch the case of a complemented constant zero + if (mapped_cell->type == ID($_NOT_) && !a_bit.wire) { + module->connect(y_bit_remap, State::S1); + continue; + } + + bit_users[a_bit].insert(mapped_cell->name); + if (mapped_cell->type == ID($_AND_)) + bit_users[b_bit].insert(mapped_cell->name); + + // Ignore inouts for topo ordering + if (y_bit.wire && !(y_bit.wire->port_input && y_bit.wire->port_output)) + bit_drivers[y_bit].insert(mapped_cell->name); + + Cell *cell = module->addCell(remap_name(stringf("$aig%s", mapped_cell->name.c_str())), + mapped_cell->type); + for (auto bit : {a_bit_remap, b_bit_remap}) + if (bit.wire) + bit2sinks[bit].push_back(cell); + + cell->setPort(ID::A, a_bit_remap); + cell->setPort(ID::Y, y_bit_remap); + if (cell->type == ID($_AND_)) + cell->setPort(ID::B, b_bit_remap); + + cell_stats[cell->type]++; + continue; + } + if (mapped_cell->type == ID($_NOT_)) { RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); @@ -1667,6 +1709,7 @@ struct Abc9OpsPass : public Pass { bool prep_box_mode = false; bool reintegrate_mode = false; bool dff_mode = false; + bool lut_mode = false; std::string write_lut_dst; int maxlut = 0; std::string write_box_dst; @@ -1752,6 +1795,10 @@ struct Abc9OpsPass : public Pass { dff_mode = true; continue; } + if (arg == "-lut") { + lut_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -1799,7 +1846,7 @@ struct Abc9OpsPass : public Pass { if (prep_xaiger_mode) prep_xaiger(mod, dff_mode); if (reintegrate_mode) - reintegrate(mod, dff_mode); + reintegrate(mod, dff_mode, lut_mode); } } } Abc9OpsPass; From b1345cbe87c341f615f9584ddf903e55ea34e699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 14 Mar 2024 22:11:37 +0100 Subject: [PATCH 2/7] Update synth scripts after abc9 cli change --- techlibs/ecp5/synth_ecp5.cc | 2 +- techlibs/gowin/synth_gowin.cc | 4 ++-- techlibs/ice40/synth_ice40.cc | 2 +- techlibs/lattice/synth_lattice.cc | 2 +- techlibs/nexus/synth_nexus.cc | 2 +- techlibs/quicklogic/synth_quicklogic.cc | 4 ++-- techlibs/xilinx/synth_xilinx.cc | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index f6215987f7f..eb41bc84049 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -388,7 +388,7 @@ struct SynthEcp5Pass : public ScriptPass abc9_opts += " -maxlut 4"; if (dff) abc9_opts += " -dff"; - run("abc9" + abc9_opts); + run("abc9 -lutlib" + abc9_opts); } else { std::string abc_args = " -dress"; if (nowidelut) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 85022c1cfa2..aacf00571ff 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -278,12 +278,12 @@ struct SynthGowinPass : public ScriptPass { if (nowidelut && abc9) { run("read_verilog -icells -lib -specify +/abc9_model.v"); - run("abc9 -maxlut 4 -W 500"); + run("abc9 -lutlib -maxlut 4 -W 500"); } else if (nowidelut && !abc9) { run("abc -lut 4"); } else if (!nowidelut && abc9) { run("read_verilog -icells -lib -specify +/abc9_model.v"); - run("abc9 -maxlut 8 -W 500"); + run("abc9 -lutlib -maxlut 8 -W 500"); } else if (!nowidelut && !abc9) { run("abc -lut 4:8"); } diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 4c691c7a5aa..b6a87d8f642 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -424,7 +424,7 @@ struct SynthIce40Pass : public ScriptPass } if (dff) abc9_opts += " -dff"; - run("abc9 " + abc9_opts); + run("abc9 -lutlib" + abc9_opts); } else run(stringf("abc -dress -lut 4 %s", dff ? "-dff" : ""), "(skip if -noabc)"); diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index cc5821ad832..fd4234ad48e 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -454,7 +454,7 @@ struct SynthLatticePass : public ScriptPass abc9_opts += " -maxlut 4"; if (dff) abc9_opts += " -dff"; - run("abc9" + abc9_opts); + run("abc9 -lutlib" + abc9_opts); } else { std::string abc_args = " -dress"; if (nowidelut) diff --git a/techlibs/nexus/synth_nexus.cc b/techlibs/nexus/synth_nexus.cc index 6fd15ba5577..c8370116085 100644 --- a/techlibs/nexus/synth_nexus.cc +++ b/techlibs/nexus/synth_nexus.cc @@ -366,7 +366,7 @@ struct SynthNexusPass : public ScriptPass abc9_opts += " -maxlut 4"; if (dff) abc9_opts += " -dff"; - run("abc9" + abc9_opts); + run("abc9 -lutlib" + abc9_opts); } else { std::string abc_args = " -dress"; if (nowidelut) diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 0e7aaa75276..c066b06ed72 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -304,7 +304,7 @@ struct SynthQuickLogicPass : public ScriptPass { if (abc9) { run("read_verilog -lib -specify -icells " + lib_path + family + "/abc9_model.v"); run("techmap -map " + lib_path + family + "/abc9_map.v"); - run("abc9 -maxlut 4 -dff"); + run("abc9 -lutlib -maxlut 4 -dff"); run("techmap -map " + lib_path + family + "/abc9_unmap.v"); } else { run("abc -luts 1,2,2,4 -dress"); @@ -314,7 +314,7 @@ struct SynthQuickLogicPass : public ScriptPass { if (check_label("map_luts", "(for qlf_k6n10f)") && (help_mode || family == "qlf_k6n10f")) { if (abc9) { - run("abc9 -maxlut 6"); + run("abc9 -lutlib -maxlut 6"); } else { run("abc -lut 6 -dress"); } diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index a242cdef167..681ad485716 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -650,7 +650,7 @@ struct SynthXilinxPass : public ScriptPass abc9_opts += stringf(" -maxlut %d", lut_size); if (dff) abc9_opts += " -dff"; - run("abc9" + abc9_opts); + run("abc9 -lutlib" + abc9_opts); } else { std::string abc_opts; From b6b7056c0ebb7268be28d0b2573af3a6039b7dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 14 Mar 2024 22:17:26 +0100 Subject: [PATCH 3/7] abc9: Fix LUT mode logic --- passes/techmap/abc9.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index e6775dc9f25..afeaee0c3e3 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -228,7 +228,7 @@ struct Abc9Pass : public ScriptPass /*arg == "-box" ||*/ arg == "-W") && argidx+1 < args.size()) { if (arg == "-lut" || arg == "-luts") - lut_mode = false; + lut_mode = true; exe_cmd << " " << arg << " " << args[++argidx]; continue; } @@ -273,6 +273,9 @@ struct Abc9Pass : public ScriptPass if (maxlut && !lutlib_mode) log_cmd_error("abc9 '-maxlut' option only applicable in conjunction with '-lutlib'.\n"); + if (lut_mode && lutlib_mode) + log_cmd_error("abc9 '-lutlib' option is in conflict with '-lut' or '-luts'.\n"); + log_assert(design); if (design->selected_modules().empty()) { log_warning("No modules selected for ABC9 techmapping.\n"); From fedd88bc77d57e8fb2f78341b723cde419a3a250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 14 Mar 2024 22:33:04 +0100 Subject: [PATCH 4/7] Update tests to account for abc9 change --- tests/arch/xilinx/bug3670.ys | 2 +- tests/arch/xilinx/dsp_abc9.ys | 2 +- tests/various/abc9.ys | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/arch/xilinx/bug3670.ys b/tests/arch/xilinx/bug3670.ys index 772072c1ee4..2f29596e4ba 100644 --- a/tests/arch/xilinx/bug3670.ys +++ b/tests/arch/xilinx/bug3670.ys @@ -1,3 +1,3 @@ read_verilog bug3670.v read_verilog -lib -specify +/xilinx/cells_sim.v -abc9 +abc9 -lutlib diff --git a/tests/arch/xilinx/dsp_abc9.ys b/tests/arch/xilinx/dsp_abc9.ys index 1d74cfa89b2..c77a522e415 100644 --- a/tests/arch/xilinx/dsp_abc9.ys +++ b/tests/arch/xilinx/dsp_abc9.ys @@ -49,7 +49,7 @@ DSP48E1 #(.AREG(1)) u2(.A(A), .B(B), .PCIN(casc), .P(P)); endmodule EOT synth_xilinx -run :prepare -abc9 +abc9 -lutlib clean check logger -expect-no-warnings diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys index e0add714b1b..a4c9de707f7 100644 --- a/tests/various/abc9.ys +++ b/tests/various/abc9.ys @@ -73,7 +73,7 @@ module abc9_test037(input [1:0] i, output o); LUT2 #(.mask(4'b0)) lut (.i(i), .o(o)); endmodule EOT -abc9 +abc9 -lutlib design -reset From 9029facc494ece3cfd174b085882186836b8c01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 14 Mar 2024 23:00:17 +0100 Subject: [PATCH 5/7] synth_intel_alm: Update for abc9 change --- techlibs/intel_alm/synth_intel_alm.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index c33eb43bf35..7a32009212f 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -289,7 +289,7 @@ struct SynthIntelALMPass : public ScriptPass { if (check_label("map_luts")) { run("techmap -map +/intel_alm/common/abc9_map.v"); - run(stringf("abc9 %s -maxlut 6 -W 600", help_mode ? "[-dff]" : dff ? "-dff" : "")); + run(stringf("abc9 -lutlib %s -maxlut 6 -W 600", help_mode ? "[-dff]" : dff ? "-dff" : "")); run("techmap -map +/intel_alm/common/abc9_unmap.v"); run("techmap -map +/intel_alm/common/alm_map.v"); run("opt -fast"); From cb2b70d7428370235f882cf1ae4e7cf843ffcc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 15 Mar 2024 13:11:19 +0100 Subject: [PATCH 6/7] read_aiger: Read the `q` xaiger section with node equivalences --- frontends/aiger/aigerparse.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index cb19b8413a5..2c4047f18d6 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -505,6 +505,26 @@ void AigerReader::parse_xaiger() boxes.emplace_back(cell); } } + else if (c == 'q') { + f.ignore(sizeof(uint32_t)); + uint32_t pairNum = parse_xaiger_literal(f); + + std::vector nodes; + nodes.resize(1000); // TODO: where can we get a reliable bound? `I` doesn't work + for (unsigned i = 0; i < pairNum; i++) { + uint32_t reprID = parse_xaiger_literal(f); + uint32_t siblingID = parse_xaiger_literal(f); + log_assert(nodes.size() > reprID && reprID > siblingID); + Cell *node = nodes[siblingID]; + if (!node) { + node = nodes[siblingID] = module->addCell(stringf("$equivclass%u", siblingID), ID($__choice)); + node->set_bool_attribute(ID::keep, true); + node->setPort(ID::A, module->wire(stringf("$aiger%d$%d", aiger_autoidx, siblingID))); + } + node->connections_.at(ID::A).append(module->wire(stringf("$aiger%d$%d", aiger_autoidx, reprID))); + nodes[reprID] = node; + } + } else if (c == 'a' || c == 'i' || c == 'o' || c == 's') { uint32_t dataSize = parse_xaiger_literal(f); f.ignore(dataSize); From 5326752a4356ef7765ea68c2f426a44981ba2bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 15 Mar 2024 13:11:35 +0100 Subject: [PATCH 7/7] abc9_ops: Reintegrate choice nodes into the circuit --- passes/techmap/abc9_ops.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 9e451276f07..7a4699f6f51 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1248,6 +1248,27 @@ void reintegrate(RTLIL::Module *module, bool dff_mode, bool lut_mode) // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); + if (mapped_cell->type == ID($__choice)) { + RTLIL::SigSpec a = mapped_cell->getPort(ID::A); + + for (auto bit : a) + bit_users[bit].insert(mapped_cell->name); + + Cell *cell = module->addCell(remap_name(mapped_cell->name.c_str()), + mapped_cell->type); + + for (auto &bit : a) + if (bit.wire) { + bit.wire = module->wires_.at(remap_name(bit.wire->name)); + bit2sinks[bit].push_back(cell); + } + + cell->set_bool_attribute(ID::keep, true); + cell->setPort(ID::A, a); + cell_stats[cell->type]++; + continue; + } + if (!lut_mode && mapped_cell->type.in(ID($_AND_), ID($_NOT_))) { RTLIL::SigBit a_bit, b_bit, y_bit; RTLIL::SigBit a_bit_remap, b_bit_remap, y_bit_remap;