mirror of
https://github.com/YosysHQ/yosys
synced 2026-05-15 06:35:34 +00:00
Merge commit 'ab316c14d2' into abc-liberty-args
This commit is contained in:
commit
f8a50e7174
371 changed files with 15324 additions and 3587 deletions
|
|
@ -55,6 +55,7 @@ OBJS += passes/techmap/extractinv.o
|
|||
OBJS += passes/techmap/cellmatch.o
|
||||
OBJS += passes/techmap/clockgate.o
|
||||
OBJS += passes/techmap/constmap.o
|
||||
OBJS += passes/techmap/arith_tree.o
|
||||
endif
|
||||
|
||||
ifeq ($(DISABLE_SPAWN),0)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/ffinit.h"
|
||||
#include "kernel/ff.h"
|
||||
#include "kernel/cost.h"
|
||||
|
|
@ -63,13 +63,19 @@
|
|||
# include <fcntl.h>
|
||||
# include <spawn.h>
|
||||
# include <sys/wait.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#if defined(__wasm)
|
||||
#include <wasi/libc.h>
|
||||
#endif
|
||||
|
||||
#include "frontends/blif/blifparse.h"
|
||||
#include "liberty_cache.h"
|
||||
|
||||
#ifdef YOSYS_LINK_ABC
|
||||
namespace abc {
|
||||
|
|
@ -130,7 +136,6 @@ struct AbcConfig
|
|||
std::string delay_target;
|
||||
std::string sop_inputs;
|
||||
std::string sop_products;
|
||||
std::string lutin_shared;
|
||||
std::vector<std::string> dont_use_cells;
|
||||
bool cleanup = true;
|
||||
bool keepff = false;
|
||||
|
|
@ -292,6 +297,8 @@ struct RunAbcState {
|
|||
bool err = false;
|
||||
DeferredLogs logs;
|
||||
dict<int, std::string> pi_map, po_map;
|
||||
std::string abc_script;
|
||||
std::string dont_use_args;
|
||||
|
||||
RunAbcState(const AbcConfig &config) : config(config) {}
|
||||
void run(ConcurrentStack<AbcProcess> &process_pool);
|
||||
|
|
@ -1016,89 +1023,95 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
|
|||
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
|
||||
module->name.c_str(), replace_tempdir(run_abc.per_run_tempdir_name, config.global_tempdir_name, run_abc.per_run_tempdir_name, config.show_tempdir).c_str());
|
||||
|
||||
std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", run_abc.per_run_tempdir_name);
|
||||
run_abc.abc_script = stringf("read_blif \"%s/input.blif\"; ", run_abc.per_run_tempdir_name);
|
||||
|
||||
if (!config.liberty_files.empty() || !config.genlib_files.empty()) {
|
||||
std::string dont_use_args;
|
||||
run_abc.dont_use_args = "";
|
||||
for (std::string dont_use_cell : config.dont_use_cells) {
|
||||
dont_use_args += stringf("-X \"%s\" ", dont_use_cell);
|
||||
run_abc.dont_use_args += stringf("-X \"%s\" ", dont_use_cell);
|
||||
}
|
||||
bool first_lib = true;
|
||||
for (std::string liberty_file : config.liberty_files) {
|
||||
abc_script += stringf("read_lib %s %s %s -w \"%s\" ; ", dont_use_args, first_lib ? "" : "-m", config.abc_liberty_args, liberty_file);
|
||||
first_lib = false;
|
||||
|
||||
std::string merged_scl = convert_liberty_files_to_merged_scl(config.liberty_files, run_abc.dont_use_args, config.exe_file);
|
||||
if (!merged_scl.empty()) {
|
||||
run_abc.abc_script += stringf("read_scl \"%s\" ; ", merged_scl.c_str());
|
||||
} else if(!config.liberty_files.empty()) {
|
||||
log_warning("ABC: Merged scl conversion failed, using liberty format\n");
|
||||
bool first_lib = true;
|
||||
for (std::string liberty_file : config.liberty_files) {
|
||||
run_abc.abc_script += stringf("read_lib %s %s %s -w \"%s\" ; ", run_abc.dont_use_args, first_lib ? "" : "-m", config.abc_liberty_args, liberty_file);
|
||||
first_lib = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::string liberty_file : config.genlib_files)
|
||||
abc_script += stringf("read_library \"%s\"; ", liberty_file);
|
||||
run_abc.abc_script += stringf("read_library \"%s\"; ", liberty_file);
|
||||
if (!config.constr_file.empty())
|
||||
abc_script += stringf("read_constr -v \"%s\"; ", config.constr_file);
|
||||
run_abc.abc_script += stringf("read_constr -v \"%s\"; ", config.constr_file);
|
||||
} else
|
||||
if (!config.lut_costs.empty())
|
||||
abc_script += stringf("read_lut %s/lutdefs.txt; ", config.global_tempdir_name);
|
||||
run_abc.abc_script += stringf("read_lut %s/lutdefs.txt; ", config.global_tempdir_name);
|
||||
else
|
||||
abc_script += stringf("read_library %s/stdcells.genlib; ", config.global_tempdir_name);
|
||||
run_abc.abc_script += stringf("read_library %s/stdcells.genlib; ", config.global_tempdir_name);
|
||||
|
||||
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] == '\'')
|
||||
abc_script += "'\\''";
|
||||
run_abc.abc_script += "'\\''";
|
||||
else if (script_file[i] == ',')
|
||||
abc_script += " ";
|
||||
run_abc.abc_script += " ";
|
||||
else
|
||||
abc_script += script_file[i];
|
||||
run_abc.abc_script += script_file[i];
|
||||
} else
|
||||
abc_script += stringf("source %s", script_file);
|
||||
run_abc.abc_script += stringf("source %s", script_file);
|
||||
} else if (!config.lut_costs.empty()) {
|
||||
bool all_luts_cost_same = true;
|
||||
for (int this_cost : config.lut_costs)
|
||||
if (this_cost != config.lut_costs.front())
|
||||
all_luts_cost_same = false;
|
||||
abc_script += config.fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
|
||||
run_abc.abc_script += config.fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
|
||||
if (all_luts_cost_same && !config.fast_mode)
|
||||
abc_script += "; lutpack {S}";
|
||||
run_abc.abc_script += "; lutpack -S 1";
|
||||
} else if (!config.liberty_files.empty() || !config.genlib_files.empty())
|
||||
abc_script += config.constr_file.empty() ?
|
||||
run_abc.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;
|
||||
run_abc.abc_script += config.fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
|
||||
else
|
||||
abc_script += config.fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
|
||||
run_abc.abc_script += config.fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
|
||||
|
||||
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 = run_abc.abc_script.find("dretime;"); pos != std::string::npos; pos = run_abc.abc_script.find("dretime;", pos+1))
|
||||
run_abc.abc_script = run_abc.abc_script.substr(0, pos) + "dretime; retime -o {D};" + run_abc.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) + config.delay_target + abc_script.substr(pos+3);
|
||||
for (size_t pos = run_abc.abc_script.find("{D}"); pos != std::string::npos; pos = run_abc.abc_script.find("{D}", pos))
|
||||
run_abc.abc_script = run_abc.abc_script.substr(0, pos) + config.delay_target + run_abc.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) + config.sop_inputs + abc_script.substr(pos+3);
|
||||
for (size_t pos = run_abc.abc_script.find("{I}"); pos != std::string::npos; pos = run_abc.abc_script.find("{I}", pos))
|
||||
run_abc.abc_script = run_abc.abc_script.substr(0, pos) + config.sop_inputs + run_abc.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) + config.sop_products + abc_script.substr(pos+3);
|
||||
for (size_t pos = run_abc.abc_script.find("{P}"); pos != std::string::npos; pos = run_abc.abc_script.find("{P}", pos))
|
||||
run_abc.abc_script = run_abc.abc_script.substr(0, pos) + config.sop_products + run_abc.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) + config.lutin_shared + abc_script.substr(pos+3);
|
||||
if (config.abc_dress)
|
||||
abc_script += stringf("; dress \"%s/input.blif\"", run_abc.per_run_tempdir_name);
|
||||
abc_script += stringf("; write_blif %s/output.blif", run_abc.per_run_tempdir_name);
|
||||
abc_script = add_echos_to_abc_cmd(abc_script);
|
||||
run_abc.abc_script += stringf("; dress \"%s/input.blif\"", run_abc.per_run_tempdir_name);
|
||||
run_abc.abc_script += stringf("; write_blif %s/output.blif", run_abc.per_run_tempdir_name);
|
||||
run_abc.abc_script = add_echos_to_abc_cmd(run_abc.abc_script);
|
||||
#if defined(REUSE_YOSYS_ABC_PROCESSES)
|
||||
if (config.is_yosys_abc())
|
||||
abc_script += "; echo; echo \"YOSYS_ABC_DONE\"\n";
|
||||
run_abc.abc_script += "; echo; echo \"YOSYS_ABC_DONE\"\n";
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i+1 < abc_script.size(); i++)
|
||||
if (abc_script[i] == ';' && abc_script[i+1] == ' ')
|
||||
abc_script[i+1] = '\n';
|
||||
for (size_t i = 0; i+1 < run_abc.abc_script.size(); i++)
|
||||
if (run_abc.abc_script[i] == ';' && run_abc.abc_script[i+1] == ' ')
|
||||
run_abc.abc_script[i+1] = '\n';
|
||||
|
||||
std::string buffer = stringf("%s/abc.script", run_abc.per_run_tempdir_name);
|
||||
FILE *f = fopen(buffer.c_str(), "wt");
|
||||
if (f == nullptr)
|
||||
log_error("Opening %s for writing failed: %s\n", buffer, strerror(errno));
|
||||
fprintf(f, "%s\n", abc_script.c_str());
|
||||
fprintf(f, "%s\n", run_abc.abc_script.c_str());
|
||||
fclose(f);
|
||||
|
||||
if (dff_mode || !clk_str.empty())
|
||||
|
|
@ -1353,7 +1366,7 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &)
|
|||
logs.log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
|
||||
count_gates, GetSize(signal_list), count_input, count_output);
|
||||
if (count_output == 0) {
|
||||
log("Don't call ABC as there is nothing to map.\n");
|
||||
logs.log("Don't call ABC as there is nothing to map.\n");
|
||||
return;
|
||||
}
|
||||
int ret;
|
||||
|
|
@ -1367,13 +1380,13 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &)
|
|||
string temp_stdouterr_name = stringf("%s/stdouterr.txt", per_run_tempdir_name);
|
||||
FILE *temp_stdouterr_w = fopen(temp_stdouterr_name.c_str(), "w");
|
||||
if (temp_stdouterr_w == NULL)
|
||||
log_error("ABC: cannot open a temporary file for output redirection");
|
||||
logs.log_error("ABC: cannot open a temporary file for output redirection");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
FILE *old_stdout = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
|
||||
FILE *old_stderr = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
|
||||
#if defined(__wasm)
|
||||
#define fd_renumber(from, to) (void)__wasi_fd_renumber(from, to)
|
||||
#define fd_renumber(from, to) (void)__wasilibc_fd_renumber(from, to)
|
||||
#else
|
||||
#define fd_renumber(from, to) dup2(from, to)
|
||||
#endif
|
||||
|
|
@ -1412,10 +1425,10 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &)
|
|||
if (std::optional<AbcProcess> process_opt = process_pool.try_pop_back()) {
|
||||
process = std::move(process_opt.value());
|
||||
} else if (std::optional<AbcProcess> process_opt = spawn_abc(config.exe_file.c_str(), logs)) {
|
||||
process = std::move(process_opt.value());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
process = std::move(process_opt.value());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
std::string cmd = stringf(
|
||||
"empty\n"
|
||||
"source %s\n", tmp_script_name);
|
||||
|
|
@ -1880,7 +1893,7 @@ struct AbcPass : public Pass {
|
|||
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR));
|
||||
log("\n");
|
||||
log(" for -lut/-luts (only one LUT size):\n");
|
||||
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack {S}"));
|
||||
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack -S 1"));
|
||||
log("\n");
|
||||
log(" for -lut/-luts (different LUT sizes):\n");
|
||||
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT));
|
||||
|
|
@ -1948,10 +1961,6 @@ struct AbcPass : public Pass {
|
|||
log(" maximum number of SOP products.\n");
|
||||
log(" (replaces {P} in the default scripts above)\n");
|
||||
log("\n");
|
||||
log(" -S <num>\n");
|
||||
log(" maximum number of LUT inputs shared.\n");
|
||||
log(" (replaces {S} in the default scripts above, default: -S 1)\n");
|
||||
log("\n");
|
||||
log(" -lut <width>\n");
|
||||
log(" generate netlist using luts of (max) the specified width.\n");
|
||||
log("\n");
|
||||
|
|
@ -2066,11 +2075,6 @@ struct AbcPass : public Pass {
|
|||
if (design->scratchpad.count("abc.P")) {
|
||||
config.sop_products = "-P " + design->scratchpad_get_string("abc.P");
|
||||
}
|
||||
if (design->scratchpad.count("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);
|
||||
config.sop_mode = design->scratchpad_get_bool("abc.sop", false);
|
||||
|
|
@ -2153,10 +2157,6 @@ struct AbcPass : public Pass {
|
|||
config.sop_products = "-P " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-S" && argidx+1 < args.size()) {
|
||||
config.lutin_shared = "-S " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-lut" && argidx+1 < args.size()) {
|
||||
lut_arg = args[++argidx];
|
||||
continue;
|
||||
|
|
@ -2468,7 +2468,7 @@ struct AbcPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
|
||||
CellTypes ct(design);
|
||||
NewCellTypes ct(design);
|
||||
|
||||
std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
|
||||
pool<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
|
||||
|
|
|
|||
|
|
@ -38,53 +38,53 @@ struct Abc9Pass : public ScriptPass
|
|||
Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { }
|
||||
void on_register() override
|
||||
{
|
||||
RTLIL::constpad["abc9.script.default"] = "+&scorr; &sweep; &dc2; &dch -f -r; &ps; &if {C} {W} {D} {R} -v; &mfs";
|
||||
RTLIL::constpad["abc9.script.default.area"] = "+&scorr; &sweep; &dc2; &dch -f -r; &ps; &if {C} {W} {D} {R} -a -v; &mfs";
|
||||
RTLIL::constpad["abc9.script.default.fast"] = "+&if {C} {W} {D} {R} -v";
|
||||
RTLIL::constpad["abc9.script.default"] = "+&scorr; &sweep; &dc2; &dch -f -r; &ps; &if {W} {D} {R} -v; &mfs";
|
||||
RTLIL::constpad["abc9.script.default.area"] = "+&scorr; &sweep; &dc2; &dch -f -r; &ps; &if {W} {D} {R} -a -v; &mfs";
|
||||
RTLIL::constpad["abc9.script.default.fast"] = "+&if {W} {D} {R} -v";
|
||||
// Based on ABC's &flow
|
||||
RTLIL::constpad["abc9.script.flow"] = "+&scorr; &sweep;" \
|
||||
"&dch -C 500;" \
|
||||
/* Round 1 */ \
|
||||
/* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 1 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
"&st; &dsdb;" \
|
||||
/* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 2 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
"&st; &syn2 -m -R 10; &dsdb;" \
|
||||
"&blut -a -K 6;" \
|
||||
/* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 3 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Round 2 */ \
|
||||
"&st; &sopb;" \
|
||||
/* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 1 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
"&st; &dsdb;" \
|
||||
/* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 2 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
"&st; &syn2 -m -R 10; &dsdb;" \
|
||||
"&blut -a -K 6;" \
|
||||
/* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 3 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Round 3 */ \
|
||||
/* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 1 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
"&st; &dsdb;" \
|
||||
/* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
/* Map 2 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;" \
|
||||
"&st; &syn2 -m -R 10; &dsdb;" \
|
||||
"&blut -a -K 6;" \
|
||||
/* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;";
|
||||
/* Map 3 */ "&unmap; &if {W} {D} {R} -v; &save; &load; &mfs;";
|
||||
// Based on ABC's &flow2
|
||||
RTLIL::constpad["abc9.script.flow2"] = "+&scorr; &sweep;" \
|
||||
/* Comm1 */ "&synch2 -K 6 -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
|
||||
/* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
|
||||
/* Comm1 */ "&synch2 -K 6 -C 500; &if -m {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
|
||||
/* Comm2 */ "&dch -C 500; &if -m {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
|
||||
"&load; &st; &sopb -R 10 -C 4; " \
|
||||
/* Comm3 */ "&synch2 -K 6 -C 500; &if -m "/*"-E 5"*/" {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
|
||||
/* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save; "\
|
||||
/* Comm3 */ "&synch2 -K 6 -C 500; &if -m "/*"-E 5"*/" {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
|
||||
/* Comm2 */ "&dch -C 500; &if -m {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save; "\
|
||||
"&load";
|
||||
// Based on ABC's &flow3 -m
|
||||
RTLIL::constpad["abc9.script.flow3"] = "+&scorr; &sweep;" \
|
||||
"&if {C} {W} {D}; &save; &st; &syn2; &if {C} {W} {D} {R} -v; &save; &load;"\
|
||||
"&st; &if {C} -g -K 6; &dch -f; &if {C} {W} {D} {R} -v; &save; &load;"\
|
||||
"&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &save; &load;"\
|
||||
"&if {W} {D}; &save; &st; &syn2; &if {W} {D} {R} -v; &save; &load;"\
|
||||
"&st; &if -g -K 6; &dch -f; &if {W} {D} {R} -v; &save; &load;"\
|
||||
"&st; &if -g -K 6; &synch2; &if {W} {D} {R} -v; &save; &load;"\
|
||||
"&mfs";
|
||||
// As above, but with &mfs calls as in the original &flow3
|
||||
RTLIL::constpad["abc9.script.flow3mfs"] = "+&scorr; &sweep;" \
|
||||
"&if {C} {W} {D}; &save; &st; &syn2; &if {C} {W} {D} {R} -v; &save; &load;"\
|
||||
"&st; &if {C} -g -K 6; &dch -f; &if {C} {W} {D} {R} -v; &mfs; &save; &load;"\
|
||||
"&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &mfs; &save; &load;"\
|
||||
"&if {W} {D}; &save; &st; &syn2; &if {W} {D} {R} -v; &save; &load;"\
|
||||
"&st; &if -g -K 6; &dch -f; &if {W} {D} {R} -v; &mfs; &save; &load;"\
|
||||
"&st; &if -g -K 6; &synch2; &if {W} {D} {R} -v; &mfs; &save; &load;"\
|
||||
"&mfs";
|
||||
}
|
||||
void help() override
|
||||
|
|
@ -121,20 +121,11 @@ struct Abc9Pass : public ScriptPass
|
|||
log(" if no -script parameter is given, the following scripts are used:\n");
|
||||
log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)));
|
||||
log("\n");
|
||||
log(" -fast\n");
|
||||
log(" use different default scripts that are slightly faster (at the cost\n");
|
||||
log(" of output quality):\n");
|
||||
log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)));
|
||||
log("\n");
|
||||
log(" -D <picoseconds>\n");
|
||||
log(" set delay target. the string {D} in the default scripts above is\n");
|
||||
log(" replaced by this option when used, and an empty string otherwise\n");
|
||||
log(" (indicating best possible delay).\n");
|
||||
log("\n");
|
||||
// log(" -S <num>\n");
|
||||
// log(" maximum number of LUT inputs shared.\n");
|
||||
// log(" (replaces {S} in the default scripts above, default: -S 1)\n");
|
||||
// log("\n");
|
||||
log(" -lut <width>\n");
|
||||
log(" generate netlist using luts of (max) the specified width.\n");
|
||||
log("\n");
|
||||
|
|
@ -226,8 +217,7 @@ struct Abc9Pass : public ScriptPass
|
|||
exe_cmd << " " << arg << " " << args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-fast" || /* arg == "-dff" || */
|
||||
/* arg == "-nocleanup" || */ arg == "-showtmp") {
|
||||
if (arg == "-showtmp") {
|
||||
exe_cmd << " " << arg;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,15 @@
|
|||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/log.h"
|
||||
#include "liberty_cache.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
#if defined(__wasm)
|
||||
#include <wasi/libc.h>
|
||||
#endif
|
||||
|
||||
#ifdef YOSYS_LINK_ABC
|
||||
namespace abc {
|
||||
|
|
@ -165,7 +169,7 @@ struct abc9_output_filter
|
|||
};
|
||||
|
||||
void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe_file,
|
||||
vector<int> lut_costs, bool dff_mode, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
|
||||
vector<int> lut_costs, bool dff_mode, std::string delay_target,
|
||||
bool show_tempdir, std::string box_file, std::string lut_file,
|
||||
std::vector<std::string> liberty_files, std::string wire_delay, std::string tempdir_name,
|
||||
std::string constr_file, std::vector<std::string> dont_use_cells, std::vector<std::string> genlib_files)
|
||||
|
|
@ -181,11 +185,19 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
|
|||
for (std::string dont_use_cell : dont_use_cells) {
|
||||
dont_use_args += stringf("-X \"%s\" ", dont_use_cell);
|
||||
}
|
||||
bool first_lib = true;
|
||||
for (std::string liberty_file : liberty_files) {
|
||||
abc9_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args, first_lib ? "" : "-m", liberty_file);
|
||||
first_lib = false;
|
||||
|
||||
std::string merged_scl = convert_liberty_files_to_merged_scl(liberty_files, dont_use_args, exe_file);
|
||||
if (!merged_scl.empty()) {
|
||||
abc9_script += stringf("read_scl \"%s\" ; ", merged_scl.c_str());
|
||||
} else if(!liberty_files.empty()) {
|
||||
log_warning("ABC: Merged scl conversion failed, using liberty format\n");
|
||||
bool first_lib = true;
|
||||
for (std::string liberty_file : liberty_files) {
|
||||
abc9_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args, first_lib ? "" : "-m", liberty_file);
|
||||
first_lib = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!constr_file.empty())
|
||||
abc9_script += stringf("read_constr -v \"%s\"; ", constr_file);
|
||||
} else if (!genlib_files.empty()) {
|
||||
|
|
@ -210,26 +222,18 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
|
|||
} else
|
||||
abc9_script += stringf("source %s", script_file);
|
||||
} else if (!lut_costs.empty() || !lut_file.empty()) {
|
||||
abc9_script += fast_mode ? RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)
|
||||
: RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos);
|
||||
abc9_script += RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos);
|
||||
} else if (!liberty_files.empty() || !genlib_files.empty()) {
|
||||
abc9_script += RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos);
|
||||
} else
|
||||
log_abort();
|
||||
|
||||
for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos))
|
||||
abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3);
|
||||
|
||||
//for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos))
|
||||
// abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3);
|
||||
|
||||
for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos))
|
||||
abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3);
|
||||
|
||||
std::string C;
|
||||
if (design->scratchpad.count("abc9.if.C"))
|
||||
C = "-C " + design->scratchpad_get_string("abc9.if.C");
|
||||
for (size_t pos = abc9_script.find("{C}"); pos != std::string::npos; pos = abc9_script.find("{C}", pos))
|
||||
abc9_script = abc9_script.substr(0, pos) + C + abc9_script.substr(pos+3);
|
||||
|
||||
std::string R;
|
||||
if (design->scratchpad.count("abc9.if.R"))
|
||||
R = "-R " + design->scratchpad_get_string("abc9.if.R");
|
||||
|
|
@ -295,7 +299,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
|
|||
FILE *old_stdout = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
|
||||
FILE *old_stderr = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
|
||||
#if defined(__wasm)
|
||||
#define fd_renumber(from, to) (void)__wasi_fd_renumber(from, to)
|
||||
#define fd_renumber(from, to) (void)__wasilibc_fd_renumber(from, to)
|
||||
#else
|
||||
#define fd_renumber(from, to) dup2(from, to)
|
||||
#endif
|
||||
|
|
@ -369,11 +373,6 @@ struct Abc9ExePass : public Pass {
|
|||
log(" if no -script parameter is given, the following scripts are used:\n");
|
||||
log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)));
|
||||
log("\n");
|
||||
log(" -fast\n");
|
||||
log(" use different default scripts that are slightly faster (at the cost\n");
|
||||
log(" of output quality):\n");
|
||||
log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)));
|
||||
log("\n");
|
||||
log(" -constr <file>\n");
|
||||
log(" pass this file with timing constraints to ABC.\n");
|
||||
log(" use with -liberty.\n");
|
||||
|
|
@ -453,9 +452,9 @@ struct Abc9ExePass : public Pass {
|
|||
std::string exe_file = yosys_abc_executable;
|
||||
std::string script_file, clk_str, box_file, lut_file, constr_file;
|
||||
std::vector<std::string> liberty_files, genlib_files, dont_use_cells;
|
||||
std::string delay_target, lutin_shared = "-S 1", wire_delay;
|
||||
std::string delay_target, wire_delay;
|
||||
std::string tempdir_name;
|
||||
bool fast_mode = false, dff_mode = false;
|
||||
bool dff_mode = false;
|
||||
bool show_tempdir = false;
|
||||
vector<int> lut_costs;
|
||||
|
||||
|
|
@ -472,7 +471,6 @@ struct Abc9ExePass : public Pass {
|
|||
}
|
||||
lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg);
|
||||
luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg);
|
||||
fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode);
|
||||
dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode);
|
||||
show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir);
|
||||
box_file = design->scratchpad_get_string("abc9.box", box_file);
|
||||
|
|
@ -504,20 +502,12 @@ struct Abc9ExePass : public Pass {
|
|||
delay_target = "-D " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
//if (arg == "-S" && argidx+1 < args.size()) {
|
||||
// lutin_shared = "-S " + args[++argidx];
|
||||
// continue;
|
||||
//}
|
||||
if (arg == "-lut" && argidx+1 < args.size()) {
|
||||
lut_arg = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-luts" && argidx+1 < args.size()) {
|
||||
lut_arg = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-fast") {
|
||||
fast_mode = true;
|
||||
luts_arg = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dff") {
|
||||
|
|
@ -622,7 +612,7 @@ struct Abc9ExePass : public Pass {
|
|||
log_cmd_error("abc9_exe '-genlib' is incompatible with '-dont_use'.\n");
|
||||
|
||||
abc9_module(design, script_file, exe_file, lut_costs, dff_mode,
|
||||
delay_target, lutin_shared, fast_mode, show_tempdir,
|
||||
delay_target, show_tempdir,
|
||||
box_file, lut_file, liberty_files, wire_delay, tempdir_name,
|
||||
constr_file, dont_use_cells, genlib_files);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@
|
|||
#include "kernel/register.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/utils.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/timinginfo.h"
|
||||
#include <optional>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
|
@ -587,6 +588,7 @@ void break_scc(RTLIL::Module *module)
|
|||
auto id = it->second;
|
||||
auto r = ids_seen.insert(id);
|
||||
cell->attributes.erase(it);
|
||||
// Cut exactly one representative cell per SCC id.
|
||||
if (!r.second)
|
||||
continue;
|
||||
for (auto &c : cell->connections_) {
|
||||
|
|
@ -710,8 +712,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
|
|||
|
||||
SigMap sigmap(module);
|
||||
|
||||
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
|
||||
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
|
||||
dict<IdString, std::vector<IdString>> box_ports;
|
||||
|
||||
for (auto cell : module->cells()) {
|
||||
|
|
@ -750,39 +750,100 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (!yosys_celltypes.cell_known(cell->type))
|
||||
continue;
|
||||
|
||||
// TODO: Speed up toposort -- we care about box ordering only
|
||||
for (auto conn : cell->connections()) {
|
||||
if (cell->input(conn.first))
|
||||
for (auto bit : sigmap(conn.second))
|
||||
bit_users[bit].insert(cell->name);
|
||||
|
||||
if (cell->output(conn.first) && !abc9_flop)
|
||||
for (auto bit : sigmap(conn.second))
|
||||
bit_drivers[bit].insert(cell->name);
|
||||
}
|
||||
toposort.node(cell->name);
|
||||
}
|
||||
|
||||
if (box_ports.empty())
|
||||
return;
|
||||
|
||||
for (auto &it : bit_users)
|
||||
if (bit_drivers.count(it.first))
|
||||
for (auto driver_cell : bit_drivers.at(it.first))
|
||||
for (auto user_cell : it.second)
|
||||
toposort.edge(driver_cell, user_cell);
|
||||
// Build the same topo graph for the initial pass and the optional retry.
|
||||
auto build_toposort = [&](TopoSort<IdString, RTLIL::sort_by_id_str> &toposort) {
|
||||
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
|
||||
|
||||
if (ys_debug(1))
|
||||
toposort.analyze_loops = true;
|
||||
for (auto cell : module->cells()) {
|
||||
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
|
||||
continue;
|
||||
if (cell->has_keep_attr())
|
||||
continue;
|
||||
|
||||
bool no_loops = toposort.sort();
|
||||
auto inst_module = design->module(cell->type);
|
||||
bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop);
|
||||
if (abc9_flop && !dff)
|
||||
continue;
|
||||
if (!(inst_module && inst_module->get_bool_attribute(ID::abc9_box)) && !yosys_celltypes.cell_known(cell->type))
|
||||
continue;
|
||||
|
||||
// TODO: Speed up toposort -- we care about box ordering only
|
||||
for (auto conn : cell->connections()) {
|
||||
if (cell->input(conn.first))
|
||||
for (auto bit : sigmap(conn.second))
|
||||
bit_users[bit].insert(cell->name);
|
||||
|
||||
if (cell->output(conn.first) && !abc9_flop)
|
||||
for (auto bit : sigmap(conn.second))
|
||||
bit_drivers[bit].insert(cell->name);
|
||||
}
|
||||
toposort.node(cell->name);
|
||||
}
|
||||
|
||||
// Build producer -> consumer edges on sigmapped nets.
|
||||
for (auto &it : bit_users)
|
||||
if (bit_drivers.count(it.first))
|
||||
for (auto driver_cell : bit_drivers.at(it.first))
|
||||
for (auto user_cell : it.second)
|
||||
toposort.edge(driver_cell, user_cell);
|
||||
if (ys_debug(1))
|
||||
toposort.analyze_loops = true;
|
||||
return toposort.sort();
|
||||
};
|
||||
|
||||
// Build TopoSort in a container, as we may need to conditionally rebuild it on retry.
|
||||
std::optional<TopoSort<IdString, RTLIL::sort_by_id_str>> toposort;
|
||||
toposort.emplace();
|
||||
bool no_loops = build_toposort(toposort.value());
|
||||
|
||||
// Fallback for residual loops after SCC cutting: insert additional
|
||||
// breakers on non-box loop cells, then re-run toposort checks.
|
||||
if (!no_loops) {
|
||||
SigSpec I, O;
|
||||
pool<IdString> broken_cells;
|
||||
|
||||
for (auto &loop : toposort.value().loops)
|
||||
for (auto cell_name : loop) {
|
||||
// Loop reports can overlap; cut each cell at most once.
|
||||
if (!broken_cells.insert(cell_name).second)
|
||||
continue;
|
||||
auto cell = module->cell(cell_name);
|
||||
log_assert(cell);
|
||||
auto inst_module = design->module(cell->type);
|
||||
if (inst_module && inst_module->get_bool_attribute(ID::abc9_box))
|
||||
continue;
|
||||
for (auto &c : cell->connections_) {
|
||||
if (c.second.is_fully_const()) continue;
|
||||
if (cell->output(c.first)) {
|
||||
Wire *w = module->addWire(NEW_ID, GetSize(c.second));
|
||||
I.append(w);
|
||||
O.append(c.second);
|
||||
c.second = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!I.empty()) {
|
||||
auto cell = module->addCell(NEW_ID, ID($__ABC9_SCC_BREAKER));
|
||||
log_assert(GetSize(I) == GetSize(O));
|
||||
cell->setParam(ID::WIDTH, GetSize(I));
|
||||
cell->setPort(ID::I, std::move(I));
|
||||
cell->setPort(ID::O, std::move(O));
|
||||
|
||||
// Rebuild topo ordering after inserting the additional breakers.
|
||||
toposort.emplace();
|
||||
no_loops = build_toposort(toposort.value());
|
||||
}
|
||||
}
|
||||
|
||||
if (ys_debug(1)) {
|
||||
unsigned i = 0;
|
||||
for (auto &it : toposort.loops) {
|
||||
for (auto &it : toposort.value().loops) {
|
||||
log(" loop %d\n", i++);
|
||||
for (auto cell_name : it) {
|
||||
auto cell = module->cell(cell_name);
|
||||
|
|
@ -806,7 +867,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
|
|||
TimingInfo timing;
|
||||
|
||||
int port_id = 1, box_count = 0;
|
||||
for (auto cell_name : toposort.sorted) {
|
||||
for (auto cell_name : toposort.value().sorted) {
|
||||
RTLIL::Cell *cell = module->cell(cell_name);
|
||||
log_assert(cell);
|
||||
|
||||
|
|
@ -1559,7 +1620,6 @@ clone_lut:
|
|||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
|
|
@ -1592,7 +1652,7 @@ static void replace_zbufs(Design *design)
|
|||
if (sig[i] == State::Sz) {
|
||||
Wire *w = mod->addWire(NEW_ID);
|
||||
Cell *ud = mod->addCell(NEW_ID, ID($tribuf));
|
||||
ud->set_bool_attribute(ID(aiger2_zbuf));
|
||||
ud->set_bool_attribute(ID::aiger2_zbuf);
|
||||
ud->setParam(ID::WIDTH, 1);
|
||||
ud->setPort(ID::Y, w);
|
||||
ud->setPort(ID::EN, State::S0);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/yosys_common.h"
|
||||
#include "kernel/utils.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
|
@ -27,7 +27,8 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
std::vector<Module*> order_modules(Design *design, std::vector<Module *> modules)
|
||||
{
|
||||
std::set<Module *> modules_set(modules.begin(), modules.end());
|
||||
TopoSort<Module*> sort;
|
||||
using Order = IdString::compare_ptr_by_name<RTLIL::NamedObject>;
|
||||
TopoSort<Module*, Order> sort;
|
||||
|
||||
for (auto m : modules) {
|
||||
sort.node(m);
|
||||
|
|
@ -49,6 +50,17 @@ struct AbcNewPass : public ScriptPass {
|
|||
experimental();
|
||||
}
|
||||
|
||||
void on_register() override
|
||||
{
|
||||
RTLIL::constpad["abc_new.script.speed"] = "+&st; &dch -r;" \
|
||||
"&nf; &st; &syn2; &if -g -K 6; &synch2 -r;" \
|
||||
"&nf; &st; &syn2; &if -g -K 6; &synch2 -r;" \
|
||||
"&nf; &st; &syn2; &if -g -K 6; &synch2 -r;" \
|
||||
"&nf; &st; &syn2; &if -g -K 6; &synch2 -r;" \
|
||||
"&nf; &st; &syn2; &if -g -K 6; &synch2 -r;" \
|
||||
"&nf";
|
||||
}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
|
|
@ -109,6 +121,11 @@ struct AbcNewPass : public ScriptPass {
|
|||
}
|
||||
extra_args(args, argidx, d);
|
||||
|
||||
// If no script provided, use a default.
|
||||
if (abc_exe_options.find("-script") == std::string::npos) {
|
||||
d->scratchpad_set_string("abc9.script", RTLIL::constpad["abc_new.script.speed"]);
|
||||
}
|
||||
|
||||
log_header(d, "Executing ABC_NEW pass.\n");
|
||||
log_push();
|
||||
run_script(d, run_from, run_to);
|
||||
|
|
|
|||
426
passes/techmap/arith_tree.cc
Normal file
426
passes/techmap/arith_tree.cc
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
/**
|
||||
* Replaces chains of $add/$sub and $macc cells with carry-save adder trees
|
||||
*
|
||||
* Terminology:
|
||||
* - parent: Cells that consume another cell's output
|
||||
* - chainable: Adds/subs with no carry-out usage
|
||||
* - chain: Connected path of chainable cells
|
||||
*/
|
||||
|
||||
#include "kernel/macc.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/wallace_tree.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct Operand {
|
||||
SigSpec sig;
|
||||
bool is_signed;
|
||||
bool negate;
|
||||
};
|
||||
|
||||
struct Traversal {
|
||||
SigMap sigmap;
|
||||
dict<SigBit, pool<Cell *>> bit_consumers;
|
||||
dict<SigBit, int> fanout;
|
||||
Traversal(Module *module) : sigmap(module)
|
||||
{
|
||||
for (auto cell : module->cells())
|
||||
for (auto &conn : cell->connections())
|
||||
if (cell->input(conn.first))
|
||||
for (auto bit : sigmap(conn.second))
|
||||
bit_consumers[bit].insert(cell);
|
||||
|
||||
for (auto &pair : bit_consumers)
|
||||
fanout[pair.first] = pair.second.size();
|
||||
|
||||
for (auto wire : module->wires())
|
||||
if (wire->port_output)
|
||||
for (auto bit : sigmap(SigSpec(wire)))
|
||||
fanout[bit]++;
|
||||
}
|
||||
};
|
||||
|
||||
struct Cells {
|
||||
pool<Cell *> addsub;
|
||||
pool<Cell *> alu;
|
||||
pool<Cell *> macc;
|
||||
|
||||
static bool is_addsub(Cell *cell) { return cell->type == ID($add) || cell->type == ID($sub); }
|
||||
|
||||
static bool is_alu(Cell *cell) { return cell->type == ID($alu); }
|
||||
|
||||
static bool is_macc(Cell *cell) { return cell->type == ID($macc) || cell->type == ID($macc_v2); }
|
||||
|
||||
bool empty() { return addsub.empty() && alu.empty() && macc.empty(); }
|
||||
|
||||
Cells(Module *module)
|
||||
{
|
||||
for (auto cell : module->cells()) {
|
||||
if (is_addsub(cell))
|
||||
addsub.insert(cell);
|
||||
else if (is_alu(cell))
|
||||
alu.insert(cell);
|
||||
else if (is_macc(cell))
|
||||
macc.insert(cell);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct AluInfo {
|
||||
Cells &cells;
|
||||
Traversal &traversal;
|
||||
bool is_subtract(Cell *cell)
|
||||
{
|
||||
SigSpec bi = traversal.sigmap(cell->getPort(ID::BI));
|
||||
SigSpec ci = traversal.sigmap(cell->getPort(ID::CI));
|
||||
return GetSize(bi) == 1 && bi[0] == State::S1 && GetSize(ci) == 1 && ci[0] == State::S1;
|
||||
}
|
||||
|
||||
bool is_add(Cell *cell)
|
||||
{
|
||||
SigSpec bi = traversal.sigmap(cell->getPort(ID::BI));
|
||||
SigSpec ci = traversal.sigmap(cell->getPort(ID::CI));
|
||||
return GetSize(bi) == 1 && bi[0] == State::S0 && GetSize(ci) == 1 && ci[0] == State::S0;
|
||||
}
|
||||
|
||||
bool is_chainable(Cell *cell)
|
||||
{
|
||||
if (!(is_add(cell) || is_subtract(cell)))
|
||||
return false;
|
||||
|
||||
for (auto bit : traversal.sigmap(cell->getPort(ID::X)))
|
||||
if (traversal.fanout.count(bit) && traversal.fanout[bit] > 0)
|
||||
return false;
|
||||
for (auto bit : traversal.sigmap(cell->getPort(ID::CO)))
|
||||
if (traversal.fanout.count(bit) && traversal.fanout[bit] > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Rewriter {
|
||||
Module *module;
|
||||
Cells &cells;
|
||||
Traversal traversal;
|
||||
AluInfo alu_info;
|
||||
|
||||
Rewriter(Module *module, Cells &cells) : module(module), cells(cells), traversal(module), alu_info{cells, traversal} {}
|
||||
|
||||
Cell *sole_chainable_consumer(SigSpec sig, const pool<Cell *> &candidates)
|
||||
{
|
||||
Cell *consumer = nullptr;
|
||||
for (auto bit : sig) {
|
||||
if (!traversal.fanout.count(bit) || traversal.fanout[bit] != 1)
|
||||
return nullptr;
|
||||
if (!traversal.bit_consumers.count(bit) || traversal.bit_consumers[bit].size() != 1)
|
||||
return nullptr;
|
||||
|
||||
Cell *c = *traversal.bit_consumers[bit].begin();
|
||||
if (!candidates.count(c))
|
||||
return nullptr;
|
||||
|
||||
if (consumer == nullptr)
|
||||
consumer = c;
|
||||
else if (consumer != c)
|
||||
return nullptr;
|
||||
}
|
||||
return consumer;
|
||||
}
|
||||
|
||||
dict<Cell *, Cell *> find_parents(const pool<Cell *> &candidates)
|
||||
{
|
||||
dict<Cell *, Cell *> parent_of;
|
||||
for (auto cell : candidates) {
|
||||
Cell *consumer = sole_chainable_consumer(traversal.sigmap(cell->getPort(ID::Y)), candidates);
|
||||
if (consumer && consumer != cell)
|
||||
parent_of[cell] = consumer;
|
||||
}
|
||||
return parent_of;
|
||||
}
|
||||
|
||||
std::pair<dict<Cell *, pool<Cell *>>, pool<Cell *>> invert_parent_map(const dict<Cell *, Cell *> &parent_of)
|
||||
{
|
||||
dict<Cell *, pool<Cell *>> children_of;
|
||||
pool<Cell *> has_parent;
|
||||
for (auto &[child, parent] : parent_of) {
|
||||
children_of[parent].insert(child);
|
||||
has_parent.insert(child);
|
||||
}
|
||||
return {children_of, has_parent};
|
||||
}
|
||||
|
||||
pool<Cell *> collect_chain(Cell *root, const dict<Cell *, pool<Cell *>> &children_of)
|
||||
{
|
||||
pool<Cell *> chain;
|
||||
std::queue<Cell *> q;
|
||||
q.push(root);
|
||||
while (!q.empty()) {
|
||||
Cell *cur = q.front();
|
||||
q.pop();
|
||||
if (!chain.insert(cur).second)
|
||||
continue;
|
||||
auto it = children_of.find(cur);
|
||||
if (it != children_of.end())
|
||||
for (auto child : it->second)
|
||||
q.push(child);
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
pool<SigBit> internal_bits(const pool<Cell *> &chain)
|
||||
{
|
||||
pool<SigBit> bits;
|
||||
for (auto cell : chain)
|
||||
for (auto bit : traversal.sigmap(cell->getPort(ID::Y)))
|
||||
bits.insert(bit);
|
||||
return bits;
|
||||
}
|
||||
|
||||
static bool overlaps(SigSpec sig, const pool<SigBit> &bits)
|
||||
{
|
||||
for (auto bit : sig)
|
||||
if (bits.count(bit))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool feeds_subtracted_port(Cell *child, Cell *parent)
|
||||
{
|
||||
bool parent_subtracts;
|
||||
if (parent->type == ID($sub))
|
||||
parent_subtracts = true;
|
||||
else if (cells.is_alu(parent))
|
||||
parent_subtracts = alu_info.is_subtract(parent);
|
||||
else
|
||||
return false;
|
||||
|
||||
if (!parent_subtracts)
|
||||
return false;
|
||||
|
||||
// Check if any bit of child's Y connects to parent's B
|
||||
SigSpec child_y = traversal.sigmap(child->getPort(ID::Y));
|
||||
SigSpec parent_b = traversal.sigmap(parent->getPort(ID::B));
|
||||
for (auto bit : child_y)
|
||||
for (auto pbit : parent_b)
|
||||
if (bit == pbit)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Operand> extract_chain_operands(const pool<Cell *> &chain, Cell *root, const dict<Cell *, Cell *> &parent_of, int &neg_compensation)
|
||||
{
|
||||
pool<SigBit> chain_bits = internal_bits(chain);
|
||||
|
||||
// Propagate negation flags through chain
|
||||
dict<Cell *, bool> negated;
|
||||
negated[root] = false;
|
||||
{
|
||||
std::queue<Cell *> q;
|
||||
q.push(root);
|
||||
while (!q.empty()) {
|
||||
Cell *cur = q.front();
|
||||
q.pop();
|
||||
for (auto cell : chain) {
|
||||
if (!parent_of.count(cell) || parent_of.at(cell) != cur)
|
||||
continue;
|
||||
if (negated.count(cell))
|
||||
continue;
|
||||
negated[cell] = negated[cur] ^ feeds_subtracted_port(cell, cur);
|
||||
q.push(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract leaf operands
|
||||
std::vector<Operand> operands;
|
||||
neg_compensation = 0;
|
||||
|
||||
for (auto cell : chain) {
|
||||
bool cell_neg = negated.count(cell) ? negated[cell] : false;
|
||||
|
||||
SigSpec a = traversal.sigmap(cell->getPort(ID::A));
|
||||
SigSpec b = traversal.sigmap(cell->getPort(ID::B));
|
||||
bool a_signed = cell->getParam(ID::A_SIGNED).as_bool();
|
||||
bool b_signed = cell->getParam(ID::B_SIGNED).as_bool();
|
||||
bool b_sub = (cell->type == ID($sub)) || (cells.is_alu(cell) && alu_info.is_subtract(cell));
|
||||
|
||||
// Only add operands not produced by other chain cells
|
||||
if (!overlaps(a, chain_bits)) {
|
||||
operands.push_back({a, a_signed, cell_neg});
|
||||
if (cell_neg)
|
||||
neg_compensation++;
|
||||
}
|
||||
if (!overlaps(b, chain_bits)) {
|
||||
bool neg = cell_neg ^ b_sub;
|
||||
operands.push_back({b, b_signed, neg});
|
||||
if (neg)
|
||||
neg_compensation++;
|
||||
}
|
||||
}
|
||||
return operands;
|
||||
}
|
||||
|
||||
bool extract_macc_operands(Cell *cell, std::vector<Operand> &operands, int &neg_compensation)
|
||||
{
|
||||
Macc macc(cell);
|
||||
neg_compensation = 0;
|
||||
|
||||
for (auto &term : macc.terms) {
|
||||
// Bail on multiplication
|
||||
if (GetSize(term.in_b) != 0)
|
||||
return false;
|
||||
operands.push_back({term.in_a, term.is_signed, term.do_subtract});
|
||||
if (term.do_subtract)
|
||||
neg_compensation++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SigSpec extend_operand(SigSpec sig, bool is_signed, int width)
|
||||
{
|
||||
if (GetSize(sig) < width) {
|
||||
SigBit pad;
|
||||
if (is_signed && GetSize(sig) > 0)
|
||||
pad = sig[GetSize(sig) - 1];
|
||||
else
|
||||
pad = State::S0;
|
||||
sig.append(SigSpec(pad, width - GetSize(sig)));
|
||||
}
|
||||
if (GetSize(sig) > width)
|
||||
sig = sig.extract(0, width);
|
||||
return sig;
|
||||
}
|
||||
|
||||
void replace_with_carry_save_tree(std::vector<Operand> &operands, SigSpec result_y, int neg_compensation, const char *desc)
|
||||
{
|
||||
int width = GetSize(result_y);
|
||||
std::vector<SigSpec> extended;
|
||||
extended.reserve(operands.size() + 1);
|
||||
|
||||
for (auto &op : operands) {
|
||||
SigSpec s = extend_operand(op.sig, op.is_signed, width);
|
||||
if (op.negate)
|
||||
s = module->Not(NEW_ID, s);
|
||||
extended.push_back(s);
|
||||
}
|
||||
|
||||
// Add correction for negated operands (-x = ~x + 1 so 1 per negation)
|
||||
if (neg_compensation > 0)
|
||||
extended.push_back(SigSpec(neg_compensation, width));
|
||||
|
||||
int compressor_count;
|
||||
auto [a, b] = wallace_reduce_scheduled(module, extended, width, &compressor_count);
|
||||
log(" %s -> %d $fa + 1 $add (%d operands, module %s)\n", desc, compressor_count, (int)operands.size(), log_id(module));
|
||||
|
||||
// Emit final add
|
||||
module->addAdd(NEW_ID, a, b, result_y, false);
|
||||
}
|
||||
|
||||
void process_chains()
|
||||
{
|
||||
pool<Cell *> candidates;
|
||||
for (auto cell : cells.addsub)
|
||||
candidates.insert(cell);
|
||||
for (auto cell : cells.alu)
|
||||
if (alu_info.is_chainable(cell))
|
||||
candidates.insert(cell);
|
||||
|
||||
if (candidates.empty())
|
||||
return;
|
||||
|
||||
auto parent_of = find_parents(candidates);
|
||||
auto [children_of, has_parent] = invert_parent_map(parent_of);
|
||||
|
||||
pool<Cell *> to_remove;
|
||||
for (auto root : candidates) {
|
||||
if (has_parent.count(root) || to_remove.count(root))
|
||||
continue; // Not a tree root
|
||||
|
||||
pool<Cell *> chain = collect_chain(root, children_of);
|
||||
if (chain.size() < 2)
|
||||
continue;
|
||||
|
||||
int neg_compensation;
|
||||
auto operands = extract_chain_operands(chain, root, parent_of, neg_compensation);
|
||||
if (operands.size() < 3)
|
||||
continue;
|
||||
|
||||
for (auto c : chain)
|
||||
to_remove.insert(c);
|
||||
|
||||
replace_with_carry_save_tree(operands, root->getPort(ID::Y), neg_compensation, "Replaced add/sub chain");
|
||||
}
|
||||
|
||||
for (auto cell : to_remove)
|
||||
module->remove(cell);
|
||||
}
|
||||
|
||||
void process_maccs()
|
||||
{
|
||||
for (auto cell : cells.macc) {
|
||||
std::vector<Operand> operands;
|
||||
int neg_compensation;
|
||||
if (!extract_macc_operands(cell, operands, neg_compensation))
|
||||
continue;
|
||||
if (operands.size() < 3)
|
||||
continue;
|
||||
|
||||
replace_with_carry_save_tree(operands, cell->getPort(ID::Y), neg_compensation, "Replaced $macc");
|
||||
module->remove(cell);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void run(Module *module)
|
||||
{
|
||||
Cells cells(module);
|
||||
|
||||
if (cells.empty())
|
||||
return;
|
||||
|
||||
Rewriter rewriter{module, cells};
|
||||
rewriter.process_chains();
|
||||
rewriter.process_maccs();
|
||||
}
|
||||
|
||||
struct ArithTreePass : public Pass {
|
||||
ArithTreePass() : Pass("arith_tree", "convert add/sub/macc chains to carry-save adder trees") {}
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" arith_tree [selection]\n");
|
||||
log("\n");
|
||||
log("This pass replaces chains of $add/$sub cells, $alu cells (with constant\n");
|
||||
log("BI/CI), and $macc/$macc_v2 cells (without multiplications) with carry-save\n");
|
||||
log("adder trees using $fa cells and a single final $add.\n");
|
||||
log("\n");
|
||||
log("The tree uses Wallace-tree scheduling: at each level, ready operands are\n");
|
||||
log("grouped into triplets and compressed via full adders, giving\n");
|
||||
log("O(log_{1.5} N) depth for N input operands.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing ARITH_TREE pass.\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
break;
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
run(module);
|
||||
}
|
||||
}
|
||||
} ArithTreePass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
@ -58,6 +58,7 @@ synth -top my_design -booth
|
|||
#include "kernel/sigtools.h"
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/macc.h"
|
||||
#include "kernel/wallace_tree.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
|
@ -317,36 +318,6 @@ struct BoothPassWorker {
|
|||
}
|
||||
}
|
||||
|
||||
SigSig WallaceSum(int width, std::vector<SigSpec> summands)
|
||||
{
|
||||
for (auto &s : summands)
|
||||
s.extend_u0(width);
|
||||
|
||||
while (summands.size() > 2) {
|
||||
std::vector<SigSpec> new_summands;
|
||||
int i;
|
||||
for (i = 0; i < (int) summands.size() - 2; i += 3) {
|
||||
SigSpec x = module->addWire(NEW_ID, width);
|
||||
SigSpec y = module->addWire(NEW_ID, width);
|
||||
BuildBitwiseFa(module, NEW_ID.str(), summands[i], summands[i + 1],
|
||||
summands[i + 2], x, y);
|
||||
new_summands.push_back(y);
|
||||
new_summands.push_back({x.extract(0, width - 1), State::S0});
|
||||
}
|
||||
|
||||
new_summands.insert(new_summands.begin(), summands.begin() + i, summands.end());
|
||||
|
||||
std::swap(summands, new_summands);
|
||||
}
|
||||
|
||||
if (!summands.size())
|
||||
return SigSig(SigSpec(width, State::S0), SigSpec(width, State::S0));
|
||||
else if (summands.size() == 1)
|
||||
return SigSig(summands[0], SigSpec(width, State::S0));
|
||||
else
|
||||
return SigSig(summands[0], summands[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
Build Multiplier.
|
||||
-------------------------
|
||||
|
|
@ -415,16 +386,16 @@ struct BoothPassWorker {
|
|||
// Later on yosys will clean up unused constants
|
||||
// DebugDumpAlignPP(aligned_pp);
|
||||
|
||||
SigSig wtree_sum = WallaceSum(z_sz, aligned_pp);
|
||||
auto [wtree_a, wtree_b] = wallace_reduce_scheduled(module, aligned_pp, z_sz);
|
||||
|
||||
// Debug code: Dump out the csa trees
|
||||
// DumpCSATrees(debug_csa_trees);
|
||||
// Build the CPA to do the final accumulation.
|
||||
log_assert(wtree_sum.second[0] == State::S0);
|
||||
log_assert(wtree_b[0] == State::S0);
|
||||
if (mapped_cpa)
|
||||
BuildCPA(module, wtree_sum.first, {State::S0, wtree_sum.second.extract_end(1)}, Z);
|
||||
BuildCPA(module, wtree_a, wtree_b, Z);
|
||||
else
|
||||
module->addAdd(NEW_ID, wtree_sum.first, {wtree_sum.second.extract_end(1), State::S0}, Z);
|
||||
module->addAdd(NEW_ID, wtree_a, wtree_b, Z);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ struct ConstmapPass : public Pass {
|
|||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (celltype.empty())
|
||||
log_cmd_error("Missing required option -cell.\n");
|
||||
|
||||
if (design->has(celltype)) {
|
||||
Module *existing = design->module(celltype);
|
||||
|
|
|
|||
145
passes/techmap/liberty_cache.h
Normal file
145
passes/techmap/liberty_cache.h
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#ifndef LIBERTY_CACHE_H
|
||||
#define LIBERTY_CACHE_H
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#ifdef YOSYS_LINK_ABC
|
||||
namespace abc {
|
||||
int Abc_RealMain(int argc, char *argv[]);
|
||||
}
|
||||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
/*
|
||||
* convert_liberty_files_to_merged_scl() - Convert multiple Liberty files to a single merged SCL cache file.
|
||||
* @liberty_files: Vector of liberty file paths to merge
|
||||
* @dont_use_args: Pre-built ABC -X flags string
|
||||
* @abc_exe: Path to ABC executable for conversion
|
||||
*
|
||||
* Return: Path to merged SCL cache file, or empty string if conversion fails
|
||||
*/
|
||||
inline std::string convert_liberty_files_to_merged_scl(const std::vector<std::string> &liberty_files, const std::string &dont_use_args, const std::string &abc_exe)
|
||||
{
|
||||
if (liberty_files.empty())
|
||||
return "";
|
||||
|
||||
std::string cache_dir = get_base_tmpdir() + "/yosys-liberty-scl-cache";
|
||||
|
||||
if (!create_directory(cache_dir)) {
|
||||
log_warning("ABC: cannot create cache directory %s, falling back to liberty format\n", cache_dir.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
// Sort to ensure consistent hash regardless of order
|
||||
std::vector<std::string> sorted_files = liberty_files;
|
||||
std::sort(sorted_files.begin(), sorted_files.end());
|
||||
std::string hash_input;
|
||||
time_t newest_mtime = 0;
|
||||
|
||||
for (const std::string &liberty_file : sorted_files) {
|
||||
struct stat liberty_stat;
|
||||
if (stat(liberty_file.c_str(), &liberty_stat) != 0) {
|
||||
log_error("ABC: cannot stat liberty file: %s\n", liberty_file.c_str());
|
||||
return "";
|
||||
}
|
||||
hash_input += liberty_file + "|";
|
||||
if (liberty_stat.st_mtime > newest_mtime)
|
||||
newest_mtime = liberty_stat.st_mtime;
|
||||
}
|
||||
|
||||
hash_input += dont_use_args;
|
||||
unsigned int hash = 0;
|
||||
|
||||
for (char c : hash_input)
|
||||
hash = hash * 31 + c;
|
||||
|
||||
std::string merged_scl = stringf("%s/yosys_merged_%08x.scl", cache_dir.c_str(), hash);
|
||||
bool need_convert = true;
|
||||
struct stat scl_stat;
|
||||
|
||||
// Check if merged SCL exists and is newer than all liberty files
|
||||
if (stat(merged_scl.c_str(), &scl_stat) == 0) {
|
||||
if (scl_stat.st_mtime >= newest_mtime) {
|
||||
log("ABC: using cached merged SCL: %s (%zu files)\n", merged_scl.c_str(), liberty_files.size());
|
||||
need_convert = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_convert) {
|
||||
// read_lib -X cell1 -X cell2 file1 ; read_lib -X cell1 -X cell2 -m file2 ; ... ; write_scl merged.scl
|
||||
std::string temp_scl = merged_scl + ".tmp";
|
||||
|
||||
#ifdef YOSYS_LINK_ABC
|
||||
std::string script_path = stringf("%s/yosys_merged_scl_convert_%08x.script", cache_dir.c_str(), hash);
|
||||
FILE *f = fopen(script_path.c_str(), "w");
|
||||
|
||||
if (f == NULL) {
|
||||
log_warning("ABC: cannot open %s for writing, falling back to liberty format\n", script_path.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
|
||||
for (const std::string &liberty_file : liberty_files) {
|
||||
fprintf(f, "read_lib %s%s-w \"%s\"\n", dont_use_args.c_str(), first ? "" : "-m ", liberty_file.c_str());
|
||||
first = false;
|
||||
}
|
||||
|
||||
fprintf(f, "write_scl \"%s\"\n", temp_scl.c_str());
|
||||
fclose(f);
|
||||
|
||||
char *abc_argv[5];
|
||||
abc_argv[0] = strdup(abc_exe.empty() ? "yosys-abc" : abc_exe.c_str());
|
||||
abc_argv[1] = strdup("-s");
|
||||
abc_argv[2] = strdup("-f");
|
||||
abc_argv[3] = strdup(script_path.c_str());
|
||||
abc_argv[4] = 0;
|
||||
int ret = abc::Abc_RealMain(4, abc_argv);
|
||||
free(abc_argv[0]);
|
||||
free(abc_argv[1]);
|
||||
free(abc_argv[2]);
|
||||
free(abc_argv[3]);
|
||||
remove(script_path.c_str());
|
||||
|
||||
if (ret != 0) {
|
||||
log_warning("ABC: merged SCL conversion failed (ret=%d), falling back to liberty format\n", ret);
|
||||
remove(temp_scl.c_str());
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
std::string abc_script;
|
||||
bool first = true;
|
||||
|
||||
for (const std::string &liberty_file : liberty_files) {
|
||||
abc_script += stringf("read_lib %s%s-w \\\"%s\\\" ; ", dont_use_args.c_str(), first ? "" : "-m ", liberty_file.c_str());
|
||||
first = false;
|
||||
}
|
||||
|
||||
abc_script += stringf("write_scl \\\"%s\\\"", temp_scl.c_str());
|
||||
std::string cmd = stringf("\"%s\" -c \"%s\" 2>&1", abc_exe.c_str(), abc_script.c_str());
|
||||
std::string abc_output;
|
||||
int ret = run_command(cmd, [&abc_output](const std::string &line) { abc_output += line + "\n"; });
|
||||
|
||||
if (ret != 0) {
|
||||
log_warning("ABC: merged SCL conversion failed, falling back to liberty format\n");
|
||||
if (!abc_output.empty()) {
|
||||
log("ABC: conversion output:\n%s", abc_output.c_str());
|
||||
}
|
||||
remove(temp_scl.c_str());
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
if (rename(temp_scl.c_str(), merged_scl.c_str()) != 0) {
|
||||
log_warning("ABC: failed to rename %s to %s, falling back to liberty format\n", temp_scl.c_str(), merged_scl.c_str());
|
||||
remove(temp_scl.c_str());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return merged_scl;
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif // LIBERTY_CACHE_H
|
||||
|
|
@ -438,6 +438,48 @@ void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell)
|
|||
}
|
||||
}
|
||||
|
||||
void simplemap_pmux(RTLIL::Module *module, RTLIL::Cell *cell)
|
||||
{
|
||||
RTLIL::SigSpec sig_a = cell->getPort(ID::A);
|
||||
RTLIL::SigSpec sig_b = cell->getPort(ID::B);
|
||||
RTLIL::SigSpec sig_s = cell->getPort(ID::S);
|
||||
RTLIL::SigSpec sig_y = cell->getPort(ID::Y);
|
||||
|
||||
int width = GetSize(sig_a);
|
||||
int s_width = GetSize(sig_s);
|
||||
|
||||
// Implement: |S
|
||||
RTLIL::SigSpec any_s = sig_s;
|
||||
logic_reduce(module, any_s, cell);
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
RTLIL::SigSpec b_and_bits;
|
||||
|
||||
// Implement: B_AND_BITS = B_AND_S[WIDTH*j+i]
|
||||
for (int j = 0; j < s_width; j++) {
|
||||
RTLIL::Cell *and_gate = module->addCell(NEW_ID, ID($_AND_));
|
||||
transfer_src(and_gate, cell);
|
||||
and_gate->setPort(ID::A, sig_b[j * width + i]);
|
||||
and_gate->setPort(ID::B, sig_s[j]);
|
||||
|
||||
RTLIL::SigSpec and_y = module->addWire(NEW_ID, 1);
|
||||
and_gate->setPort(ID::Y, and_y);
|
||||
b_and_bits.append(and_y);
|
||||
}
|
||||
|
||||
// Implement: Y_B[i] = |B_AND_BITS
|
||||
logic_reduce(module, b_and_bits, cell);
|
||||
|
||||
// Implement: Y[i] = |S ? Y_B[i] : A[i]
|
||||
RTLIL::Cell *mux_gate = module->addCell(NEW_ID, ID($_MUX_));
|
||||
transfer_src(mux_gate, cell);
|
||||
mux_gate->setPort(ID::A, sig_a[i]);
|
||||
mux_gate->setPort(ID::B, b_and_bits);
|
||||
mux_gate->setPort(ID::S, any_s);
|
||||
mux_gate->setPort(ID::Y, sig_y[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
|
||||
{
|
||||
mappers[ID($not)] = simplemap_not;
|
||||
|
|
@ -461,6 +503,7 @@ void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)>
|
|||
mappers[ID($ne)] = simplemap_eqne;
|
||||
mappers[ID($nex)] = simplemap_eqne;
|
||||
mappers[ID($mux)] = simplemap_mux;
|
||||
mappers[ID($pmux)] = simplemap_pmux;
|
||||
mappers[ID($bwmux)] = simplemap_bwmux;
|
||||
mappers[ID($tribuf)] = simplemap_tribuf;
|
||||
mappers[ID($bmux)] = simplemap_bmux;
|
||||
|
|
@ -515,7 +558,7 @@ struct SimplemapPass : public Pass {
|
|||
log("\n");
|
||||
log(" $not, $pos, $and, $or, $xor, $xnor\n");
|
||||
log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n");
|
||||
log(" $logic_not, $logic_and, $logic_or, $mux, $tribuf\n");
|
||||
log(" $logic_not, $logic_and, $logic_or, $mux, $pmux, $tribuf\n");
|
||||
log(" $sr, $ff, $dff, $dffe, $dffsr, $dffsre, $adff, $adffe, $aldff, $aldffe, $sdff,\n");
|
||||
log(" $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n");
|
||||
log("\n");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue