From 94913a9f5ada47ec714933d014a9e206e7ebec61 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Tue, 27 Aug 2024 17:34:56 +0300 Subject: [PATCH 01/22] cxxrtl: use octal encoding of non-printables. "\x0a" is a perfectly valid escape sequence, but unfortunately "\x0ac" is equivalent to "\xac", and not "\x0a" "c" as we might expect --- *any* number of hexadecimal characters after the "\x" is accepted. This can be hit pretty easily if a newline is present in a format string. "\x{...}" syntax is only available as of C++23, so use octal format instead; a maximum of 3 digits following the backslash is accepted. The alternative would be to render every escape like `" "\x0a" "`, but it seems more effort that way. --- kernel/fmt.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kernel/fmt.cc b/kernel/fmt.cc index d1c6b8ac9..44ad8351d 100644 --- a/kernel/fmt.cc +++ b/kernel/fmt.cc @@ -634,10 +634,11 @@ std::string escape_cxx_string(const std::string &input) output.push_back('\\'); output.push_back(c); } else { - char l = c & 0xf, h = (c >> 4) & 0xf; - output.append("\\x"); - output.push_back((h < 10 ? '0' + h : 'a' + h - 10)); - output.push_back((l < 10 ? '0' + l : 'a' + l - 10)); + char l = c & 0x7, m = (c >> 3) & 0x7, h = (c >> 6) & 0x3; + output.push_back('\\'); + output.push_back('0' + h); + output.push_back('0' + m); + output.push_back('0' + l); } } output.push_back('"'); From d0da1b56beb90f9633ed58cf0b52ea79d979ac86 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Tue, 27 Aug 2024 18:36:43 +0300 Subject: [PATCH 02/22] cxxrtl: backend: don't drop bits 2 and 5 on non-printable format. --- backends/cxxrtl/cxxrtl_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 8dc14863d..7e7bace6c 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -616,7 +616,7 @@ std::string escape_c_string(const std::string &input) output.push_back('\\'); output.push_back(c); } else { - char l = c & 0x3, m = (c >> 3) & 0x3, h = (c >> 6) & 0x3; + char l = c & 0x7, m = (c >> 3) & 0x7, h = (c >> 6) & 0x3; output.append("\\"); output.push_back('0' + h); output.push_back('0' + m); From 9a14ab8d98cdaaf2a680ad744aeb11db2226c592 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Fri, 28 Feb 2025 13:51:22 +0200 Subject: [PATCH 03/22] splitcells: Fix the assertion bug caused by out-of-bound offset --- passes/cmds/splitcells.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/passes/cmds/splitcells.cc b/passes/cmds/splitcells.cc index 074bf0f64..e3d509564 100644 --- a/passes/cmds/splitcells.cc +++ b/passes/cmds/splitcells.cc @@ -103,8 +103,7 @@ struct SplitcellsWorker auto slice_signal = [&](SigSpec old_sig) -> SigSpec { SigSpec new_sig; - for (int i = 0; i < GetSize(old_sig); i += GetSize(outsig)) { - int offset = i+slice_lsb; + for (int offset = slice_lsb; offset <= GetSize(old_sig); offset += GetSize(outsig)) { int length = std::min(GetSize(old_sig)-offset, slice_msb-slice_lsb+1); new_sig.append(old_sig.extract(offset, length)); } From de032d2e2ac766df596ab4a11ecf14175b9c8fb4 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Fri, 28 Feb 2025 23:16:04 +0200 Subject: [PATCH 04/22] splitcells: change for-loop condition --- passes/cmds/splitcells.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/splitcells.cc b/passes/cmds/splitcells.cc index e3d509564..d2063a0c8 100644 --- a/passes/cmds/splitcells.cc +++ b/passes/cmds/splitcells.cc @@ -103,7 +103,7 @@ struct SplitcellsWorker auto slice_signal = [&](SigSpec old_sig) -> SigSpec { SigSpec new_sig; - for (int offset = slice_lsb; offset <= GetSize(old_sig); offset += GetSize(outsig)) { + for (int offset = slice_lsb; offset < GetSize(old_sig); offset += GetSize(outsig)) { int length = std::min(GetSize(old_sig)-offset, slice_msb-slice_lsb+1); new_sig.append(old_sig.extract(offset, length)); } From f62a9be15352d000228584bcb1984030dbefe6e4 Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:24:57 -0500 Subject: [PATCH 05/22] Initial file list support --- frontends/verilog/verilog_frontend.cc | 76 +++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index d363d71fb..5328ad404 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -26,6 +26,8 @@ * */ +#include + #include "verilog_frontend.h" #include "preproc.h" #include "kernel/yosys.h" @@ -672,6 +674,80 @@ struct VerilogDefines : public Pass { } } VerilogDefines; +struct VerilogFilelist : public Pass { + VerilogFilelist() : Pass("verilog_filelist", "use filelist") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" verilog_filelist [options]\n"); + log("\n"); + log("Load a Verilog file list, and pass list of Verilog files to read_verilog command.\n"); + log("\n"); + log(" -Fflist\n"); + log(" File list file contains list of Verilog to be parsed, any\n"); + log(" ' path is relative to the file list file'\n"); + log("\n"); + log(" -Fflist\n"); + log(" File list file contains list of Verilog to be parsed, any\n"); + log(" ' path is relative to current working directroy'\n"); + log("\n"); + } + + void parse_flist_rel_filelist(const std::string &flist_path, RTLIL::Design *design) + { + std::ifstream ifs(flist_path); + if (!ifs.is_open()) { + log_error("file list file does not exist"); + exit(1); + } + + std::filesystem::path flist_parent_dir = std::filesystem::path(flist_path).parent_path(); + + std::string v_file_name; + while (std::getline(ifs, v_file_name)) { + if (v_file_name.empty()) { + continue; + } + std::string v_file_path = flist_parent_dir.string() + '/' + v_file_name; + log("Verilog file %s\n", v_file_path.c_str()); + + bool is_sv = (std::filesystem::path(v_file_path).extension() == ".sv"); + + std::string command = "read_verilog"; + if (is_sv) { + command += " -sv"; + } + command = command + ' ' + v_file_path; + Pass::call(design, command); + } + } + + void parse_flist_rel_pwd(const std::string &flist_path, RTLIL::Design *design) { log("pwd %s\n", flist_path.c_str()); } + + void execute(std::vector args, RTLIL::Design *design) override + { + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-F" && argidx + 1 < args.size()) { + std::string flist_path = args[++argidx]; + parse_flist_rel_filelist(flist_path, design); + continue; + } + if (arg == "-f" && argidx + 1 < args.size()) { + std::string flist_path = args[++argidx]; + parse_flist_rel_pwd(flist_path, design); + continue; + } + break; + } + + if (args.size() != argidx) + cmd_error(args, argidx, "Extra argument."); + } +} VerilogFilelist; + YOSYS_NAMESPACE_END // the yyerror function used by bison to report parser errors From 8f46f53f183b9e4cb7011b185ba0632efdf95514 Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:29:56 -0500 Subject: [PATCH 06/22] Add clangd cache to gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5c3d8f4e9..3c209ff4f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.gcno *~ __pycache__ +/.cache /.cproject /.project /.settings @@ -52,3 +53,4 @@ __pycache__ /venv /boost /ffi +/compile_commands.json From 0678c4dec97d0ad3d83220c75cee8d65f419a4f1 Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Sun, 2 Mar 2025 21:07:00 -0500 Subject: [PATCH 07/22] Coding style update --- frontends/verilog/verilog_frontend.cc | 60 +++++++++++++++------------ 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 5328ad404..d2cea3599 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -674,56 +674,61 @@ struct VerilogDefines : public Pass { } } VerilogDefines; -struct VerilogFilelist : public Pass { - VerilogFilelist() : Pass("verilog_filelist", "use filelist") {} +struct VerilogFileList : public Pass { + VerilogFileList() : Pass("read_verilog_file_list", "Parse a Verilog file list") {} void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" verilog_filelist [options]\n"); + log(" read_verilog_file_list [options]\n"); log("\n"); - log("Load a Verilog file list, and pass list of Verilog files to read_verilog command.\n"); + log("Parse a Verilog file list, and pass the list of Verilog files to read_verilog command.\n"); log("\n"); - log(" -Fflist\n"); - log(" File list file contains list of Verilog to be parsed, any\n"); - log(" ' path is relative to the file list file'\n"); + log(" -F file_list_path\n"); + log(" File list file contains list of Verilog files to be parsed, any\n"); + log(" ' path is treated relative to the file list file'\n"); log("\n"); - log(" -Fflist\n"); - log(" File list file contains list of Verilog to be parsed, any\n"); - log(" ' path is relative to current working directroy'\n"); + log(" -f file_list_path\n"); + log(" File list file contains list of Verilog files to be parsed, any\n"); + log(" ' path is treated relative to current working directroy'\n"); log("\n"); } - void parse_flist_rel_filelist(const std::string &flist_path, RTLIL::Design *design) + void parse_file_list(const std::string &file_list_path, RTLIL::Design *design, bool relative_to_file_list_path) { - std::ifstream ifs(flist_path); - if (!ifs.is_open()) { - log_error("file list file does not exist"); + std::ifstream flist(file_list_path); + if (!flist.is_open()) { + log_error("Verilog file list file does not exist"); exit(1); } - std::filesystem::path flist_parent_dir = std::filesystem::path(flist_path).parent_path(); + std::filesystem::path file_list_parent_dir = std::filesystem::path(file_list_path).parent_path(); std::string v_file_name; - while (std::getline(ifs, v_file_name)) { + while (std::getline(flist, v_file_name)) { if (v_file_name.empty()) { continue; } - std::string v_file_path = flist_parent_dir.string() + '/' + v_file_name; - log("Verilog file %s\n", v_file_path.c_str()); - bool is_sv = (std::filesystem::path(v_file_path).extension() == ".sv"); + std::string verilog_file_path; + if (relative_to_file_list_path) { + verilog_file_path = file_list_parent_dir.string() + '/' + v_file_name; + } else { + verilog_file_path = std::filesystem::current_path().string() + '/' + v_file_name; + } + + bool is_sv = (std::filesystem::path(verilog_file_path).extension() == ".sv"); std::string command = "read_verilog"; if (is_sv) { command += " -sv"; } - command = command + ' ' + v_file_path; + command = command + ' ' + verilog_file_path; Pass::call(design, command); } - } - void parse_flist_rel_pwd(const std::string &flist_path, RTLIL::Design *design) { log("pwd %s\n", flist_path.c_str()); } + flist.close(); + } void execute(std::vector args, RTLIL::Design *design) override { @@ -731,20 +736,21 @@ struct VerilogFilelist : public Pass { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-F" && argidx + 1 < args.size()) { - std::string flist_path = args[++argidx]; - parse_flist_rel_filelist(flist_path, design); + std::string file_list_path = args[++argidx]; + parse_file_list(file_list_path, design, true); continue; } if (arg == "-f" && argidx + 1 < args.size()) { - std::string flist_path = args[++argidx]; - parse_flist_rel_pwd(flist_path, design); + std::string file_list_path = args[++argidx]; + parse_file_list(file_list_path, design, false); continue; } break; } - if (args.size() != argidx) + if (args.size() != argidx) { cmd_error(args, argidx, "Extra argument."); + } } } VerilogFilelist; From 8ec96ec8065bb42570ddc5ecd843331a31990032 Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Fri, 7 Mar 2025 00:50:28 -0500 Subject: [PATCH 08/22] Address most comments --- .gitignore | 2 +- frontends/verilog/verilog_frontend.cc | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 3c209ff4f..239ae742b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ __pycache__ /qtcreator.config /qtcreator.creator /qtcreator.creator.user +/compile_commands.json /coverage.info /coverage_html /Makefile.conf @@ -53,4 +54,3 @@ __pycache__ /venv /boost /ffi -/compile_commands.json diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index d2cea3599..fd317bf22 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -686,11 +686,11 @@ struct VerilogFileList : public Pass { log("\n"); log(" -F file_list_path\n"); log(" File list file contains list of Verilog files to be parsed, any\n"); - log(" ' path is treated relative to the file list file'\n"); + log(" path is treated relative to the file list file\n"); log("\n"); log(" -f file_list_path\n"); log(" File list file contains list of Verilog files to be parsed, any\n"); - log(" ' path is treated relative to current working directroy'\n"); + log(" path is treated relative to current working directroy\n"); log("\n"); } @@ -710,21 +710,21 @@ struct VerilogFileList : public Pass { continue; } - std::string verilog_file_path; + std::filesystem::path verilog_file_path; if (relative_to_file_list_path) { - verilog_file_path = file_list_parent_dir.string() + '/' + v_file_name; + verilog_file_path = file_list_parent_dir / v_file_name; } else { - verilog_file_path = std::filesystem::current_path().string() + '/' + v_file_name; + verilog_file_path = std::filesystem::current_path() / v_file_name; } - bool is_sv = (std::filesystem::path(verilog_file_path).extension() == ".sv"); + bool is_sv = (verilog_file_path.extension() == ".sv"); - std::string command = "read_verilog"; + std::vector read_verilog_cmd = {"read_verilog", "-defer"}; if (is_sv) { - command += " -sv"; + read_verilog_cmd.push_back("-sv"); } - command = command + ' ' + verilog_file_path; - Pass::call(design, command); + read_verilog_cmd.push_back(verilog_file_path.string()); + Pass::call(design, read_verilog_cmd); } flist.close(); @@ -748,9 +748,7 @@ struct VerilogFileList : public Pass { break; } - if (args.size() != argidx) { - cmd_error(args, argidx, "Extra argument."); - } + extra_args(args, argidx, design); } } VerilogFilelist; From ac31bad6569306450a28d9cd0bdf52ed51aceb93 Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Fri, 7 Mar 2025 00:57:39 -0500 Subject: [PATCH 09/22] Address all comments --- frontends/verilog/verilog_frontend.cc | 72 +++++++++++++-------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index fd317bf22..723f2d589 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -674,6 +674,42 @@ struct VerilogDefines : public Pass { } } VerilogDefines; +static void parse_file_list(const std::string &file_list_path, RTLIL::Design *design, bool relative_to_file_list_path) +{ + std::ifstream flist(file_list_path); + if (!flist.is_open()) { + log_error("Verilog file list file does not exist"); + exit(1); + } + + std::filesystem::path file_list_parent_dir = std::filesystem::path(file_list_path).parent_path(); + + std::string v_file_name; + while (std::getline(flist, v_file_name)) { + if (v_file_name.empty()) { + continue; + } + + std::filesystem::path verilog_file_path; + if (relative_to_file_list_path) { + verilog_file_path = file_list_parent_dir / v_file_name; + } else { + verilog_file_path = std::filesystem::current_path() / v_file_name; + } + + bool is_sv = (verilog_file_path.extension() == ".sv"); + + std::vector read_verilog_cmd = {"read_verilog", "-defer"}; + if (is_sv) { + read_verilog_cmd.push_back("-sv"); + } + read_verilog_cmd.push_back(verilog_file_path.string()); + Pass::call(design, read_verilog_cmd); + } + + flist.close(); +} + struct VerilogFileList : public Pass { VerilogFileList() : Pass("read_verilog_file_list", "Parse a Verilog file list") {} void help() override @@ -694,42 +730,6 @@ struct VerilogFileList : public Pass { log("\n"); } - void parse_file_list(const std::string &file_list_path, RTLIL::Design *design, bool relative_to_file_list_path) - { - std::ifstream flist(file_list_path); - if (!flist.is_open()) { - log_error("Verilog file list file does not exist"); - exit(1); - } - - std::filesystem::path file_list_parent_dir = std::filesystem::path(file_list_path).parent_path(); - - std::string v_file_name; - while (std::getline(flist, v_file_name)) { - if (v_file_name.empty()) { - continue; - } - - std::filesystem::path verilog_file_path; - if (relative_to_file_list_path) { - verilog_file_path = file_list_parent_dir / v_file_name; - } else { - verilog_file_path = std::filesystem::current_path() / v_file_name; - } - - bool is_sv = (verilog_file_path.extension() == ".sv"); - - std::vector read_verilog_cmd = {"read_verilog", "-defer"}; - if (is_sv) { - read_verilog_cmd.push_back("-sv"); - } - read_verilog_cmd.push_back(verilog_file_path.string()); - Pass::call(design, read_verilog_cmd); - } - - flist.close(); - } - void execute(std::vector args, RTLIL::Design *design) override { size_t argidx; From bf1eab565b0f843b9472794f0fbfeabaa49091f7 Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Fri, 7 Mar 2025 20:20:27 -0500 Subject: [PATCH 10/22] Fix compile on WASI platform --- frontends/verilog/verilog_frontend.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 723f2d589..737481743 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -26,7 +26,9 @@ * */ +#if !defined(__wasm) #include +#endif #include "verilog_frontend.h" #include "preproc.h" @@ -674,6 +676,8 @@ struct VerilogDefines : public Pass { } } VerilogDefines; +#if !defined(__wasm) + static void parse_file_list(const std::string &file_list_path, RTLIL::Design *design, bool relative_to_file_list_path) { std::ifstream flist(file_list_path); @@ -721,12 +725,10 @@ struct VerilogFileList : public Pass { log("Parse a Verilog file list, and pass the list of Verilog files to read_verilog command.\n"); log("\n"); log(" -F file_list_path\n"); - log(" File list file contains list of Verilog files to be parsed, any\n"); - log(" path is treated relative to the file list file\n"); + log(" File list file contains list of Verilog files to be parsed, any path is treated relative to the file list file\n"); log("\n"); log(" -f file_list_path\n"); - log(" File list file contains list of Verilog files to be parsed, any\n"); - log(" path is treated relative to current working directroy\n"); + log(" File list file contains list of Verilog files to be parsed, any path is treated relative to current working directroy\n"); log("\n"); } @@ -752,6 +754,8 @@ struct VerilogFileList : public Pass { } } VerilogFilelist; +#endif + YOSYS_NAMESPACE_END // the yyerror function used by bison to report parser errors From 98eefc5d1adcf6aec1dce8877c2f4f0780fa085b Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Fri, 7 Mar 2025 20:44:21 -0500 Subject: [PATCH 11/22] Add file list support to read pass --- frontends/verific/verific.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index cdd0ed802..19f17b0ff 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -4298,7 +4298,7 @@ struct ReadPass : public Pass { log("\n"); log(" read {-f|-F} \n"); log("\n"); - log("Load and execute the specified command file. (Requires Verific.)\n"); + log("Load and execute the specified command file.\n"); log("Check verific command for more information about supported commands in file.\n"); log("\n"); log("\n"); @@ -4412,10 +4412,10 @@ struct ReadPass : public Pass { if (args[1] == "-f" || args[1] == "-F") { if (use_verific) { args[0] = "verific"; - Pass::call(design, args); } else { - cmd_error(args, 1, "This version of Yosys is built without Verific support.\n"); + args[0] = "read_verilog_file_list"; } + Pass::call(design, args); return; } From be3dfdc5ad01019d7f843f1acb9a1640316e60ab Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Mon, 10 Mar 2025 19:41:22 +0200 Subject: [PATCH 12/22] splitcells: add tests --- tests/various/bug4909.ys | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/various/bug4909.ys diff --git a/tests/various/bug4909.ys b/tests/various/bug4909.ys new file mode 100644 index 000000000..bf8cfb45b --- /dev/null +++ b/tests/various/bug4909.ys @@ -0,0 +1,44 @@ +read_rtlil << EOF +autoidx 20 +attribute \src "3510.v:2.1-26.10" +attribute \cells_not_processed 1 +attribute \tamara_triplicate 1 +module \top + attribute \src "3510.v:14.3-17.8" + wire width 4 $0\reg5[3:0] + attribute $bugpoint 1 + wire width 4 $auto$bugpoint.cc:258:simplify_something$12 + wire $delete_wire$14 + attribute \src "3510.v:13.19-13.59" + wire width 4 $xnor$3510.v:13$1_Y + attribute \src "3510.v:11.23-11.27" + wire width 4 \reg5 + attribute \src "3510.v:8.24-8.29" + wire width 3 \wire4 + attribute \src "3510.v:3.33-3.34" + wire width 12 output 1 \y + attribute \src "3510.v:13.19-13.59" + cell $xnor $xnor$3510.v:13$1 + parameter \A_SIGNED 0 + parameter \A_WIDTH 3 + parameter \B_SIGNED 0 + parameter \B_WIDTH 4 + parameter \Y_WIDTH 4 + connect \A 3'x + connect \B $auto$bugpoint.cc:258:simplify_something$12 + connect \Y $xnor$3510.v:13$1_Y + end + attribute \src "3510.v:14.3-17.8" + process $proc$3510.v:14$2 + assign $0\reg5[3:0] { \wire4 [2] \wire4 } + sync posedge $delete_wire$14 + update \reg5 $0\reg5[3:0] + end + connect \y [4:0] { \reg5 1'0 } + connect \wire4 $xnor$3510.v:13$1_Y [2:0] +end +EOF + +prep +splitcells + From a5f34d04f8f3f9305c18bdfb79e13e59ac15ac39 Mon Sep 17 00:00:00 2001 From: Jason Xu <40355221+JasonBrave@users.noreply.github.com> Date: Tue, 11 Mar 2025 18:50:44 -0400 Subject: [PATCH 13/22] Address comments --- frontends/verific/verific.cc | 4 ++++ frontends/verilog/verilog_frontend.cc | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 19f17b0ff..a320a6efd 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -4413,7 +4413,11 @@ struct ReadPass : public Pass { if (use_verific) { args[0] = "verific"; } else { +#if !defined(__wasm) args[0] = "read_verilog_file_list"; +#else + cmd_error(args, 1, "Command files are not supported on this platform.\n"); +#endif } Pass::call(design, args); return; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 737481743..e4e705c39 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -722,13 +722,16 @@ struct VerilogFileList : public Pass { log("\n"); log(" read_verilog_file_list [options]\n"); log("\n"); - log("Parse a Verilog file list, and pass the list of Verilog files to read_verilog command.\n"); + log("Parse a Verilog file list, and pass the list of Verilog files to read_verilog\n"); + log("command\n"); log("\n"); log(" -F file_list_path\n"); - log(" File list file contains list of Verilog files to be parsed, any path is treated relative to the file list file\n"); + log(" File list file contains list of Verilog files to be parsed, any path is\n"); + log(" treated relative to the file list file\n"); log("\n"); log(" -f file_list_path\n"); - log(" File list file contains list of Verilog files to be parsed, any path is treated relative to current working directroy\n"); + log(" File list file contains list of Verilog files to be parsed, any path is\n"); + log(" treated relative to current working directroy\n"); log("\n"); } From 9593d942959047fd12005d4ddf3aea0215ef6ada Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 14 Mar 2025 18:08:41 -0700 Subject: [PATCH 14/22] Reduce verbosity of splitcells debug --- passes/cmds/splitcells.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/cmds/splitcells.cc b/passes/cmds/splitcells.cc index a33d968d8..c5d12413b 100644 --- a/passes/cmds/splitcells.cc +++ b/passes/cmds/splitcells.cc @@ -88,7 +88,7 @@ struct SplitcellsWorker } if (GetSize(slices) <= 1) return 0; if (limit != -1 && GetSize(slices) > limit) { // skip if number of slices is above limit - log("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices)); + log_debug("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices)); return 0; } slices.push_back(GetSize(outsig)); @@ -158,7 +158,7 @@ struct SplitcellsWorker if (GetSize(slices) <= 1) return 0; if (limit != -1 && GetSize(slices) > limit) { // skip if number of slices is above limit - log("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices)); + log_debug("Skipping %s cell %s/%s with high slice count %d.\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(slices)); return 0; } slices.push_back(GetSize(outsig)); From ecd289b9969bcf531ba1fcfe5f2599e848b7042a Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 00:38:32 -0700 Subject: [PATCH 15/22] Small simplemap rename --- passes/techmap/simplemap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 4ca3b8ab7..4e596911c 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -245,7 +245,7 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) bool is_signed = cell->parameters.at(ID::A_SIGNED).as_bool(); bool is_ne = cell->type.in(ID($ne), ID($nex)); - RTLIL::SigSpec xor_out = module->addWire(NEW_ID2_SUFFIX("xor_out"), max(GetSize(sig_a), GetSize(sig_b))); // SILIMATE: Improve the naming + RTLIL::SigSpec xor_out = module->addWire(NEW_ID2_SUFFIX("xor"), max(GetSize(sig_a), GetSize(sig_b))); // SILIMATE: Improve the naming RTLIL::Cell *xor_cell = module->addXor(NEW_ID2, sig_a, sig_b, xor_out, is_signed, cell->get_src_attribute()); // SILIMATE: Improve the naming xor_cell->attributes = cell->attributes; simplemap_bitop(module, xor_cell); From 4bf3338e1eab1cb8c24c69106540d362297ce434 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 02:29:12 -0700 Subject: [PATCH 16/22] Muxpack until not possible --- passes/opt/muxpack.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index fe60d5404..bb3fffff2 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -436,9 +436,15 @@ struct MuxpackPass : public Pass { int pmux_count = 0; for (auto module : design->selected_modules()) { - MuxpackWorker worker(module, assume_excl, make_excl); - mux_count += worker.mux_count; - pmux_count += worker.pmux_count; + int worker_mux_count = 0; + int worker_pmux_count = 0; + do { + MuxpackWorker worker(module, assume_excl, make_excl); + mux_count += worker.mux_count; + pmux_count += worker.pmux_count; + worker_mux_count = worker.mux_count; + worker_pmux_count = worker.pmux_count; + } while (worker_mux_count + worker_pmux_count > 0); } log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count); From 7ddf0b6d7cf5483599bedfec1c5dd59a7551d498 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 02:29:39 -0700 Subject: [PATCH 17/22] Remove numeric suffix in NEW_ID2 --- kernel/yosys_common.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 9678ff965..dbd683380 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -334,7 +334,19 @@ RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std: #define NEW_ID_SUFFIX(suffix) \ YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix) -#define NEW_ID2 module->uniquify(cell->name.str()) +inline std::string removeNumericSuffix(const std::string& str) { + size_t pos = str.rfind('_'); // Find the last underscore + + if (pos != std::string::npos && pos + 1 < str.size()) { + // Check if everything after the underscore is a digit + if (std::all_of(str.begin() + pos + 1, str.end(), ::isdigit)) { + return str.substr(0, pos); // Return the string without the suffix + } + } + return str; // Return unchanged if no numeric suffix found +} + +#define NEW_ID2 module->uniquify(removeNumericSuffix(cell->name.str())) #define NEW_ID2_SUFFIX(suffix) module->uniquify(cell->name.str() + "_" + suffix) #define NEW_ID3 module->uniquify(cell_name.str()) #define NEW_ID3_SUFFIX(suffix) module->uniquify(cell_name.str() + "_" + suffix) From 11dd7becdd4493bbd9d7b3690b09784cc258e2ad Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 02:30:18 -0700 Subject: [PATCH 18/22] Add opt_balance_tree -arith_only --- passes/silimate/opt_balance_tree.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/passes/silimate/opt_balance_tree.cc b/passes/silimate/opt_balance_tree.cc index 929504d6c..5d893658a 100644 --- a/passes/silimate/opt_balance_tree.cc +++ b/passes/silimate/opt_balance_tree.cc @@ -444,7 +444,9 @@ struct OptBalanceTreePass : public Pass { log(" will be replicated and balanced into a tree, but the original\n"); log(" cell will remain, driving its original loads.\n"); log(" -fanout_limit n\n"); - log(" max fanout to split.\n"); + log(" Max fanout to split.\n"); + log(" -arith_only\n"); + log(" Only balance arithmetic cells.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -452,6 +454,7 @@ struct OptBalanceTreePass : public Pass { log_header(design, "Executing OPT_BALANCE_TREE pass (cell cascades to trees).\n"); bool allow_off_chain = false; + bool arith_only = false; size_t argidx; int limit = -1; for (argidx = 1; argidx < args.size(); argidx++) { @@ -463,13 +466,18 @@ struct OptBalanceTreePass : public Pass { limit = std::stoi(args[++argidx]); continue; } + if (args[argidx] == "-arith_only") { + arith_only = true; + continue; + } break; } extra_args(args, argidx, design); // Count of all cells that were packed dict cell_count; - const vector cell_types = {ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul)}; + vector cell_types = {ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul)}; + if (arith_only) cell_types = {ID($add), ID($mul)}; for (auto module : design->selected_modules()) { OptBalanceTreeWorker worker(design, module, cell_types, allow_off_chain, limit); for (auto cell : worker.cell_count) { From bc3ca6210ca2a9c1594475a1cbb92015957c73d1 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 04:06:28 -0700 Subject: [PATCH 19/22] Add back operator optimization for Verific frontend --- frontends/verific/verific.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 11fb23dfa..9fed0f2e4 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -3123,6 +3123,9 @@ std::string verific_import(Design *design, const std::mapfirst.c_str()); nl->PostElaborationProcess(); + + log(" Running operator optimization for %s.\n", it->first.c_str()); + nl->OperatorOptimization(); } if (nl_done.count(it->first) == 0) { From a08ab5a67b374518da5706346871697feaaa54cd Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 04:09:28 -0700 Subject: [PATCH 20/22] Add opt_expr's missing mux_ornot and mux_andnot cases (still needs testing) --- passes/opt/opt_expr.cc | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 5a39378d9..4f810c35a 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1520,6 +1520,27 @@ skip_identity: goto next_cell; } + if (consume_x && mux_bool && (cell->type == ID($_MUX_) || (cell->type == ID($mux) && cell->parameters[ID::WIDTH] == 1)) && cell->getPort(ID::A) == State::S1) { + cover_list("opt.opt_expr.mux_ornot", "$mux", "$_MUX_", cell->type.str()); + log_debug("Replacing %s cell `%s' in module `%s' with or-gate and not-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); + cell->setPort(ID::A, module->Not(NEW_ID2_SUFFIX("not"), cell->getPort(ID::S), false, cell->get_src_attribute())); + cell->unsetPort(ID::S); + if (cell->type == ID($mux)) { + Const width = cell->parameters[ID::WIDTH]; + cell->parameters[ID::A_WIDTH] = width; + cell->parameters[ID::B_WIDTH] = width; + cell->parameters[ID::Y_WIDTH] = width; + cell->parameters[ID::A_SIGNED] = 0; + cell->parameters[ID::B_SIGNED] = 0; + cell->parameters.erase(ID::WIDTH); + cell->type = ID($or); + } else + cell->type = ID($_OR_); + module->rename(cell, NEW_ID2_SUFFIX("ornot")); + did_something = true; + goto next_cell; + } + if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) { cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); @@ -1540,6 +1561,27 @@ skip_identity: goto next_cell; } + if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S0) { + cover_list("opt.opt_expr.mux_andnot", "$mux", "$_MUX_", cell->type.str()); + log_debug("Replacing %s cell `%s' in module `%s' with and-gate and not-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); + cell->setPort(ID::B, module->Not(NEW_ID2_SUFFIX("not"), cell->getPort(ID::S), false, cell->get_src_attribute())); + cell->unsetPort(ID::S); + if (cell->type == ID($mux)) { + Const width = cell->parameters[ID::WIDTH]; + cell->parameters[ID::A_WIDTH] = width; + cell->parameters[ID::B_WIDTH] = width; + cell->parameters[ID::Y_WIDTH] = width; + cell->parameters[ID::A_SIGNED] = 0; + cell->parameters[ID::B_SIGNED] = 0; + cell->parameters.erase(ID::WIDTH); + cell->type = ID($and); + } else + cell->type = ID($_AND_); + module->rename(cell, NEW_ID2_SUFFIX("andnot")); + did_something = true; + goto next_cell; + } + if (mux_undef && cell->type.in(ID($mux), ID($pmux))) { RTLIL::SigSpec new_a, new_b, new_s; int width = GetSize(cell->getPort(ID::A)); From dc75774c5b7642955d6585af073c3d75e5155f24 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 04:10:08 -0700 Subject: [PATCH 21/22] Breakreduce pass (still needs testing) --- passes/silimate/Makefile.inc | 1 + passes/silimate/breakreduce.cc | 241 +++++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 passes/silimate/breakreduce.cc diff --git a/passes/silimate/Makefile.inc b/passes/silimate/Makefile.inc index c936b0f54..bbf508994 100644 --- a/passes/silimate/Makefile.inc +++ b/passes/silimate/Makefile.inc @@ -2,6 +2,7 @@ OBJS += passes/silimate/activity.o OBJS += passes/silimate/annotate_cell_fanout.o OBJS += passes/silimate/annotate_logic_depth.o +OBJS += passes/silimate/breakreduce.o OBJS += passes/silimate/breaksop.o OBJS += passes/silimate/bus_rebuild.o OBJS += passes/silimate/longloop_select.o diff --git a/passes/silimate/breakreduce.cc b/passes/silimate/breakreduce.cc new file mode 100644 index 000000000..95d8e4a83 --- /dev/null +++ b/passes/silimate/breakreduce.cc @@ -0,0 +1,241 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * Copyright (C) 2025 Akash Levy + * + * 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 + +static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell *cell) +{ + while (sig.size() > 1) + { + RTLIL::SigSpec sig_t = module->addWire(NEW_ID2_SUFFIX("t"), sig.size() / 2); // SILIMATE: Improve the naming + + for (int i = 0; i < sig.size(); i += 2) + { + if (i+1 == sig.size()) { + sig_t.append(sig[i]); + continue; + } + + RTLIL::Cell *gate = module->addCell(NEW_ID2, ID($or)); // SILIMATE: Improve the naming + gate->attributes = cell->attributes; + gate->setPort(ID::A, sig[i]); + gate->setPort(ID::B, sig[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); + gate->fixup_parameters(); + } + + sig = sig_t; + } + + if (sig.size() == 0) + sig = State::S0; +} + +void breakreduce(RTLIL::Module *module, RTLIL::Cell *cell) +{ + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + + if (sig_y.size() == 0) + return; + + if (sig_a.size() == 0) { + if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + return; + } + + if (sig_y.size() > 1) { + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + sig_y = sig_y.extract(0, 1); + } + + IdString gate_type; + if (cell->type == ID($reduce_and)) gate_type = ID($and); + if (cell->type == ID($reduce_or)) gate_type = ID($or); + if (cell->type == ID($reduce_xor)) gate_type = ID($xor); + if (cell->type == ID($reduce_xnor)) gate_type = ID($xor); + if (cell->type == ID($reduce_bool)) gate_type = ID($or); + log_assert(!gate_type.empty()); + + RTLIL::Cell *last_output_cell = NULL; + + while (sig_a.size() > 1) + { + RTLIL::SigSpec sig_t = module->addWire(NEW_ID2_SUFFIX("t"), sig_a.size() / 2); // SILIMATE: Improve the naming + + for (int i = 0; i < sig_a.size(); i += 2) + { + if (i+1 == sig_a.size()) { + sig_t.append(sig_a[i]); + continue; + } + + RTLIL::Cell *gate = module->addCell(NEW_ID2, gate_type); // SILIMATE: Improve the naming + gate->attributes = cell->attributes; + gate->setPort(ID::A, sig_a[i]); + gate->setPort(ID::B, sig_a[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); + gate->fixup_parameters(); + last_output_cell = gate; + } + + sig_a = sig_t; + } + + if (cell->type == ID($reduce_xnor)) { + RTLIL::SigSpec sig_t = module->addWire(NEW_ID2_SUFFIX("t")); // SILIMATE: Improve the naming + RTLIL::Cell *gate = module->addCell(NEW_ID2, ID($not)); // SILIMATE: Improve the naming + gate->attributes = cell->attributes; + gate->setPort(ID::A, sig_a); + gate->setPort(ID::Y, sig_t); + gate->fixup_parameters(); + last_output_cell = gate; + sig_a = sig_t; + } + + if (last_output_cell == NULL) { + module->connect(RTLIL::SigSig(sig_y, sig_a)); + } else { + last_output_cell->setPort(ID::Y, sig_y); + } + + module->remove(cell); +} + +void breaklognot(RTLIL::Module *module, RTLIL::Cell *cell) +{ + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + logic_reduce(module, sig_a, cell); + + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + + if (sig_y.size() == 0) + return; + + if (sig_y.size() > 1) { + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + sig_y = sig_y.extract(0, 1); + } + + RTLIL::Cell *gate = module->addCell(NEW_ID2, ID($not)); // SILIMATE: Improve the naming + gate->attributes = cell->attributes; + gate->setPort(ID::A, sig_a); + gate->setPort(ID::Y, sig_y); + gate->fixup_parameters(); + + module->remove(cell); +} + +void breaklogbin(RTLIL::Module *module, RTLIL::Cell *cell) +{ + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + logic_reduce(module, sig_a, cell); + + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + logic_reduce(module, sig_b, cell); + + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + + if (sig_y.size() == 0) + return; + + if (sig_y.size() > 1) { + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + sig_y = sig_y.extract(0, 1); + } + + IdString gate_type; + if (cell->type == ID($logic_and)) gate_type = ID($and); + if (cell->type == ID($logic_or)) gate_type = ID($or); + log_assert(!gate_type.empty()); + + RTLIL::Cell *gate = module->addCell(NEW_ID2, gate_type); // SILIMATE: Improve the naming + gate->attributes = cell->attributes; + gate->setPort(ID::A, sig_a); + gate->setPort(ID::B, sig_b); + gate->setPort(ID::Y, sig_y); + gate->fixup_parameters(); + + module->remove(cell); +} + +void breakeqne(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_y = cell->getPort(ID::Y); + bool is_signed = cell->parameters.at(ID::A_SIGNED).as_bool(); + bool is_ne = cell->type.in(ID($ne), ID($nex)); + + RTLIL::SigSpec xor_out = module->addWire(NEW_ID2_SUFFIX("xor"), max(GetSize(sig_a), GetSize(sig_b))); // SILIMATE: Improve the naming + RTLIL::Cell *xor_cell = module->addXor(NEW_ID2, sig_a, sig_b, xor_out, is_signed, cell->get_src_attribute()); // SILIMATE: Improve the naming + xor_cell->attributes = cell->attributes; + + RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID2_SUFFIX("reduce_out")); // SILIMATE: Improve the naming + RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID2_SUFFIX("reduce_or"), xor_out, reduce_out, false, cell->get_src_attribute()); // SILIMATE: Improve the naming + reduce_cell->attributes = cell->attributes; + breakreduce(module, reduce_cell); + + if (!is_ne) { + RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID2_SUFFIX("not"), reduce_out, sig_y, false, cell->get_src_attribute()); // SILIMATE: Improve the naming + not_cell->attributes = cell->attributes; + breaklognot(module, not_cell); + } + + module->remove(cell); +} + +struct BreakReducePass : public Pass { + BreakReducePass() : Pass("breakreduce", "break reduce-style cells into trees of primitives") { } + void help() override + { + log("\n"); + log(" breakreduce [selection]\n"); + log("\n"); + log("Break reduce-style ($reduce_*/$logic_*/$*eq*) cells into trees of primitives.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing BREAKREDUCE pass (break reduce-style cells into trees of primitives).\n"); + extra_args(args, 1, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) + if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) + breakreduce(module, cell); + else if (cell->type.in("$logic_and", "$logic_or")) + breaklogbin(module, cell); + else if (cell->type.in("$logic_not")) + breaklognot(module, cell); + else if (cell->type.in("$eq", "$ne", "$eqx", "$nex")) + breakeqne(module, cell); + } +} BreakReducePass; + +PRIVATE_NAMESPACE_END From d9af46538c0159bcb721d602e4f864ee0d749eec Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 17 Mar 2025 04:12:06 -0700 Subject: [PATCH 22/22] opt_expand peepopt (still needs testing) --- passes/silimate/.gitignore | 1 + passes/silimate/Makefile.inc | 10 ++++ passes/silimate/opt_expand.cc | 76 ++++++++++++++++++++++++++++++ passes/silimate/peepopt_expand.pmg | 75 +++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 passes/silimate/.gitignore create mode 100644 passes/silimate/opt_expand.cc create mode 100644 passes/silimate/peepopt_expand.pmg diff --git a/passes/silimate/.gitignore b/passes/silimate/.gitignore new file mode 100644 index 000000000..9342ac23b --- /dev/null +++ b/passes/silimate/.gitignore @@ -0,0 +1 @@ +/peepopt*.h \ No newline at end of file diff --git a/passes/silimate/Makefile.inc b/passes/silimate/Makefile.inc index bbf508994..c60e0693e 100644 --- a/passes/silimate/Makefile.inc +++ b/passes/silimate/Makefile.inc @@ -12,3 +12,13 @@ OBJS += passes/silimate/segv.o OBJS += passes/silimate/selectconst.o OBJS += passes/silimate/splitfanout.o OBJS += passes/silimate/splitnetlist.o + +OBJS += passes/silimate/opt_expand.o +GENFILES += passes/silimate/peepopt_expand.h +passes/silimate/opt_expand.o: passes/silimate/peepopt_expand.h +$(eval $(call add_extra_objs,passes/silimate/peepopt_expand.h)) + +PEEPOPT_PATTERN = passes/silimate/peepopt_expand.pmg + +passes/silimate/peepopt_expand.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) + $(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/silimate/opt_expand.cc b/passes/silimate/opt_expand.cc new file mode 100644 index 000000000..ddb13b0c1 --- /dev/null +++ b/passes/silimate/opt_expand.cc @@ -0,0 +1,76 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * Akash Levy + * + * 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 + +bool did_something; + +#include "passes/silimate/peepopt_expand.h" + +struct OptExpandPass : public Pass { + OptExpandPass() : Pass("opt_expand", "expand conjunction") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" opt_expand [selection]\n"); + log("\n"); + log("This pass expands conjunction (AND) operations into disjunction (OR).\n"); + log("\n"); + log("y = (a | b) & c ===> y = (a & c) | (b & c)\n"); + log("\n"); + log(" -max_iters n\n"); + log(" max number of pass iterations to run.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing OPT_EXPAND pass (expand conjunction into disjunction).\n"); + + size_t argidx; + int max_iters = 10000; + for (argidx = 1; argidx < args.size(); argidx++) { + // No extra arguments + if (args[argidx] == "-max_iters" && argidx + 1 < args.size()) { + max_iters = std::stoi(args[++argidx]); + continue; + } + break; + } + extra_args(args, argidx, design); + for (auto module : design->selected_modules()) + { + did_something = true; + for (int i = 0; did_something && i < max_iters; i++) + { + log("ITERATION OF OPT_EXPAND\n"); + did_something = false; + peepopt_pm pm(module); + pm.setup(module->selected_cells()); + pm.run_expand(); + } + } + } +} PeepoptPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/silimate/peepopt_expand.pmg b/passes/silimate/peepopt_expand.pmg new file mode 100644 index 000000000..2c1787854 --- /dev/null +++ b/passes/silimate/peepopt_expand.pmg @@ -0,0 +1,75 @@ +pattern expand +// +// Authored by Akash Levy of Silimate, Inc. under ISC license. +// +// Expand logical conjunction (&) across (|) +// +// y = (a | b) & c ===> y = (a & c) | (b & c) +// + +state and_a and_b and_y or_a or_b or_y + +match or_gate + // Select OR gate + select or_gate->type.in($or, $_OR_) + set or_a port(or_gate, \A) + set or_b port(or_gate, \B) + set or_y port(or_gate, \Y) +endmatch + +code + // Fanout of each OR gate Y bit should be 1 (no bit-split) + if (nusers(or_y) != 2) + reject; +endcode + +match and_gate + // Select AND gate + select and_gate->type.in($and, $_AND_) + + // Set ports, allowing A and B to be swapped + choice A {\A, \B} + define B (A == \A ? \B : \A) + set and_a port(and_gate, A) + set and_b port(and_gate, B) + set and_y port(and_gate, \Y) + + // Connection + index port(and_gate, A) === or_y +endmatch + +code and_a and_b and_y or_a or_b or_y + // Unset all ports + and_gate->unsetPort(\A); + and_gate->unsetPort(\B); + and_gate->unsetPort(\Y); + or_gate->unsetPort(\A); + or_gate->unsetPort(\B); + or_gate->unsetPort(\Y); + + // Create new intermediate wires + Cell *cell = and_gate; + Wire *new_or_a = module->addWire(NEW_ID2, GetSize(and_y)); + Wire *new_or_b = module->addWire(NEW_ID2, GetSize(and_y)); + + // Create new AND gates connected to the OR gate + module->addAnd(NEW_ID2, or_a, and_b, new_or_a, false, cell->get_src_attribute()); + module->addAnd(NEW_ID2, or_b, and_b, new_or_b, false, cell->get_src_attribute()); + + // Update OR gate ports + or_gate->setPort(\A, new_or_a); + or_gate->setPort(\B, new_or_b); + or_gate->setPort(\Y, and_y); + + // Rename OR gate for formal + cell = or_gate; + module->rename(or_gate, NEW_ID2); + + // Remove AND gate + autoremove(and_gate); + + // Log, fixup, accept + log("expand pattern in %s: and=%s, or=%s\n", log_id(module), log_id(and_gate), log_id(or_gate)); + did_something = true; + accept; +endcode