From 42fcd41716598e31a1a1df39635110da4809ef43 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 01:26:24 +0000 Subject: [PATCH 1/8] Move ABC pass state to a struct instead of storing it in global variables. --- passes/techmap/abc.cc | 124 +++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index cc37677ce..16d27a0e6 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -113,23 +113,42 @@ bool map_mux8; bool map_mux16; bool markgroups; -int map_autoidx; -SigMap assign_map; -RTLIL::Module *module; -std::vector signal_list; -dict signal_map; -FfInitVals initvals; + pool enabled_gates; bool cmos_cost; -bool had_init; -bool clk_polarity, en_polarity, arst_polarity, srst_polarity; -RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; -dict pi_map, po_map; +struct AbcModuleState { + int map_autoidx = 0; + SigMap assign_map; + RTLIL::Module *module = nullptr; + std::vector signal_list; + dict signal_map; + FfInitVals initvals; + bool had_init = false; -int undef_bits_lost; + bool clk_polarity = false; + bool en_polarity = false; + bool arst_polarity = false; + bool srst_polarity = false; + RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; + dict pi_map, po_map; -int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1) + int undef_bits_lost = 0; + + int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(RTLIL::SigSpec sig); + void extract_cell(RTLIL::Cell *cell, bool keepff); + std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); + void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); + void handle_loops(); + void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, + std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, + bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, + std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, + const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells); +}; + +int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { assign_map.apply(bit); @@ -167,14 +186,14 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, return gate.id; } -void mark_port(RTLIL::SigSpec sig) +void AbcModuleState::mark_port(RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void extract_cell(RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -377,7 +396,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) } } -std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) +std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire) { std::string abc_sname = abc_name.substr(1); bool isnew = false; @@ -416,7 +435,7 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); } -void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts) +void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts) { if (f == nullptr) return; @@ -445,7 +464,7 @@ void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &w fprintf(f, "}\n"); } -void handle_loops() +void AbcModuleState::handle_loops() { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -646,13 +665,15 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho struct abc_output_filter { + const AbcModuleState &state; bool got_cr; int escape_seq_state; std::string linebuf; std::string tempdir_name; bool show_tempdir; - abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) + abc_output_filter(const AbcModuleState& state, std::string tempdir_name, bool show_tempdir) + : state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir) { got_cr = false; escape_seq_state = 0; @@ -693,8 +714,8 @@ struct abc_output_filter int pi, po; if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", - pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", - po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + pi, state.pi_map.count(pi) ? state.pi_map.at(pi).c_str() : "???", + po, state.po_map.count(po) ? state.po_map.at(po).c_str() : "???"); return; } @@ -703,20 +724,16 @@ struct abc_output_filter } }; -void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) { module = current_module; + initvals.set(&assign_map, module); map_autoidx = autoidx++; - signal_map.clear(); - signal_list.clear(); - pi_map.clear(); - po_map.clear(); - if (clk_str != "$") { clk_polarity = true; @@ -1109,7 +1126,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC - abc_output_filter filt(tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, show_tempdir); int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); #else string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str()); @@ -1652,13 +1669,6 @@ struct AbcPass : public Pass { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); - assign_map.clear(); - signal_list.clear(); - signal_map.clear(); - initvals.clear(); - pi_map.clear(); - po_map.clear(); - std::string exe_file = yosys_abc_executable; std::string script_file, default_liberty_file, constr_file, clk_str; std::vector liberty_files, genlib_files, dont_use_cells; @@ -1667,13 +1677,6 @@ struct AbcPass : public Pass { bool show_tempdir = false, sop_mode = false; bool abc_dress = false; vector lut_costs; - markgroups = false; - - map_mux4 = false; - map_mux8 = false; - map_mux16 = false; - enabled_gates.clear(); - cmos_cost = false; // get arguments from scratchpad first, then override by command arguments std::string lut_arg, luts_arg, g_arg; @@ -2049,11 +2052,10 @@ struct AbcPass : public Pass { continue; } - assign_map.set(mod); - initvals.set(&assign_map, mod); - if (!dff_mode || !clk_str.empty()) { - abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + AbcModuleState state; + state.assign_map.set(mod); + state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); continue; } @@ -2074,6 +2076,10 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; + SigMap assign_map; + assign_map.set(mod); + FfInitVals initvals; + initvals.set(&assign_map, mod); for (auto cell : all_cells) { clkdomain_t key; @@ -2207,27 +2213,21 @@ struct AbcPass : public Pass { std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); for (auto &it : assigned_cells) { - clk_polarity = std::get<0>(it.first); - clk_sig = assign_map(std::get<1>(it.first)); - en_polarity = std::get<2>(it.first); - en_sig = assign_map(std::get<3>(it.first)); - arst_polarity = std::get<4>(it.first); - arst_sig = assign_map(std::get<5>(it.first)); - srst_polarity = std::get<6>(it.first); - srst_sig = assign_map(std::get<7>(it.first)); - abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", + AbcModuleState state; + state.assign_map.set(mod); + state.clk_polarity = std::get<0>(it.first); + state.clk_sig = assign_map(std::get<1>(it.first)); + state.en_polarity = std::get<2>(it.first); + state.en_sig = assign_map(std::get<3>(it.first)); + state.arst_polarity = std::get<4>(it.first); + state.arst_sig = assign_map(std::get<5>(it.first)); + state.srst_polarity = std::get<6>(it.first); + state.srst_sig = assign_map(std::get<7>(it.first)); + state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !state.clk_sig.empty(), "$", keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); - assign_map.set(mod); } } - assign_map.clear(); - signal_list.clear(); - signal_map.clear(); - initvals.clear(); - pi_map.clear(); - po_map.clear(); - log_pop(); } } AbcPass; From 4e5e1a0388dea7a0001377a5fc6ea77049ef0791 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 03:38:54 +0000 Subject: [PATCH 2/8] Move the input parameters to `abc_module` that are identical across modules to an `AbcConfig` struct. --- passes/techmap/abc.cc | 260 ++++++++++++++++++++++-------------------- 1 file changed, 137 insertions(+), 123 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 16d27a0e6..28e39998d 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -117,7 +117,30 @@ bool markgroups; pool enabled_gates; bool cmos_cost; +struct AbcConfig +{ + std::string script_file; + std::string exe_file; + std::vector liberty_files; + std::vector genlib_files; + std::string constr_file; + vector lut_costs; + std::string delay_target; + std::string sop_inputs; + std::string sop_products; + std::string lutin_shared; + std::vector dont_use_cells; + bool cleanup = true; + bool keepff = false; + bool fast_mode = false; + bool show_tempdir = false; + bool sop_mode = false; + bool abc_dress = false; +}; + struct AbcModuleState { + const AbcConfig &config; + int map_autoidx = 0; SigMap assign_map; RTLIL::Module *module = nullptr; @@ -135,17 +158,16 @@ struct AbcModuleState { int undef_bits_lost = 0; + AbcModuleState(const AbcConfig &config) : config(config) {} + int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(RTLIL::SigSpec sig); void extract_cell(RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); void handle_loops(); - void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, - std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells); + void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + bool dff_mode, std::string clk_str); }; int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) @@ -724,11 +746,8 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, - std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + bool dff_mode, std::string clk_str) { module = current_module; initvals.set(&assign_map, module); @@ -805,38 +824,39 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); std::string tempdir_name; - if (cleanup) + if (config.cleanup) tempdir_name = get_base_tmpdir() + "/"; else tempdir_name = "_tmp_"; tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX"; tempdir_name = make_temp_dir(tempdir_name); log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n", - module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); + module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, config.show_tempdir).c_str()); std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str()); - if (!liberty_files.empty() || !genlib_files.empty()) { + if (!config.liberty_files.empty() || !config.genlib_files.empty()) { std::string dont_use_args; - for (std::string dont_use_cell : dont_use_cells) { + for (std::string dont_use_cell : config.dont_use_cells) { dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str()); } bool first_lib = true; - for (std::string liberty_file : liberty_files) { + for (std::string liberty_file : config.liberty_files) { abc_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args.c_str(), first_lib ? "" : "-m", liberty_file.c_str()); first_lib = false; } - for (std::string liberty_file : genlib_files) + for (std::string liberty_file : config.genlib_files) abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str()); - if (!constr_file.empty()) - abc_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str()); + if (!config.constr_file.empty()) + abc_script += stringf("read_constr -v \"%s\"; ", config.constr_file.c_str()); } else - if (!lut_costs.empty()) + if (!config.lut_costs.empty()) abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); else abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str()); - if (!script_file.empty()) { + if (!config.script_file.empty()) { + const std::string &script_file = config.script_file; if (script_file[0] == '+') { for (size_t i = 1; i < script_file.size(); i++) if (script_file[i] == '\'') @@ -847,37 +867,38 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo abc_script += script_file[i]; } else abc_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty()) { + } else if (!config.lut_costs.empty()) { bool all_luts_cost_same = true; - for (int this_cost : lut_costs) - if (this_cost != lut_costs.front()) + for (int this_cost : config.lut_costs) + if (this_cost != config.lut_costs.front()) all_luts_cost_same = false; - abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; - if (all_luts_cost_same && !fast_mode) + abc_script += config.fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; + if (all_luts_cost_same && !config.fast_mode) abc_script += "; lutpack {S}"; - } else if (!liberty_files.empty() || !genlib_files.empty()) - abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); - else if (sop_mode) - abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; + } else if (!config.liberty_files.empty() || !config.genlib_files.empty()) + abc_script += config.constr_file.empty() ? + (config.fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (config.fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); + else if (config.sop_mode) + abc_script += config.fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; else - abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; + abc_script += config.fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; - if (script_file.empty() && !delay_target.empty()) + if (config.script_file.empty() && !config.delay_target.empty()) for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) - abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.delay_target + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{I}", pos)) - abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.sop_inputs + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{P}", pos)) - abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.sop_products + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) - abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3); - if (abc_dress) + abc_script = abc_script.substr(0, pos) + config.lutin_shared + abc_script.substr(pos+3); + if (config.abc_dress) abc_script += stringf("; dress \"%s/input.blif\"", tempdir_name.c_str()); abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str()); abc_script = add_echos_to_abc_cmd(abc_script); @@ -913,7 +934,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo had_init = false; for (auto c : cells) - extract_cell(c, keepff); + extract_cell(c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); @@ -1112,21 +1133,21 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at(ID($_MUX_))); fclose(f); - if (!lut_costs.empty()) { + if (!config.lut_costs.empty()) { buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); if (f == nullptr) log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - for (int i = 0; i < GetSize(lut_costs); i++) - fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + for (int i = 0; i < GetSize(config.lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, config.lut_costs.at(i)); fclose(f); } - buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); - log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", config.exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, config.show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC - abc_output_filter filt(*this, tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, config.show_tempdir); int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); #else string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str()); @@ -1150,7 +1171,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo // These needs to be mutable, supposedly due to getopt char *abc_argv[5]; string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); - abc_argv[0] = strdup(exe_file.c_str()); + abc_argv[0] = strdup(config.exe_file.c_str()); abc_argv[1] = strdup("-s"); abc_argv[2] = strdup("-f"); abc_argv[3] = strdup(tmp_script_name.c_str()); @@ -1167,7 +1188,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo fclose(old_stdout); fclose(old_stderr); std::ifstream temp_stdouterr_r(temp_stdouterr_name); - abc_output_filter filt(tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, config.show_tempdir); for (std::string line; std::getline(temp_stdouterr_r, line); ) filt.next_line(line + "\n"); temp_stdouterr_r.close(); @@ -1181,9 +1202,9 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (ifs.fail()) log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - bool builtin_lib = liberty_files.empty() && genlib_files.empty(); + bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode); + parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); ifs.close(); @@ -1459,7 +1480,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log("Don't call ABC as there is nothing to map.\n"); } - if (cleanup) + if (config.cleanup) { log("Removing temp directory.\n"); remove_directory(tempdir_name); @@ -1669,57 +1690,52 @@ struct AbcPass : public Pass { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); - std::string exe_file = yosys_abc_executable; - std::string script_file, default_liberty_file, constr_file, clk_str; - std::vector liberty_files, genlib_files, dont_use_cells; - std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; - bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; - bool show_tempdir = false, sop_mode = false; - bool abc_dress = false; - vector lut_costs; + AbcConfig config; // get arguments from scratchpad first, then override by command arguments std::string lut_arg, luts_arg, g_arg; - exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */); - script_file = design->scratchpad_get_string("abc.script", script_file); - default_liberty_file = design->scratchpad_get_string("abc.liberty", default_liberty_file); - constr_file = design->scratchpad_get_string("abc.constr", constr_file); + config.exe_file = design->scratchpad_get_string("abc.exe", yosys_abc_executable /* inherit default value if not set */); + config.script_file = design->scratchpad_get_string("abc.script", ""); + std::string default_liberty_file = design->scratchpad_get_string("abc.liberty", ""); + config.constr_file = design->scratchpad_get_string("abc.constr", ""); if (design->scratchpad.count("abc.D")) { - delay_target = "-D " + design->scratchpad_get_string("abc.D"); + config.delay_target = "-D " + design->scratchpad_get_string("abc.D"); } if (design->scratchpad.count("abc.I")) { - sop_inputs = "-I " + design->scratchpad_get_string("abc.I"); + config.sop_inputs = "-I " + design->scratchpad_get_string("abc.I"); } if (design->scratchpad.count("abc.P")) { - sop_products = "-P " + design->scratchpad_get_string("abc.P"); + config.sop_products = "-P " + design->scratchpad_get_string("abc.P"); } if (design->scratchpad.count("abc.S")) { - lutin_shared = "-S " + design->scratchpad_get_string("abc.S"); + config.lutin_shared = "-S " + design->scratchpad_get_string("abc.S"); + } else { + config.lutin_shared = "-S 1"; } lut_arg = design->scratchpad_get_string("abc.lut", lut_arg); luts_arg = design->scratchpad_get_string("abc.luts", luts_arg); - sop_mode = design->scratchpad_get_bool("abc.sop", sop_mode); + config.sop_mode = design->scratchpad_get_bool("abc.sop", false); map_mux4 = design->scratchpad_get_bool("abc.mux4", map_mux4); map_mux8 = design->scratchpad_get_bool("abc.mux8", map_mux8); map_mux16 = design->scratchpad_get_bool("abc.mux16", map_mux16); - abc_dress = design->scratchpad_get_bool("abc.dress", abc_dress); + config.abc_dress = design->scratchpad_get_bool("abc.dress", false); g_arg = design->scratchpad_get_string("abc.g", g_arg); - fast_mode = design->scratchpad_get_bool("abc.fast", fast_mode); - dff_mode = design->scratchpad_get_bool("abc.dff", dff_mode); + config.fast_mode = design->scratchpad_get_bool("abc.fast", false); + bool dff_mode = design->scratchpad_get_bool("abc.dff", false); + std::string clk_str; if (design->scratchpad.count("abc.clk")) { clk_str = design->scratchpad_get_string("abc.clk"); dff_mode = true; } - keepff = design->scratchpad_get_bool("abc.keepff", keepff); - cleanup = !design->scratchpad_get_bool("abc.nocleanup", !cleanup); - keepff = design->scratchpad_get_bool("abc.keepff", keepff); - show_tempdir = design->scratchpad_get_bool("abc.showtmp", show_tempdir); + config.keepff = design->scratchpad_get_bool("abc.keepff", false); + config.cleanup = !design->scratchpad_get_bool("abc.nocleanup", false); + config.show_tempdir = design->scratchpad_get_bool("abc.showtmp", false); markgroups = design->scratchpad_get_bool("abc.markgroups", markgroups); if (design->scratchpad_get_bool("abc.debug")) { - cleanup = false; - show_tempdir = true; + config.cleanup = false; + config.show_tempdir = true; } size_t argidx, g_argidx = -1; @@ -1736,43 +1752,43 @@ struct AbcPass : public Pass { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-exe" && argidx+1 < args.size()) { - exe_file = args[++argidx]; + config.exe_file = args[++argidx]; continue; } if (arg == "-script" && argidx+1 < args.size()) { - script_file = args[++argidx]; + config.script_file = args[++argidx]; continue; } if (arg == "-liberty" && argidx+1 < args.size()) { - liberty_files.push_back(args[++argidx]); + config.liberty_files.push_back(args[++argidx]); continue; } if (arg == "-dont_use" && argidx+1 < args.size()) { - dont_use_cells.push_back(args[++argidx]); + config.dont_use_cells.push_back(args[++argidx]); continue; } if (arg == "-genlib" && argidx+1 < args.size()) { - genlib_files.push_back(args[++argidx]); + config.genlib_files.push_back(args[++argidx]); continue; } if (arg == "-constr" && argidx+1 < args.size()) { - constr_file = args[++argidx]; + config.constr_file = args[++argidx]; continue; } if (arg == "-D" && argidx+1 < args.size()) { - delay_target = "-D " + args[++argidx]; + config.delay_target = "-D " + args[++argidx]; continue; } if (arg == "-I" && argidx+1 < args.size()) { - sop_inputs = "-I " + args[++argidx]; + config.sop_inputs = "-I " + args[++argidx]; continue; } if (arg == "-P" && argidx+1 < args.size()) { - sop_products = "-P " + args[++argidx]; + config.sop_products = "-P " + args[++argidx]; continue; } if (arg == "-S" && argidx+1 < args.size()) { - lutin_shared = "-S " + args[++argidx]; + config.lutin_shared = "-S " + args[++argidx]; continue; } if (arg == "-lut" && argidx+1 < args.size()) { @@ -1784,7 +1800,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-sop") { - sop_mode = true; + config.sop_mode = true; continue; } if (arg == "-mux4") { @@ -1800,7 +1816,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-dress") { - abc_dress = true; + config.abc_dress = true; continue; } if (arg == "-g" && argidx+1 < args.size()) { @@ -1812,7 +1828,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-fast") { - fast_mode = true; + config.fast_mode = true; continue; } if (arg == "-dff") { @@ -1825,15 +1841,15 @@ struct AbcPass : public Pass { continue; } if (arg == "-keepff") { - keepff = true; + config.keepff = true; continue; } if (arg == "-nocleanup") { - cleanup = false; + config.cleanup = false; continue; } if (arg == "-showtmp") { - show_tempdir = true; + config.show_tempdir = true; continue; } if (arg == "-markgroups") { @@ -1844,25 +1860,25 @@ struct AbcPass : public Pass { } extra_args(args, argidx, design); - if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty()) - liberty_files.push_back(default_liberty_file); + if (config.genlib_files.empty() && config.liberty_files.empty() && !default_liberty_file.empty()) + config.liberty_files.push_back(default_liberty_file); - rewrite_filename(script_file); - if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') - script_file = std::string(pwd) + "/" + script_file; - for (int i = 0; i < GetSize(liberty_files); i++) { - rewrite_filename(liberty_files[i]); - if (!liberty_files[i].empty() && !is_absolute_path(liberty_files[i])) - liberty_files[i] = std::string(pwd) + "/" + liberty_files[i]; + rewrite_filename(config.script_file); + if (!config.script_file.empty() && !is_absolute_path(config.script_file) && config.script_file[0] != '+') + config.script_file = std::string(pwd) + "/" + config.script_file; + for (int i = 0; i < GetSize(config.liberty_files); i++) { + rewrite_filename(config.liberty_files[i]); + if (!config.liberty_files[i].empty() && !is_absolute_path(config.liberty_files[i])) + config.liberty_files[i] = std::string(pwd) + "/" + config.liberty_files[i]; } - for (int i = 0; i < GetSize(genlib_files); i++) { - rewrite_filename(genlib_files[i]); - if (!genlib_files[i].empty() && !is_absolute_path(genlib_files[i])) - genlib_files[i] = std::string(pwd) + "/" + genlib_files[i]; + for (int i = 0; i < GetSize(config.genlib_files); i++) { + rewrite_filename(config.genlib_files[i]); + if (!config.genlib_files[i].empty() && !is_absolute_path(config.genlib_files[i])) + config.genlib_files[i] = std::string(pwd) + "/" + config.genlib_files[i]; } - rewrite_filename(constr_file); - if (!constr_file.empty() && !is_absolute_path(constr_file)) - constr_file = std::string(pwd) + "/" + constr_file; + rewrite_filename(config.constr_file); + if (!config.constr_file.empty() && !is_absolute_path(config.constr_file)) + config.constr_file = std::string(pwd) + "/" + config.constr_file; // handle -lut argument if (!lut_arg.empty()) { @@ -1875,24 +1891,24 @@ struct AbcPass : public Pass { lut_mode = atoi(lut_arg.c_str()); lut_mode2 = lut_mode; } - lut_costs.clear(); + config.lut_costs.clear(); for (int i = 0; i < lut_mode; i++) - lut_costs.push_back(1); + config.lut_costs.push_back(1); for (int i = lut_mode; i < lut_mode2; i++) - lut_costs.push_back(2 << (i - lut_mode)); + config.lut_costs.push_back(2 << (i - lut_mode)); } //handle -luts argument if (!luts_arg.empty()){ - lut_costs.clear(); + config.lut_costs.clear(); for (auto &tok : split_tokens(luts_arg, ",")) { auto parts = split_tokens(tok, ":"); - if (GetSize(parts) == 0 && !lut_costs.empty()) - lut_costs.push_back(lut_costs.back()); + if (GetSize(parts) == 0 && !config.lut_costs.empty()) + config.lut_costs.push_back(config.lut_costs.back()); else if (GetSize(parts) == 1) - lut_costs.push_back(atoi(parts.at(0).c_str())); + config.lut_costs.push_back(atoi(parts.at(0).c_str())); else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < std::atoi(parts.at(0).c_str())) - lut_costs.push_back(atoi(parts.at(1).c_str())); + while (GetSize(config.lut_costs) < std::atoi(parts.at(0).c_str())) + config.lut_costs.push_back(atoi(parts.at(1).c_str())); else log_cmd_error("Invalid -luts syntax.\n"); } @@ -2023,9 +2039,9 @@ struct AbcPass : public Pass { } } - if (!lut_costs.empty() && !(liberty_files.empty() && genlib_files.empty())) + if (!config.lut_costs.empty() && !(config.liberty_files.empty() && config.genlib_files.empty())) log_cmd_error("Got -lut and -liberty/-genlib! These two options are exclusive.\n"); - if (!constr_file.empty() && (liberty_files.empty() && genlib_files.empty())) + if (!config.constr_file.empty() && (config.liberty_files.empty() && config.genlib_files.empty())) log_cmd_error("Got -constr but no -liberty/-genlib!\n"); if (enabled_gates.empty()) { @@ -2053,10 +2069,9 @@ struct AbcPass : public Pass { } if (!dff_mode || !clk_str.empty()) { - AbcModuleState state; + AbcModuleState state(config); state.assign_map.set(mod); - state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); + state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); continue; } @@ -2213,7 +2228,7 @@ struct AbcPass : public Pass { std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); for (auto &it : assigned_cells) { - AbcModuleState state; + AbcModuleState state(config); state.assign_map.set(mod); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); @@ -2223,8 +2238,7 @@ struct AbcPass : public Pass { state.arst_sig = assign_map(std::get<5>(it.first)); state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); - state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !state.clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); + state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); } } From 2a9d37fb12157991139a60517f0b2ce668589e81 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 03:54:41 +0000 Subject: [PATCH 3/8] Move code in `abc_module()` that modifies the design into a new function `extract()` Splits up the big `abc_module()` function and isolates the code that modifies the design after running ABC. --- passes/techmap/abc.cc | 491 ++++++++++++++++++++++-------------------- 1 file changed, 255 insertions(+), 236 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 28e39998d..494494a49 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -148,6 +148,7 @@ struct AbcModuleState { dict signal_map; FfInitVals initvals; bool had_init = false; + bool did_run_abc = false; bool clk_polarity = false; bool en_polarity = false; @@ -158,6 +159,8 @@ struct AbcModuleState { int undef_bits_lost = 0; + std::string tempdir_name; + AbcModuleState(const AbcConfig &config) : config(config) {} int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); @@ -168,6 +171,8 @@ struct AbcModuleState { void handle_loops(); void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, bool dff_mode, std::string clk_str); + void extract(RTLIL::Design *design); + void finish(); }; int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) @@ -823,7 +828,6 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (dff_mode && clk_sig.empty()) log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); - std::string tempdir_name; if (config.cleanup) tempdir_name = get_base_tmpdir() + "/"; else @@ -1193,194 +1197,155 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo filt.next_line(line + "\n"); temp_stdouterr_r.close(); #endif - if (ret != 0) + if (ret != 0) { log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif"); - std::ifstream ifs; - ifs.open(buffer); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - - bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); - RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); - - ifs.close(); - - log_header(design, "Re-integrating ABC results.\n"); - RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist)); - if (mapped_mod == nullptr) - log_error("ABC output file does not contain a module `netlist'.\n"); - for (auto w : mapped_mod->wires()) { - RTLIL::Wire *orig_wire = nullptr; - RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); - if (orig_wire != nullptr && orig_wire->attributes.count(ID::src)) - wire->attributes[ID::src] = orig_wire->attributes[ID::src]; - if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; - design->select(module, wire); + return; } + did_run_abc = true; + return; + } + log("Don't call ABC as there is nothing to map.\n"); +} - SigMap mapped_sigmap(mapped_mod); - FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod); +void AbcModuleState::extract(RTLIL::Design *design) +{ + if (!did_run_abc) { + return; + } - dict cell_stats; - for (auto c : mapped_mod->cells()) + std::string buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif"); + std::ifstream ifs; + ifs.open(buffer); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + + bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); + RTLIL::Design *mapped_design = new RTLIL::Design; + parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); + + ifs.close(); + + log_header(design, "Re-integrating ABC results.\n"); + RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist)); + if (mapped_mod == nullptr) + log_error("ABC output file does not contain a module `netlist'.\n"); + for (auto w : mapped_mod->wires()) { + RTLIL::Wire *orig_wire = nullptr; + RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); + if (orig_wire != nullptr && orig_wire->attributes.count(ID::src)) + wire->attributes[ID::src] = orig_wire->attributes[ID::src]; + if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; + design->select(module, wire); + } + + SigMap mapped_sigmap(mapped_mod); + FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod); + + dict cell_stats; + for (auto c : mapped_mod->cells()) + { + if (builtin_lib) { - if (builtin_lib) - { - cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type.in(ID(ZERO), ID(ONE))) { - RTLIL::SigSig conn; - RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); - conn.first = module->wire(name_y); - conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); - module->connect(conn); - continue; - } - if (c->type == ID(BUF)) { - RTLIL::SigSig conn; - RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); - RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); - conn.first = module->wire(name_y); - conn.second = module->wire(name_a); - module->connect(conn); - continue; - } - if (c->type == ID(NOT)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(MUX), ID(NMUX))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::S, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX4)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX8)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX16)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, - ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AOI3), ID(OAI3))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AOI4), ID(OAI4))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(DFF)) { - log_assert(clk_sig.size() == 1); - FfData ff(module, &initvals, remap_name(c->name)); - ff.width = 1; - ff.is_fine = true; - ff.has_clk = true; - ff.pol_clk = clk_polarity; - ff.sig_clk = clk_sig; - if (en_sig.size() != 0) { - log_assert(en_sig.size() == 1); - ff.has_ce = true; - ff.pol_ce = en_polarity; - ff.sig_ce = en_sig; - } - RTLIL::Const init = mapped_initvals(c->getPort(ID::Q)); - if (had_init) - ff.val_init = init; - else - ff.val_init = State::Sx; - if (arst_sig.size() != 0) { - log_assert(arst_sig.size() == 1); - ff.has_arst = true; - ff.pol_arst = arst_polarity; - ff.sig_arst = arst_sig; - ff.val_arst = init; - } - if (srst_sig.size() != 0) { - log_assert(srst_sig.size() == 1); - ff.has_srst = true; - ff.pol_srst = srst_polarity; - ff.sig_srst = srst_sig; - ff.val_srst = init; - } - ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name)); - ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name)); - RTLIL::Cell *cell = ff.emit(); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - design->select(module, cell); - continue; - } - } - else - cell_stats[RTLIL::unescape_id(c->type)]++; - - if (c->type.in(ID(_const0_), ID(_const1_))) { + cell_stats[RTLIL::unescape_id(c->type)]++; + if (c->type.in(ID(ZERO), ID(ONE))) { RTLIL::SigSig conn; - conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); - conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); + RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); + conn.first = module->wire(name_y); + conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); module->connect(conn); continue; } - - if (c->type == ID(_dff_)) { + if (c->type == ID(BUF)) { + RTLIL::SigSig conn; + RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); + RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); + conn.first = module->wire(name_y); + conn.second = module->wire(name_a); + module->connect(conn); + continue; + } + if (c->type == ID(NOT)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(MUX), ID(NMUX))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::S, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX4)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX8)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX16)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, + ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AOI3), ID(OAI3))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AOI4), ID(OAI4))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(DFF)) { log_assert(clk_sig.size() == 1); FfData ff(module, &initvals, remap_name(c->name)); ff.width = 1; @@ -1390,6 +1355,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo ff.sig_clk = clk_sig; if (en_sig.size() != 0) { log_assert(en_sig.size() == 1); + ff.has_ce = true; ff.pol_ce = en_polarity; ff.sig_ce = en_sig; } @@ -1400,12 +1366,14 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo ff.val_init = State::Sx; if (arst_sig.size() != 0) { log_assert(arst_sig.size() == 1); + ff.has_arst = true; ff.pol_arst = arst_polarity; ff.sig_arst = arst_sig; ff.val_arst = init; } if (srst_sig.size() != 0) { log_assert(srst_sig.size() == 1); + ff.has_srst = true; ff.pol_srst = srst_polarity; ff.sig_srst = srst_sig; ff.val_srst = init; @@ -1417,69 +1385,116 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo design->select(module, cell); continue; } + } + else + cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { - SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); - continue; - } - - RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - cell->parameters = c->parameters; - for (auto &conn : c->connections()) { - RTLIL::SigSpec newsig; - for (auto &c : conn.second.chunks()) { - if (c.width == 0) - continue; - log_assert(c.width == 1); - newsig.append(module->wire(remap_name(c.wire->name))); - } - cell->setPort(conn.first, newsig); - } - design->select(module, cell); + if (c->type.in(ID(_const0_), ID(_const1_))) { + RTLIL::SigSig conn; + conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); + conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); + module->connect(conn); + continue; } - for (auto conn : mapped_mod->connections()) { - if (!conn.first.is_fully_const()) - conn.first = module->wire(remap_name(conn.first.as_wire()->name)); - if (!conn.second.is_fully_const()) - conn.second = module->wire(remap_name(conn.second.as_wire()->name)); + if (c->type == ID(_dff_)) { + log_assert(clk_sig.size() == 1); + FfData ff(module, &initvals, remap_name(c->name)); + ff.width = 1; + ff.is_fine = true; + ff.has_clk = true; + ff.pol_clk = clk_polarity; + ff.sig_clk = clk_sig; + if (en_sig.size() != 0) { + log_assert(en_sig.size() == 1); + ff.pol_ce = en_polarity; + ff.sig_ce = en_sig; + } + RTLIL::Const init = mapped_initvals(c->getPort(ID::Q)); + if (had_init) + ff.val_init = init; + else + ff.val_init = State::Sx; + if (arst_sig.size() != 0) { + log_assert(arst_sig.size() == 1); + ff.pol_arst = arst_polarity; + ff.sig_arst = arst_sig; + ff.val_arst = init; + } + if (srst_sig.size() != 0) { + log_assert(srst_sig.size() == 1); + ff.pol_srst = srst_polarity; + ff.sig_srst = srst_sig; + ff.val_srst = init; + } + ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name)); + ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name)); + RTLIL::Cell *cell = ff.emit(); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + design->select(module, cell); + continue; + } + + if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { + SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + continue; + } + + RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + cell->parameters = c->parameters; + for (auto &conn : c->connections()) { + RTLIL::SigSpec newsig; + for (auto &c : conn.second.chunks()) { + if (c.width == 0) + continue; + log_assert(c.width == 1); + newsig.append(module->wire(remap_name(c.wire->name))); + } + cell->setPort(conn.first, newsig); + } + design->select(module, cell); + } + + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) + conn.first = module->wire(remap_name(conn.first.as_wire()->name)); + if (!conn.second.is_fully_const()) + conn.second = module->wire(remap_name(conn.second.as_wire()->name)); + module->connect(conn); + } + + cell_stats.sort(); + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + for (auto &si : signal_list) + if (si.is_port) { + char buffer[100]; + snprintf(buffer, 100, "\\ys__n%d", si.id); + RTLIL::SigSig conn; + if (si.type != G(NONE)) { + conn.first = si.bit; + conn.second = module->wire(remap_name(buffer)); + out_wires++; + } else { + conn.first = module->wire(remap_name(buffer)); + conn.second = si.bit; + in_wires++; + } module->connect(conn); } + log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); - cell_stats.sort(); - for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); - int in_wires = 0, out_wires = 0; - for (auto &si : signal_list) - if (si.is_port) { - char buffer[100]; - snprintf(buffer, 100, "\\ys__n%d", si.id); - RTLIL::SigSig conn; - if (si.type != G(NONE)) { - conn.first = si.bit; - conn.second = module->wire(remap_name(buffer)); - out_wires++; - } else { - conn.first = module->wire(remap_name(buffer)); - conn.second = si.bit; - in_wires++; - } - module->connect(conn); - } - log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); - log("ABC RESULTS: input signals: %8d\n", in_wires); - log("ABC RESULTS: output signals: %8d\n", out_wires); - - delete mapped_design; - } - else - { - log("Don't call ABC as there is nothing to map.\n"); - } + delete mapped_design; +} +void AbcModuleState::finish() +{ if (config.cleanup) { log("Removing temp directory.\n"); @@ -2072,6 +2087,8 @@ struct AbcPass : public Pass { AbcModuleState state(config); state.assign_map.set(mod); state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); + state.extract(design); + state.finish(); continue; } @@ -2239,6 +2256,8 @@ struct AbcPass : public Pass { state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); + state.extract(design); + state.finish(); } } From 6ac315d65f09eb009a7fdfa7065809a283b950b1 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 04:17:48 +0000 Subject: [PATCH 4/8] Make `module` a parameter of the function so we can change its constness in context --- passes/techmap/abc.cc | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 494494a49..fb889f530 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -143,7 +143,6 @@ struct AbcModuleState { int map_autoidx = 0; SigMap assign_map; - RTLIL::Module *module = nullptr; std::vector signal_list; dict signal_map; FfInitVals initvals; @@ -165,13 +164,13 @@ struct AbcModuleState { int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(RTLIL::SigSpec sig); - void extract_cell(RTLIL::Cell *cell, bool keepff); + void extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(); - void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + void handle_loops(RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(RTLIL::Design *design); + void extract(RTLIL::Design *design, RTLIL::Module *module); void finish(); }; @@ -220,7 +219,7 @@ void AbcModuleState::mark_port(RTLIL::SigSpec sig) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -491,7 +490,7 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void AbcModuleState::handle_loops() +void AbcModuleState::handle_loops(RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -751,10 +750,9 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, bool dff_mode, std::string clk_str) { - module = current_module; initvals.set(&assign_map, module); map_autoidx = autoidx++; @@ -938,7 +936,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo had_init = false; for (auto c : cells) - extract_cell(c, config.keepff); + extract_cell(module, c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); @@ -964,7 +962,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (srst_sig.size() != 0) mark_port(srst_sig); - handle_loops(); + handle_loops(module); buffer = stringf("%s/input.blif", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); @@ -1207,7 +1205,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(RTLIL::Design *design) +void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -2087,7 +2085,7 @@ struct AbcPass : public Pass { AbcModuleState state(config); state.assign_map.set(mod); state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); - state.extract(design); + state.extract(design, mod); state.finish(); continue; } @@ -2256,7 +2254,7 @@ struct AbcPass : public Pass { state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); - state.extract(design); + state.extract(design, mod); state.finish(); } } From ebef91880d2bd70901b2540ca3d43eac0947090d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 04:19:09 +0000 Subject: [PATCH 5/8] Fix indentation --- passes/techmap/abc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index fb889f530..0c2576c1a 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -947,8 +947,8 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co } for (auto cell : module->cells()) - for (auto &port_it : cell->connections()) - mark_port(port_it.second); + for (auto &port_it : cell->connections()) + mark_port(port_it.second); if (clk_sig.size() != 0) mark_port(clk_sig); From d32c5b6d0e1c6a7e44bb1640d549d8c9e44eaaef Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sat, 26 Jul 2025 09:34:37 +0000 Subject: [PATCH 6/8] Mark kept FF output wires as ports directly instead of via the 'keep' attribute --- passes/techmap/abc.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 0c2576c1a..62ce8da96 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -291,12 +291,13 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool return; } - if (keepff) - for (auto &c : ff.sig_q.chunks()) - if (c.wire != nullptr) - c.wire->attributes[ID::keep] = 1; - - map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + int gate_id = map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + if (keepff) { + SigBit bit = ff.sig_q; + if (assign_map(bit).wire != nullptr) { + signal_list[gate_id].is_port = true; + } + } ff.remove(); return; @@ -942,7 +943,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); for (auto wire : module->wires()) { - if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) + if (wire->port_id > 0) mark_port(wire); } From d3b0c0df1adcef1cce02edf0c28821e42dcc5c89 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 17 Jul 2025 06:16:54 +0000 Subject: [PATCH 7/8] Preserve `assign_map` across ABC invocations. Currently `assign_map` is rebuilt from the module from scratch every time we invoke ABC. That doesn't scale when we do thousands of ABC runs over large modules. Instead, create it once and then maintain incrementally it as we update the module. --- passes/techmap/abc.cc | 130 ++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 62ce8da96..8a2816307 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -142,7 +142,6 @@ struct AbcModuleState { const AbcConfig &config; int map_autoidx = 0; - SigMap assign_map; std::vector signal_list; dict signal_map; FfInitVals initvals; @@ -162,19 +161,19 @@ struct AbcModuleState { AbcModuleState(const AbcConfig &config) : config(config) {} - int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); - void mark_port(RTLIL::SigSpec sig); - void extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); + int map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(const SigMap &assign_map, RTLIL::SigSpec sig); + void extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(RTLIL::Module *module); - void abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, + void handle_loops(SigMap &assign_map, RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(RTLIL::Design *design, RTLIL::Module *module); + void extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); void finish(); }; -int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) +int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { assign_map.apply(bit); @@ -212,14 +211,14 @@ int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1 return gate.id; } -void AbcModuleState::mark_port(RTLIL::SigSpec sig) +void AbcModuleState::mark_port(const SigMap &assign_map, RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -291,7 +290,7 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool return; } - int gate_id = map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + int gate_id = map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); if (keepff) { SigBit bit = ff.sig_q; if (assign_map(bit).wire != nullptr) { @@ -299,6 +298,8 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool } } + map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); + ff.remove(); return; } @@ -311,7 +312,7 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_a); assign_map.apply(sig_y); - map_signal(sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(sig_a)); + map_signal(assign_map, sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(assign_map, sig_a)); module->remove(cell); return; @@ -327,25 +328,25 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_b); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); if (cell->type == ID($_AND_)) - map_signal(sig_y, G(AND), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(AND), mapped_a, mapped_b); else if (cell->type == ID($_NAND_)) - map_signal(sig_y, G(NAND), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(NAND), mapped_a, mapped_b); else if (cell->type == ID($_OR_)) - map_signal(sig_y, G(OR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(OR), mapped_a, mapped_b); else if (cell->type == ID($_NOR_)) - map_signal(sig_y, G(NOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(NOR), mapped_a, mapped_b); else if (cell->type == ID($_XOR_)) - map_signal(sig_y, G(XOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(XOR), mapped_a, mapped_b); else if (cell->type == ID($_XNOR_)) - map_signal(sig_y, G(XNOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(XNOR), mapped_a, mapped_b); else if (cell->type == ID($_ANDNOT_)) - map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(ANDNOT), mapped_a, mapped_b); else if (cell->type == ID($_ORNOT_)) - map_signal(sig_y, G(ORNOT), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(ORNOT), mapped_a, mapped_b); else log_abort(); @@ -365,11 +366,11 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_s); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_s = map_signal(sig_s); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_s = map_signal(assign_map, sig_s); - map_signal(sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); + map_signal(assign_map, sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); return; @@ -387,11 +388,11 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_c); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_c = map_signal(sig_c); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_c = map_signal(assign_map, sig_c); - map_signal(sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); + map_signal(assign_map, sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); module->remove(cell); return; @@ -411,12 +412,12 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_d); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_c = map_signal(sig_c); - int mapped_d = map_signal(sig_d); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_c = map_signal(assign_map, sig_c); + int mapped_d = map_signal(assign_map, sig_d); - map_signal(sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); + map_signal(assign_map, sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); module->remove(cell); return; @@ -491,7 +492,13 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void AbcModuleState::handle_loops(RTLIL::Module *module) +void connect(SigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) +{ + module->connect(conn); + assign_map.add(conn.first, conn.second); +} + +void AbcModuleState::handle_loops(SigMap &assign_map, RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -596,7 +603,7 @@ void AbcModuleState::handle_loops(RTLIL::Module *module) first_line = false; } - int id3 = map_signal(RTLIL::SigSpec(wire)); + int id3 = map_signal(assign_map, RTLIL::SigSpec(wire)); signal_list[id1].is_port = true; signal_list[id3].is_port = true; log_assert(id3 == int(in_edges_count.size())); @@ -615,7 +622,7 @@ void AbcModuleState::handle_loops(RTLIL::Module *module) } edges[id1].swap(edges[id3]); - module->connect(RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit)); + connect(assign_map, module, RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit)); dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count); } } @@ -751,7 +758,7 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { initvals.set(&assign_map, module); @@ -937,33 +944,33 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co had_init = false; for (auto c : cells) - extract_cell(module, c, config.keepff); + extract_cell(assign_map, module, c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); for (auto wire : module->wires()) { if (wire->port_id > 0) - mark_port(wire); + mark_port(assign_map, wire); } for (auto cell : module->cells()) for (auto &port_it : cell->connections()) - mark_port(port_it.second); + mark_port(assign_map, port_it.second); if (clk_sig.size() != 0) - mark_port(clk_sig); + mark_port(assign_map, clk_sig); if (en_sig.size() != 0) - mark_port(en_sig); + mark_port(assign_map, en_sig); if (arst_sig.size() != 0) - mark_port(arst_sig); + mark_port(assign_map, arst_sig); if (srst_sig.size() != 0) - mark_port(srst_sig); + mark_port(assign_map, srst_sig); - handle_loops(module); + handle_loops(assign_map, module); buffer = stringf("%s/input.blif", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); @@ -1206,7 +1213,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) +void AbcModuleState::extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -1251,7 +1258,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); conn.first = module->wire(name_y); conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); - module->connect(conn); + connect(assign_map, module, conn); continue; } if (c->type == ID(BUF)) { @@ -1260,7 +1267,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); conn.first = module->wire(name_y); conn.second = module->wire(name_a); - module->connect(conn); + connect(assign_map, module, conn); continue; } if (c->type == ID(NOT)) { @@ -1392,7 +1399,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::SigSig conn; conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); - module->connect(conn); + connect(assign_map, module, conn); continue; } @@ -1437,7 +1444,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); + connect(assign_map, module, RTLIL::SigSig(my_a, my_y)); continue; } @@ -1462,7 +1469,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) conn.first = module->wire(remap_name(conn.first.as_wire()->name)); if (!conn.second.is_fully_const()) conn.second = module->wire(remap_name(conn.second.as_wire()->name)); - module->connect(conn); + connect(assign_map, module, conn); } cell_stats.sort(); @@ -1483,7 +1490,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) conn.second = si.bit; in_wires++; } - module->connect(conn); + connect(assign_map, module, conn); } log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); log("ABC RESULTS: input signals: %8d\n", in_wires); @@ -2077,6 +2084,9 @@ struct AbcPass : public Pass { for (auto mod : design->selected_modules()) { + SigMap assign_map; + assign_map.set(mod); + if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; @@ -2084,9 +2094,8 @@ struct AbcPass : public Pass { if (!dff_mode || !clk_str.empty()) { AbcModuleState state(config); - state.assign_map.set(mod); - state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); - state.extract(design, mod); + state.abc_module(design, mod, assign_map, mod->selected_cells(), dff_mode, clk_str); + state.extract(assign_map, design, mod); state.finish(); continue; } @@ -2107,8 +2116,6 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - SigMap assign_map; - assign_map.set(mod); FfInitVals initvals; initvals.set(&assign_map, mod); for (auto cell : all_cells) @@ -2245,7 +2252,6 @@ struct AbcPass : public Pass { for (auto &it : assigned_cells) { AbcModuleState state(config); - state.assign_map.set(mod); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); state.en_polarity = std::get<2>(it.first); @@ -2254,8 +2260,8 @@ struct AbcPass : public Pass { state.arst_sig = assign_map(std::get<5>(it.first)); state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); - state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); - state.extract(design, mod); + state.abc_module(design, mod, assign_map, it.second, !state.clk_sig.empty(), "$"); + state.extract(assign_map, design, mod); state.finish(); } } From a54a673586dfeb91e857b2574927a153c7a7f1d7 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sun, 27 Jul 2025 23:44:41 +0000 Subject: [PATCH 8/8] Compute `is_port` in AbcPass without iterating through all cells and wires in the module every time we run ABC. This does not scale when we run ABC thousands of times in a single AbcPass. --- kernel/ffinit.h | 6 +- kernel/ffmerge.h | 2 +- kernel/hashlib.h | 3 +- kernel/sigtools.h | 172 +++++++++++++++++++++++++++++++++--------- passes/techmap/abc.cc | 172 +++++++++++++++++++++++++++++------------- 5 files changed, 264 insertions(+), 91 deletions(-) diff --git a/kernel/ffinit.h b/kernel/ffinit.h index 6d4c97ac3..66c13b68f 100644 --- a/kernel/ffinit.h +++ b/kernel/ffinit.h @@ -27,10 +27,10 @@ YOSYS_NAMESPACE_BEGIN struct FfInitVals { - const SigMap *sigmap; + const SigMapView *sigmap; dict> initbits; - void set(const SigMap *sigmap_, RTLIL::Module *module) + void set(const SigMapView *sigmap_, RTLIL::Module *module) { sigmap = sigmap_; initbits.clear(); @@ -126,7 +126,7 @@ struct FfInitVals initbits.clear(); } - FfInitVals (const SigMap *sigmap, RTLIL::Module *module) + FfInitVals (const SigMapView *sigmap, RTLIL::Module *module) { set(sigmap, module); } diff --git a/kernel/ffmerge.h b/kernel/ffmerge.h index 5428da324..028987503 100644 --- a/kernel/ffmerge.h +++ b/kernel/ffmerge.h @@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN struct FfMergeHelper { - const SigMap *sigmap; + const SigMapView *sigmap; RTLIL::Module *module; FfInitVals *initvals; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 4144d701d..fdde7696d 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -1327,7 +1327,8 @@ public: return p; } - // Merge sets if the given indices belong to different sets + // Merge sets if the given indices belong to different sets. + // Makes ifind(j) the root of the merged set. void imerge(int i, int j) { i = ifind(i); diff --git a/kernel/sigtools.h b/kernel/sigtools.h index 3b0d7b40d..7962eaa70 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -237,6 +237,42 @@ using sort_by_name_id_guard = typename std::enable_if class SigSet> : public SigSet::type>> {}; +struct SigMapView +{ + mfp database; + + // Modify bit to its representative + void apply(RTLIL::SigBit &bit) const + { + bit = database.find(bit); + } + + void apply(RTLIL::SigSpec &sig) const + { + for (auto &bit : sig) + apply(bit); + } + + RTLIL::SigBit operator()(RTLIL::SigBit bit) const + { + apply(bit); + return bit; + } + + RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const + { + apply(sig); + return sig; + } + + RTLIL::SigSpec operator()(RTLIL::Wire *wire) const + { + SigSpec sig(wire); + apply(sig); + return sig; + } +}; + /** * SigMap wraps a union-find "database" * to map SigBits of a module to canonical representative SigBits. @@ -244,10 +280,8 @@ class SigSet> : public SigSet database; - SigMap(RTLIL::Module *module = NULL) { if (module != NULL) @@ -320,37 +354,6 @@ struct SigMap inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); } - // Modify bit to its representative - void apply(RTLIL::SigBit &bit) const - { - bit = database.find(bit); - } - - void apply(RTLIL::SigSpec &sig) const - { - for (auto &bit : sig) - apply(bit); - } - - RTLIL::SigBit operator()(RTLIL::SigBit bit) const - { - apply(bit); - return bit; - } - - RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const - { - apply(sig); - return sig; - } - - RTLIL::SigSpec operator()(RTLIL::Wire *wire) const - { - SigSpec sig(wire); - apply(sig); - return sig; - } - // All non-const bits RTLIL::SigSpec allbits() const { @@ -362,6 +365,107 @@ struct SigMap } }; +/** + * SiValgMap wraps a union-find "database" to map SigBits of a module to + * canonical representative SigBits plus some optional Val value associated with the bits. + * Val has a commutative, associative, idempotent operator|=, a default constructor + * which constructs an identity element, and a copy constructor. + * SigBits that are connected share a set in the underlying database; + * the associated value is the "sum" of all the values associated with the contributing bits. + * If any of the SigBits in a set are a constant, the canonical SigBit is a constant. + */ +template +struct SigValMap final : public SigMapView +{ + dict values; + + void swap(SigValMap &other) + { + database.swap(other.database); + values.swap(other.values); + } + + void clear() + { + database.clear(); + values.clear(); + } + + // Rebuild SigMap for all connections in module + void set(RTLIL::Module *module) + { + int bitcount = 0; + for (auto &it : module->connections()) + bitcount += it.first.size(); + + database.clear(); + values.clear(); + database.reserve(bitcount); + + for (auto &it : module->connections()) + add(it.first, it.second); + } + + // Add connections from "from" to "to", bit-by-bit. + void add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to) + { + log_assert(GetSize(from) == GetSize(to)); + + for (int i = 0; i < GetSize(from); i++) + { + int bfi = database.lookup(from[i]); + int bti = database.lookup(to[i]); + if (bfi == bti) { + continue; + } + + const RTLIL::SigBit &bf = database[bfi]; + const RTLIL::SigBit &bt = database[bti]; + if (bf.wire == nullptr) { + // bf is constant so make it the canonical representative. + database.imerge(bti, bfi); + merge_value(bt, bf); + } else { + // Make bt the canonical representative. + database.imerge(bfi, bti); + merge_value(bf, bt); + } + } + } + + void addVal(const RTLIL::SigBit &bit, const Val &val) + { + values[database.find(bit)] |= val; + } + + void addVal(const RTLIL::SigSpec &sig, const Val &val) + { + for (const auto &bit : sig) + addVal(bit, val); + } + + Val apply_and_get_value(RTLIL::SigBit &bit) const + { + bit = database.find(bit); + auto it = values.find(bit); + return it == values.end() ? Val() : it->second; + } + +private: + void merge_value(const RTLIL::SigBit &from, const RTLIL::SigBit &to) + { + auto it = values.find(from); + if (it == values.end()) { + return; + } + // values[to] could resize the underlying `entries` so + // finish using `it` first. + Val v = it->second; + values.erase(it); + values[to] |= v; + } +}; + YOSYS_NAMESPACE_END #endif /* SIGTOOLS_H */ diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 8a2816307..e79566d3b 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -138,6 +138,18 @@ struct AbcConfig bool abc_dress = false; }; +struct AbcSigVal { + bool is_port; + + AbcSigVal(bool is_port = false) : is_port(is_port) {} + AbcSigVal &operator|=(const AbcSigVal &other) { + is_port |= other.is_port; + return *this; + } +}; + +using AbcSigMap = SigValMap; + struct AbcModuleState { const AbcConfig &config; @@ -161,21 +173,21 @@ struct AbcModuleState { AbcModuleState(const AbcConfig &config) : config(config) {} - int map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); - void mark_port(const SigMap &assign_map, RTLIL::SigSpec sig); - void extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); + int map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig); + bool extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(SigMap &assign_map, RTLIL::Module *module); - void abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, + void handle_loops(AbcSigMap &assign_map, RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); + void extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); void finish(); }; -int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) +int AbcModuleState::map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { - assign_map.apply(bit); + AbcSigVal val = assign_map.apply_and_get_value(bit); if (bit == State::Sx) undef_bits_lost++; @@ -188,7 +200,7 @@ int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate gate.in2 = -1; gate.in3 = -1; gate.in4 = -1; - gate.is_port = false; + gate.is_port = bit.wire != nullptr && val.is_port; gate.bit = bit; gate.init = initvals(bit); signal_list.push_back(gate); @@ -211,40 +223,40 @@ int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate return gate.id; } -void AbcModuleState::mark_port(const SigMap &assign_map, RTLIL::SigSpec sig) +void AbcModuleState::mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) +bool AbcModuleState::extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); gate_type_t type = G(FF); if (!ff.has_clk) - return; + return false; if (ff.has_gclk) - return; + return false; if (ff.has_aload) - return; + return false; if (ff.has_sr) - return; + return false; if (!ff.is_fine) - return; + return false; if (clk_polarity != ff.pol_clk) - return; + return false; if (clk_sig != assign_map(ff.sig_clk)) - return; + return false; if (ff.has_ce) { if (en_polarity != ff.pol_ce) - return; + return false; if (en_sig != assign_map(ff.sig_ce)) - return; + return false; } else { if (GetSize(en_sig) != 0) - return; + return false; } if (ff.val_init == State::S1) { type = G(FF1); @@ -255,39 +267,39 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul } if (ff.has_arst) { if (arst_polarity != ff.pol_arst) - return; + return false; if (arst_sig != assign_map(ff.sig_arst)) - return; + return false; if (ff.val_arst == State::S1) { if (type == G(FF0)) - return; + return false; type = G(FF1); } else if (ff.val_arst == State::S0) { if (type == G(FF1)) - return; + return false; type = G(FF0); } } else { if (GetSize(arst_sig) != 0) - return; + return false; } if (ff.has_srst) { if (srst_polarity != ff.pol_srst) - return; + return false; if (srst_sig != assign_map(ff.sig_srst)) - return; + return false; if (ff.val_srst == State::S1) { if (type == G(FF0)) - return; + return false; type = G(FF1); } else if (ff.val_srst == State::S0) { if (type == G(FF1)) - return; + return false; type = G(FF0); } } else { if (GetSize(srst_sig) != 0) - return; + return false; } int gate_id = map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); @@ -301,7 +313,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); ff.remove(); - return; + return true; } if (cell->type.in(ID($_BUF_), ID($_NOT_))) @@ -315,7 +327,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(assign_map, sig_a)); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) @@ -351,7 +363,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul log_abort(); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_MUX_), ID($_NMUX_))) @@ -373,7 +385,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AOI3_), ID($_OAI3_))) @@ -395,7 +407,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AOI4_), ID($_OAI4_))) @@ -420,8 +432,10 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); module->remove(cell); - return; + return true; } + + return false; } std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire) @@ -492,13 +506,13 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void connect(SigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) +void connect(AbcSigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) { module->connect(conn); assign_map.add(conn.first, conn.second); } -void AbcModuleState::handle_loops(SigMap &assign_map, RTLIL::Module *module) +void AbcModuleState::handle_loops(AbcSigMap &assign_map, RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -758,7 +772,7 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { initvals.set(&assign_map, module); @@ -943,18 +957,18 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, Si undef_bits_lost = 0; had_init = false; + std::vector kept_cells; for (auto c : cells) - extract_cell(assign_map, module, c, config.keepff); + if (!extract_cell(assign_map, module, c, config.keepff)) + kept_cells.push_back(c); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); - for (auto wire : module->wires()) { - if (wire->port_id > 0) - mark_port(assign_map, wire); - } - - for (auto cell : module->cells()) + // Wires with port_id > 0 and connections to cells outside our cell set have already + // been accounted for via AbcSigVal::is_port. Now we just need to account for + // connections to cells inside our cell set that weren't removed by extract_cell(). + for (auto cell : kept_cells) for (auto &port_it : cell->connections()) mark_port(assign_map, port_it.second); @@ -1213,7 +1227,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, Si log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) +void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -1510,6 +1524,47 @@ void AbcModuleState::finish() log_pop(); } +// For every signal that connects cells from different sets, or a cell in a set to a cell not in any set, +// mark it as a port in `assign_map`. +void assign_cell_connection_ports(RTLIL::Module *module, const std::vector *> &cell_sets, + AbcSigMap &assign_map) +{ + pool cells_in_no_set; + for (RTLIL::Cell *cell : module->cells()) { + cells_in_no_set.insert(cell); + } + // For every canonical signal in `assign_map`, the index of the set it is connected to, + // or -1 if it connects a cell in one set to a cell in another set or not in any set. + dict signal_cell_set; + for (int i = 0; i < int(cell_sets.size()); ++i) { + for (RTLIL::Cell *cell : *cell_sets[i]) { + cells_in_no_set.erase(cell); + for (auto &port_it : cell->connections()) { + for (SigBit bit : port_it.second) { + assign_map.apply(bit); + auto it = signal_cell_set.find(bit); + if (it == signal_cell_set.end()) + signal_cell_set[bit] = i; + else if (it->second >= 0 && it->second != i) { + it->second = -1; + assign_map.addVal(bit, AbcSigVal(true)); + } + } + } + } + } + for (RTLIL::Cell *cell : cells_in_no_set) { + for (auto &port_it : cell->connections()) { + for (SigBit bit : port_it.second) { + assign_map.apply(bit); + auto it = signal_cell_set.find(bit); + if (it != signal_cell_set.end() && it->second >= 0) + assign_map.addVal(bit, AbcSigVal(true)); + } + } + } +} + struct AbcPass : public Pass { AbcPass() : Pass("abc", "use ABC for technology mapping") { } void help() override @@ -2084,17 +2139,24 @@ struct AbcPass : public Pass { for (auto mod : design->selected_modules()) { - SigMap assign_map; - assign_map.set(mod); - if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } + AbcSigMap assign_map; + assign_map.set(mod); + + for (auto wire : mod->wires()) + if (wire->port_id > 0) + assign_map.addVal(SigSpec(wire), AbcSigVal(true)); + if (!dff_mode || !clk_str.empty()) { + std::vector cells = mod->selected_cells(); + assign_cell_connection_ports(mod, {&cells}, assign_map); + AbcModuleState state(config); - state.abc_module(design, mod, assign_map, mod->selected_cells(), dff_mode, clk_str); + state.abc_module(design, mod, assign_map, cells, dff_mode, clk_str); state.extract(assign_map, design, mod); state.finish(); continue; @@ -2250,6 +2312,12 @@ struct AbcPass : public Pass { std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)), std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); + { + std::vector*> cell_sets; + for (auto &it : assigned_cells) + cell_sets.push_back(&it.second); + assign_cell_connection_ports(mod, cell_sets, assign_map); + } for (auto &it : assigned_cells) { AbcModuleState state(config); state.clk_polarity = std::get<0>(it.first);