mirror of
https://github.com/YosysHQ/yosys
synced 2026-03-02 19:56:57 +00:00
Merge branch 'main' into emil/turbo-celltypes
This commit is contained in:
commit
2a2c91e78a
265 changed files with 11258 additions and 3014 deletions
|
|
@ -39,6 +39,7 @@ OBJS += passes/techmap/muxcover.o
|
|||
OBJS += passes/techmap/aigmap.o
|
||||
OBJS += passes/techmap/tribuf.o
|
||||
OBJS += passes/techmap/lut2mux.o
|
||||
OBJS += passes/techmap/lut2bmux.o
|
||||
OBJS += passes/techmap/nlutmap.o
|
||||
OBJS += passes/techmap/shregmap.o
|
||||
OBJS += passes/techmap/deminout.o
|
||||
|
|
|
|||
|
|
@ -143,6 +143,14 @@ struct AbcConfig
|
|||
bool markgroups = false;
|
||||
pool<std::string> enabled_gates;
|
||||
bool cmos_cost = false;
|
||||
|
||||
bool is_yosys_abc() const {
|
||||
#ifdef ABCEXTERNAL
|
||||
return false;
|
||||
#else
|
||||
return exe_file == yosys_abc_executable;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
struct AbcSigVal {
|
||||
|
|
@ -155,7 +163,12 @@ struct AbcSigVal {
|
|||
}
|
||||
};
|
||||
|
||||
#if defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN)
|
||||
// REUSE_YOSYS_ABC_PROCESSES only works when ABC is built with ENABLE_READLINE.
|
||||
#if defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN) && defined(YOSYS_ENABLE_READLINE)
|
||||
#define REUSE_YOSYS_ABC_PROCESSES
|
||||
#endif
|
||||
|
||||
#ifdef REUSE_YOSYS_ABC_PROCESSES
|
||||
struct AbcProcess
|
||||
{
|
||||
pid_t pid;
|
||||
|
|
@ -188,10 +201,10 @@ struct AbcProcess
|
|||
int status;
|
||||
int ret = waitpid(pid, &status, 0);
|
||||
if (ret != pid) {
|
||||
log_error("waitpid(%d) failed", pid);
|
||||
log_error("waitpid(%d) failed\n", pid);
|
||||
}
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
log_error("ABC failed with status %X", status);
|
||||
log_error("ABC failed with status %X\n", status);
|
||||
}
|
||||
if (from_child_pipe >= 0)
|
||||
close(from_child_pipe);
|
||||
|
|
@ -203,12 +216,12 @@ std::optional<AbcProcess> spawn_abc(const char* abc_exe, DeferredLogs &logs) {
|
|||
// fork()s.
|
||||
int to_child_pipe[2];
|
||||
if (pipe2(to_child_pipe, O_CLOEXEC) != 0) {
|
||||
logs.log_error("pipe failed");
|
||||
logs.log_error("pipe failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
int from_child_pipe[2];
|
||||
if (pipe2(from_child_pipe, O_CLOEXEC) != 0) {
|
||||
logs.log_error("pipe failed");
|
||||
logs.log_error("pipe failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
@ -221,39 +234,39 @@ std::optional<AbcProcess> spawn_abc(const char* abc_exe, DeferredLogs &logs) {
|
|||
|
||||
posix_spawn_file_actions_t file_actions;
|
||||
if (posix_spawn_file_actions_init(&file_actions) != 0) {
|
||||
logs.log_error("posix_spawn_file_actions_init failed");
|
||||
logs.log_error("posix_spawn_file_actions_init failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (posix_spawn_file_actions_addclose(&file_actions, to_child_pipe[1]) != 0) {
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed");
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (posix_spawn_file_actions_addclose(&file_actions, from_child_pipe[0]) != 0) {
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed");
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (posix_spawn_file_actions_adddup2(&file_actions, to_child_pipe[0], STDIN_FILENO) != 0) {
|
||||
logs.log_error("posix_spawn_file_actions_adddup2 failed");
|
||||
logs.log_error("posix_spawn_file_actions_adddup2 failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (posix_spawn_file_actions_adddup2(&file_actions, from_child_pipe[1], STDOUT_FILENO) != 0) {
|
||||
logs.log_error("posix_spawn_file_actions_adddup2 failed");
|
||||
logs.log_error("posix_spawn_file_actions_adddup2 failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (posix_spawn_file_actions_addclose(&file_actions, to_child_pipe[0]) != 0) {
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed");
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (posix_spawn_file_actions_addclose(&file_actions, from_child_pipe[1]) != 0) {
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed");
|
||||
logs.log_error("posix_spawn_file_actions_addclose failed\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
char arg1[] = "-s";
|
||||
char* argv[] = { strdup(abc_exe), arg1, nullptr };
|
||||
if (0 != posix_spawn(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) {
|
||||
logs.log_error("posix_spawn %s failed", abc_exe);
|
||||
if (0 != posix_spawnp(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) {
|
||||
logs.log_error("posix_spawnp %s failed (errno=%s)\n", abc_exe, strerror(errno));
|
||||
return std::nullopt;
|
||||
}
|
||||
free(argv[0]);
|
||||
|
|
@ -272,7 +285,7 @@ using AbcSigMap = SigValMap<AbcSigVal>;
|
|||
struct RunAbcState {
|
||||
const AbcConfig &config;
|
||||
|
||||
std::string tempdir_name;
|
||||
std::string per_run_tempdir_name;
|
||||
std::vector<gate_t> signal_list;
|
||||
bool did_run = false;
|
||||
bool err = false;
|
||||
|
|
@ -823,16 +836,23 @@ std::string fold_abc_cmd(std::string str)
|
|||
return new_str;
|
||||
}
|
||||
|
||||
std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
|
||||
std::string replace_tempdir(std::string text, std::string_view global_tempdir_name, std::string_view per_run_tempdir_name, bool show_tempdir)
|
||||
{
|
||||
if (show_tempdir)
|
||||
return text;
|
||||
|
||||
while (1) {
|
||||
size_t pos = text.find(tempdir_name);
|
||||
size_t pos = text.find(global_tempdir_name);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name));
|
||||
text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(global_tempdir_name));
|
||||
}
|
||||
|
||||
while (1) {
|
||||
size_t pos = text.find(per_run_tempdir_name);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(per_run_tempdir_name));
|
||||
}
|
||||
|
||||
std::string selfdir_name = proc_self_dirname();
|
||||
|
|
@ -854,11 +874,12 @@ struct abc_output_filter
|
|||
bool got_cr;
|
||||
int escape_seq_state;
|
||||
std::string linebuf;
|
||||
std::string tempdir_name;
|
||||
std::string global_tempdir_name;
|
||||
std::string per_run_tempdir_name;
|
||||
bool show_tempdir;
|
||||
|
||||
abc_output_filter(RunAbcState& state, std::string tempdir_name, bool show_tempdir)
|
||||
: state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir)
|
||||
abc_output_filter(RunAbcState& state, std::string global_tempdir_name, std::string per_run_tempdir_name, bool show_tempdir)
|
||||
: state(state), global_tempdir_name(global_tempdir_name), per_run_tempdir_name(per_run_tempdir_name), show_tempdir(show_tempdir)
|
||||
{
|
||||
got_cr = false;
|
||||
escape_seq_state = 0;
|
||||
|
|
@ -885,7 +906,7 @@ struct abc_output_filter
|
|||
return;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
state.logs.log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir));
|
||||
state.logs.log("ABC: %s\n", replace_tempdir(linebuf, global_tempdir_name, per_run_tempdir_name, show_tempdir));
|
||||
got_cr = false, linebuf.clear();
|
||||
return;
|
||||
}
|
||||
|
|
@ -986,15 +1007,15 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
|
|||
|
||||
const AbcConfig &config = run_abc.config;
|
||||
if (config.cleanup)
|
||||
run_abc.tempdir_name = get_base_tmpdir() + "/";
|
||||
run_abc.per_run_tempdir_name = get_base_tmpdir() + "/";
|
||||
else
|
||||
run_abc.tempdir_name = "_tmp_";
|
||||
run_abc.tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
|
||||
run_abc.tempdir_name = make_temp_dir(run_abc.tempdir_name);
|
||||
run_abc.per_run_tempdir_name = "_tmp_";
|
||||
run_abc.per_run_tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX";
|
||||
run_abc.per_run_tempdir_name = make_temp_dir(run_abc.per_run_tempdir_name);
|
||||
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
|
||||
module->name.c_str(), replace_tempdir(run_abc.tempdir_name, run_abc.tempdir_name, config.show_tempdir).c_str());
|
||||
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.tempdir_name);
|
||||
std::string 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;
|
||||
|
|
@ -1060,18 +1081,19 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
|
|||
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.tempdir_name);
|
||||
abc_script += stringf("; write_blif %s/output.blif", run_abc.tempdir_name);
|
||||
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);
|
||||
#if defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN)
|
||||
abc_script += "; echo \"YOSYS_ABC_DONE\"\n";
|
||||
#if defined(REUSE_YOSYS_ABC_PROCESSES)
|
||||
if (config.is_yosys_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';
|
||||
|
||||
std::string buffer = stringf("%s/abc.script", run_abc.tempdir_name);
|
||||
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));
|
||||
|
|
@ -1127,42 +1149,86 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
|
|||
handle_loops(assign_map, module);
|
||||
}
|
||||
|
||||
#if defined(REUSE_YOSYS_ABC_PROCESSES)
|
||||
static bool is_abc_prompt(const std::string &line, std::string &rest) {
|
||||
size_t pos = 0;
|
||||
while (true) {
|
||||
// The prompt may not start at the start of the line, because
|
||||
// ABC can output progress and maybe other data that isn't
|
||||
// newline-terminated.
|
||||
size_t start = line.find("abc ", pos);
|
||||
if (start == std::string::npos)
|
||||
return false;
|
||||
pos = start + 4;
|
||||
|
||||
size_t digits = 0;
|
||||
while (pos + digits < line.size() && line[pos + digits] >= '0' && line[pos + digits] <= '9')
|
||||
++digits;
|
||||
if (digits < 2)
|
||||
return false;
|
||||
if (line.substr(pos + digits, 2) == "> ") {
|
||||
rest = line.substr(pos + digits + 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool read_until_abc_done(abc_output_filter &filt, int fd, DeferredLogs &logs) {
|
||||
std::string line;
|
||||
char buf[1024];
|
||||
bool seen_source_cmd = false;
|
||||
bool seen_yosys_abc_done = false;
|
||||
while (true) {
|
||||
int ret = read(fd, buf, sizeof(buf) - 1);
|
||||
if (ret < 0) {
|
||||
logs.log_error("Failed to read from ABC, errno=%d", errno);
|
||||
logs.log_error("Failed to read from ABC, errno=%d\n", errno);
|
||||
return false;
|
||||
}
|
||||
if (ret == 0) {
|
||||
logs.log_error("ABC exited prematurely");
|
||||
logs.log_error("ABC exited prematurely\n");
|
||||
return false;
|
||||
}
|
||||
char *start = buf;
|
||||
char *end = buf + ret;
|
||||
while (start < end) {
|
||||
char *p = static_cast<char*>(memchr(start, '\n', end - start));
|
||||
if (p == nullptr) {
|
||||
break;
|
||||
char *upto = p == nullptr ? end : p + 1;
|
||||
line.append(start, upto - start);
|
||||
start = upto;
|
||||
|
||||
std::string rest;
|
||||
bool is_prompt = is_abc_prompt(line, rest);
|
||||
if (is_prompt && seen_source_cmd) {
|
||||
// This is the first prompt after we sourced the script.
|
||||
// We are done here.
|
||||
// We won't have seen a newline yet since ABC is waiting at the prompt.
|
||||
if (!seen_yosys_abc_done)
|
||||
logs.log_error("ABC script did not complete successfully\n");
|
||||
return seen_yosys_abc_done;
|
||||
}
|
||||
line.append(start, p + 1 - start);
|
||||
if (line.substr(0, 14) == "YOSYS_ABC_DONE") {
|
||||
// Ignore any leftover output, there should only be a prompt perhaps
|
||||
return true;
|
||||
if (line.empty() || line[line.size() - 1] != '\n') {
|
||||
// No newline yet, wait for more text
|
||||
continue;
|
||||
}
|
||||
filt.next_line(line);
|
||||
if (is_prompt && rest.substr(0, 7) == "source ")
|
||||
seen_source_cmd = true;
|
||||
if (line.substr(0, 14) == "YOSYS_ABC_DONE")
|
||||
seen_yosys_abc_done = true;
|
||||
line.clear();
|
||||
start = p + 1;
|
||||
}
|
||||
line.append(start, end - start);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(REUSE_YOSYS_ABC_PROCESSES)
|
||||
void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
|
||||
#else
|
||||
void RunAbcState::run(ConcurrentStack<AbcProcess> &)
|
||||
#endif
|
||||
{
|
||||
std::string buffer = stringf("%s/input.blif", tempdir_name);
|
||||
std::string buffer = stringf("%s/input.blif", per_run_tempdir_name);
|
||||
FILE *f = fopen(buffer.c_str(), "wt");
|
||||
if (f == nullptr) {
|
||||
logs.log("Opening %s for writing failed: %s\n", buffer, strerror(errno));
|
||||
|
|
@ -1285,15 +1351,19 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
|
|||
|
||||
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)
|
||||
{
|
||||
std::string tmp_script_name = stringf("%s/abc.script", tempdir_name);
|
||||
logs.log("Running ABC script: %s\n", replace_tempdir(tmp_script_name, tempdir_name, config.show_tempdir));
|
||||
if (count_output == 0) {
|
||||
log("Don't call ABC as there is nothing to map.\n");
|
||||
return;
|
||||
}
|
||||
int ret;
|
||||
std::string tmp_script_name = stringf("%s/abc.script", per_run_tempdir_name);
|
||||
do {
|
||||
logs.log("Running ABC script: %s\n", replace_tempdir(tmp_script_name, config.global_tempdir_name, per_run_tempdir_name, config.show_tempdir));
|
||||
|
||||
errno = 0;
|
||||
abc_output_filter filt(*this, tempdir_name, config.show_tempdir);
|
||||
abc_output_filter filt(*this, config.global_tempdir_name, per_run_tempdir_name, config.show_tempdir);
|
||||
#ifdef YOSYS_LINK_ABC
|
||||
string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name);
|
||||
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");
|
||||
|
|
@ -1318,7 +1388,7 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
|
|||
abc_argv[2] = strdup("-f");
|
||||
abc_argv[3] = strdup(tmp_script_name.c_str());
|
||||
abc_argv[4] = 0;
|
||||
int ret = abc::Abc_RealMain(4, abc_argv);
|
||||
ret = abc::Abc_RealMain(4, abc_argv);
|
||||
free(abc_argv[0]);
|
||||
free(abc_argv[1]);
|
||||
free(abc_argv[2]);
|
||||
|
|
@ -1333,39 +1403,42 @@ void RunAbcState::run(ConcurrentStack<AbcProcess> &process_pool)
|
|||
for (std::string line; std::getline(temp_stdouterr_r, line); )
|
||||
filt.next_line(line + "\n");
|
||||
temp_stdouterr_r.close();
|
||||
#elif defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN)
|
||||
AbcProcess process;
|
||||
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;
|
||||
}
|
||||
std::string cmd = stringf(
|
||||
"empty\n"
|
||||
"source %s\n", tmp_script_name);
|
||||
int ret = write(process.to_child_pipe, cmd.c_str(), cmd.size());
|
||||
if (ret != static_cast<int>(cmd.size())) {
|
||||
logs.log_error("write failed");
|
||||
return;
|
||||
}
|
||||
ret = read_until_abc_done(filt, process.from_child_pipe, logs) ? 0 : 1;
|
||||
if (ret == 0) {
|
||||
process_pool.push_back(std::move(process));
|
||||
}
|
||||
break;
|
||||
#else
|
||||
std::string cmd = stringf("\"%s\" -s -f %s/abc.script 2>&1", config.exe_file.c_str(), tempdir_name.c_str());
|
||||
int ret = run_command(cmd, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
logs.log_error("ABC: execution of script \"%s\" failed: return code %d (errno=%d).\n", tmp_script_name, ret, errno);
|
||||
return;
|
||||
#if defined(REUSE_YOSYS_ABC_PROCESSES)
|
||||
if (config.is_yosys_abc()) {
|
||||
AbcProcess process;
|
||||
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;
|
||||
}
|
||||
std::string cmd = stringf(
|
||||
"empty\n"
|
||||
"source %s\n", tmp_script_name);
|
||||
ret = write(process.to_child_pipe, cmd.c_str(), cmd.size());
|
||||
if (ret != static_cast<int>(cmd.size())) {
|
||||
logs.log_error("write failed");
|
||||
return;
|
||||
}
|
||||
ret = read_until_abc_done(filt, process.from_child_pipe, logs) ? 0 : 1;
|
||||
if (ret == 0) {
|
||||
process_pool.push_back(std::move(process));
|
||||
}
|
||||
break;
|
||||
}
|
||||
did_run = true;
|
||||
#endif
|
||||
std::string cmd = stringf("\"%s\" -s -f %s 2>&1", config.exe_file, tmp_script_name);
|
||||
ret = run_command(cmd, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
|
||||
#endif
|
||||
} while (false);
|
||||
if (ret != 0) {
|
||||
logs.log_error("ABC: execution of script \"%s\" failed: return code %d (errno=%d).\n", tmp_script_name, ret, errno);
|
||||
return;
|
||||
}
|
||||
log("Don't call ABC as there is nothing to map.\n");
|
||||
did_run = true;
|
||||
}
|
||||
|
||||
void emit_global_input_files(const AbcConfig &config)
|
||||
|
|
@ -1437,7 +1510,7 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL
|
|||
return;
|
||||
}
|
||||
|
||||
std::string buffer = stringf("%s/%s", run_abc.tempdir_name, "output.blif");
|
||||
std::string buffer = stringf("%s/%s", run_abc.per_run_tempdir_name, "output.blif");
|
||||
std::ifstream ifs;
|
||||
ifs.open(buffer);
|
||||
if (ifs.fail())
|
||||
|
|
@ -1724,7 +1797,7 @@ void AbcModuleState::finish()
|
|||
if (run_abc.config.cleanup)
|
||||
{
|
||||
log("Removing temp directory.\n");
|
||||
remove_directory(run_abc.tempdir_name);
|
||||
remove_directory(run_abc.per_run_tempdir_name);
|
||||
}
|
||||
log_pop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,9 +219,7 @@ struct Abc9Pass : public ScriptPass
|
|||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
std::string arg = args[argidx];
|
||||
if ((arg == "-exe" || arg == "-script" || arg == "-D" ||
|
||||
/*arg == "-S" ||*/ arg == "-lut" || arg == "-luts" ||
|
||||
/*arg == "-box" ||*/ arg == "-W" || arg == "-genlib" ||
|
||||
arg == "-constr" || arg == "-dont_use" || arg == "-liberty") &&
|
||||
arg == "-lut" || arg == "-luts" || arg == "-W") &&
|
||||
argidx+1 < args.size()) {
|
||||
if (arg == "-lut" || arg == "-luts")
|
||||
lut_mode = true;
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
|
|||
}
|
||||
|
||||
abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name);
|
||||
if (design->scratchpad_get_bool("abc9.verify")) {
|
||||
if (design->scratchpad_get_bool("abc9.verify", true)) {
|
||||
if (dff_mode)
|
||||
abc9_script += "; &verify -s";
|
||||
else
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ std::vector<Module*> order_modules(Design *design, std::vector<Module *> modules
|
|||
sort.edge(submodule, m);
|
||||
}
|
||||
}
|
||||
log_assert(sort.sort());
|
||||
bool is_sorted = sort.sort();
|
||||
log_assert(is_sorted);
|
||||
return sort.sorted;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ struct BufnormPass : public Pass {
|
|||
return mapped_bits.at(bit);
|
||||
};
|
||||
|
||||
auto make_buffer_f = [&](const IdString &type, const SigSpec &src, const SigSpec &dst)
|
||||
auto make_buffer_f = [&](IdString type, const SigSpec &src, const SigSpec &dst)
|
||||
{
|
||||
auto it = old_buffers.find(pair<IdString, SigSpec>(type, dst));
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ struct DffunmapPass : public Pass {
|
|||
continue;
|
||||
|
||||
FfData ff(&initvals, cell);
|
||||
IdString name = cell->name;
|
||||
|
||||
if (!ff.has_clk)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ int bindec(unsigned char v)
|
|||
r += (~((v & 2) - 1)) & 10;
|
||||
r += (~((v & 4) - 1)) & 100;
|
||||
r += (~((v & 8) - 1)) & 1000;
|
||||
r += (~((v & 16) - 1)) & 10000;
|
||||
r += (~((v & 32) - 1)) & 100000;
|
||||
r += (~((v & 64) - 1)) & 1000000;
|
||||
r += (~((v & 128) - 1)) & 10000000;
|
||||
r += (~((v & 16) - 1)) & 10'000;
|
||||
r += (~((v & 32) - 1)) & 100'000;
|
||||
r += (~((v & 64) - 1)) & 1'000'000;
|
||||
r += (~((v & 128) - 1)) & 10'000'000;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -827,6 +827,17 @@ std::string vlog_identifier(std::string str)
|
|||
return str;
|
||||
}
|
||||
|
||||
void event2vl_wire(std::string &edge, LibertyExpression& parsed, const std::string& wire)
|
||||
{
|
||||
edge.clear();
|
||||
if (parsed.kind == LibertyExpression::Kind::NOT) {
|
||||
edge = "negedge " + wire;
|
||||
// parsed = parsed.children[0];
|
||||
} else {
|
||||
edge = "posedge " + wire;
|
||||
}
|
||||
}
|
||||
|
||||
void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
|
||||
{
|
||||
edge.clear();
|
||||
|
|
@ -843,33 +854,160 @@ void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
|
|||
}
|
||||
}
|
||||
|
||||
void clear_preset_var(std::string var, std::string type)
|
||||
enum ClearPresetVar {
|
||||
Error,
|
||||
L,
|
||||
H,
|
||||
T,
|
||||
X,
|
||||
};
|
||||
|
||||
ClearPresetVar clear_preset_var(std::string type)
|
||||
{
|
||||
if (type.find('L') != std::string::npos) {
|
||||
return ClearPresetVar::L;
|
||||
}
|
||||
if (type.find('H') != std::string::npos) {
|
||||
return ClearPresetVar::H;
|
||||
}
|
||||
if (type.find('T') != std::string::npos) {
|
||||
return ClearPresetVar::T;
|
||||
}
|
||||
if (type.find('X') != std::string::npos) {
|
||||
return ClearPresetVar::X;
|
||||
}
|
||||
return ClearPresetVar::X;
|
||||
}
|
||||
|
||||
void print_clear_preset_var(std::string var, ClearPresetVar type)
|
||||
{
|
||||
if (type == ClearPresetVar::L) {
|
||||
printf(" %s <= 0;\n", var.c_str());
|
||||
return;
|
||||
}
|
||||
if (type.find('H') != std::string::npos) {
|
||||
if (type == ClearPresetVar::H) {
|
||||
printf(" %s <= 1;\n", var.c_str());
|
||||
return;
|
||||
}
|
||||
if (type.find('T') != std::string::npos) {
|
||||
if (type == ClearPresetVar::T) {
|
||||
printf(" %s <= ~%s;\n", var.c_str(), var.c_str());
|
||||
return;
|
||||
}
|
||||
if (type.find('X') != std::string::npos) {
|
||||
if (type == ClearPresetVar::X) {
|
||||
printf(" %s <= 'bx;\n", var.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct FfEdge {
|
||||
std::string edge;
|
||||
std::string expr;
|
||||
};
|
||||
struct FfEdges {
|
||||
FfEdge clock;
|
||||
FfEdge clear;
|
||||
FfEdge preset;
|
||||
std::string edge;
|
||||
void wired(FfEdge& edge, const LibertyAst* ast, const std::string& wire, const char* tag) {
|
||||
auto* found = ast->find(tag);
|
||||
if (!found)
|
||||
return;
|
||||
auto lexer = LibertyExpression::Lexer(found->value);
|
||||
auto expr = LibertyExpression::parse(lexer);
|
||||
event2vl_wire(edge.edge, expr, wire);
|
||||
edge.expr = expr.vlog_str();
|
||||
}
|
||||
FfEdges(LibertyAst* child, const std::string& clear_wire, const std::string& preset_wire) {
|
||||
wired(clear, child, clear_wire, "clear");
|
||||
wired(preset, child, preset_wire, "preset");
|
||||
event2vl(child->find("clocked_on"), clock.edge, clock.expr);
|
||||
edge = "";
|
||||
if (!clock.edge.empty())
|
||||
edge += (edge.empty() ? "" : ", ") + clock.edge;
|
||||
if (!clear.edge.empty())
|
||||
edge += (edge.empty() ? "" : ", ") + clear.edge;
|
||||
if (!preset.edge.empty())
|
||||
edge += (edge.empty() ? "" : ", ") + preset.edge;
|
||||
}
|
||||
};
|
||||
|
||||
struct FfVar {
|
||||
std::string var;
|
||||
std::string edge;
|
||||
FfEdge clear;
|
||||
FfEdge preset;
|
||||
// Value for both asserted
|
||||
const char* clear_preset_var_name;
|
||||
std::string next_state;
|
||||
const char* else_prefix = "";
|
||||
public:
|
||||
void proc_header() {
|
||||
printf(" always @(%s) begin\n", edge.c_str());
|
||||
}
|
||||
void proc_footer() {
|
||||
if (*else_prefix)
|
||||
printf(" end\n");
|
||||
|
||||
printf(" end\n");
|
||||
}
|
||||
void proc_cond(FfEdge& edge, const char* value) {
|
||||
printf(" %sif (%s) begin\n", else_prefix, edge.expr.c_str());
|
||||
printf(" %s <= %s;\n", var.c_str(), value);
|
||||
printf(" end\n");
|
||||
else_prefix = "else ";
|
||||
}
|
||||
void proc_cond_clear() { proc_cond(clear, "0"); }
|
||||
void proc_cond_preset() { proc_cond(preset, "1"); }
|
||||
void proc_next_state() {
|
||||
if (*else_prefix)
|
||||
printf(" %sbegin\n", else_prefix);
|
||||
printf(" %s <= %s;\n", var.c_str(), next_state.c_str());
|
||||
}
|
||||
void proc(LibertyAst* child) {
|
||||
else_prefix = "";
|
||||
proc_header();
|
||||
if (!clear.expr.empty() && !preset.expr.empty()) {
|
||||
ClearPresetVar clear_preset = clear_preset_var(find_non_null(child, clear_preset_var_name)->value);
|
||||
if (clear_preset == ClearPresetVar::L) {
|
||||
proc_cond_clear();
|
||||
proc_cond_preset();
|
||||
proc_next_state();
|
||||
proc_footer();
|
||||
return;
|
||||
} else if (clear_preset == ClearPresetVar::H) {
|
||||
// Notice that preset and clear are swapped
|
||||
proc_cond_preset();
|
||||
proc_cond_clear();
|
||||
proc_next_state();
|
||||
proc_footer();
|
||||
return;
|
||||
} else {
|
||||
// Boo, we have to emit non-synthesizable verilog
|
||||
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear.expr.c_str(), preset.expr.c_str());
|
||||
print_clear_preset_var(var, clear_preset);
|
||||
printf(" end\n");
|
||||
else_prefix = "else ";
|
||||
}
|
||||
}
|
||||
if (!clear.expr.empty()) {
|
||||
proc_cond_clear();
|
||||
}
|
||||
if (!preset.expr.empty()) {
|
||||
proc_cond_preset();
|
||||
}
|
||||
proc_next_state();
|
||||
proc_footer();
|
||||
}
|
||||
};
|
||||
|
||||
void gen_verilogsim_cell(const LibertyAst *ast)
|
||||
{
|
||||
if (ast->find("statetable") != NULL)
|
||||
return;
|
||||
|
||||
CHECK_NV(ast->args.size(), == 1);
|
||||
printf("module %s (", vlog_identifier(ast->args[0]).c_str());
|
||||
auto module_name = vlog_identifier(ast->args[0]);
|
||||
printf("module %s (", module_name.c_str());
|
||||
bool first = true;
|
||||
for (auto child : ast->children) {
|
||||
if (child->id != "pin")
|
||||
|
|
@ -883,13 +1021,29 @@ void gen_verilogsim_cell(const LibertyAst *ast)
|
|||
for (auto child : ast->children) {
|
||||
if (child->id != "ff" && child->id != "latch")
|
||||
continue;
|
||||
printf(" reg ");
|
||||
first = true;
|
||||
std::string iq = "";
|
||||
for (auto arg : child->args) {
|
||||
if (first)
|
||||
printf(" reg ");
|
||||
printf("%s%s", first ? "" : ", ", vlog_identifier(arg).c_str());
|
||||
if (first)
|
||||
iq = vlog_identifier(arg);
|
||||
first = false;
|
||||
}
|
||||
printf(";\n");
|
||||
if (!first)
|
||||
printf(";\n");
|
||||
first = true;
|
||||
for (auto gchild : child->children) {
|
||||
if (gchild->id == "clear" || gchild->id == "preset") {
|
||||
if (first)
|
||||
printf(" wire ");
|
||||
printf("%s%s_%s", first ? "" : ", ", iq.c_str(), gchild->id.c_str());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
if (!first)
|
||||
printf(";\n");
|
||||
}
|
||||
|
||||
for (auto child : ast->children) {
|
||||
|
|
@ -909,63 +1063,45 @@ void gen_verilogsim_cell(const LibertyAst *ast)
|
|||
if (child->id != "ff" || child->args.size() != 2)
|
||||
continue;
|
||||
|
||||
std::string iq_var = vlog_identifier(child->args[0]);
|
||||
std::string iqn_var = vlog_identifier(child->args[1]);
|
||||
auto iq_name = vlog_identifier(child->args[0]);
|
||||
auto clear_wire = iq_name + "_clear";
|
||||
auto preset_wire = iq_name + "_preset";
|
||||
FfEdges edges(child, clear_wire, preset_wire);
|
||||
|
||||
std::string clock_edge, clock_expr;
|
||||
event2vl(child->find("clocked_on"), clock_edge, clock_expr);
|
||||
|
||||
std::string clear_edge, clear_expr;
|
||||
event2vl(child->find("clear"), clear_edge, clear_expr);
|
||||
|
||||
std::string preset_edge, preset_expr;
|
||||
event2vl(child->find("preset"), preset_edge, preset_expr);
|
||||
|
||||
std::string edge = "";
|
||||
if (!clock_edge.empty())
|
||||
edge += (edge.empty() ? "" : ", ") + clock_edge;
|
||||
if (!clear_edge.empty())
|
||||
edge += (edge.empty() ? "" : ", ") + clear_edge;
|
||||
if (!preset_edge.empty())
|
||||
edge += (edge.empty() ? "" : ", ") + preset_edge;
|
||||
|
||||
if (edge.empty())
|
||||
if (edges.edge.empty())
|
||||
continue;
|
||||
|
||||
printf(" always @(%s) begin\n", edge.c_str());
|
||||
std::string next_state = func2vl(find_non_null(child, "next_state")->value);
|
||||
std::string not_next_state = std::string("~(") + next_state + ")";
|
||||
|
||||
const char *else_prefix = "";
|
||||
if (!clear_expr.empty() && !preset_expr.empty()) {
|
||||
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
|
||||
clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
|
||||
clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
|
||||
printf(" end\n");
|
||||
else_prefix = "else ";
|
||||
}
|
||||
if (!clear_expr.empty()) {
|
||||
printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
|
||||
printf(" %s <= 0;\n", iq_var.c_str());
|
||||
printf(" %s <= 1;\n", iqn_var.c_str());
|
||||
printf(" end\n");
|
||||
else_prefix = "else ";
|
||||
}
|
||||
if (!preset_expr.empty()) {
|
||||
printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
|
||||
printf(" %s <= 1;\n", iq_var.c_str());
|
||||
printf(" %s <= 0;\n", iqn_var.c_str());
|
||||
printf(" end\n");
|
||||
else_prefix = "else ";
|
||||
}
|
||||
if (*else_prefix)
|
||||
printf(" %sbegin\n", else_prefix);
|
||||
std::string expr = find_non_null(child, "next_state")->value;
|
||||
printf(" // %s\n", expr.c_str());
|
||||
printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
|
||||
printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
|
||||
if (*else_prefix)
|
||||
printf(" end\n");
|
||||
|
||||
printf(" end\n");
|
||||
if (edges.clear.expr.length())
|
||||
std::swap(clear_wire, edges.clear.expr);
|
||||
if (edges.preset.expr.length())
|
||||
std::swap(preset_wire, edges.preset.expr);
|
||||
auto iq = FfVar {
|
||||
.var = vlog_identifier(child->args[0]),
|
||||
.edge = edges.edge,
|
||||
.clear = edges.clear,
|
||||
.preset = edges.preset,
|
||||
.clear_preset_var_name = "clear_preset_var1",
|
||||
.next_state = next_state,
|
||||
};
|
||||
auto iqn = FfVar {
|
||||
.var = vlog_identifier(child->args[1]),
|
||||
.edge = edges.edge,
|
||||
// Swapped clear and preset
|
||||
.clear = edges.preset,
|
||||
.preset = edges.clear,
|
||||
.clear_preset_var_name = "clear_preset_var2",
|
||||
.next_state = not_next_state,
|
||||
};
|
||||
iq.proc(child);
|
||||
iqn.proc(child);
|
||||
if (edges.clear.expr.length())
|
||||
printf(" assign %s = %s;\n", edges.clear.expr.c_str(), clear_wire.c_str());
|
||||
if (edges.preset.expr.length())
|
||||
printf(" assign %s = %s;\n", edges.preset.expr.c_str(), preset_wire.c_str());
|
||||
}
|
||||
|
||||
for (auto child : ast->children)
|
||||
|
|
@ -990,8 +1126,8 @@ void gen_verilogsim_cell(const LibertyAst *ast)
|
|||
const char *else_prefix = "";
|
||||
if (!clear_expr.empty() && !preset_expr.empty()) {
|
||||
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
|
||||
clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
|
||||
clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
|
||||
print_clear_preset_var(iq_var, clear_preset_var(find_non_null(child, "clear_preset_var1")->value));
|
||||
print_clear_preset_var(iqn_var, clear_preset_var(find_non_null(child, "clear_preset_var2")->value));
|
||||
printf(" end\n");
|
||||
else_prefix = "else ";
|
||||
}
|
||||
|
|
|
|||
58
passes/techmap/lut2bmux.cc
Normal file
58
passes/techmap/lut2bmux.cc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct Lut2BmuxPass : public Pass {
|
||||
Lut2BmuxPass() : Pass("lut2bmux", "convert $lut to $bmux") { }
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" lut2bmux [options] [selection]\n");
|
||||
log("\n");
|
||||
log("This pass converts $lut cells to $bmux cells.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing LUT2BMUX pass (convert $lut to $bmux).\n");
|
||||
|
||||
size_t argidx = 1;
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto module : design->selected_modules())
|
||||
for (auto cell : module->selected_cells()) {
|
||||
if (cell->type == ID($lut)) {
|
||||
cell->type = ID($bmux);
|
||||
cell->setPort(ID::S, cell->getPort(ID::A));
|
||||
cell->setPort(ID::A, cell->getParam(ID::LUT));
|
||||
cell->unsetParam(ID::LUT);
|
||||
cell->fixup_parameters();
|
||||
log("Converted %s.%s to BMUX cell.\n", log_id(module), log_id(cell));
|
||||
}
|
||||
}
|
||||
}
|
||||
} Lut2BmuxPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
int lut2mux(Cell *cell)
|
||||
int lut2mux(Cell *cell, bool word_mode)
|
||||
{
|
||||
SigSpec sig_a = cell->getPort(ID::A);
|
||||
SigSpec sig_y = cell->getPort(ID::Y);
|
||||
|
|
@ -32,7 +32,10 @@ int lut2mux(Cell *cell)
|
|||
|
||||
if (GetSize(sig_a) == 1)
|
||||
{
|
||||
cell->module->addMuxGate(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
|
||||
if (!word_mode)
|
||||
cell->module->addMuxGate(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
|
||||
else
|
||||
cell->module->addMux(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -44,10 +47,13 @@ int lut2mux(Cell *cell)
|
|||
Const lut1 = lut.extract(0, GetSize(lut)/2);
|
||||
Const lut2 = lut.extract(GetSize(lut)/2, GetSize(lut)/2);
|
||||
|
||||
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y1, lut1));
|
||||
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y2, lut2));
|
||||
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y1, lut1), word_mode);
|
||||
count += lut2mux(cell->module->addLut(NEW_ID, sig_a_lo, sig_y2, lut2), word_mode);
|
||||
|
||||
cell->module->addMuxGate(NEW_ID, sig_y1, sig_y2, sig_a_hi, sig_y);
|
||||
if (!word_mode)
|
||||
cell->module->addMuxGate(NEW_ID, sig_y1, sig_y2, sig_a_hi, sig_y);
|
||||
else
|
||||
cell->module->addMux(NEW_ID, sig_y1, sig_y2, sig_a_hi, sig_y);
|
||||
}
|
||||
|
||||
cell->module->remove(cell);
|
||||
|
|
@ -55,26 +61,33 @@ int lut2mux(Cell *cell)
|
|||
}
|
||||
|
||||
struct Lut2muxPass : public Pass {
|
||||
Lut2muxPass() : Pass("lut2mux", "convert $lut to $_MUX_") { }
|
||||
Lut2muxPass() : Pass("lut2mux", "convert $lut to $mux/$_MUX_") { }
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" lut2mux [options] [selection]\n");
|
||||
log("\n");
|
||||
log("This pass converts $lut cells to $_MUX_ gates.\n");
|
||||
log("This pass converts $lut cells to $mux/$_MUX_ gates.\n");
|
||||
log("\n");
|
||||
log(" -word\n");
|
||||
log(" Convert $lut cells with a single input to word-level $mux gates.\n");
|
||||
log(" The default is to convert them to bit-level $_MUX_ gates.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n");
|
||||
log_header(design, "Executing LUT2MUX pass (convert $lut to $mux/$_MUX_).\n");
|
||||
log("ARGS:"); for (auto &a: args) log(" [%s]", a.c_str()); log("\n");
|
||||
|
||||
size_t argidx;
|
||||
bool word_mode = false;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
// if (args[argidx] == "-v") {
|
||||
// continue;
|
||||
// }
|
||||
if (args[argidx] == "-word") {
|
||||
word_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -83,7 +96,7 @@ struct Lut2muxPass : public Pass {
|
|||
for (auto cell : module->selected_cells()) {
|
||||
if (cell->type == ID($lut)) {
|
||||
IdString cell_name = cell->name;
|
||||
int count = lut2mux(cell);
|
||||
int count = lut2mux(cell, word_mode);
|
||||
log("Converted %s.%s to %d MUX cells.\n", log_id(module), log_id(cell_name), count);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
USING_YOSYS_NAMESPACE
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
static void transfer_attr (Cell* to, const Cell* from, const IdString& attr) {
|
||||
static void transfer_attr (Cell* to, const Cell* from, IdString attr) {
|
||||
if (from->has_attribute(attr))
|
||||
to->attributes[attr] = from->attributes.at(attr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,9 +333,6 @@ struct TechmapWorker
|
|||
|
||||
RTLIL::Cell *c = module->addCell(c_name, tpl_cell);
|
||||
design->select(module, c);
|
||||
|
||||
if (c->type.begins_with("\\$"))
|
||||
c->type = c->type.substr(1);
|
||||
|
||||
if (c->type == ID::_TECHMAP_PLACEHOLDER_ && tpl_cell->has_attribute(ID::techmap_chtype)) {
|
||||
c->type = RTLIL::escape_id(tpl_cell->get_string_attribute(ID::techmap_chtype));
|
||||
|
|
@ -436,13 +433,9 @@ struct TechmapWorker
|
|||
if (handled_cells.count(cell) > 0)
|
||||
continue;
|
||||
|
||||
std::string cell_type = cell->type.str();
|
||||
if (in_recursion && cell->type.begins_with("\\$"))
|
||||
cell_type = cell_type.substr(1);
|
||||
|
||||
if (celltypeMap.count(cell_type) == 0) {
|
||||
if (assert_mode && cell_type.back() != '_')
|
||||
log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell_type));
|
||||
if (celltypeMap.count(cell->type) == 0) {
|
||||
if (assert_mode && !cell->type.ends_with("_"))
|
||||
log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell->type));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -454,7 +447,7 @@ struct TechmapWorker
|
|||
if (GetSize(sig) == 0)
|
||||
continue;
|
||||
|
||||
for (auto &tpl_name : celltypeMap.at(cell_type)) {
|
||||
for (auto &tpl_name : celltypeMap.at(cell->type)) {
|
||||
RTLIL::Module *tpl = map->module(tpl_name);
|
||||
RTLIL::Wire *port = tpl->wire(conn.first);
|
||||
if (port && port->port_input)
|
||||
|
|
@ -481,12 +474,7 @@ struct TechmapWorker
|
|||
log_assert(cell == module->cell(cell->name));
|
||||
bool mapped_cell = false;
|
||||
|
||||
std::string cell_type = cell->type.str();
|
||||
|
||||
if (in_recursion && cell->type.begins_with("\\$"))
|
||||
cell_type = cell_type.substr(1);
|
||||
|
||||
for (auto &tpl_name : celltypeMap.at(cell_type))
|
||||
for (auto &tpl_name : celltypeMap.at(cell->type))
|
||||
{
|
||||
IdString derived_name = tpl_name;
|
||||
RTLIL::Module *tpl = map->module(tpl_name);
|
||||
|
|
@ -508,8 +496,6 @@ struct TechmapWorker
|
|||
|
||||
if (!extmapper_name.empty())
|
||||
{
|
||||
cell->type = cell_type;
|
||||
|
||||
if ((extern_mode && !in_recursion) || extmapper_name == "wrap")
|
||||
{
|
||||
std::string m_name = stringf("$extern:%s:%s", extmapper_name, log_id(cell->type));
|
||||
|
|
@ -935,11 +921,6 @@ struct TechmapWorker
|
|||
RTLIL::Module *m = design->addModule(m_name);
|
||||
tpl->cloneInto(m);
|
||||
|
||||
for (auto cell : m->cells()) {
|
||||
if (cell->type.begins_with("\\$"))
|
||||
cell->type = cell->type.substr(1);
|
||||
}
|
||||
|
||||
module_queue.insert(m);
|
||||
}
|
||||
|
||||
|
|
@ -1168,7 +1149,7 @@ struct TechmapPass : public Pass {
|
|||
|
||||
std::vector<std::string> map_files;
|
||||
std::vector<RTLIL::IdString> dont_map;
|
||||
std::string verilog_frontend = "verilog -nooverwrite -noblackbox";
|
||||
std::string verilog_frontend = "verilog -nooverwrite -noblackbox -icells";
|
||||
int max_iter = -1;
|
||||
|
||||
size_t argidx;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue