diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 07f9ee45d..03a4c9cfc 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -703,11 +703,19 @@ struct abc_output_filter } }; -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, +// substitute every instance of 'placeholder' in 'str' with 'replacement' +void substitute(std::string &str, const std::string &placeholder, const std::string &replacement) { + for (size_t pos = str.find(placeholder); pos != std::string::npos; pos = str.find(placeholder, pos)) { + str = str.substr(0, pos) + replacement + str.substr(pos + placeholder.length()); + } +} + +void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, + std::string input_file, std::string output_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) + const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells, + bool custom_flow) { module = current_module; map_autoidx = autoidx++; @@ -717,6 +725,122 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin pi_map.clear(); po_map.clear(); + std::string tempdir_name; + if (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/%s'..\n", + module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str(), input_file.c_str()); + + + // load in user provided script + std::string user_script = ""; + if (!script_file.empty()) { + if (script_file[0] == '+') { // inline user script + for (size_t i = 1; i < script_file.size(); i++) + if (script_file[i] == '\'') + user_script += "'\\''"; + else if (script_file[i] == ',') + user_script += " "; + else + user_script += script_file[i]; + } else { + // read in user script + std::ifstream ifs(script_file.c_str()); + if(ifs.is_open()) { + user_script.assign( (std::istreambuf_iterator(ifs) ), + (std::istreambuf_iterator() ) ); + } else { + log_error("Opening %s for reading failed\n", script_file.c_str()); + } + } + } + + std::string abc_script; + // in a custom flow the user-script handles everything itself + if(custom_flow == false) { + abc_script = stringf("read_blif \"%s/%s\"; ", tempdir_name.c_str(), input_file.c_str()); // read netlist into ABC + + // load libraries and constraints + if (!liberty_files.empty() || !genlib_files.empty()) { + std::string dont_use_args; + for (std::string dont_use_cell : 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) { + 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) + 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()); + } else if (!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()); + + // add user script or build optimization script + if (user_script.length() > 0) { + abc_script += "\n\n" + user_script + "\n\n"; + } else if (!lut_costs.empty()) { + bool all_luts_cost_same = true; + for (int this_cost : lut_costs) + if (this_cost != 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 += "; 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 + abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; + + if (script_file.empty() && !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); + + if (abc_dress) + abc_script += stringf("; dress \"%s/%s\"", tempdir_name.c_str(), input_file.c_str()); + + // set output location + abc_script += stringf("; write_blif %s/%s", tempdir_name.c_str(), output_file.c_str()); + abc_script = add_echos_to_abc_cmd(abc_script); + + for (size_t i = 0; i+1 < abc_script.size(); i++) + if (abc_script[i] == ';' && abc_script[i+1] == ' ') + abc_script[i+1] = '\n'; + } else { + // user provides a custom flow script + if(user_script.length() > 0) { + abc_script = user_script; + } else { + log_error("Flag -customflow requires -script \n"); + } + } + + // replace placeholders in abc.script + substitute(abc_script, "{D}", delay_target); + substitute(abc_script, "{I}", sop_inputs); + substitute(abc_script, "{P}", sop_products); + substitute(abc_script, "{S}", lutin_shared); + substitute(abc_script, "{tmpdir}", tempdir_name.c_str()); + + // write script file + std::string buffer = stringf("%s/abc.script", tempdir_name.c_str()); + FILE *f = fopen(buffer.c_str(), "wt"); + if (f == nullptr) + log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); + fprintf(f, "%s\n", abc_script.c_str()); + fclose(f); + + // parse clock domain if (clk_str != "$") { clk_polarity = true; @@ -787,95 +911,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (dff_mode && clk_sig.empty()) log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); - std::string tempdir_name; - if (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()); - - std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str()); - - if (!liberty_files.empty() || !genlib_files.empty()) { - std::string dont_use_args; - for (std::string dont_use_cell : 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) { - 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) - 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()); - } else - if (!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 (script_file[0] == '+') { - for (size_t i = 1; i < script_file.size(); i++) - if (script_file[i] == '\'') - abc_script += "'\\''"; - else if (script_file[i] == ',') - abc_script += " "; - else - abc_script += script_file[i]; - } else - abc_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty()) { - bool all_luts_cost_same = true; - for (int this_cost : lut_costs) - if (this_cost != 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 += "; 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 - abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; - - if (script_file.empty() && !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); - - 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); - - 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); - - 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 += 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); - - for (size_t i = 0; i+1 < abc_script.size(); i++) - if (abc_script[i] == ';' && abc_script[i+1] == ' ') - abc_script[i+1] = '\n'; - - std::string buffer = stringf("%s/abc.script", tempdir_name.c_str()); - FILE *f = fopen(buffer.c_str(), "wt"); - if (f == nullptr) - log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - fprintf(f, "%s\n", abc_script.c_str()); - fclose(f); - if (dff_mode || !clk_str.empty()) { if (clk_sig.size() == 0) @@ -924,7 +959,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin handle_loops(); - buffer = stringf("%s/input.blif", tempdir_name.c_str()); + buffer = stringf("%s/%s", tempdir_name.c_str(), input_file.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)); @@ -1158,7 +1193,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin 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"); + buffer = stringf("%s/%s", tempdir_name.c_str(), output_file.c_str()); std::ifstream ifs; ifs.open(buffer); if (ifs.fail()) @@ -1633,6 +1668,18 @@ struct AbcPass : public Pass { log(" preserve naming by an equivalence check between the original and\n"); log(" post-ABC netlists (experimental).\n"); log("\n"); + log(" -customflow\n"); + log(" User script defines the full ABC flow, not just optimization.\n"); + log(" Yosys will no longer generate a script to read and write snippets.\n"); + log(" The script is processed and copied to {tmpdir}/abc.script.\n"); + log(" The following additional placeholder can be used:\n"); + log(" {tmpdir}: execution directory for ABC call\n"); + log(" {input}: generated snippet file to be processed in ABC\n"); + log(" {output}: processed ABC output file\n"); + log(" in/out can be set via the scratchpad, the defaults are:\n"); + log(" abc.input = input.blif\n"); + log(" abc.output = output.blif\n"); + log("\n"); log("When no target cell library is specified the Yosys standard cell library is\n"); log("loaded into ABC before the ABC script is executed.\n"); log("\n"); @@ -1661,10 +1708,13 @@ struct AbcPass : public Pass { 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 input_file = "input.blif"; + std::string output_file = "output.blif"; 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; + bool custom_flow = false; vector lut_costs; markgroups = false; @@ -1699,6 +1749,7 @@ struct AbcPass : public Pass { 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); + custom_flow = design->scratchpad_get_bool("abc.customflow", custom_flow); g_arg = design->scratchpad_get_string("abc.g", g_arg); fast_mode = design->scratchpad_get_bool("abc.fast", fast_mode); @@ -1799,6 +1850,10 @@ struct AbcPass : public Pass { abc_dress = true; continue; } + if (arg == "-customflow") { + custom_flow = true; + continue; + } if (arg == "-g" && argidx+1 < args.size()) { if (g_arg_from_cmd) log_cmd_error("Can only use -g once. Please combine."); @@ -1840,6 +1895,11 @@ struct AbcPass : public Pass { } extra_args(args, argidx, design); + if(custom_flow) { + input_file = design->scratchpad_get_string("abc.input", input_file); + output_file = design->scratchpad_get_string("abc.output", output_file); + } + if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty()) liberty_files.push_back(default_liberty_file); @@ -2052,8 +2112,8 @@ struct AbcPass : public Pass { 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, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); + abc_module(design, mod, script_file, exe_file, input_file, output_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, custom_flow); continue; } @@ -2214,8 +2274,8 @@ struct AbcPass : public Pass { 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(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); + abc_module(design, mod, script_file, exe_file, input_file, output_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !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, custom_flow); assign_map.set(mod); } }