From d4e0437cfd5046d7f80450c2507a5a73cfafcfba Mon Sep 17 00:00:00 2001 From: Natalia Date: Mon, 24 Nov 2025 15:56:28 -0800 Subject: [PATCH 01/83] Fix Verific run-test.mk setup --- tests/verific/run-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/verific/run-test.sh b/tests/verific/run-test.sh index 2e340916d..1d39e2093 100755 --- a/tests/verific/run-test.sh +++ b/tests/verific/run-test.sh @@ -2,4 +2,4 @@ set -eu source ../gen-tests-makefile.sh generate_mk --yosys-scripts --bash -sed -i '1i\export ASAN_OPTIONS=halt_on_error=0' run-test.mk +echo "$(echo 'export ASAN_OPTIONS=halt_on_error=0'; cat run-test.mk)" > run-test.mk \ No newline at end of file From 214d09a8c6a4280ef45d436f97412411861a56b6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 27 Nov 2025 14:57:02 +0100 Subject: [PATCH 02/83] .github: everything that triggers on main or PRs should trigger on merge queue commit --- .github/workflows/extra-builds.yml | 1 + .github/workflows/prepare-docs.yml | 2 +- .github/workflows/test-build.yml | 1 + .github/workflows/test-compile.yml | 1 + .github/workflows/test-sanitizers.yml | 1 + .github/workflows/test-verific.yml | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index b22a399db..5a2454fd4 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check diff --git a/.github/workflows/prepare-docs.yml b/.github/workflows/prepare-docs.yml index f19b1c7af..e3d917942 100644 --- a/.github/workflows/prepare-docs.yml +++ b/.github/workflows/prepare-docs.yml @@ -1,6 +1,6 @@ name: Build docs artifact with Verific -on: [push, pull_request] +on: [push, pull_request, merge_group] jobs: check_docs_rebuild: diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 8c1a3bbd2..ab6eb3148 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 31c8bccf6..000d1c400 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 4c8e3ec51..11a339cd3 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # ignore PRs due to time needed # allow triggering tests, ignores skip check workflow_dispatch: diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 6619e1124..adc6f59d8 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -5,6 +5,7 @@ on: push: branches: - main + merge_group: # test PRs pull_request: # allow triggering tests, ignores skip check From 7e75200b2af3c7aab29843273afd6b69c2cc5375 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 25 Nov 2025 02:22:32 +0000 Subject: [PATCH 03/83] Check that we don't use logging during multithreading --- kernel/log.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/log.cc b/kernel/log.cc index d712eda2c..6691a80af 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -203,6 +203,8 @@ static void logv_string(std::string_view format, std::string str) { void log_formatted_string(std::string_view format, std::string str) { + log_assert(!Multithreading::active()); + if (log_make_debug && !ys_debug(1)) return; logv_string(format, std::move(str)); @@ -210,6 +212,8 @@ void log_formatted_string(std::string_view format, std::string str) void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str) { + log_assert(!Multithreading::active()); + bool pop_errfile = false; log_spacer(); @@ -249,6 +253,8 @@ void log_formatted_header(RTLIL::Design *design, std::string_view format, std::s void log_formatted_warning(std::string_view prefix, std::string message) { + log_assert(!Multithreading::active()); + bool suppressed = false; for (auto &re : log_nowarn_regexes) From cebb80250c90cea2740b41a1bae9512bc92a2b41 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 1 Dec 2025 19:40:17 +0100 Subject: [PATCH 04/83] aiger2: formatting --- backends/aiger2/aiger.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/backends/aiger2/aiger.cc b/backends/aiger2/aiger.cc index 41e1b91c1..499dfd22d 100644 --- a/backends/aiger2/aiger.cc +++ b/backends/aiger2/aiger.cc @@ -24,6 +24,7 @@ #include "kernel/register.h" #include "kernel/celltypes.h" +#include "kernel/rtlil.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -845,11 +846,14 @@ struct XAigerAnalysis : Index { return false; int max = 1; - for (auto wire : mod->wires()) - if (wire->port_input && !wire->port_output) - for (int i = 0; i < wire->width; i++) { - int ilevel = visit(cursor, driver->getPort(wire->name)[i]); - max = std::max(max, ilevel + 1); + for (auto wire : mod->wires()) { + if (wire->port_input && !wire->port_output) { + SigSpec port = driver->getPort(wire->name); + for (int i = 0; i < wire->width; i++) { + int ilevel = visit(cursor, port[i]); + max = std::max(max, ilevel + 1); + } + } } lits[idx] = max; From b2270ae1c888a29712c99f7c658ffc1cb3ee83e1 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 1 Dec 2025 19:40:58 +0100 Subject: [PATCH 05/83] aiger2: fix case where submodule cell input port has empty SigSpec --- backends/aiger2/aiger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/aiger2/aiger.cc b/backends/aiger2/aiger.cc index 499dfd22d..babc29826 100644 --- a/backends/aiger2/aiger.cc +++ b/backends/aiger2/aiger.cc @@ -849,7 +849,7 @@ struct XAigerAnalysis : Index { for (auto wire : mod->wires()) { if (wire->port_input && !wire->port_output) { SigSpec port = driver->getPort(wire->name); - for (int i = 0; i < wire->width; i++) { + for (int i = 0; i < std::min(wire->width, port.size()); i++) { int ilevel = visit(cursor, port[i]); max = std::max(max, ilevel + 1); } From 9ec361beab10941bf70fd2de4a82752c6eae8a11 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Dec 2025 14:03:12 +1300 Subject: [PATCH 06/83] test_cell.cc: Generate .aag for all compatible cells Skips (with warning) on cells that didn't convert to avoid `write_aiger` from raising an error. --- passes/tests/test_cell.cc | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 73af155bd..4d28e659b 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -1143,7 +1143,29 @@ struct TestCellPass : public Pass { else uut = create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv); if (!write_prefix.empty()) { - Pass::call(design, stringf("write_rtlil %s_%s_%05d.il", write_prefix, cell_type.c_str()+1, i)); + string writer = "write_rtlil"; + string suffix = "il"; + if (techmap_cmd.compare("aigmap") == 0) { + // try to convert to aiger + Pass::call(design, techmap_cmd); + bool is_unconverted = false; + for (auto *mod : design->selected_modules()) + for (auto *cell : mod->selected_cells()) + if (!cell->type.in(ID::$_NOT_, ID::$_AND_)) { + is_unconverted = true; + break; + } + if (is_unconverted) { + // skip unconverted cells + log_warning("Skipping %s\n", cell_type); + delete design; + break; + } else { + writer = "write_aiger -ascii"; + suffix = "aag"; + } + } + Pass::call(design, stringf("%s %s_%s_%05d.%s", writer, write_prefix, cell_type.c_str()+1, i, suffix)); } else if (edges) { Pass::call(design, "dump gold"); run_edges_test(design, verbose); From e2e792275698749457e8ea65df8f9c9132a18cf9 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Dec 2025 14:03:12 +1300 Subject: [PATCH 07/83] tests/aiger: Compare .aag outputs against known Any files that differ (e.g. due to compiler order of operations changing) will trigger an error. --- tests/aiger/.gitignore | 1 + tests/aiger/run-test.sh | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore index 4bb3e67f6..ef347c9d3 100644 --- a/tests/aiger/.gitignore +++ b/tests/aiger/.gitignore @@ -1,2 +1,3 @@ /*_ref.v /neg.out/ +/gate/ diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh index ca7339ff0..bd22f31ed 100755 --- a/tests/aiger/run-test.sh +++ b/tests/aiger/run-test.sh @@ -57,3 +57,9 @@ for y in *.ys; do echo "Running $y." ../../yosys -ql ${y%.*}.log $y done + +# compare aigmap with reference +# make gold with: rm gold/*; yosys --no-version -p "test_cell -aigmap -w gold/ -n 1 -s 1 all" +rm -rf gate; mkdir gate +../../yosys --no-version -p "test_cell -aigmap -w gate/ -n 1 -s 1 all" +diff --brief gold gate | tee aigmap.err From 6842003e76bc728052b8b26cf8379fcc6a85228a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Dec 2025 14:03:12 +1300 Subject: [PATCH 08/83] tests/aiger: Add gold .aag files Generated with changes from 26f2c111 --- tests/aiger/gold/__ANDNOT__00000.aag | 7 +++ tests/aiger/gold/__AND__00000.aag | 7 +++ tests/aiger/gold/__AOI3__00000.aag | 9 ++++ tests/aiger/gold/__AOI4__00000.aag | 11 +++++ tests/aiger/gold/__BUF__00000.aag | 5 ++ tests/aiger/gold/__MUX__00000.aag | 10 ++++ tests/aiger/gold/__NAND__00000.aag | 7 +++ tests/aiger/gold/__NMUX__00000.aag | 10 ++++ tests/aiger/gold/__NOR__00000.aag | 7 +++ tests/aiger/gold/__NOT__00000.aag | 5 ++ tests/aiger/gold/__OAI3__00000.aag | 9 ++++ tests/aiger/gold/__OAI4__00000.aag | 11 +++++ tests/aiger/gold/__ORNOT__00000.aag | 7 +++ tests/aiger/gold/__OR__00000.aag | 7 +++ tests/aiger/gold/__XNOR__00000.aag | 9 ++++ tests/aiger/gold/__XOR__00000.aag | 9 ++++ tests/aiger/gold/_add_00000.aag | 62 +++++++++++++++++++++++++ tests/aiger/gold/_alu_00000.aag | 45 ++++++++++++++++++ tests/aiger/gold/_and_00000.aag | 28 +++++++++++ tests/aiger/gold/_buf_00000.aag | 15 ++++++ tests/aiger/gold/_eq_00000.aag | 46 ++++++++++++++++++ tests/aiger/gold/_ge_00000.aag | 9 ++++ tests/aiger/gold/_gt_00000.aag | 48 +++++++++++++++++++ tests/aiger/gold/_le_00000.aag | 52 +++++++++++++++++++++ tests/aiger/gold/_logic_and_00000.aag | 30 ++++++++++++ tests/aiger/gold/_logic_not_00000.aag | 15 ++++++ tests/aiger/gold/_logic_or_00000.aag | 29 ++++++++++++ tests/aiger/gold/_lt_00000.aag | 43 +++++++++++++++++ tests/aiger/gold/_mux_00000.aag | 10 ++++ tests/aiger/gold/_ne_00000.aag | 40 ++++++++++++++++ tests/aiger/gold/_not_00000.aag | 11 +++++ tests/aiger/gold/_or_00000.aag | 11 +++++ tests/aiger/gold/_pos_00000.aag | 9 ++++ tests/aiger/gold/_reduce_and_00000.aag | 7 +++ tests/aiger/gold/_reduce_bool_00000.aag | 13 ++++++ tests/aiger/gold/_reduce_or_00000.aag | 7 +++ tests/aiger/gold/_reduce_xnor_00000.aag | 30 ++++++++++++ tests/aiger/gold/_reduce_xor_00000.aag | 9 ++++ tests/aiger/gold/_sub_00000.aag | 20 ++++++++ tests/aiger/gold/_xnor_00000.aag | 17 +++++++ tests/aiger/gold/_xor_00000.aag | 12 +++++ 41 files changed, 748 insertions(+) create mode 100644 tests/aiger/gold/__ANDNOT__00000.aag create mode 100644 tests/aiger/gold/__AND__00000.aag create mode 100644 tests/aiger/gold/__AOI3__00000.aag create mode 100644 tests/aiger/gold/__AOI4__00000.aag create mode 100644 tests/aiger/gold/__BUF__00000.aag create mode 100644 tests/aiger/gold/__MUX__00000.aag create mode 100644 tests/aiger/gold/__NAND__00000.aag create mode 100644 tests/aiger/gold/__NMUX__00000.aag create mode 100644 tests/aiger/gold/__NOR__00000.aag create mode 100644 tests/aiger/gold/__NOT__00000.aag create mode 100644 tests/aiger/gold/__OAI3__00000.aag create mode 100644 tests/aiger/gold/__OAI4__00000.aag create mode 100644 tests/aiger/gold/__ORNOT__00000.aag create mode 100644 tests/aiger/gold/__OR__00000.aag create mode 100644 tests/aiger/gold/__XNOR__00000.aag create mode 100644 tests/aiger/gold/__XOR__00000.aag create mode 100644 tests/aiger/gold/_add_00000.aag create mode 100644 tests/aiger/gold/_alu_00000.aag create mode 100644 tests/aiger/gold/_and_00000.aag create mode 100644 tests/aiger/gold/_buf_00000.aag create mode 100644 tests/aiger/gold/_eq_00000.aag create mode 100644 tests/aiger/gold/_ge_00000.aag create mode 100644 tests/aiger/gold/_gt_00000.aag create mode 100644 tests/aiger/gold/_le_00000.aag create mode 100644 tests/aiger/gold/_logic_and_00000.aag create mode 100644 tests/aiger/gold/_logic_not_00000.aag create mode 100644 tests/aiger/gold/_logic_or_00000.aag create mode 100644 tests/aiger/gold/_lt_00000.aag create mode 100644 tests/aiger/gold/_mux_00000.aag create mode 100644 tests/aiger/gold/_ne_00000.aag create mode 100644 tests/aiger/gold/_not_00000.aag create mode 100644 tests/aiger/gold/_or_00000.aag create mode 100644 tests/aiger/gold/_pos_00000.aag create mode 100644 tests/aiger/gold/_reduce_and_00000.aag create mode 100644 tests/aiger/gold/_reduce_bool_00000.aag create mode 100644 tests/aiger/gold/_reduce_or_00000.aag create mode 100644 tests/aiger/gold/_reduce_xnor_00000.aag create mode 100644 tests/aiger/gold/_reduce_xor_00000.aag create mode 100644 tests/aiger/gold/_sub_00000.aag create mode 100644 tests/aiger/gold/_xnor_00000.aag create mode 100644 tests/aiger/gold/_xor_00000.aag diff --git a/tests/aiger/gold/__ANDNOT__00000.aag b/tests/aiger/gold/__ANDNOT__00000.aag new file mode 100644 index 000000000..93f5c0044 --- /dev/null +++ b/tests/aiger/gold/__ANDNOT__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +6 +6 5 2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__AND__00000.aag b/tests/aiger/gold/__AND__00000.aag new file mode 100644 index 000000000..5b0148022 --- /dev/null +++ b/tests/aiger/gold/__AND__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +6 +6 4 2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__AOI3__00000.aag b/tests/aiger/gold/__AOI3__00000.aag new file mode 100644 index 000000000..a726927fe --- /dev/null +++ b/tests/aiger/gold/__AOI3__00000.aag @@ -0,0 +1,9 @@ +aag 5 3 0 1 2 +2 +4 +6 +10 +8 4 2 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/__AOI4__00000.aag b/tests/aiger/gold/__AOI4__00000.aag new file mode 100644 index 000000000..4044dc5a8 --- /dev/null +++ b/tests/aiger/gold/__AOI4__00000.aag @@ -0,0 +1,11 @@ +aag 7 4 0 1 3 +2 +4 +6 +8 +14 +10 4 2 +12 8 6 +14 13 11 +c +Generated by Yosys diff --git a/tests/aiger/gold/__BUF__00000.aag b/tests/aiger/gold/__BUF__00000.aag new file mode 100644 index 000000000..7a4cd3156 --- /dev/null +++ b/tests/aiger/gold/__BUF__00000.aag @@ -0,0 +1,5 @@ +aag 1 1 0 1 0 +2 +2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__MUX__00000.aag b/tests/aiger/gold/__MUX__00000.aag new file mode 100644 index 000000000..4d1757a65 --- /dev/null +++ b/tests/aiger/gold/__MUX__00000.aag @@ -0,0 +1,10 @@ +aag 6 3 0 1 3 +2 +4 +6 +13 +8 7 2 +10 6 4 +12 11 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NAND__00000.aag b/tests/aiger/gold/__NAND__00000.aag new file mode 100644 index 000000000..bc42187b1 --- /dev/null +++ b/tests/aiger/gold/__NAND__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 4 2 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NMUX__00000.aag b/tests/aiger/gold/__NMUX__00000.aag new file mode 100644 index 000000000..b939855f9 --- /dev/null +++ b/tests/aiger/gold/__NMUX__00000.aag @@ -0,0 +1,10 @@ +aag 6 3 0 1 3 +2 +4 +6 +12 +8 7 2 +10 6 4 +12 11 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NOR__00000.aag b/tests/aiger/gold/__NOR__00000.aag new file mode 100644 index 000000000..30b1d6c95 --- /dev/null +++ b/tests/aiger/gold/__NOR__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +6 +6 5 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__NOT__00000.aag b/tests/aiger/gold/__NOT__00000.aag new file mode 100644 index 000000000..0c9119cea --- /dev/null +++ b/tests/aiger/gold/__NOT__00000.aag @@ -0,0 +1,5 @@ +aag 1 1 0 1 0 +2 +3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__OAI3__00000.aag b/tests/aiger/gold/__OAI3__00000.aag new file mode 100644 index 000000000..9f8af1f72 --- /dev/null +++ b/tests/aiger/gold/__OAI3__00000.aag @@ -0,0 +1,9 @@ +aag 5 3 0 1 2 +2 +4 +6 +11 +8 5 3 +10 9 6 +c +Generated by Yosys diff --git a/tests/aiger/gold/__OAI4__00000.aag b/tests/aiger/gold/__OAI4__00000.aag new file mode 100644 index 000000000..871c05ba3 --- /dev/null +++ b/tests/aiger/gold/__OAI4__00000.aag @@ -0,0 +1,11 @@ +aag 7 4 0 1 3 +2 +4 +6 +8 +15 +10 5 3 +12 9 7 +14 13 11 +c +Generated by Yosys diff --git a/tests/aiger/gold/__ORNOT__00000.aag b/tests/aiger/gold/__ORNOT__00000.aag new file mode 100644 index 000000000..fc7263fce --- /dev/null +++ b/tests/aiger/gold/__ORNOT__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 4 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__OR__00000.aag b/tests/aiger/gold/__OR__00000.aag new file mode 100644 index 000000000..d5e8085c2 --- /dev/null +++ b/tests/aiger/gold/__OR__00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 5 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/__XNOR__00000.aag b/tests/aiger/gold/__XNOR__00000.aag new file mode 100644 index 000000000..18bb92393 --- /dev/null +++ b/tests/aiger/gold/__XNOR__00000.aag @@ -0,0 +1,9 @@ +aag 5 2 0 1 3 +2 +4 +11 +6 4 2 +8 5 3 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/__XOR__00000.aag b/tests/aiger/gold/__XOR__00000.aag new file mode 100644 index 000000000..ab4bc32ad --- /dev/null +++ b/tests/aiger/gold/__XOR__00000.aag @@ -0,0 +1,9 @@ +aag 5 2 0 1 3 +2 +4 +10 +6 4 2 +8 5 3 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/_add_00000.aag b/tests/aiger/gold/_add_00000.aag new file mode 100644 index 000000000..9f22bc0f3 --- /dev/null +++ b/tests/aiger/gold/_add_00000.aag @@ -0,0 +1,62 @@ +aag 51 4 0 8 47 +2 +4 +6 +8 +14 +30 +42 +54 +66 +78 +90 +102 +10 6 2 +12 7 3 +14 13 11 +16 6 2 +18 8 4 +20 9 5 +22 21 19 +24 22 16 +26 21 19 +28 27 11 +30 29 25 +32 21 16 +34 33 19 +36 35 22 +38 33 19 +40 38 27 +42 41 37 +44 35 21 +46 45 19 +48 47 22 +50 45 19 +52 50 27 +54 53 49 +56 47 21 +58 57 19 +60 59 22 +62 57 19 +64 62 27 +66 65 61 +68 59 21 +70 69 19 +72 71 22 +74 69 19 +76 74 27 +78 77 73 +80 71 21 +82 81 19 +84 83 22 +86 81 19 +88 86 27 +90 89 85 +92 83 21 +94 93 19 +96 95 22 +98 93 19 +100 98 27 +102 101 97 +c +Generated by Yosys diff --git a/tests/aiger/gold/_alu_00000.aag b/tests/aiger/gold/_alu_00000.aag new file mode 100644 index 000000000..3fdb09ea5 --- /dev/null +++ b/tests/aiger/gold/_alu_00000.aag @@ -0,0 +1,45 @@ +aag 33 5 0 9 28 +2 +4 +6 +8 +10 +27 +35 +36 +38 +40 +8 +48 +58 +66 +12 8 6 +14 9 7 +16 15 13 +18 16 2 +20 15 13 +22 21 3 +24 23 10 +26 25 19 +28 8 4 +30 9 5 +32 31 27 +34 33 29 +36 35 8 +38 23 19 +40 31 29 +42 38 10 +44 23 19 +46 45 11 +48 47 43 +50 40 27 +52 31 29 +54 25 19 +56 54 53 +58 57 51 +60 35 8 +62 33 29 +64 62 9 +66 65 61 +c +Generated by Yosys diff --git a/tests/aiger/gold/_and_00000.aag b/tests/aiger/gold/_and_00000.aag new file mode 100644 index 000000000..6d3bab8d3 --- /dev/null +++ b/tests/aiger/gold/_and_00000.aag @@ -0,0 +1,28 @@ +aag 17 11 0 8 6 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +24 +26 +28 +30 +32 +34 +34 +34 +24 14 2 +26 16 4 +28 18 6 +30 20 8 +32 22 10 +34 22 12 +c +Generated by Yosys diff --git a/tests/aiger/gold/_buf_00000.aag b/tests/aiger/gold/_buf_00000.aag new file mode 100644 index 000000000..d373a6a80 --- /dev/null +++ b/tests/aiger/gold/_buf_00000.aag @@ -0,0 +1,15 @@ +aag 6 6 0 6 0 +2 +4 +6 +8 +10 +12 +2 +4 +6 +8 +10 +12 +c +Generated by Yosys diff --git a/tests/aiger/gold/_eq_00000.aag b/tests/aiger/gold/_eq_00000.aag new file mode 100644 index 000000000..e3cbcd2fc --- /dev/null +++ b/tests/aiger/gold/_eq_00000.aag @@ -0,0 +1,46 @@ +aag 38 11 0 5 27 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +76 +0 +0 +0 +0 +24 10 2 +26 11 3 +28 27 25 +30 12 4 +32 13 5 +34 33 31 +36 35 29 +38 14 6 +40 15 7 +42 41 39 +44 43 36 +46 16 8 +48 17 9 +50 49 47 +52 51 44 +54 18 8 +56 19 9 +58 57 55 +60 59 52 +62 20 8 +64 21 9 +66 65 63 +68 67 60 +70 22 8 +72 23 9 +74 73 71 +76 75 68 +c +Generated by Yosys diff --git a/tests/aiger/gold/_ge_00000.aag b/tests/aiger/gold/_ge_00000.aag new file mode 100644 index 000000000..8ccc44797 --- /dev/null +++ b/tests/aiger/gold/_ge_00000.aag @@ -0,0 +1,9 @@ +aag 3 2 0 3 1 +2 +4 +7 +0 +0 +6 4 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/_gt_00000.aag b/tests/aiger/gold/_gt_00000.aag new file mode 100644 index 000000000..cc0905ea1 --- /dev/null +++ b/tests/aiger/gold/_gt_00000.aag @@ -0,0 +1,48 @@ +aag 43 10 0 2 33 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +86 +0 +22 20 7 +24 21 6 +26 25 23 +28 18 7 +30 16 7 +32 14 7 +34 12 7 +36 10 5 +38 9 2 +40 8 3 +42 41 38 +44 11 4 +46 45 43 +48 47 37 +50 13 6 +52 51 49 +54 53 35 +56 15 6 +58 57 55 +60 59 33 +62 17 6 +64 63 61 +66 65 31 +68 19 6 +70 69 67 +72 71 29 +74 73 25 +76 75 23 +78 77 26 +80 25 23 +82 75 23 +84 82 81 +86 85 79 +c +Generated by Yosys diff --git a/tests/aiger/gold/_le_00000.aag b/tests/aiger/gold/_le_00000.aag new file mode 100644 index 000000000..75a138267 --- /dev/null +++ b/tests/aiger/gold/_le_00000.aag @@ -0,0 +1,52 @@ +aag 47 12 0 2 35 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +24 +94 +0 +26 25 8 +28 24 9 +30 29 27 +32 23 8 +34 21 8 +36 19 8 +38 17 8 +40 15 6 +42 13 4 +44 11 2 +46 12 5 +48 47 44 +50 49 43 +52 14 7 +54 53 51 +56 55 41 +58 16 9 +60 59 57 +62 61 39 +64 18 9 +66 65 63 +68 67 37 +70 20 9 +72 71 69 +74 73 35 +76 22 9 +78 77 75 +80 79 33 +82 81 29 +84 83 27 +86 85 30 +88 29 27 +90 83 27 +92 90 89 +94 93 87 +c +Generated by Yosys diff --git a/tests/aiger/gold/_logic_and_00000.aag b/tests/aiger/gold/_logic_and_00000.aag new file mode 100644 index 000000000..d68c6fc34 --- /dev/null +++ b/tests/aiger/gold/_logic_and_00000.aag @@ -0,0 +1,30 @@ +aag 21 11 0 6 10 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +42 +0 +0 +0 +0 +0 +24 5 3 +26 24 7 +28 26 9 +30 28 11 +32 30 13 +34 17 15 +36 34 19 +38 36 21 +40 38 23 +42 41 33 +c +Generated by Yosys diff --git a/tests/aiger/gold/_logic_not_00000.aag b/tests/aiger/gold/_logic_not_00000.aag new file mode 100644 index 000000000..7798b23e9 --- /dev/null +++ b/tests/aiger/gold/_logic_not_00000.aag @@ -0,0 +1,15 @@ +aag 7 4 0 5 3 +2 +4 +6 +8 +14 +0 +0 +0 +0 +10 5 3 +12 10 7 +14 12 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/_logic_or_00000.aag b/tests/aiger/gold/_logic_or_00000.aag new file mode 100644 index 000000000..12b3364d4 --- /dev/null +++ b/tests/aiger/gold/_logic_or_00000.aag @@ -0,0 +1,29 @@ +aag 21 11 0 5 10 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +43 +0 +0 +0 +0 +24 5 3 +26 24 7 +28 26 9 +30 28 11 +32 30 13 +34 17 15 +36 34 19 +38 36 21 +40 38 23 +42 40 32 +c +Generated by Yosys diff --git a/tests/aiger/gold/_lt_00000.aag b/tests/aiger/gold/_lt_00000.aag new file mode 100644 index 000000000..2169b4a53 --- /dev/null +++ b/tests/aiger/gold/_lt_00000.aag @@ -0,0 +1,43 @@ +aag 34 9 0 6 25 +2 +4 +6 +8 +10 +12 +14 +16 +18 +68 +0 +0 +0 +0 +0 +20 19 10 +22 18 11 +24 23 21 +26 19 8 +28 17 6 +30 15 4 +32 12 3 +34 13 2 +36 35 32 +38 14 5 +40 39 37 +42 41 31 +44 16 7 +46 45 43 +48 47 29 +50 18 9 +52 51 49 +54 53 27 +56 55 23 +58 57 21 +60 59 24 +62 23 21 +64 57 21 +66 64 63 +68 67 61 +c +Generated by Yosys diff --git a/tests/aiger/gold/_mux_00000.aag b/tests/aiger/gold/_mux_00000.aag new file mode 100644 index 000000000..4d1757a65 --- /dev/null +++ b/tests/aiger/gold/_mux_00000.aag @@ -0,0 +1,10 @@ +aag 6 3 0 1 3 +2 +4 +6 +13 +8 7 2 +10 6 4 +12 11 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/_ne_00000.aag b/tests/aiger/gold/_ne_00000.aag new file mode 100644 index 000000000..e4d894bde --- /dev/null +++ b/tests/aiger/gold/_ne_00000.aag @@ -0,0 +1,40 @@ +aag 29 10 0 8 19 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +59 +0 +0 +0 +0 +0 +0 +0 +22 12 2 +24 13 3 +26 25 23 +28 14 4 +30 15 5 +32 31 29 +34 33 27 +36 16 6 +38 17 7 +40 39 37 +42 41 34 +44 18 8 +46 19 9 +48 47 45 +50 49 42 +52 20 10 +54 21 11 +56 55 53 +58 57 50 +c +Generated by Yosys diff --git a/tests/aiger/gold/_not_00000.aag b/tests/aiger/gold/_not_00000.aag new file mode 100644 index 000000000..3c5ede656 --- /dev/null +++ b/tests/aiger/gold/_not_00000.aag @@ -0,0 +1,11 @@ +aag 6 6 0 2 0 +2 +4 +6 +8 +10 +12 +3 +5 +c +Generated by Yosys diff --git a/tests/aiger/gold/_or_00000.aag b/tests/aiger/gold/_or_00000.aag new file mode 100644 index 000000000..58714e461 --- /dev/null +++ b/tests/aiger/gold/_or_00000.aag @@ -0,0 +1,11 @@ +aag 6 4 0 2 2 +2 +4 +6 +8 +11 +13 +10 5 3 +12 7 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/_pos_00000.aag b/tests/aiger/gold/_pos_00000.aag new file mode 100644 index 000000000..29a2dd61a --- /dev/null +++ b/tests/aiger/gold/_pos_00000.aag @@ -0,0 +1,9 @@ +aag 1 1 0 5 0 +2 +2 +2 +2 +2 +2 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_and_00000.aag b/tests/aiger/gold/_reduce_and_00000.aag new file mode 100644 index 000000000..06db9a1dd --- /dev/null +++ b/tests/aiger/gold/_reduce_and_00000.aag @@ -0,0 +1,7 @@ +aag 1 1 0 3 0 +2 +2 +0 +0 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_bool_00000.aag b/tests/aiger/gold/_reduce_bool_00000.aag new file mode 100644 index 000000000..48a1410c8 --- /dev/null +++ b/tests/aiger/gold/_reduce_bool_00000.aag @@ -0,0 +1,13 @@ +aag 7 4 0 3 3 +2 +4 +6 +8 +15 +0 +0 +10 5 3 +12 10 7 +14 12 9 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_or_00000.aag b/tests/aiger/gold/_reduce_or_00000.aag new file mode 100644 index 000000000..d5e8085c2 --- /dev/null +++ b/tests/aiger/gold/_reduce_or_00000.aag @@ -0,0 +1,7 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 5 3 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_xnor_00000.aag b/tests/aiger/gold/_reduce_xnor_00000.aag new file mode 100644 index 000000000..6ad6ac39e --- /dev/null +++ b/tests/aiger/gold/_reduce_xnor_00000.aag @@ -0,0 +1,30 @@ +aag 25 6 0 2 19 +2 +4 +6 +8 +10 +12 +51 +0 +14 4 2 +16 5 3 +18 17 15 +20 18 6 +22 17 15 +24 23 7 +26 25 21 +28 26 8 +30 25 21 +32 31 9 +34 33 29 +36 34 10 +38 33 29 +40 39 11 +42 41 37 +44 42 12 +46 41 37 +48 47 13 +50 49 45 +c +Generated by Yosys diff --git a/tests/aiger/gold/_reduce_xor_00000.aag b/tests/aiger/gold/_reduce_xor_00000.aag new file mode 100644 index 000000000..ab4bc32ad --- /dev/null +++ b/tests/aiger/gold/_reduce_xor_00000.aag @@ -0,0 +1,9 @@ +aag 5 2 0 1 3 +2 +4 +10 +6 4 2 +8 5 3 +10 9 7 +c +Generated by Yosys diff --git a/tests/aiger/gold/_sub_00000.aag b/tests/aiger/gold/_sub_00000.aag new file mode 100644 index 000000000..e9d976b32 --- /dev/null +++ b/tests/aiger/gold/_sub_00000.aag @@ -0,0 +1,20 @@ +aag 16 13 0 1 3 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +24 +26 +33 +28 17 2 +30 16 3 +32 31 29 +c +Generated by Yosys diff --git a/tests/aiger/gold/_xnor_00000.aag b/tests/aiger/gold/_xnor_00000.aag new file mode 100644 index 000000000..9dd097862 --- /dev/null +++ b/tests/aiger/gold/_xnor_00000.aag @@ -0,0 +1,17 @@ +aag 10 4 0 4 6 +2 +4 +6 +8 +15 +21 +21 +21 +10 6 2 +12 7 3 +14 13 11 +16 8 4 +18 9 5 +20 19 17 +c +Generated by Yosys diff --git a/tests/aiger/gold/_xor_00000.aag b/tests/aiger/gold/_xor_00000.aag new file mode 100644 index 000000000..453b8d0ee --- /dev/null +++ b/tests/aiger/gold/_xor_00000.aag @@ -0,0 +1,12 @@ +aag 8 5 0 1 3 +2 +4 +6 +8 +10 +16 +12 8 2 +14 9 3 +16 15 13 +c +Generated by Yosys From b2e527c67eec62859dc31ed13720b174698f8907 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Dec 2025 14:17:16 +1300 Subject: [PATCH 09/83] tests/aiger: Only write aigmap.err on error --- tests/aiger/run-test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh index bd22f31ed..a4de58e30 100755 --- a/tests/aiger/run-test.sh +++ b/tests/aiger/run-test.sh @@ -63,3 +63,4 @@ done rm -rf gate; mkdir gate ../../yosys --no-version -p "test_cell -aigmap -w gate/ -n 1 -s 1 all" diff --brief gold gate | tee aigmap.err +rm aigmap.err From 36f0e0392fdcbf2fb3bd051ac73b88ec530510b5 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 2 Dec 2025 15:26:21 +0100 Subject: [PATCH 10/83] aiger2: add crash test --- tests/techmap/abc_speed_gia_only.script | 28 ++++++++++++ tests/techmap/xaiger2-5169.ys | 60 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 tests/techmap/abc_speed_gia_only.script create mode 100644 tests/techmap/xaiger2-5169.ys diff --git a/tests/techmap/abc_speed_gia_only.script b/tests/techmap/abc_speed_gia_only.script new file mode 100644 index 000000000..d3730fdb5 --- /dev/null +++ b/tests/techmap/abc_speed_gia_only.script @@ -0,0 +1,28 @@ +&st +&dch -r +&nf +&st +&syn2 +&if -g -K 6 +&synch2 -r +&nf +&st +&syn2 +&if -g -K 6 +&synch2 -r +&nf +&st +&syn2 +&if -g -K 6 +&synch2 -r +&nf +&st +&syn2 +&if -g -K 6 +&synch2 -r +&nf +&st +&syn2 +&if -g -K 6 +&synch2 -r +&nf diff --git a/tests/techmap/xaiger2-5169.ys b/tests/techmap/xaiger2-5169.ys new file mode 100644 index 000000000..110f17346 --- /dev/null +++ b/tests/techmap/xaiger2-5169.ys @@ -0,0 +1,60 @@ +read_rtlil < Y) = 453; + (D1 => Y) = 449; + (D2 => Y) = 488; + (D3 => Y) = 484; + (S0 => Y) = 422; + (S1 => Y) = 385; + endspecify + + assign Y = S1 ? (S0 ? D3 : D2) : + (S0 ? D1 : D0); + +endmodule + +EOF + +logger -expect error "Malformed design" 1 +abc_new -script abc_speed_gia_only.script -liberty ../../tests/liberty/normal.lib -liberty ../../tests/liberty/dff.lib From 52b1245547e0aabf7aa0c29680c5e27e2564f919 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 00:25:21 +0000 Subject: [PATCH 11/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 15aaf870c..81ad6ccce 100644 --- a/Makefile +++ b/Makefile @@ -162,7 +162,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+0 +YOSYS_VER := 0.60+1 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 7219ac94b3d3f878e5b5a843c4ced619e1904c2c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 30 Sep 2025 15:42:10 +0000 Subject: [PATCH 12/83] Add YOSYS_MAX_THREADS --- kernel/threading.cc | 19 +++++++++++++++++-- kernel/threading.h | 4 ++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/kernel/threading.cc b/kernel/threading.cc index 49fddaa7c..dcc044c89 100644 --- a/kernel/threading.cc +++ b/kernel/threading.cc @@ -3,6 +3,20 @@ YOSYS_NAMESPACE_BEGIN +static int init_max_threads() +{ + const char *v = getenv("YOSYS_MAX_THREADS"); + if (v == nullptr) + return INT32_MAX; + return atoi(v); +} + +static int get_max_threads() +{ + static int max_threads = init_max_threads(); + return max_threads; +} + void DeferredLogs::flush() { for (auto &m : logs) @@ -12,10 +26,11 @@ void DeferredLogs::flush() YOSYS_NAMESPACE_PREFIX log("%s", m.text.c_str()); } -int ThreadPool::pool_size(int reserved_cores, int max_threads) +int ThreadPool::pool_size(int reserved_cores, int max_worker_threads) { #ifdef YOSYS_ENABLE_THREADS - int num_threads = std::min(std::thread::hardware_concurrency() - reserved_cores, max_threads); + int available_threads = std::min(std::thread::hardware_concurrency(), get_max_threads()); + int num_threads = std::min(available_threads - reserved_cores, max_worker_threads); return std::max(0, num_threads); #else return 0; diff --git a/kernel/threading.h b/kernel/threading.h index c34abf850..b8cd62f87 100644 --- a/kernel/threading.h +++ b/kernel/threading.h @@ -127,9 +127,9 @@ class ThreadPool public: // Computes the number of worker threads to use. // `reserved_cores` cores are set aside for other threads (e.g. work on the main thread). - // `max_threads` --- don't return more workers than this. + // `max_worker_threads` --- don't return more workers than this. // The result may be 0. - static int pool_size(int reserved_cores, int max_threads); + static int pool_size(int reserved_cores, int max_worker_threads); // Create a pool of threads running the given closure (parameterized by thread number). // `pool_size` must be the result of a `pool_size()` call. From fc951a28d39c2135d46b020b9f6ad4be9ee225f6 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 30 Sep 2025 18:54:51 +0000 Subject: [PATCH 13/83] Limit YOSYS_MAX_THREADS to 4 when running makefile-tests so we don't overload systems when running 'make -j... test' --- tests/gen-tests-makefile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gen-tests-makefile.sh b/tests/gen-tests-makefile.sh index e3308506b..a0fb23ac3 100755 --- a/tests/gen-tests-makefile.sh +++ b/tests/gen-tests-makefile.sh @@ -9,7 +9,7 @@ generate_target() { echo "all: $target_name" echo ".PHONY: $target_name" echo "$target_name:" - printf "\t@%s\n" "$test_command" + printf "\t@YOSYS_MAX_THREADS=4 %s\n" "$test_command" printf "\t@echo 'Passed %s'\n" "$target_name" } From a871415abf3b6000c6302b35ef7781f9a58c8d87 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 27 Nov 2025 21:57:35 +0000 Subject: [PATCH 14/83] Limit YOSYS_MAX_THREADS to 4 when running seed-tests --- tests/arch/run-test.sh | 1 + tests/asicworld/run-test.sh | 1 + tests/blif/run-test.sh | 1 + tests/bram/run-test.sh | 1 + tests/common-env.sh | 1 + tests/cxxrtl/run-test.sh | 1 + tests/fmt/run-test.sh | 1 + tests/fsm/run-test.sh | 1 + tests/functional/run-test.sh | 1 + tests/hana/run-test.sh | 1 + tests/liberty/run-test.sh | 1 + tests/memfile/run-test.sh | 1 + tests/memlib/run-test.sh | 1 + tests/opt_share/run-test.sh | 1 + tests/peepopt/run-test.sh | 1 + tests/proc/run-test.sh | 1 + tests/rpc/run-test.sh | 1 + tests/select/run-test.sh | 1 + tests/share/run-test.sh | 1 + tests/simple/run-test.sh | 1 + tests/simple_abc9/run-test.sh | 1 + tests/svinterfaces/run-test.sh | 1 + tests/xprop/run-test.sh | 1 + 23 files changed, 23 insertions(+) create mode 100644 tests/common-env.sh diff --git a/tests/arch/run-test.sh b/tests/arch/run-test.sh index 68f925b34..7602717d2 100755 --- a/tests/arch/run-test.sh +++ b/tests/arch/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh index 5131ed646..c9b4118a7 100755 --- a/tests/asicworld/run-test.sh +++ b/tests/asicworld/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh OPTIND=1 seed="" # default to no seed specified diff --git a/tests/blif/run-test.sh b/tests/blif/run-test.sh index e9698386e..2e3f5235c 100755 --- a/tests/blif/run-test.sh +++ b/tests/blif/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/bram/run-test.sh b/tests/bram/run-test.sh index 37fc91d0e..47f24f5dd 100755 --- a/tests/bram/run-test.sh +++ b/tests/bram/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh # run this test many times: # MAKE="make -j8" time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done' diff --git a/tests/common-env.sh b/tests/common-env.sh new file mode 100644 index 000000000..f3a411280 --- /dev/null +++ b/tests/common-env.sh @@ -0,0 +1 @@ +export YOSYS_MAX_THREADS=4 diff --git a/tests/cxxrtl/run-test.sh b/tests/cxxrtl/run-test.sh index 4b542e180..aa7a0c26c 100755 --- a/tests/cxxrtl/run-test.sh +++ b/tests/cxxrtl/run-test.sh @@ -1,4 +1,5 @@ #!/bin/bash +source ../common-env.sh set -ex diff --git a/tests/fmt/run-test.sh b/tests/fmt/run-test.sh index 88ee6e238..a3402f953 100644 --- a/tests/fmt/run-test.sh +++ b/tests/fmt/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -ex diff --git a/tests/fsm/run-test.sh b/tests/fsm/run-test.sh index dc60c69c4..139ea8261 100755 --- a/tests/fsm/run-test.sh +++ b/tests/fsm/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh # run this test many times: # time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done' diff --git a/tests/functional/run-test.sh b/tests/functional/run-test.sh index e0bedf8d4..7c38f3190 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) diff --git a/tests/hana/run-test.sh b/tests/hana/run-test.sh index 99be37f5e..8533e5544 100755 --- a/tests/hana/run-test.sh +++ b/tests/hana/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh OPTIND=1 seed="" # default to no seed specified diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh index 5afdb727e..d5fb65e16 100755 --- a/tests/liberty/run-test.sh +++ b/tests/liberty/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -eo pipefail for x in *.lib; do diff --git a/tests/memfile/run-test.sh b/tests/memfile/run-test.sh index db0ec54ee..44c1e4821 100755 --- a/tests/memfile/run-test.sh +++ b/tests/memfile/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e diff --git a/tests/memlib/run-test.sh b/tests/memlib/run-test.sh index 5f230a03e..9e95fb255 100755 --- a/tests/memlib/run-test.sh +++ b/tests/memlib/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -eu OPTIND=1 diff --git a/tests/opt_share/run-test.sh b/tests/opt_share/run-test.sh index e80cd4214..e3a6e8b7b 100755 --- a/tests/opt_share/run-test.sh +++ b/tests/opt_share/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh # run this test many times: # time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done' diff --git a/tests/peepopt/run-test.sh b/tests/peepopt/run-test.sh index e9698386e..2e3f5235c 100644 --- a/tests/peepopt/run-test.sh +++ b/tests/peepopt/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/proc/run-test.sh b/tests/proc/run-test.sh index e9698386e..2e3f5235c 100755 --- a/tests/proc/run-test.sh +++ b/tests/proc/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/rpc/run-test.sh b/tests/rpc/run-test.sh index 624043750..0d58b0de2 100755 --- a/tests/rpc/run-test.sh +++ b/tests/rpc/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/select/run-test.sh b/tests/select/run-test.sh index e9698386e..2e3f5235c 100755 --- a/tests/select/run-test.sh +++ b/tests/select/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/share/run-test.sh b/tests/share/run-test.sh index a7b5fc4a0..0cef580a7 100755 --- a/tests/share/run-test.sh +++ b/tests/share/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh # run this test many times: # time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done' diff --git a/tests/simple/run-test.sh b/tests/simple/run-test.sh index b9e79f34a..c3711fe3e 100755 --- a/tests/simple/run-test.sh +++ b/tests/simple/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh OPTIND=1 seed="" # default to no seed specified diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh index 5669321ac..0b3e5061f 100755 --- a/tests/simple_abc9/run-test.sh +++ b/tests/simple_abc9/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh OPTIND=1 seed="" # default to no seed specified diff --git a/tests/svinterfaces/run-test.sh b/tests/svinterfaces/run-test.sh index 71bdcd67a..28ce627d9 100755 --- a/tests/svinterfaces/run-test.sh +++ b/tests/svinterfaces/run-test.sh @@ -1,4 +1,5 @@ #/bin/bash -e +source ../common-env.sh ./runone.sh svinterface1 ./runone.sh svinterface_at_top diff --git a/tests/xprop/run-test.sh b/tests/xprop/run-test.sh index 84b7c4ac4..303c0bb3b 100755 --- a/tests/xprop/run-test.sh +++ b/tests/xprop/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e python3 generate.py $@ From 2ca28d964b1133e08e0240de2b905d41951e0186 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 27 Nov 2025 22:04:12 +0000 Subject: [PATCH 15/83] Limit YOSYS_MAX_THREADS to 4 for abcopt-tests --- tests/aiger/run-test.sh | 1 + tests/alumacc/run-test.sh | 1 + tests/memories/run-test.sh | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh index ca7339ff0..f0e27088b 100755 --- a/tests/aiger/run-test.sh +++ b/tests/aiger/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e diff --git a/tests/alumacc/run-test.sh b/tests/alumacc/run-test.sh index e9698386e..2e3f5235c 100644 --- a/tests/alumacc/run-test.sh +++ b/tests/alumacc/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e for x in *.ys; do echo "Running $x.." diff --git a/tests/memories/run-test.sh b/tests/memories/run-test.sh index 4f1da7ce7..8f83e11a1 100755 --- a/tests/memories/run-test.sh +++ b/tests/memories/run-test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +source ../common-env.sh set -e From 638e904f9123cb8cceb01dee3cc67a62c1b65cee Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 26 Nov 2025 22:47:15 +0000 Subject: [PATCH 16/83] Remove cover() coverage tracking --- Makefile | 9 -- kernel/driver.cc | 27 ------ kernel/log.cc | 51 ----------- kernel/log.h | 48 ---------- kernel/rtlil.cc | 190 +-------------------------------------- passes/cmds/Makefile.inc | 1 - passes/cmds/cover.cc | 163 --------------------------------- passes/opt/opt_expr.cc | 69 +------------- 8 files changed, 2 insertions(+), 556 deletions(-) delete mode 100644 passes/cmds/cover.cc diff --git a/Makefile b/Makefile index 81ad6ccce..7d18be90a 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,6 @@ ENABLE_VERIFIC_HIER_TREE := 1 ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0 ENABLE_VERIFIC_EDIF := 0 ENABLE_VERIFIC_LIBERTY := 0 -ENABLE_COVER := 1 ENABLE_LIBYOSYS := 0 ENABLE_LIBYOSYS_STATIC := 0 ENABLE_ZLIB := 1 @@ -249,9 +248,6 @@ ifneq ($(SANITIZER),) $(info [Clang Sanitizer] $(SANITIZER)) CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER) LINKFLAGS += -g -fsanitize=$(SANITIZER) -ifneq ($(findstring address,$(SANITIZER)),) -ENABLE_COVER := 0 -endif ifneq ($(findstring memory,$(SANITIZER)),) CXXFLAGS += -fPIE -fsanitize-memory-track-origins LINKFLAGS += -fPIE -fsanitize-memory-track-origins @@ -548,10 +544,6 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE endif endif -ifeq ($(ENABLE_COVER),1) -CXXFLAGS += -DYOSYS_ENABLE_COVER -endif - ifeq ($(ENABLE_CCACHE),1) CXX := ccache $(CXX) else @@ -729,7 +721,6 @@ OBJS += passes/hierarchy/hierarchy.o OBJS += passes/cmds/select.o OBJS += passes/cmds/show.o OBJS += passes/cmds/stat.o -OBJS += passes/cmds/cover.o OBJS += passes/cmds/design.o OBJS += passes/cmds/plugin.o diff --git a/kernel/driver.cc b/kernel/driver.cc index 4097411b4..06fa6b11b 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -764,33 +764,6 @@ int main(int argc, char **argv) } } -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE")) - { - string filename; - FILE *f; - - if (getenv("YOSYS_COVER_DIR")) { - filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid()); - filename = make_temp_file(filename); - } else { - filename = getenv("YOSYS_COVER_FILE"); - } - - f = fopen(filename.c_str(), "a+"); - - if (f == NULL) - log_error("Can't create coverage file `%s'.\n", filename); - - log("\n", filename); - - for (auto &it : get_coverage_data()) - fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str()); - - fclose(f); - } -#endif - log_check_expected(); yosys_atexit(); diff --git a/kernel/log.cc b/kernel/log.cc index d712eda2c..5cd1d7f4f 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -681,55 +681,4 @@ void log_check_expected() check_err("prefixed error", pattern, item); } -// --------------------------------------------------- -// This is the magic behind the code coverage counters -// --------------------------------------------------- -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - -dict> extra_coverage_data; - -void cover_extra(std::string parent, std::string id, bool increment) { - if (extra_coverage_data.count(id) == 0) { - for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) - if (p->id == parent) - extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func); - log_assert(extra_coverage_data.count(id)); - } - if (increment) - extra_coverage_data[id].second++; -} - -dict> get_coverage_data() -{ - dict> coverage_data; - - for (auto &it : pass_register) { - std::string key = stringf("passes.%s", it.first); - coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__); - coverage_data[key].second += it.second->call_counter; - } - - for (auto &it : extra_coverage_data) { - if (coverage_data.count(it.first)) - log_warning("found duplicate coverage id \"%s\".\n", it.first); - coverage_data[it.first].first = it.second.first; - coverage_data[it.first].second += it.second.second; - } - - for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) { - if (coverage_data.count(p->id)) - log_warning("found duplicate coverage id \"%s\".\n", p->id); - coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func); - coverage_data[p->id].second += p->counter.load(std::memory_order_relaxed); - } - - for (auto &it : coverage_data) - if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/")) - it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/")); - - return coverage_data; -} - -#endif - YOSYS_NAMESPACE_END diff --git a/kernel/log.h b/kernel/log.h index 197cfab8d..63faf7091 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -291,54 +291,6 @@ void log_abort_internal(const char *file, int line); #define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) -// --------------------------------------------------- -// This is the magic behind the code coverage counters -// --------------------------------------------------- - -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - -#define cover(_id) do { \ - static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \ - __d.counter.fetch_add(1, std::memory_order_relaxed); \ -} while (0) - -struct CoverData { - const char *file, *func, *id; - int line; - std::atomic counter; -}; - -// this two symbols are created by the linker __start_yosys_cover_listfor the "yosys_cover_list" ELF section -extern "C" struct CoverData __start_yosys_cover_list[]; -extern "C" struct CoverData __stop_yosys_cover_list[]; - -extern dict> extra_coverage_data; - -void cover_extra(std::string parent, std::string id, bool increment = true); -dict> get_coverage_data(); - -#define cover_list(_id, ...) do { cover(_id); \ - std::string r = cover_list_worker(_id, __VA_ARGS__); \ - log_assert(r.empty()); \ -} while (0) - -static inline std::string cover_list_worker(std::string, std::string last) { - return last; -} - -template -std::string cover_list_worker(std::string prefix, std::string first, T... rest) { - std::string selected = cover_list_worker(prefix, rest...); - cover_extra(prefix, prefix + "." + first, first == selected); - return first == selected ? "" : selected; -} - -#else -# define cover(...) do { } while (0) -# define cover_list(...) do { } while (0) -#endif - - // ------------------------------------------------------------ // everything below this line are utilities for troubleshooting // ------------------------------------------------------------ diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 6960b7620..d92aec73b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -883,8 +883,6 @@ RTLIL::State RTLIL::Const::const_iterator::operator*() const { bool RTLIL::Const::is_fully_zero() const { - cover("kernel.rtlil.const.is_fully_zero"); - if (auto str = get_if_str()) { for (char ch : *str) if (ch != 0) @@ -903,8 +901,6 @@ bool RTLIL::Const::is_fully_zero() const bool RTLIL::Const::is_fully_ones() const { - cover("kernel.rtlil.const.is_fully_ones"); - if (auto str = get_if_str()) { for (char ch : *str) if (ch != (char)0xff) @@ -922,8 +918,6 @@ bool RTLIL::Const::is_fully_ones() const bool RTLIL::Const::is_fully_def() const { - cover("kernel.rtlil.const.is_fully_def"); - if (is_str()) return true; @@ -937,8 +931,6 @@ bool RTLIL::Const::is_fully_def() const bool RTLIL::Const::is_fully_undef() const { - cover("kernel.rtlil.const.is_fully_undef"); - if (auto str = get_if_str()) return str->empty(); @@ -952,8 +944,6 @@ bool RTLIL::Const::is_fully_undef() const bool RTLIL::Const::is_fully_undef_x_only() const { - cover("kernel.rtlil.const.is_fully_undef_x_only"); - if (auto str = get_if_str()) return str->empty(); @@ -967,8 +957,6 @@ bool RTLIL::Const::is_fully_undef_x_only() const bool RTLIL::Const::is_onehot(int *pos) const { - cover("kernel.rtlil.const.is_onehot"); - bool found = false; int size = GetSize(*this); for (int i = 0; i < size; i++) { @@ -4648,8 +4636,6 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const RTLIL::SigSpec::SigSpec(std::initializer_list parts) { - cover("kernel.rtlil.sigspec.init.list"); - init_empty_bits(); log_assert(parts.size() > 0); auto ie = parts.begin(); @@ -4660,8 +4646,6 @@ RTLIL::SigSpec::SigSpec(std::initializer_list parts) RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) { - cover("kernel.rtlil.sigspec.init.const"); - if (GetSize(value) != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(value); @@ -4673,8 +4657,6 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) { - cover("kernel.rtlil.sigspec.init.const.move"); - if (GetSize(value) != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(value); @@ -4686,8 +4668,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) { - cover("kernel.rtlil.sigspec.init.chunk"); - if (chunk.width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(chunk); @@ -4699,8 +4679,6 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) { - cover("kernel.rtlil.sigspec.init.chunk.move"); - if (chunk.width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(chunk); @@ -4712,8 +4690,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) { - cover("kernel.rtlil.sigspec.init.wire"); - if (wire->width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(wire); @@ -4725,8 +4701,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) { - cover("kernel.rtlil.sigspec.init.wire_part"); - if (width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(wire, offset, width); @@ -4738,8 +4712,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) RTLIL::SigSpec::SigSpec(const std::string &str) { - cover("kernel.rtlil.sigspec.init.str"); - if (str.size() != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(str); @@ -4751,8 +4723,6 @@ RTLIL::SigSpec::SigSpec(const std::string &str) RTLIL::SigSpec::SigSpec(int val, int width) { - cover("kernel.rtlil.sigspec.init.int"); - if (width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(val, width); @@ -4763,8 +4733,6 @@ RTLIL::SigSpec::SigSpec(int val, int width) RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) { - cover("kernel.rtlil.sigspec.init.state"); - if (width != 0) { rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(bit, width); @@ -4775,8 +4743,6 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) { - cover("kernel.rtlil.sigspec.init.bit"); - if (width != 0) { if (bit.wire == NULL) { rep_ = CHUNK; @@ -4797,8 +4763,6 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) RTLIL::SigSpec::SigSpec(const std::vector &chunks) { - cover("kernel.rtlil.sigspec.init.stdvec_chunks"); - init_empty_bits(); for (const auto &c : chunks) append(c); @@ -4807,8 +4771,6 @@ RTLIL::SigSpec::SigSpec(const std::vector &chunks) RTLIL::SigSpec::SigSpec(const std::vector &bits) { - cover("kernel.rtlil.sigspec.init.stdvec_bits"); - init_empty_bits(); for (const auto &bit : bits) append(bit); @@ -4817,8 +4779,6 @@ RTLIL::SigSpec::SigSpec(const std::vector &bits) RTLIL::SigSpec::SigSpec(const pool &bits) { - cover("kernel.rtlil.sigspec.init.pool_bits"); - init_empty_bits(); for (const auto &bit : bits) append(bit); @@ -4827,8 +4787,6 @@ RTLIL::SigSpec::SigSpec(const pool &bits) RTLIL::SigSpec::SigSpec(const std::set &bits) { - cover("kernel.rtlil.sigspec.init.stdset_bits"); - init_empty_bits(); for (const auto &bit : bits) append(bit); @@ -4837,8 +4795,6 @@ RTLIL::SigSpec::SigSpec(const std::set &bits) RTLIL::SigSpec::SigSpec(bool bit) { - cover("kernel.rtlil.sigspec.init.bool"); - rep_ = CHUNK; new (&chunk_) RTLIL::SigChunk(bit ? RTLIL::S1 : RTLIL::S0); check(); @@ -4874,8 +4830,6 @@ void RTLIL::SigSpec::unpack() if (rep_ == BITS) return; - cover("kernel.rtlil.sigspec.convert.unpack"); - std::vector bits; bits.reserve(chunk_.width); for (int i = 0; i < chunk_.width; i++) @@ -4891,8 +4845,6 @@ void RTLIL::SigSpec::try_repack() if (rep_ != BITS) return; - cover("kernel.rtlil.sigspec.convert.try_repack"); - int bits_size = GetSize(bits_); if (bits_size == 0) return; @@ -4921,8 +4873,6 @@ void RTLIL::SigSpec::try_repack() Hasher::hash_t RTLIL::SigSpec::updhash() const { - cover("kernel.rtlil.sigspec.hash"); - Hasher h; for (auto &c : chunks()) if (c.wire == NULL) { @@ -4943,7 +4893,6 @@ Hasher::hash_t RTLIL::SigSpec::updhash() const void RTLIL::SigSpec::sort() { unpack(); - cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); hash_.clear(); try_repack(); @@ -4952,8 +4901,6 @@ void RTLIL::SigSpec::sort() void RTLIL::SigSpec::sort_and_unify() { unpack(); - cover("kernel.rtlil.sigspec.sort_and_unify"); - // A copy of the bits vector is used to prevent duplicating the logic from // SigSpec::SigSpec(std::vector). This incurrs an extra copy but // that isn't showing up as significant in profiles. @@ -5009,8 +4956,6 @@ void RTLIL::SigSpec::replace(const dict &rules) void RTLIL::SigSpec::replace(const dict &rules, RTLIL::SigSpec *other) const { - cover("kernel.rtlil.sigspec.replace_dict"); - log_assert(other != NULL); log_assert(size() == other->size()); @@ -5038,8 +4983,6 @@ void RTLIL::SigSpec::replace(const std::map &rules void RTLIL::SigSpec::replace(const std::map &rules, RTLIL::SigSpec *other) const { - cover("kernel.rtlil.sigspec.replace_map"); - log_assert(other != NULL); log_assert(size() == other->size()); @@ -5073,11 +5016,6 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { log_assert(size() == other->size()); @@ -5128,11 +5066,6 @@ void RTLIL::SigSpec::remove(const pool &pattern, RTLIL::SigSpec * void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { @@ -5166,11 +5099,6 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { @@ -5204,11 +5132,6 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec *other) { - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - unpack(); if (other != NULL) { @@ -5242,11 +5165,6 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const { - if (other) - cover("kernel.rtlil.sigspec.extract_other"); - else - cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || size() == other->size()); RTLIL::SigSpec ret; @@ -5280,11 +5198,6 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLI RTLIL::SigSpec RTLIL::SigSpec::extract(const pool &pattern, const RTLIL::SigSpec *other) const { - if (other) - cover("kernel.rtlil.sigspec.extract_other"); - else - cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || size() == other->size()); std::vector bits_match = to_sigbit_vector(); @@ -5310,8 +5223,6 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const pool &pattern, const void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) { - cover("kernel.rtlil.sigspec.replace_pos"); - if (with.size() == 0) return; @@ -5336,8 +5247,6 @@ void RTLIL::SigSpec::remove_const() { if (rep_ == CHUNK) { - cover("kernel.rtlil.sigspec.remove_const.packed"); - if (chunk_.wire == NULL) { chunk_.~SigChunk(); init_empty_bits(); @@ -5346,8 +5255,6 @@ void RTLIL::SigSpec::remove_const() } else { - cover("kernel.rtlil.sigspec.remove_const.unpacked"); - std::vector new_bits; new_bits.reserve(bits_.size()); for (auto &bit : bits_) @@ -5365,8 +5272,6 @@ void RTLIL::SigSpec::remove_const() void RTLIL::SigSpec::remove(int offset, int length) { - cover("kernel.rtlil.sigspec.remove_pos"); - if (length == 0) return; @@ -5389,8 +5294,6 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const log_assert(length >= 0); log_assert(offset + length <= size()); - cover("kernel.rtlil.sigspec.extract_pos"); - SigSpec extracted; Chunks cs = chunks(); auto it = cs.begin(); @@ -5444,8 +5347,6 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) return; } - cover("kernel.rtlil.sigspec.append"); - hash_.clear(); if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { if (chunk_.wire == NULL) { @@ -5477,8 +5378,6 @@ void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) } if (rep_ == CHUNK && chunk_.wire == bit.wire) { - cover("kernel.rtlil.sigspec.append_bit.packed"); - if (chunk_.wire == NULL) { chunk_.data.push_back(bit.data); chunk_.width++; @@ -5492,15 +5391,12 @@ void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) unpack(); - cover("kernel.rtlil.sigspec.append_bit.unpacked"); bits_.push_back(bit); check(); } void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { - cover("kernel.rtlil.sigspec.extend_u0"); - if (size() > width) remove(width, size() - width); @@ -5515,8 +5411,6 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const { - cover("kernel.rtlil.sigspec.repeat"); - RTLIL::SigSpec sig; for (int i = 0; i < num; i++) sig.append(*this); @@ -5528,8 +5422,6 @@ void RTLIL::SigSpec::check(Module *mod) const { if (rep_ == CHUNK) { - cover("kernel.rtlil.sigspec.check.packed"); - log_assert(chunk_.width != 0); if (chunk_.wire == NULL) { log_assert(chunk_.offset == 0); @@ -5543,14 +5435,8 @@ void RTLIL::SigSpec::check(Module *mod) const log_assert(chunk_.wire->module == mod); } } - else if (size() > 64) + else if (size() <= 64) { - cover("kernel.rtlil.sigspec.check.skip"); - } - else - { - cover("kernel.rtlil.sigspec.check.unpacked"); - if (mod != nullptr) { for (const RTLIL::SigBit &bit : bits_) if (bit.wire != nullptr) @@ -5562,8 +5448,6 @@ void RTLIL::SigSpec::check(Module *mod) const bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.comp_lt"); - if (this == &other) return false; @@ -5577,14 +5461,11 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const ++other_it; } - cover("kernel.rtlil.sigspec.comp_lt.equal"); return false; } bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.comp_eq"); - if (this == &other) return true; @@ -5598,14 +5479,11 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const ++other_it; } - cover("kernel.rtlil.sigspec.comp_eq.equal"); return true; } bool RTLIL::SigSpec::is_wire() const { - cover("kernel.rtlil.sigspec.is_wire"); - Chunks cs = chunks(); auto it = cs.begin(); if (it == cs.end()) @@ -5616,8 +5494,6 @@ bool RTLIL::SigSpec::is_wire() const bool RTLIL::SigSpec::is_chunk() const { - cover("kernel.rtlil.sigspec.is_chunk"); - Chunks cs = chunks(); auto it = cs.begin(); if (it == cs.end()) @@ -5635,8 +5511,6 @@ bool RTLIL::SigSpec::known_driver() const bool RTLIL::SigSpec::is_fully_const() const { - cover("kernel.rtlil.sigspec.is_fully_const"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5645,8 +5519,6 @@ bool RTLIL::SigSpec::is_fully_const() const bool RTLIL::SigSpec::is_fully_zero() const { - cover("kernel.rtlil.sigspec.is_fully_zero"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5659,8 +5531,6 @@ bool RTLIL::SigSpec::is_fully_zero() const bool RTLIL::SigSpec::is_fully_ones() const { - cover("kernel.rtlil.sigspec.is_fully_ones"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5673,8 +5543,6 @@ bool RTLIL::SigSpec::is_fully_ones() const bool RTLIL::SigSpec::is_fully_def() const { - cover("kernel.rtlil.sigspec.is_fully_def"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5687,8 +5555,6 @@ bool RTLIL::SigSpec::is_fully_def() const bool RTLIL::SigSpec::is_fully_undef() const { - cover("kernel.rtlil.sigspec.is_fully_undef"); - for (auto &chunk : chunks()) { if (chunk.width > 0 && chunk.wire != NULL) return false; @@ -5701,8 +5567,6 @@ bool RTLIL::SigSpec::is_fully_undef() const bool RTLIL::SigSpec::has_const() const { - cover("kernel.rtlil.sigspec.has_const"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire == NULL) return true; @@ -5711,8 +5575,6 @@ bool RTLIL::SigSpec::has_const() const bool RTLIL::SigSpec::has_const(State state) const { - cover("kernel.rtlil.sigspec.has_const"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire == NULL && std::find(chunk.data.begin(), chunk.data.end(), state) != chunk.data.end()) return true; @@ -5722,8 +5584,6 @@ bool RTLIL::SigSpec::has_const(State state) const bool RTLIL::SigSpec::has_marked_bits() const { - cover("kernel.rtlil.sigspec.has_marked_bits"); - for (auto &chunk : chunks()) if (chunk.width > 0 && chunk.wire == NULL) { for (RTLIL::State d : chunk.data) @@ -5735,8 +5595,6 @@ bool RTLIL::SigSpec::has_marked_bits() const bool RTLIL::SigSpec::is_onehot(int *pos) const { - cover("kernel.rtlil.sigspec.is_onehot"); - if (std::optional c = try_as_const()) return c->is_onehot(pos); return false; @@ -5744,8 +5602,6 @@ bool RTLIL::SigSpec::is_onehot(int *pos) const bool RTLIL::SigSpec::as_bool() const { - cover("kernel.rtlil.sigspec.as_bool"); - std::optional c = try_as_const(); log_assert(c.has_value()); return c->as_bool(); @@ -5753,8 +5609,6 @@ bool RTLIL::SigSpec::as_bool() const int RTLIL::SigSpec::as_int(bool is_signed) const { - cover("kernel.rtlil.sigspec.as_int"); - std::optional c = try_as_const(); log_assert(c.has_value()); return c->as_int(is_signed); @@ -5762,8 +5616,6 @@ int RTLIL::SigSpec::as_int(bool is_signed) const bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const { - cover("kernel.rtlil.sigspec.convertible_to_int"); - std::optional c = try_as_const(); if (!c.has_value()) return false; @@ -5772,8 +5624,6 @@ bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const std::optional RTLIL::SigSpec::try_as_int(bool is_signed) const { - cover("kernel.rtlil.sigspec.try_as_int"); - std::optional c = try_as_const(); if (!c.has_value()) return std::nullopt; @@ -5782,8 +5632,6 @@ std::optional RTLIL::SigSpec::try_as_int(bool is_signed) const int RTLIL::SigSpec::as_int_saturating(bool is_signed) const { - cover("kernel.rtlil.sigspec.try_as_int"); - std::optional c = try_as_const(); log_assert(c.has_value()); return c->as_int_saturating(is_signed); @@ -5791,8 +5639,6 @@ int RTLIL::SigSpec::as_int_saturating(bool is_signed) const std::string RTLIL::SigSpec::as_string() const { - cover("kernel.rtlil.sigspec.as_string"); - std::string str; str.reserve(size()); std::vector chunks = *this; @@ -5808,8 +5654,6 @@ std::string RTLIL::SigSpec::as_string() const std::optional RTLIL::SigSpec::try_as_const() const { - cover("kernel.rtlil.sigspec.as_const"); - Chunks cs = chunks(); auto it = cs.begin(); if (it == cs.end()) @@ -5822,8 +5666,6 @@ std::optional RTLIL::SigSpec::try_as_const() const RTLIL::Const RTLIL::SigSpec::as_const() const { - cover("kernel.rtlil.sigspec.as_const"); - std::optional c = try_as_const(); log_assert(c.has_value()); return *c; @@ -5831,8 +5673,6 @@ RTLIL::Const RTLIL::SigSpec::as_const() const RTLIL::Wire *RTLIL::SigSpec::as_wire() const { - cover("kernel.rtlil.sigspec.as_wire"); - Chunks cs = chunks(); auto it = cs.begin(); log_assert(it != cs.end()); @@ -5843,8 +5683,6 @@ RTLIL::Wire *RTLIL::SigSpec::as_wire() const RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const { - cover("kernel.rtlil.sigspec.as_chunk"); - Chunks cs = chunks(); auto it = cs.begin(); log_assert(it != cs.end()); @@ -5855,14 +5693,11 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const RTLIL::SigBit RTLIL::SigSpec::as_bit() const { - cover("kernel.rtlil.sigspec.as_bit"); return RTLIL::SigBit(*this); } bool RTLIL::SigSpec::match(const char* pattern) const { - cover("kernel.rtlil.sigspec.match"); - int pattern_len = strlen(pattern); log_assert(pattern_len == size()); @@ -5892,8 +5727,6 @@ bool RTLIL::SigSpec::match(const char* pattern) const std::set RTLIL::SigSpec::to_sigbit_set() const { - cover("kernel.rtlil.sigspec.to_sigbit_set"); - std::set sigbits; for (auto &c : chunks()) for (int i = 0; i < c.width; i++) @@ -5903,8 +5736,6 @@ std::set RTLIL::SigSpec::to_sigbit_set() const pool RTLIL::SigSpec::to_sigbit_pool() const { - cover("kernel.rtlil.sigspec.to_sigbit_pool"); - pool sigbits; sigbits.reserve(size()); for (auto &c : chunks()) @@ -5915,8 +5746,6 @@ pool RTLIL::SigSpec::to_sigbit_pool() const std::vector RTLIL::SigSpec::to_sigbit_vector() const { - cover("kernel.rtlil.sigspec.to_sigbit_vector"); - std::vector result; result.reserve(size()); for (SigBit bit : *this) @@ -5926,8 +5755,6 @@ std::vector RTLIL::SigSpec::to_sigbit_vector() const std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.to_sigbit_map"); - int this_size = size(); log_assert(this_size == other.size()); @@ -5940,8 +5767,6 @@ std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::SigSpec &other) const { - cover("kernel.rtlil.sigspec.to_sigbit_dict"); - int this_size = size(); log_assert(this_size == other.size()); @@ -5965,9 +5790,6 @@ static void sigspec_parse_split(std::vector &tokens, const std::str bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { - cover("kernel.rtlil.sigspec.parse"); - - std::vector tokens; sigspec_parse_split(tokens, str, ','); @@ -5981,7 +5803,6 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri continue; if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { - cover("kernel.rtlil.sigspec.parse.const"); VERILOG_FRONTEND::ConstParser p{Location()}; auto ast = p.const2ast(netname); if (ast == nullptr) @@ -5993,8 +5814,6 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri if (module == NULL) return false; - cover("kernel.rtlil.sigspec.parse.net"); - if (netname[0] != '$' && netname[0] != '\\') netname = "\\" + netname; @@ -6023,13 +5842,11 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri std::vector index_tokens; sigspec_parse_split(index_tokens, indices.substr(1, indices.size()-2), ':'); if (index_tokens.size() == 1) { - cover("kernel.rtlil.sigspec.parse.bit_sel"); int a = atoi(index_tokens.at(0).c_str()); if (a < 0 || a >= wire->width) return false; sig.append(RTLIL::SigSpec(wire, a)); } else { - cover("kernel.rtlil.sigspec.parse.part_sel"); int a = atoi(index_tokens.at(0).c_str()); int b = atoi(index_tokens.at(1).c_str()); if (a > b) { @@ -6054,8 +5871,6 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL if (str.empty() || str[0] != '@') return parse(sig, module, str); - cover("kernel.rtlil.sigspec.parse.sel"); - str = RTLIL::escape_id(str.substr(1)); if (design->selection_vars.count(str) == 0) return false; @@ -6072,13 +5887,11 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { if (str == "0") { - cover("kernel.rtlil.sigspec.parse.rhs_zeros"); sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.size()); return true; } if (str == "~0") { - cover("kernel.rtlil.sigspec.parse.rhs_ones"); sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.size()); return true; } @@ -6088,7 +5901,6 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R long int val = strtol(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { sig = RTLIL::SigSpec(val, lhs.size()); - cover("kernel.rtlil.sigspec.parse.rhs_dec"); return true; } } diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 14ea9c52a..b1b1383b1 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -27,7 +27,6 @@ OBJS += passes/cmds/logcmd.o OBJS += passes/cmds/tee.o OBJS += passes/cmds/write_file.o OBJS += passes/cmds/connwrappers.o -OBJS += passes/cmds/cover.o OBJS += passes/cmds/trace.o OBJS += passes/cmds/plugin.o OBJS += passes/cmds/check.o diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc deleted file mode 100644 index 7f217329c..000000000 --- a/passes/cmds/cover.cc +++ /dev/null @@ -1,163 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2014 Claire Xenia Wolf - * - * 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/log_help.h" -#include - -#ifndef _WIN32 -# include -#else -# include -#endif - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct CoverPass : public Pass { - CoverPass() : Pass("cover", "print code coverage counters") { - internal(); - } - bool formatted_help() override { - auto *help = PrettyHelp::get_current(); - help->set_group("passes/status"); - return false; - } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" cover [options] [pattern]\n"); - log("\n"); - log("Print the code coverage counters collected using the cover() macro in the Yosys\n"); - log("C++ code. This is useful to figure out what parts of Yosys are utilized by a\n"); - log("test bench.\n"); - log("\n"); - log(" -q\n"); - log(" Do not print output to the normal destination (console and/or log file)\n"); - log("\n"); - log(" -o file\n"); - log(" Write output to this file, truncate if exists.\n"); - log("\n"); - log(" -a file\n"); - log(" Write output to this file, append if exists.\n"); - log("\n"); - log(" -d dir\n"); - log(" Write output to a newly created file in the specified directory.\n"); - log("\n"); - log("When one or more pattern (shell wildcards) are specified, then only counters\n"); - log("matching at least one pattern are printed.\n"); - log("\n"); - log("\n"); - log("It is also possible to instruct Yosys to print the coverage counters on program\n"); - log("exit to a file using environment variables:\n"); - log("\n"); - log(" YOSYS_COVER_DIR=\"{dir-name}\" yosys {args}\n"); - log("\n"); - log(" This will create a file (with an auto-generated name) in this\n"); - log(" directory and write the coverage counters to it.\n"); - log("\n"); - log(" YOSYS_COVER_FILE=\"{file-name}\" yosys {args}\n"); - log("\n"); - log(" This will append the coverage counters to the specified file.\n"); - log("\n"); - log("\n"); - log("Hint: Use the following AWK command to consolidate Yosys coverage files:\n"); - log("\n"); - log(" gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p)\n"); - log(" printf \"%%-60s %%10d %%s\\n\", p[i], c[i], i; }' {files} | sort -k3\n"); - log("\n"); - log("\n"); - log("Coverage counters are only available in Yosys for Linux.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - std::vector out_files; - std::vector patterns; - bool do_log = true; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-q") { - do_log = false; - continue; - } - if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) { - const char *open_mode = args[argidx] == "-a" ? "a+" : "w"; - const std::string &filename = args[++argidx]; - FILE *f = nullptr; - if (args[argidx-1] == "-d") { - #if defined(_WIN32) || defined(__wasm) - log_cmd_error("The 'cover -d' option is not supported on this platform.\n"); - #else - char filename_buffer[4096]; - snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid()); - f = fdopen(mkstemps(filename_buffer, 4), "w"); - #endif - } else { - f = fopen(filename.c_str(), open_mode); - } - if (f == NULL) { - for (auto f : out_files) - fclose(f); - log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx]); - } - out_files.push_back(f); - continue; - } - break; - } - while (argidx < args.size() && args[argidx].compare(0, 1, "-") != 0) - patterns.push_back(args[argidx++]); - extra_args(args, argidx, design); - - if (do_log) { - log_header(design, "Printing code coverage counters.\n"); - log("\n"); - } - -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - for (auto &it : get_coverage_data()) { - if (!patterns.empty()) { - for (auto &p : patterns) - if (patmatch(p.c_str(), it.first.c_str())) - goto pattern_match; - continue; - } - pattern_match: - for (auto f : out_files) - fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str()); - if (do_log) - log("%-60s %10d %s\n", it.second.first, it.second.second, it.first); - } -#else - for (auto f : out_files) - fclose(f); - - log_cmd_error("This version of Yosys was not built with support for code coverage counters.\n"); -#endif - - for (auto f : out_files) - fclose(f); - } -} CoverPass; - -PRIVATE_NAMESPACE_END diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 86d96ea7a..ffe678d2f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -297,8 +297,6 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ log_debug("\n"); } - cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); - module->remove(cell); did_something = true; return true; @@ -520,7 +518,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto cell : cells.sorted) { -#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) +#define ACTION_DO(_p_, _s_) do { replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) #define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_)) bool detect_const_and = false; @@ -567,19 +565,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (detect_const_and && (found_zero || found_inv || (found_undef && consume_x))) { - cover("opt.opt_expr.const_and"); replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); goto next_cell; } if (detect_const_or && (found_one || found_inv || (found_undef && consume_x))) { - cover("opt.opt_expr.const_or"); replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); goto next_cell; } if (non_const_input != State::Sm && !found_undef) { - cover("opt.opt_expr.and_or_buffer"); replace_cell(assign_map, module, cell, "and_or_buffer", ID::Y, non_const_input); goto next_cell; } @@ -591,12 +586,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons SigBit sig_b = assign_map(cell->getPort(ID::B)); if (!keepdc && (sig_a == sig_b || sig_a == State::Sx || sig_a == State::Sz || sig_b == State::Sx || sig_b == State::Sz)) { if (cell->type.in(ID($xor), ID($_XOR_))) { - cover("opt.opt_expr.const_xor"); replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0); goto next_cell; } if (cell->type.in(ID($xnor), ID($_XNOR_))) { - cover("opt.opt_expr.const_xnor"); // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_ int width = GetSize(cell->getPort(ID::Y)); replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width)); @@ -609,7 +602,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons std::swap(sig_a, sig_b); if (sig_b == State::S0 || sig_b == State::S1) { if (cell->type.in(ID($xor), ID($_XOR_))) { - cover("opt.opt_expr.xor_buffer"); SigSpec sig_y; if (cell->type == ID($xor)) sig_y = (sig_b == State::S1 ? module->Not(NEW_ID, sig_a).as_bit() : sig_a); @@ -620,7 +612,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons goto next_cell; } if (cell->type.in(ID($xnor), ID($_XNOR_))) { - cover("opt.opt_expr.xnor_buffer"); SigSpec sig_y; if (cell->type == ID($xnor)) { sig_y = (sig_b == State::S1 ? sig_a : module->Not(NEW_ID, sig_a).as_bit()); @@ -641,13 +632,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1) { if (cell->type == ID($reduce_xnor)) { - cover("opt.opt_expr.reduce_xnor_not"); log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n", log_id(cell->type), log_id(cell->name), log_id(module)); cell->type = ID($not); did_something = true; } else { - cover("opt.opt_expr.unary_buffer"); replace_cell(assign_map, module, cell, "unary_buffer", ID::Y, cell->getPort(ID::A)); } goto next_cell; @@ -663,7 +652,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (a_fully_const != b_fully_const) { - cover("opt.opt_expr.bitwise_logic_one_const"); log_debug("Replacing %s cell `%s' in module `%s' having one fully constant input\n", log_id(cell->type), log_id(cell->name), log_id(module)); RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y)); @@ -815,7 +803,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons new_sig_a.append(neutral_bit); if (GetSize(new_sig_a) < GetSize(sig_a)) { - cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); cell->setPort(ID::A, new_sig_a); @@ -838,7 +825,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons new_sig_b.append(neutral_bit); if (GetSize(new_sig_b) < GetSize(sig_b)) { - cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); cell->setPort(ID::B, new_sig_b); @@ -864,7 +850,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { - cover("opt.opt_expr.fine.$reduce_and"); log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort(ID::A, sig_a = new_a); @@ -890,7 +875,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { - cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort(ID::A, sig_a = new_a); @@ -916,7 +900,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { - cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); cell->setPort(ID::B, sig_b = new_b); @@ -951,7 +934,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons break; } if (i > 0) { - cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str()); log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module)); SigSpec new_a = sig_a.extract_end(i); SigSpec new_b = sig_b.extract_end(i); @@ -1008,7 +990,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons break; } if (i > 0) { - cover("opt.opt_expr.fine.$alu"); log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module)); SigSpec new_a = sig_a.extract_end(i); SigSpec new_b = sig_b.extract_end(i); @@ -1047,8 +1028,6 @@ skip_fine_alu: if (0) { found_the_x_bit: - cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", - "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell->type.str()); if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); else @@ -1070,7 +1049,6 @@ skip_fine_alu: } if (width < GetSize(sig_a)) { - cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str()); sig_a.remove(width, GetSize(sig_a)-width); cell->setPort(ID::A, sig_a); cell->setParam(ID::A_WIDTH, width); @@ -1081,13 +1059,11 @@ skip_fine_alu: if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 && invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { - cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A)))); goto next_cell; } if (cell->type.in(ID($_MUX_), ID($mux)) && invert_map.count(assign_map(cell->getPort(ID::S))) != 0) { - cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); RTLIL::SigSpec tmp = cell->getPort(ID::A); cell->setPort(ID::A, cell->getPort(ID::B)); @@ -1170,7 +1146,6 @@ skip_fine_alu: if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1)); if (input.match("01 ")) ACTION_DO(ID::Y, input.extract(0, 1)); if (input.match("10 ")) { - cover("opt.opt_expr.mux_to_inv"); cell->type = ID($_NOT_); cell->setPort(ID::A, input.extract(0, 1)); cell->unsetPort(ID::B); @@ -1197,7 +1172,6 @@ skip_fine_alu: if (input == State::S1) ACTION_DO(ID::Y, cell->getPort(ID::A)); if (input == State::S0 && !a.is_fully_undef()) { - cover("opt.opt_expr.action_" S__LINE__); log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); cell->setPort(ID::A, SigSpec(State::Sx, GetSize(a))); @@ -1222,7 +1196,6 @@ skip_fine_alu: log_assert(GetSize(a) == GetSize(b)); for (int i = 0; i < GetSize(a); i++) { if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) { - cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S0 : RTLIL::State::S1); new_y.extend_u0(cell->parameters[ID::Y_WIDTH].as_int(), false); replace_cell(assign_map, module, cell, "isneq", ID::Y, new_y); @@ -1235,7 +1208,6 @@ skip_fine_alu: } if (new_a.size() == 0) { - cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S1 : RTLIL::State::S0); new_y.extend_u0(cell->parameters[ID::Y_WIDTH].as_int(), false); replace_cell(assign_map, module, cell, "empty", ID::Y, new_y); @@ -1243,7 +1215,6 @@ skip_fine_alu: } if (new_a.size() < a.size() || new_b.size() < b.size()) { - cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); cell->setPort(ID::A, new_a); cell->setPort(ID::B, new_b); cell->parameters[ID::A_WIDTH] = new_a.size(); @@ -1258,7 +1229,6 @@ skip_fine_alu: RTLIL::SigSpec b = assign_map(cell->getPort(ID::B)); if (a.is_fully_const() && !b.is_fully_const()) { - cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str()); cell->setPort(ID::A, b); cell->setPort(ID::B, a); std::swap(a, b); @@ -1273,7 +1243,6 @@ skip_fine_alu: RTLIL::SigSpec input = b; ACTION_DO(ID::Y, cell->getPort(ID::A)); } else { - cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->type = ID($not); cell->parameters.erase(ID::B_WIDTH); @@ -1288,7 +1257,6 @@ skip_fine_alu: if (cell->type.in(ID($eq), ID($ne)) && (assign_map(cell->getPort(ID::A)).is_fully_zero() || assign_map(cell->getPort(ID::B)).is_fully_zero())) { - cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool"); cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool); @@ -1336,8 +1304,6 @@ skip_fine_alu: sig_y[i] = sig_a[GetSize(sig_a)-1]; } - cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); - log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort(ID::B))), shift_bits, log_id(module), log_signal(sig_y)); @@ -1410,11 +1376,6 @@ skip_fine_alu: if (identity_wrt_a || identity_wrt_b) { - if (identity_wrt_a) - cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); - if (identity_wrt_b) - cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); - log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); @@ -1463,14 +1424,12 @@ skip_identity: if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) { - cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str()); replace_cell(assign_map, module, cell, "mux_bool", ID::Y, cell->getPort(ID::S)); goto next_cell; } if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S1 && cell->getPort(ID::B) == State::S0) { - cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::A, cell->getPort(ID::S)); cell->unsetPort(ID::B); @@ -1489,7 +1448,6 @@ skip_identity: } if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0) { - cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::A, cell->getPort(ID::S)); cell->unsetPort(ID::S); @@ -1509,7 +1467,6 @@ skip_identity: } 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)); cell->setPort(ID::B, cell->getPort(ID::S)); cell->unsetPort(ID::S); @@ -1533,7 +1490,6 @@ skip_identity: int width = GetSize(cell->getPort(ID::A)); if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) || cell->getPort(ID::S).is_fully_undef()) { - cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_undef", ID::Y, cell->getPort(ID::A)); goto next_cell; } @@ -1552,17 +1508,14 @@ skip_identity: new_s = new_s.extract(0, new_s.size()-1); } if (new_s.size() == 0) { - cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_empty", ID::Y, new_a); goto next_cell; } if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) { - cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str()); replace_cell(assign_map, module, cell, "mux_sel01", ID::Y, new_s); goto next_cell; } if (cell->getPort(ID::S).size() != new_s.size()) { - cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", GetSize(cell->getPort(ID::S)) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::A, new_a); @@ -1602,7 +1555,6 @@ skip_identity: RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \ cell->parameters[ID::A_SIGNED].as_bool(), false, \ cell->parameters[ID::Y_WIDTH].as_int())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \ goto next_cell; \ } \ @@ -1617,7 +1569,6 @@ skip_identity: cell->parameters[ID::A_SIGNED].as_bool(), \ cell->parameters[ID::B_SIGNED].as_bool(), \ cell->parameters[ID::Y_WIDTH].as_int())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \ goto next_cell; \ } \ @@ -1629,7 +1580,6 @@ skip_identity: assign_map.apply(a), assign_map.apply(b); \ if (a.is_fully_const() && b.is_fully_const()) { \ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \ goto next_cell; \ } \ @@ -1642,7 +1592,6 @@ skip_identity: assign_map.apply(a), assign_map.apply(b), assign_map.apply(s); \ if (a.is_fully_const() && b.is_fully_const() && s.is_fully_const()) { \ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), s.as_const())); \ - cover("opt.opt_expr.const.$" #_t); \ replace_cell(assign_map, module, cell, stringf("%s, %s, %s", log_signal(a), log_signal(b), log_signal(s)), ID::Y, y); \ goto next_cell; \ } \ @@ -1759,8 +1708,6 @@ skip_identity: { if (sig_a.is_fully_zero()) { - cover("opt.opt_expr.mul_shift.zero"); - log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", cell->name.c_str(), module->name.c_str()); @@ -1774,11 +1721,6 @@ skip_identity: int exp; if (sig_a.is_onehot(&exp) && !(a_signed && exp == GetSize(sig_a) - 1)) { - if (swapped_ab) - cover("opt.opt_expr.mul_shift.swapped"); - else - cover("opt.opt_expr.mul_shift.unswapped"); - log_debug("Replacing multiply-by-%s cell `%s' in module `%s' with shift-by-%d.\n", log_signal(sig_a), cell->name.c_str(), module->name.c_str(), exp); @@ -1812,8 +1754,6 @@ skip_identity: break; if (a_zeros || b_zeros) { int y_zeros = a_zeros + b_zeros; - cover("opt.opt_expr.mul_low_zeros"); - log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n", a_zeros, b_zeros, cell->name.c_str(), module->name.c_str()); @@ -1855,8 +1795,6 @@ skip_identity: { if (sig_b.is_fully_zero()) { - cover("opt.opt_expr.divmod_zero"); - log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", cell->name.c_str(), module->name.c_str()); @@ -1872,8 +1810,6 @@ skip_identity: { if (cell->type.in(ID($div), ID($divfloor))) { - cover("opt.opt_expr.div_shift"); - bool is_truncating = cell->type == ID($div); log_debug("Replacing %s-divide-by-%s cell `%s' in module `%s' with shift-by-%d.\n", is_truncating ? "truncating" : "flooring", @@ -1902,8 +1838,6 @@ skip_identity: } else if (cell->type.in(ID($mod), ID($modfloor))) { - cover("opt.opt_expr.mod_mask"); - bool is_truncating = cell->type == ID($mod); log_debug("Replacing %s-modulo-by-%s cell `%s' in module `%s' with bitmask.\n", is_truncating ? "truncating" : "flooring", @@ -2028,7 +1962,6 @@ skip_identity: sig_ci = p.second; } - cover("opt.opt_expr.alu_split"); module->remove(cell); did_something = true; From 0e31e389f2cf5b29e900e56285b3d1f058f38c29 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 00:25:44 +0000 Subject: [PATCH 17/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7d18be90a..bbae8bdc7 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+1 +YOSYS_VER := 0.60+8 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From d274ff862735ed7f55e511d3d0a8affe4079545e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 5 Dec 2025 09:45:47 +0000 Subject: [PATCH 18/83] Delete prefix strings on shutdown to avoid triggering leak warnings. Fixes #5532 --- kernel/yosys_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 55e7b71eb..47dae5473 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -299,8 +299,8 @@ RTLIL::IdString new_id_suffix(std::string_view file, int line, std::string_view #define NEW_ID \ YOSYS_NAMESPACE_PREFIX RTLIL::IdString::new_autoidx_with_prefix([](std::string_view func) -> const std::string * { \ - static const std::string *prefix = YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func); \ - return prefix; \ + static std::unique_ptr prefix(YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func)); \ + return prefix.get(); \ }(__FUNCTION__)) #define NEW_ID_SUFFIX(suffix) \ YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix) From 23e1b0656c080d5e777ad4e22c02a15d4811789d Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 9 Dec 2025 11:58:43 +0100 Subject: [PATCH 19/83] version: add git hash string --- Makefile | 7 +++++-- kernel/yosys.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index bbae8bdc7..5d81feae8 100644 --- a/Makefile +++ b/Makefile @@ -177,8 +177,10 @@ CXXFLAGS += -DYOSYS_VER=\\"$(YOSYS_VER)\\" \ TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit) ifneq ($(findstring Format:,$(TARBALL_GIT_REV)),) GIT_REV := $(shell GIT_DIR=$(YOSYS_SRC)/.git git rev-parse --short=9 HEAD || echo UNKNOWN) +GIT_DIRTY := $(shell GIT_DIR=$(YOSYS_SRC)/.git git diff --exit-code --quiet 2>/dev/null; if [ $$? -ne 0 ]; then echo "-dirty"; fi) else GIT_REV := $(TARBALL_GIT_REV) +GIT_DIRTY := "" endif OBJS = kernel/version_$(GIT_REV).o @@ -791,12 +793,13 @@ endif $(Q) mkdir -p $(dir $@) $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< -YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) $(shell \ +YOSYS_GIT_STR := $(GIT_REV)$(GIT_DIRTY) +YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(notdir $(CXX)) $(shell \ $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS))) kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile $(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc - $(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; }" > kernel/version_$(GIT_REV).cc + $(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; const char *yosys_git_hash_str=\"$(YOSYS_GIT_STR)\"; }" > kernel/version_$(GIT_REV).cc ifeq ($(ENABLE_VERIFIC),1) CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) diff --git a/kernel/yosys.h b/kernel/yosys.h index b455ad496..9f5a16a9c 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -81,6 +81,7 @@ extern std::set yosys_input_files, yosys_output_files; // from kernel/version_*.o (cc source generated from Makefile) extern const char *yosys_version_str; +extern const char *yosys_git_hash_str; const char* yosys_maybe_version(); // from passes/cmds/design.cc From 6acb79afa26e91682e576c8d0a1e185147cb4bc4 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 9 Dec 2025 11:58:57 +0100 Subject: [PATCH 20/83] driver: add --git-hash --- kernel/driver.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/driver.cc b/kernel/driver.cc index 06fa6b11b..fa78bad59 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -255,6 +255,7 @@ int main(int argc, char **argv) ("h,help", "print this help message. If given, print help for .", cxxopts::value(), "[]") ("V,version", "print version information and exit") + ("git-hash", "print git commit hash and exit") ("infile", "input files", cxxopts::value>()) ; options.add_options("logging") @@ -332,6 +333,10 @@ int main(int argc, char **argv) std::cout << yosys_version_str << std::endl; exit(0); } + if (result.count("git-hash")) { + std::cout << yosys_git_hash_str << std::endl; + exit(0); + } if (result.count("S")) { passes_commands.push_back("synth"); run_shell = false; From cf9ab4c89940bea22737f204c759a202be186128 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 9 Dec 2025 13:50:17 +0100 Subject: [PATCH 21/83] Cleanup version.cc creation for VS build --- .github/workflows/extra-builds.yml | 2 +- Makefile | 18 ++++++++++-------- misc/create_vcxsrc.sh | 7 +------ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index b22a399db..e8b11ef2f 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -37,7 +37,7 @@ jobs: persist-credentials: false - run: sudo apt-get install libfl-dev - name: Build - run: make vcxsrc YOSYS_VER=latest + run: make vcxsrc YOSYS_COMPILER="Visual Studio" VCX_DIR_NAME=yosys-win32-vcxsrc-latest - uses: actions/upload-artifact@v4 with: name: vcxsrc diff --git a/Makefile b/Makefile index 5d81feae8..b47ec9abd 100644 --- a/Makefile +++ b/Makefile @@ -794,8 +794,8 @@ endif $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< YOSYS_GIT_STR := $(GIT_REV)$(GIT_DIRTY) -YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(notdir $(CXX)) $(shell \ - $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS))) +YOSYS_COMPILER := $(notdir $(CXX)) $(shell $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)) +YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(YOSYS_COMPILER)) kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile $(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc @@ -1203,15 +1203,17 @@ qtcreator: { echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes touch qtcreator.creator -vcxsrc: $(GENFILES) $(EXTRA_TARGETS) - rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip} +VCX_DIR_NAME := yosys-win32-vcxsrc-$(YOSYS_VER) +vcxsrc: $(GENFILES) $(EXTRA_TARGETS) kernel/version_$(GIT_REV).cc + rm -rf $(VCX_DIR_NAME){,.zip} + cp -f kernel/version_$(GIT_REV).cc kernel/version.cc set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \ echo "Analyse: $$f" >&2; cpp -std=c++17 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt echo "libs/fst/fst_win_unistd.h" >> srcfiles.txt - bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV) - echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc - zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc - zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/ + echo "kernel/version.cc" >> srcfiles.txt + bash misc/create_vcxsrc.sh $(VCX_DIR_NAME) $(YOSYS_VER) + zip $(VCX_DIR_NAME)/genfiles.zip $(GENFILES) kernel/version.cc + zip -r $(VCX_DIR_NAME).zip $(VCX_DIR_NAME)/ rm -f srcfiles.txt kernel/version.cc config-clean: clean diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh index 228003bad..42a690ce6 100644 --- a/misc/create_vcxsrc.sh +++ b/misc/create_vcxsrc.sh @@ -1,9 +1,8 @@ #!/bin/bash set -ex -vcxsrc="$1-$2" +vcxsrc="$1" yosysver="$2" -gitsha="$3" rm -rf YosysVS-Tpl-v2.zip YosysVS wget https://github.com/YosysHQ/yosys/releases/download/resources/YosysVS-Tpl-v2.zip @@ -33,7 +32,6 @@ popd head -n$n "$vcxsrc"/YosysVS/YosysVS.vcxproj egrep '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,,' egrep -v '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,,' - echo '' tail -n +$((n+1)) "$vcxsrc"/YosysVS/YosysVS.vcxproj } > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new @@ -48,9 +46,6 @@ mkdir -p "$vcxsrc"/yosys tar -cf - -T srcfiles.txt | tar -xf - -C "$vcxsrc"/yosys cp -r share "$vcxsrc"/ -echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys" \ - "$yosysver (git sha1 $gitsha, Visual Studio)\"; }" > "$vcxsrc"/yosys/kernel/version.cc - cat > "$vcxsrc"/readme-git.txt << EOT Want to use a git working copy for the yosys source code? Open "Git Bash" in this directory and run: From 2e9db8b850bbdfc88dc5956ef64a7e69125c6091 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 00:26:36 +0000 Subject: [PATCH 22/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b47ec9abd..3fc5f4d07 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+8 +YOSYS_VER := 0.60+15 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 77f846e992e5d1c612cc0e527e49df0abee0448b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 10 Dec 2025 11:03:44 +0100 Subject: [PATCH 23/83] Update ABC as per 2025-12-10 --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index 131a50dd7..bd05a6454 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 131a50dd773f21ebbfc51da1d182438382a04209 +Subproject commit bd05a6454e8c157caaa58ceda676ae0249d8e27c From 7f3ea4110313d497209d3cfa005deba8550d9b21 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 1 Dec 2025 23:38:46 +0100 Subject: [PATCH 24/83] cellaigs: fix function argument evaluation order --- kernel/cellaigs.cc | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index fd3c7bb67..21c72f695 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -185,37 +185,50 @@ struct AigMaker int or_gate(int A, int B) { - return nand_gate(not_gate(A), not_gate(B)); + int not_a = not_gate(A); + int not_b = not_gate(B); + return nand_gate(not_a, not_b); } int nor_gate(int A, int B) { - return and_gate(not_gate(A), not_gate(B)); + int not_a = not_gate(A); + int not_b = not_gate(B); + return and_gate(not_a, not_b); } int xor_gate(int A, int B) { - return nor_gate(and_gate(A, B), nor_gate(A, B)); + int a_and_b = and_gate(A, B); + int a_nor_b = nor_gate(A, B); + return nor_gate(a_and_b, a_nor_b); } int xnor_gate(int A, int B) { - return or_gate(and_gate(A, B), nor_gate(A, B)); + int a_and_b = and_gate(A, B); + int a_nor_b = nor_gate(A, B); + return or_gate(a_and_b, a_nor_b); } int andnot_gate(int A, int B) { - return and_gate(A, not_gate(B)); + int not_b = not_gate(B); + return and_gate(A, not_b); } int ornot_gate(int A, int B) { - return or_gate(A, not_gate(B)); + int not_b = not_gate(B); + return or_gate(A, not_b); } int mux_gate(int A, int B, int S) { - return or_gate(and_gate(A, not_gate(S)), and_gate(B, S)); + int not_s = not_gate(S); + int a_active = and_gate(A, not_s); + int b_active = and_gate(B, S); + return or_gate(a_active, b_active); } vector adder(const vector &A, const vector &B, int carry, vector *X = nullptr, vector *CO = nullptr) From 882001cb01827a445b8cffd305df8068c69a34a4 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 2 Dec 2025 15:07:37 +0100 Subject: [PATCH 25/83] cellaigs: fix adder function argument evaluation order --- kernel/cellaigs.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 21c72f695..ca80d43cc 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -231,17 +231,22 @@ struct AigMaker return or_gate(a_active, b_active); } - vector adder(const vector &A, const vector &B, int carry, vector *X = nullptr, vector *CO = nullptr) + vector adder(const vector &A, const vector &B, int carry_in, vector *X = nullptr, vector *CO = nullptr) { vector Y(GetSize(A)); log_assert(GetSize(A) == GetSize(B)); for (int i = 0; i < GetSize(A); i++) { - Y[i] = xor_gate(xor_gate(A[i], B[i]), carry); - carry = or_gate(and_gate(A[i], B[i]), and_gate(or_gate(A[i], B[i]), carry)); + int a_xor_b = xor_gate(A[i], B[i]); + int a_or_b = or_gate(A[i], B[i]); + int a_and_b = and_gate(A[i], B[i]); + Y[i] = xor_gate(a_xor_b, carry_in); + int tmp = and_gate(a_or_b, carry_in); + int carry_out = or_gate(a_and_b, tmp); if (X != nullptr) - X->at(i) = xor_gate(A[i], B[i]); + X->at(i) = a_xor_b; if (CO != nullptr) - CO->at(i) = carry; + CO->at(i) = carry_out; + carry_in = carry_out; } return Y; } From d932ce7f470d756432b845d07d8b3a2e8d142734 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 2 Dec 2025 15:08:02 +0100 Subject: [PATCH 26/83] cellaigs: formatting --- kernel/cellaigs.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index ca80d43cc..54979ccb5 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -325,13 +325,13 @@ Aig::Aig(Cell *cell) int A = mk.inport(ID::A, i); int B = mk.inport(ID::B, i); int Y = cell->type.in(ID($and), ID($_AND_)) ? mk.and_gate(A, B) : - cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) : + cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) : cell->type.in(ID($or), ID($_OR_)) ? mk.or_gate(A, B) : - cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) : + cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) : cell->type.in(ID($xor), ID($_XOR_)) ? mk.xor_gate(A, B) : cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B) : - cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) : - cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1; + cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) : + cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1; mk.outport(Y, ID::Y, i); } goto optimize; From 99e873efc98b9bef98855dc6683ad4d711fb588d Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 10 Dec 2025 12:41:13 +0100 Subject: [PATCH 27/83] cellaigs: fix AOI and OAI ordering --- kernel/cellaigs.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 54979ccb5..0f897cd58 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -483,7 +483,8 @@ Aig::Aig(Cell *cell) int B = mk.inport(ID::B); int C = mk.inport(ID::C); int D = mk.inport(ID::D); - int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D)); + int a_and_b = mk.and_gate(A, B); + int Y = mk.nor_gate(a_and_b, mk.and_gate(C, D)); mk.outport(Y, ID::Y); goto optimize; } @@ -494,7 +495,8 @@ Aig::Aig(Cell *cell) int B = mk.inport(ID::B); int C = mk.inport(ID::C); int D = mk.inport(ID::D); - int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D)); + int a_or_b = mk.or_gate(A, B); + int Y = mk.nand_gate(a_or_b, mk.or_gate(C, D)); mk.outport(Y, ID::Y); goto optimize; } From 54b278d57496cf771490d1f4d343cff65a078a89 Mon Sep 17 00:00:00 2001 From: Yannick Lamarre Date: Fri, 23 Feb 2024 21:33:14 -0500 Subject: [PATCH 28/83] Add tests for implicit wires in generate blocks. Signed-off-by: Yannick Lamarre --- tests/verilog/genblk_wire.sv | 20 ++++++++++++++++++++ tests/verilog/genblk_wire.ys | 17 +++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/verilog/genblk_wire.sv create mode 100644 tests/verilog/genblk_wire.ys diff --git a/tests/verilog/genblk_wire.sv b/tests/verilog/genblk_wire.sv new file mode 100644 index 000000000..ef95fa98a --- /dev/null +++ b/tests/verilog/genblk_wire.sv @@ -0,0 +1,20 @@ +module gold(a, b); + output wire [1:0] a; + input wire [1:0] b; + genvar i; + for (i = 0; i < 2; i++) begin + wire x; + assign x = b[i]; + assign a[i] = x; + end +endmodule + +module gate(a, b); + output wire [1:0] a; + input wire [1:0] b; + genvar i; + for (i = 0; i < 2; i++) begin + assign x = b[i]; + assign a[i] = x; + end +endmodule diff --git a/tests/verilog/genblk_wire.ys b/tests/verilog/genblk_wire.ys new file mode 100644 index 000000000..582303760 --- /dev/null +++ b/tests/verilog/genblk_wire.ys @@ -0,0 +1,17 @@ +logger -expect warning "Identifier `\\genblk1[[]0[]]\.x' is implicitly declared." 1 +logger -expect warning "Identifier `\\genblk1[[]1[]]\.x' is implicitly declared." 1 +read_verilog -sv genblk_wire.sv +logger -check-expected + +select -assert-count 1 gate/genblk1[0].x +select -assert-count 1 gate/genblk1[1].x +select -assert-count 0 gate/genblk1[2].x + +select -assert-count 1 gold/genblk1[0].x +select -assert-count 1 gold/genblk1[1].x +select -assert-count 0 gold/genblk1[2].x + +proc +equiv_make gold gate equiv +equiv_simple +equiv_status -assert From 9814f9dc4f16c623822a6fd140a1d0c6c8d79a0d Mon Sep 17 00:00:00 2001 From: Yannick Lamarre Date: Fri, 23 Feb 2024 21:42:16 -0500 Subject: [PATCH 29/83] Add autowires in genblk/for expension Signed-off-by: Yannick Lamarre --- frontends/ast/simplify.cc | 88 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 83174e963..f65bf4f24 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -4690,6 +4690,7 @@ void AstNode::expand_genblock(const std::string &prefix) switch (child->type) { case AST_WIRE: + case AST_AUTOWIRE: case AST_MEMORY: case AST_STRUCT: case AST_UNION: @@ -4718,6 +4719,93 @@ void AstNode::expand_genblock(const std::string &prefix) } break; + case AST_IDENTIFIER: + if (!child->str.empty() && prefix.size() > 0) { + bool is_resolved = false; + std::string identifier_str = child->str; + if (current_ast_mod != nullptr && identifier_str.compare(0, current_ast_mod->str.size(), current_ast_mod->str) == 0) { + if (identifier_str.at(current_ast_mod->str.size()) == '.') { + identifier_str = '\\' + identifier_str.substr(current_ast_mod->str.size()+1, identifier_str.size()); + } + } + // search starting in the innermost scope and then stepping outward + for (size_t ppos = prefix.size() - 1; ppos; --ppos) { + if (prefix.at(ppos) != '.') continue; + + std::string new_prefix = prefix.substr(0, ppos + 1); + auto attempt_resolve = [&new_prefix](const std::string &ident) -> std::string { + std::string new_name = prefix_id(new_prefix, ident); + if (current_scope.count(new_name)) + return new_name; + return {}; + }; + + // attempt to resolve the full identifier + std::string resolved = attempt_resolve(identifier_str); + if (!resolved.empty()) { + is_resolved = true; + break; + } + // attempt to resolve hierarchical prefixes within the identifier, + // as the prefix could refer to a local scope which exists but + // hasn't yet been elaborated + for (size_t spos = identifier_str.size() - 1; spos; --spos) { + if (identifier_str.at(spos) != '.') continue; + resolved = attempt_resolve(identifier_str.substr(0, spos)); + if (!resolved.empty()) { + is_resolved = true; + identifier_str = resolved + identifier_str.substr(spos); + ppos = 1; // break outer loop + break; + } + } + if (current_scope.count(identifier_str) == 0) { + AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; + for (auto& node : current_scope_ast->children) { + switch (node->type) { + case AST_PARAMETER: + case AST_LOCALPARAM: + case AST_WIRE: + case AST_AUTOWIRE: + case AST_GENVAR: + case AST_MEMORY: + case AST_FUNCTION: + case AST_TASK: + case AST_DPI_FUNCTION: + if (prefix_id(new_prefix, identifier_str) == node->str) { + is_resolved = true; + current_scope[node->str] = node.get(); + } + break; + case AST_ENUM: + current_scope[node->str] = node.get(); + for (auto& enum_node : node->children) { + log_assert(enum_node->type==AST_ENUM_ITEM); + if (prefix_id(new_prefix, identifier_str) == enum_node->str) { + is_resolved = true; + current_scope[enum_node->str] = enum_node.get(); + } + } + break; + default: + break; + } + } + } + } + if ((current_scope.count(identifier_str) == 0) && is_resolved == false) { + if (current_ast_mod == nullptr) { + input_error("Identifier `%s' is implicitly declared outside of a module.\n", child->str.c_str()); + } else if (flag_autowire || identifier_str == "\\$global_clock") { + auto auto_wire = std::make_unique(child->location, AST_AUTOWIRE); + auto_wire->str = identifier_str; + children.push_back(std::move(auto_wire)); + } else { + input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", identifier_str.c_str()); + } + } + } + break; default: break; } From c1ec625f4746f69834235c60cfb0da850704b691 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 00:26:11 +0000 Subject: [PATCH 30/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3fc5f4d07..958007e7b 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+15 +YOSYS_VER := 0.60+25 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 4da0c552dde2ea39856c3d6a827e6136c1a51720 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:26:24 +1300 Subject: [PATCH 31/83] tests/aiger: Fix pipe hiding diff exit status --- tests/aiger/run-test.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh index a4de58e30..7b0a29ce0 100755 --- a/tests/aiger/run-test.sh +++ b/tests/aiger/run-test.sh @@ -62,5 +62,8 @@ done # make gold with: rm gold/*; yosys --no-version -p "test_cell -aigmap -w gold/ -n 1 -s 1 all" rm -rf gate; mkdir gate ../../yosys --no-version -p "test_cell -aigmap -w gate/ -n 1 -s 1 all" -diff --brief gold gate | tee aigmap.err +( + set -o pipefail + diff --brief gold gate | tee aigmap.err +) rm aigmap.err From 2833a44503e76ec47482dbc2c307fdd3ada947f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 13 Dec 2025 00:24:42 +0000 Subject: [PATCH 32/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 958007e7b..83ec0d0b2 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+25 +YOSYS_VER := 0.60+36 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 52dc8c5eff5edd48b889a93b55cf1f44e5b2daf3 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Fri, 12 Dec 2025 14:44:18 +0200 Subject: [PATCH 33/83] pyosys: fix install failure when ABCEXTERNAL is set While pyosys technically supports an external abc in installation, the attempt to always copy yosys-abc regardless would cause `make install` to crash. `__init__.py` already handles yosys-abc not existing, so this just skips the install. --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 958007e7b..a964fa33e 100644 --- a/Makefile +++ b/Makefile @@ -1052,7 +1052,9 @@ ifeq ($(ENABLE_PYOSYS),1) $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so $(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys ifeq ($(ENABLE_ABC),1) - $(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc +ifeq ($(ABCEXTERNAL),) + $(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-abc$(EXE) $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc$(EXE) +endif endif endif endif From 9d3d8bf502f4b09bcf43b81b6a109b944939abb8 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 15 Dec 2025 09:40:04 +1300 Subject: [PATCH 34/83] Switch posix_spawn to posix_spawnp --- passes/techmap/abc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 0963ecfde..a25a79ae8 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -252,8 +252,8 @@ std::optional spawn_abc(const char* abc_exe, DeferredLogs &logs) { 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", abc_exe); return std::nullopt; } free(argv[0]); From 24f4902156220c39a91c2783f038c14ec0130a23 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:17:19 +1300 Subject: [PATCH 35/83] Don't mention iverilog if the error wasn't from iverilog --- tests/tools/autotest.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 47b06d575..1afe304a5 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -170,12 +170,14 @@ do test_count=0 test_passes() { "$toolsdir"/../../yosys -b "verilog $backend_opts" -o ${bn}_syn${test_count}.v "$@" + touch ${bn}.iverilog compile_and_run ${bn}_tb_syn${test_count} ${bn}_out_syn${test_count} \ ${bn}_tb.v ${bn}_syn${test_count}.v "${libs[@]}" \ "$toolsdir"/../../techlibs/common/simlib.v \ "$toolsdir"/../../techlibs/common/simcells.v if $genvcd; then mv testbench.vcd ${bn}_syn${test_count}.vcd; fi "$toolsdir/cmp_tbdata" ${bn}_out_ref ${bn}_out_syn${test_count} + rm ${bn}.iverilog test_count=$(( test_count + 1 )) } @@ -227,7 +229,9 @@ do else echo "${status_prefix}${did_firrtl}-> ERROR!" if $warn_iverilog_git; then - echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog." + if [ -f ${bn}.out/${bn}.iverilog ]; then + echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog." + fi fi $keeprunning || exit 1 fi From c69be9d7678031eea7696bd11e91869ef3495a11 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:31:17 +1300 Subject: [PATCH 36/83] Missed an iverilog Should now still report an iverilog issue if `iverilog` doesn't exist. --- tests/tools/autotest.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 1afe304a5..c9a12b66b 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -162,9 +162,11 @@ do cp ../${bn}_tb.v ${bn}_tb.v fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi + touch ${bn}.iverilog compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.${refext} "${libs[@]}" \ "$toolsdir"/../../techlibs/common/simlib.v \ "$toolsdir"/../../techlibs/common/simcells.v + rm ${bn}.iverilog if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi test_count=0 From 4d61ce63d35a3191d070fc62db9ce1e705847c23 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 00:26:36 +0000 Subject: [PATCH 37/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 50b5c7241..0075a3bae 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+36 +YOSYS_VER := 0.60+39 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 2ded4bd893b977d1a3927bec3bfa49dfaad70dd7 Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <126305457+nataliakokoromyti@users.noreply.github.com> Date: Tue, 16 Dec 2025 04:16:03 -0800 Subject: [PATCH 38/83] Update run-test.sh fix: preserve newline at eof --- tests/verific/run-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/verific/run-test.sh b/tests/verific/run-test.sh index 1d39e2093..1666ee1f9 100755 --- a/tests/verific/run-test.sh +++ b/tests/verific/run-test.sh @@ -2,4 +2,4 @@ set -eu source ../gen-tests-makefile.sh generate_mk --yosys-scripts --bash -echo "$(echo 'export ASAN_OPTIONS=halt_on_error=0'; cat run-test.mk)" > run-test.mk \ No newline at end of file +{ echo 'export ASAN_OPTIONS=halt_on_error=0'; cat run-test.mk; } > run-test.mk.tmp && mv run-test.mk.tmp run-test.mk From cf8be2bae758471019213bbbcbc06690a41ccd9e Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <126305457+nataliakokoromyti@users.noreply.github.com> Date: Tue, 16 Dec 2025 09:33:47 -0800 Subject: [PATCH 39/83] Update ice40_wrapcarry.cc --- techlibs/ice40/ice40_wrapcarry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ice40/ice40_wrapcarry.cc b/techlibs/ice40/ice40_wrapcarry.cc index 82218ff11..b0588f5e1 100644 --- a/techlibs/ice40/ice40_wrapcarry.cc +++ b/techlibs/ice40/ice40_wrapcarry.cc @@ -141,7 +141,7 @@ struct Ice40WrapCarryPass : public Pass { else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived)) continue; else - log_abort(); + continue; if (!src.empty()) { carry->attributes.insert(std::make_pair(ID::src, src)); From e289e4c89322dd7476cf599a474365f6303f3f20 Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <126305457+nataliakokoromyti@users.noreply.github.com> Date: Wed, 17 Dec 2025 01:31:32 -0800 Subject: [PATCH 40/83] add ID::src to allowlist instead --- techlibs/ice40/ice40_wrapcarry.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/ice40/ice40_wrapcarry.cc b/techlibs/ice40/ice40_wrapcarry.cc index b0588f5e1..f62019617 100644 --- a/techlibs/ice40/ice40_wrapcarry.cc +++ b/techlibs/ice40/ice40_wrapcarry.cc @@ -138,10 +138,10 @@ struct Ice40WrapCarryPass : public Pass { lut->attributes[a.first.c_str() + strlen("\\SB_LUT4.")] = a.second; else if (a.first == ID::src) src = a.second; - else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived)) + else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived, ID::src)) continue; else - continue; + log_abort(); if (!src.empty()) { carry->attributes.insert(std::make_pair(ID::src, src)); From 45d654e2d7baf332b33e7b7bd00c81019c7606ac Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Wed, 17 Dec 2025 20:25:24 +0100 Subject: [PATCH 41/83] avoid merging formal properties --- frontends/ast/genrtlil.cc | 1 + frontends/verific/verificsva.cc | 5 ++++- passes/opt/opt_merge.cc | 5 +++++ tests/opt/opt_merge_properties.ys | 16 ++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/opt/opt_merge_properties.ys diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index c26750c98..86ea70b51 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -844,6 +844,7 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::Cell *cell = current_module->addCell(cellname, ID($check)); set_src_attr(cell, ast); + cell->set_bool_attribute(ID(keep)); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first); diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index dffe6e8e0..c2cfe7e75 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -1846,7 +1846,10 @@ struct VerificSvaImporter if (mode_assume) c = module->addAssume(root_name, sig_a_q, sig_en_q); if (mode_cover) c = module->addCover(root_name, sig_a_q, sig_en_q); - if (c) importer->import_attributes(c->attributes, root); + if (c) { + c->set_bool_attribute(ID(keep)); + importer->import_attributes(c->attributes, root); + } } } catch (ParserErrorException) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 6cdcbc822..307c2bcd3 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -227,6 +227,11 @@ struct OptMergeWorker ct.cell_types.erase(ID($anyconst)); ct.cell_types.erase(ID($allseq)); ct.cell_types.erase(ID($allconst)); + ct.cell_types.erase(ID($check)); + ct.cell_types.erase(ID($assert)); + ct.cell_types.erase(ID($assume)); + ct.cell_types.erase(ID($live)); + ct.cell_types.erase(ID($cover)); log("Finding identical cells in module `%s'.\n", module->name); assign_map.set(module); diff --git a/tests/opt/opt_merge_properties.ys b/tests/opt/opt_merge_properties.ys new file mode 100644 index 000000000..dddc13bfb --- /dev/null +++ b/tests/opt/opt_merge_properties.ys @@ -0,0 +1,16 @@ +read_verilog -sv < Date: Thu, 18 Dec 2025 00:22:53 +0000 Subject: [PATCH 42/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0075a3bae..9c361294d 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+39 +YOSYS_VER := 0.60+51 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 772d821fb0f68bcf0c2baf321ebd1aa64965fe42 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 19 Dec 2025 18:30:17 +0100 Subject: [PATCH 43/83] opt_expr: reindent test --- tests/opt/opt_expr_combined_assign.ys | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/opt/opt_expr_combined_assign.ys b/tests/opt/opt_expr_combined_assign.ys index b18923c7b..f84978a0a 100644 --- a/tests/opt/opt_expr_combined_assign.ys +++ b/tests/opt/opt_expr_combined_assign.ys @@ -5,7 +5,7 @@ initial begin a |= i; a |= j; end - assign o = a; + assign o = a; endmodule EOT proc @@ -19,10 +19,10 @@ read_verilog -sv < Date: Fri, 19 Dec 2025 18:32:06 +0100 Subject: [PATCH 44/83] opt_expr: avoid multiple drivers issue #4792 in combined assign tests --- tests/opt/opt_expr_combined_assign.ys | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/opt/opt_expr_combined_assign.ys b/tests/opt/opt_expr_combined_assign.ys index f84978a0a..823ca959a 100644 --- a/tests/opt/opt_expr_combined_assign.ys +++ b/tests/opt/opt_expr_combined_assign.ys @@ -1,7 +1,8 @@ read_verilog -sv < Date: Tue, 16 Dec 2025 01:39:39 +0000 Subject: [PATCH 45/83] Implement design_equal command --- passes/cmds/Makefile.inc | 1 + passes/cmds/design_equal.cc | 352 +++++++++++++++++++++++++++++ tests/various/design_equal_fail.ys | 22 ++ tests/various/design_equal_pass.ys | 17 ++ 4 files changed, 392 insertions(+) create mode 100644 passes/cmds/design_equal.cc create mode 100644 tests/various/design_equal_fail.ys create mode 100644 tests/various/design_equal_pass.ys diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index b1b1383b1..dc12c92c2 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -5,6 +5,7 @@ endif OBJS += passes/cmds/add.o OBJS += passes/cmds/delete.o OBJS += passes/cmds/design.o +OBJS += passes/cmds/design_equal.o OBJS += passes/cmds/select.o OBJS += passes/cmds/show.o OBJS += passes/cmds/viz.o diff --git a/passes/cmds/design_equal.cc b/passes/cmds/design_equal.cc new file mode 100644 index 000000000..a949db9ff --- /dev/null +++ b/passes/cmds/design_equal.cc @@ -0,0 +1,352 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * 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/rtlil.h" + +YOSYS_NAMESPACE_BEGIN + +class ModuleComparator +{ + RTLIL::Module *mod_a; + RTLIL::Module *mod_b; + +public: + ModuleComparator(RTLIL::Module *mod_a, RTLIL::Module *mod_b) : mod_a(mod_a), mod_b(mod_b) {} + + bool compare_sigbit(const RTLIL::SigBit &a, const RTLIL::SigBit &b) + { + if (a.wire == nullptr && b.wire == nullptr) + return a.data == b.data; + if (a.wire != nullptr && b.wire != nullptr) + return a.wire->name == b.wire->name && a.offset == b.offset; + return false; + } + + bool compare_sigspec(const RTLIL::SigSpec &a, const RTLIL::SigSpec &b) + { + if (a.size() != b.size()) return false; + auto it_a = a.begin(), it_b = b.begin(); + for (; it_a != a.end(); ++it_a, ++it_b) { + if (!compare_sigbit(*it_a, *it_b)) return false; + } + return true; + } + + std::string compare_attributes(const RTLIL::AttrObject *a, const RTLIL::AttrObject *b) + { + for (const auto &it : a->attributes) { + if (b->attributes.count(it.first) == 0) + return "missing attribute " + std::string(log_id(it.first)) + " in second design"; + if (it.second != b->attributes.at(it.first)) + return "attribute " + std::string(log_id(it.first)) + " mismatch: " + log_const(it.second) + " != " + log_const(b->attributes.at(it.first)); + } + for (const auto &it : b->attributes) + if (a->attributes.count(it.first) == 0) + return "missing attribute " + std::string(log_id(it.first)) + " in first design"; + return ""; + } + + std::string compare_wires(const RTLIL::Wire *a, const RTLIL::Wire *b) + { + if (a->name != b->name) + return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (a->width != b->width) + return "width mismatch: " + std::to_string(a->width) + " != " + std::to_string(b->width); + if (a->start_offset != b->start_offset) + return "start_offset mismatch: " + std::to_string(a->start_offset) + " != " + std::to_string(b->start_offset); + if (a->port_id != b->port_id) + return "port_id mismatch: " + std::to_string(a->port_id) + " != " + std::to_string(b->port_id); + if (a->port_input != b->port_input) + return "port_input mismatch: " + std::to_string(a->port_input) + " != " + std::to_string(b->port_input); + if (a->port_output != b->port_output) + return "port_output mismatch: " + std::to_string(a->port_output) + " != " + std::to_string(b->port_output); + if (a->upto != b->upto) + return "upto mismatch: " + std::to_string(a->upto) + " != " + std::to_string(b->upto); + if (a->is_signed != b->is_signed) + return "is_signed mismatch: " + std::to_string(a->is_signed) + " != " + std::to_string(b->is_signed); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + return ""; + } + + void check_wires() + { + for (const auto &it : mod_a->wires_) { + if (mod_b->wires_.count(it.first) == 0) + log_error("Module %s missing wire %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_wires(it.second, mod_b->wires_.at(it.first)); !mismatch.empty()) + log_error("Module %s wire %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch); + } + for (const auto &it : mod_b->wires_) + if (mod_a->wires_.count(it.first) == 0) + log_error("Module %s missing wire %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + std::string compare_memories(const RTLIL::Memory *a, const RTLIL::Memory *b) + { + if (a->name != b->name) + return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (a->width != b->width) + return "width mismatch: " + std::to_string(a->width) + " != " + std::to_string(b->width); + if (a->start_offset != b->start_offset) + return "start_offset mismatch: " + std::to_string(a->start_offset) + " != " + std::to_string(b->start_offset); + if (a->size != b->size) + return "size mismatch: " + std::to_string(a->size) + " != " + std::to_string(b->size); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + return ""; + } + + std::string compare_cells(const RTLIL::Cell *a, const RTLIL::Cell *b) + { + if (a->name != b->name) + return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (a->type != b->type) + return "type mismatch: " + std::string(log_id(a->type)) + " != " + log_id(b->type); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + + for (const auto &it : a->parameters) { + if (b->parameters.count(it.first) == 0) + return "parameter mismatch: missing parameter " + std::string(log_id(it.first)) + " in second design"; + if (it.second != b->parameters.at(it.first)) + return "parameter mismatch: " + std::string(log_id(it.first)) + " mismatch: " + log_const(it.second) + " != " + log_const(b->parameters.at(it.first)); + } + for (const auto &it : b->parameters) + if (a->parameters.count(it.first) == 0) + return "parameter mismatch: missing parameter " + std::string(log_id(it.first)) + " in first design"; + + for (const auto &it : a->connections()) { + if (b->connections().count(it.first) == 0) + return "connection mismatch: missing connection " + std::string(log_id(it.first)) + " in second design"; + if (!compare_sigspec(it.second, b->connections().at(it.first))) + return "connection " + std::string(log_id(it.first)) + " mismatch: " + log_signal(it.second) + " != " + log_signal(b->connections().at(it.first)); + } + for (const auto &it : b->connections()) + if (a->connections().count(it.first) == 0) + return "connection mismatch: missing connection " + std::string(log_id(it.first)) + " in first design"; + + return ""; + } + + void check_cells() + { + for (const auto &it : mod_a->cells_) { + if (mod_b->cells_.count(it.first) == 0) + log_error("Module %s missing cell %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_cells(it.second, mod_b->cells_.at(it.first)); !mismatch.empty()) + log_error("Module %s cell %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch); + } + for (const auto &it : mod_b->cells_) + if (mod_a->cells_.count(it.first) == 0) + log_error("Module %s missing cell %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + void check_memories() + { + for (const auto &it : mod_a->memories) { + if (mod_b->memories.count(it.first) == 0) + log_error("Module %s missing memory %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_memories(it.second, mod_b->memories.at(it.first)); !mismatch.empty()) + log_error("Module %s memory %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch); + } + for (const auto &it : mod_b->memories) + if (mod_a->memories.count(it.first) == 0) + log_error("Module %s missing memory %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + std::string compare_case_rules(const RTLIL::CaseRule *a, const RTLIL::CaseRule *b) + { + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) return mismatch; + + if (a->compare.size() != b->compare.size()) + return "compare size mismatch: " + std::to_string(a->compare.size()) + " != " + std::to_string(b->compare.size()); + for (size_t i = 0; i < a->compare.size(); i++) + if (!compare_sigspec(a->compare[i], b->compare[i])) + return "compare " + std::to_string(i) + " mismatch: " + log_signal(a->compare[i]) + " != " + log_signal(b->compare[i]); + + if (a->actions.size() != b->actions.size()) + return "actions size mismatch: " + std::to_string(a->actions.size()) + " != " + std::to_string(b->actions.size()); + for (size_t i = 0; i < a->actions.size(); i++) { + if (!compare_sigspec(a->actions[i].first, b->actions[i].first)) + return "action " + std::to_string(i) + " first mismatch: " + log_signal(a->actions[i].first) + " != " + log_signal(b->actions[i].first); + if (!compare_sigspec(a->actions[i].second, b->actions[i].second)) + return "action " + std::to_string(i) + " second mismatch: " + log_signal(a->actions[i].second) + " != " + log_signal(b->actions[i].second); + } + + if (a->switches.size() != b->switches.size()) + return "switches size mismatch: " + std::to_string(a->switches.size()) + " != " + std::to_string(b->switches.size()); + for (size_t i = 0; i < a->switches.size(); i++) + if (std::string mismatch = compare_switch_rules(a->switches[i], b->switches[i]); !mismatch.empty()) + return "switch " + std::to_string(i) + " " + mismatch; + + return ""; + } + + std::string compare_switch_rules(const RTLIL::SwitchRule *a, const RTLIL::SwitchRule *b) + { + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + if (!compare_sigspec(a->signal, b->signal)) + return "signal mismatch: " + log_signal(a->signal) + " != " + log_signal(b->signal); + + if (a->cases.size() != b->cases.size()) + return "cases size mismatch: " + std::to_string(a->cases.size()) + " != " + std::to_string(b->cases.size()); + for (size_t i = 0; i < a->cases.size(); i++) + if (std::string mismatch = compare_case_rules(a->cases[i], b->cases[i]); !mismatch.empty()) + return "case " + std::to_string(i) + " " + mismatch; + + return ""; + } + + std::string compare_sync_rules(const RTLIL::SyncRule *a, const RTLIL::SyncRule *b) + { + if (a->type != b->type) + return "type mismatch: " + std::to_string(a->type) + " != " + std::to_string(b->type); + if (!compare_sigspec(a->signal, b->signal)) + return "signal mismatch: " + log_signal(a->signal) + " != " + log_signal(b->signal); + if (a->actions.size() != b->actions.size()) + return "actions size mismatch: " + std::to_string(a->actions.size()) + " != " + std::to_string(b->actions.size()); + for (size_t i = 0; i < a->actions.size(); i++) { + if (!compare_sigspec(a->actions[i].first, b->actions[i].first)) + return "action " + std::to_string(i) + " first mismatch: " + log_signal(a->actions[i].first) + " != " + log_signal(b->actions[i].first); + if (!compare_sigspec(a->actions[i].second, b->actions[i].second)) + return "action " + std::to_string(i) + " second mismatch: " + log_signal(a->actions[i].second) + " != " + log_signal(b->actions[i].second); + } + if (a->mem_write_actions.size() != b->mem_write_actions.size()) + return "mem_write_actions size mismatch: " + std::to_string(a->mem_write_actions.size()) + " != " + std::to_string(b->mem_write_actions.size()); + for (size_t i = 0; i < a->mem_write_actions.size(); i++) { + const auto &ma = a->mem_write_actions[i]; + const auto &mb = b->mem_write_actions[i]; + if (ma.memid != mb.memid) + return "mem_write_actions " + std::to_string(i) + " memid mismatch: " + log_id(ma.memid) + " != " + log_id(mb.memid); + if (!compare_sigspec(ma.address, mb.address)) + return "mem_write_actions " + std::to_string(i) + " address mismatch: " + log_signal(ma.address) + " != " + log_signal(mb.address); + if (!compare_sigspec(ma.data, mb.data)) + return "mem_write_actions " + std::to_string(i) + " data mismatch: " + log_signal(ma.data) + " != " + log_signal(mb.data); + if (!compare_sigspec(ma.enable, mb.enable)) + return "mem_write_actions " + std::to_string(i) + " enable mismatch: " + log_signal(ma.enable) + " != " + log_signal(mb.enable); + if (ma.priority_mask != mb.priority_mask) + return "mem_write_actions " + std::to_string(i) + " priority_mask mismatch: " + log_const(ma.priority_mask) + " != " + log_const(mb.priority_mask); + if (std::string mismatch = compare_attributes(&ma, &mb); !mismatch.empty()) + return "mem_write_actions " + std::to_string(i) + " " + mismatch; + } + return ""; + } + + std::string compare_processes(const RTLIL::Process *a, const RTLIL::Process *b) + { + if (a->name != b->name) return "name mismatch: " + std::string(log_id(a->name)) + " != " + log_id(b->name); + if (std::string mismatch = compare_attributes(a, b); !mismatch.empty()) + return mismatch; + if (std::string mismatch = compare_case_rules(&a->root_case, &b->root_case); !mismatch.empty()) + return "case rule " + mismatch; + if (a->syncs.size() != b->syncs.size()) + return "sync count mismatch: " + std::to_string(a->syncs.size()) + " != " + std::to_string(b->syncs.size()); + for (size_t i = 0; i < a->syncs.size(); i++) + if (std::string mismatch = compare_sync_rules(a->syncs[i], b->syncs[i]); !mismatch.empty()) + return "sync " + std::to_string(i) + " " + mismatch; + return ""; + } + + void check_processes() + { + for (auto &it : mod_a->processes) { + if (mod_b->processes.count(it.first) == 0) + log_error("Module %s missing process %s in second design.\n", log_id(mod_a->name), log_id(it.first)); + if (std::string mismatch = compare_processes(it.second, mod_b->processes.at(it.first)); !mismatch.empty()) + log_error("Module %s process %s %s.\n", log_id(mod_a->name), log_id(it.first), mismatch.c_str()); + } + for (auto &it : mod_b->processes) + if (mod_a->processes.count(it.first) == 0) + log_error("Module %s missing process %s in first design.\n", log_id(mod_b->name), log_id(it.first)); + } + + void check_connections() + { + const auto &conns_a = mod_a->connections(); + const auto &conns_b = mod_b->connections(); + if (conns_a.size() != conns_b.size()) { + log_error("Module %s connection count differs: %zu != %zu\n", log_id(mod_a->name), conns_a.size(), conns_b.size()); + } else { + for (size_t i = 0; i < conns_a.size(); i++) { + if (!compare_sigspec(conns_a[i].first, conns_b[i].first)) + log_error("Module %s connection %zu LHS %s != %s.\n", log_id(mod_a->name), i, log_signal(conns_a[i].first), log_signal(conns_b[i].first)); + if (!compare_sigspec(conns_a[i].second, conns_b[i].second)) + log_error("Module %s connection %zu RHS %s != %s.\n", log_id(mod_a->name), i, log_signal(conns_a[i].second), log_signal(conns_b[i].second)); + } + } + } + + void check() + { + if (mod_a->name != mod_b->name) + log_error("Modules have different names: %s != %s\n", log_id(mod_a->name), log_id(mod_b->name)); + if (std::string mismatch = compare_attributes(mod_a, mod_b); !mismatch.empty()) + log_error("Module %s %s.\n", log_id(mod_a->name), mismatch); + check_wires(); + check_cells(); + check_memories(); + check_connections(); + check_processes(); + } +}; + +struct DesignEqualPass : public Pass { + DesignEqualPass() : Pass("design_equal", "check if two designs are the same") { } + void help() override + { + log("\n"); + log(" design_equal \n"); + log("\n"); + log("Compare the current design with the design previously saved under the given\n"); + log("name. Abort with an error if the designs are different.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + if (args.size() != 2) + log_cmd_error("Missing argument.\n"); + + std::string check_name = args[1]; + if (saved_designs.count(check_name) == 0) + log_cmd_error("No saved design '%s' found!\n", check_name.c_str()); + + RTLIL::Design *other = saved_designs.at(check_name); + + for (auto &it : design->modules_) { + RTLIL::Module *mod = it.second; + if (!other->has(mod->name)) + log_error("Second design missing module %s.\n", log_id(mod->name)); + + ModuleComparator cmp(mod, other->module(mod->name)); + cmp.check(); + } + for (auto &it : other->modules_) { + RTLIL::Module *mod = it.second; + if (!design->has(mod->name)) + log_error("First design missing module %s.\n", log_id(mod->name)); + } + + log("Designs are identical.\n"); + } +} DesignEqualPass; + +YOSYS_NAMESPACE_END diff --git a/tests/various/design_equal_fail.ys b/tests/various/design_equal_fail.ys new file mode 100644 index 000000000..330d8d838 --- /dev/null +++ b/tests/various/design_equal_fail.ys @@ -0,0 +1,22 @@ +logger -expect error "Second design missing module top_renamed" 1 + +read_rtlil < Date: Wed, 17 Dec 2025 03:11:06 +0000 Subject: [PATCH 46/83] Add -legalize option to read_rtlil --- frontends/rtlil/rtlil_frontend.cc | 141 +++++++++++++++++++++++++----- kernel/rtlil.cc | 7 ++ kernel/rtlil.h | 3 + 3 files changed, 131 insertions(+), 20 deletions(-) diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 271962725..a1412d983 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -40,6 +40,7 @@ struct RTLILFrontendWorker { bool flag_nooverwrite = false; bool flag_overwrite = false; bool flag_lib = false; + bool flag_legalize = false; int line_num; std::string line_buf; @@ -322,6 +323,17 @@ struct RTLILFrontendWorker { return val; } + RTLIL::Wire *legalize_wire(RTLIL::IdString id) + { + int wires_size = current_module->wires_size(); + if (wires_size == 0) + error("No wires found for legalization"); + int hash = hash_ops::hash(id).yield(); + RTLIL::Wire *wire = current_module->wire_at(abs(hash % wires_size)); + log("Legalizing wire `%s' to `%s'.\n", log_id(id), log_id(wire->name)); + return wire; + } + RTLIL::SigSpec parse_sigspec() { RTLIL::SigSpec sig; @@ -339,8 +351,12 @@ struct RTLILFrontendWorker { std::optional id = try_parse_id(); if (id.has_value()) { RTLIL::Wire *wire = current_module->wire(*id); - if (wire == nullptr) - error("Wire `%s' not found.", *id); + if (wire == nullptr) { + if (flag_legalize) + wire = legalize_wire(*id); + else + error("Wire `%s' not found.", *id); + } sig = RTLIL::SigSpec(wire); } else { sig = RTLIL::SigSpec(parse_const()); @@ -349,17 +365,44 @@ struct RTLILFrontendWorker { while (try_parse_char('[')) { int left = parse_integer(); - if (left >= sig.size() || left < 0) - error("bit index %d out of range", left); + if (left >= sig.size() || left < 0) { + if (flag_legalize) { + int legalized; + if (sig.size() == 0) + legalized = 0; + else + legalized = std::max(0, std::min(left, sig.size() - 1)); + log("Legalizing bit index %d to %d.\n", left, legalized); + left = legalized; + } else { + error("bit index %d out of range", left); + } + } if (try_parse_char(':')) { int right = parse_integer(); - if (right < 0) - error("bit index %d out of range", right); - if (left < right) - error("invalid slice [%d:%d]", left, right); - sig = sig.extract(right, left-right+1); + if (right < 0) { + if (flag_legalize) { + log("Legalizing bit index %d to %d.\n", right, 0); + right = 0; + } else + error("bit index %d out of range", right); + } + if (left < right) { + if (flag_legalize) { + log("Legalizing bit index %d to %d.\n", left, right); + left = right; + } else + error("invalid slice [%d:%d]", left, right); + } + if (flag_legalize && left >= sig.size()) + log("Legalizing slice %d:%d by igoring it\n", left, right); + else + sig = sig.extract(right, left - right + 1); } else { - sig = sig.extract(left); + if (flag_legalize && left >= sig.size()) + log("Legalizing slice %d by igoring it\n", left); + else + sig = sig.extract(left); } expect_char(']'); } @@ -476,8 +519,14 @@ struct RTLILFrontendWorker { { std::optional id = try_parse_id(); if (id.has_value()) { - if (current_module->wire(*id) != nullptr) - error("RTLIL error: redefinition of wire %s.", *id); + if (current_module->wire(*id) != nullptr) { + if (flag_legalize) { + log("Legalizing redefinition of wire %s.\n", *id); + pool wires = {current_module->wire(*id)}; + current_module->remove(wires); + } else + error("RTLIL error: redefinition of wire %s.", *id); + } wire = current_module->addWire(std::move(*id)); break; } @@ -528,8 +577,13 @@ struct RTLILFrontendWorker { { std::optional id = try_parse_id(); if (id.has_value()) { - if (current_module->memories.count(*id) != 0) - error("RTLIL error: redefinition of memory %s.", *id); + if (current_module->memories.count(*id) != 0) { + if (flag_legalize) { + log("Legalizing redefinition of memory %s.\n", *id); + current_module->remove(current_module->memories.at(*id)); + } else + error("RTLIL error: redefinition of memory %s.", *id); + } memory->name = std::move(*id); break; } @@ -551,14 +605,36 @@ struct RTLILFrontendWorker { expect_eol(); } + void legalize_width_parameter(RTLIL::Cell *cell, RTLIL::IdString port_name) + { + std::string width_param_name = port_name.str() + "_WIDTH"; + if (cell->parameters.count(width_param_name) == 0) + return; + RTLIL::Const ¶m = cell->parameters.at(width_param_name); + if (param.as_int() != 0) + return; + cell->parameters[width_param_name] = RTLIL::Const(cell->getPort(port_name).size()); + } + void parse_cell() { RTLIL::IdString cell_type = parse_id(); RTLIL::IdString cell_name = parse_id(); expect_eol(); - if (current_module->cell(cell_name) != nullptr) - error("RTLIL error: redefinition of cell %s.", cell_name); + if (current_module->cell(cell_name) != nullptr) { + if (flag_legalize) { + RTLIL::IdString new_name; + int suffix = 1; + do { + new_name = RTLIL::IdString(cell_name.str() + "_" + std::to_string(suffix)); + ++suffix; + } while (current_module->cell(new_name) != nullptr); + log("Legalizing redefinition of cell %s by renaming to %s.\n", cell_name, new_name); + cell_name = new_name; + } else + error("RTLIL error: redefinition of cell %s.", cell_name); + } RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type); cell->attributes = std::move(attrbuf); @@ -587,9 +663,15 @@ struct RTLILFrontendWorker { expect_eol(); } else if (try_parse_keyword("connect")) { RTLIL::IdString port_name = parse_id(); - if (cell->hasPort(port_name)) - error("RTLIL error: redefinition of cell port %s.", port_name); + if (cell->hasPort(port_name)) { + if (flag_legalize) + log("Legalizing redefinition of cell port %s.", port_name); + else + error("RTLIL error: redefinition of cell port %s.", port_name); + } cell->setPort(std::move(port_name), parse_sigspec()); + if (flag_legalize) + legalize_width_parameter(cell, port_name); expect_eol(); } else if (try_parse_keyword("end")) { expect_eol(); @@ -606,6 +688,11 @@ struct RTLILFrontendWorker { error("dangling attribute"); RTLIL::SigSpec s1 = parse_sigspec(); RTLIL::SigSpec s2 = parse_sigspec(); + if (flag_legalize) { + int min_size = std::min(s1.size(), s2.size()); + s1 = s1.extract(0, min_size); + s2 = s2.extract(0, min_size); + } current_module->connect(std::move(s1), std::move(s2)); expect_eol(); } @@ -682,8 +769,13 @@ struct RTLILFrontendWorker { RTLIL::IdString proc_name = parse_id(); expect_eol(); - if (current_module->processes.count(proc_name) != 0) - error("RTLIL error: redefinition of process %s.", proc_name); + if (current_module->processes.count(proc_name) != 0) { + if (flag_legalize) { + log("Legalizing redefinition of process %s.\n", proc_name); + current_module->remove(current_module->processes.at(proc_name)); + } else + error("RTLIL error: redefinition of process %s.", proc_name); + } RTLIL::Process *proc = current_module->addProcess(std::move(proc_name)); proc->attributes = std::move(attrbuf); @@ -804,6 +896,11 @@ struct RTLILFrontend : public Frontend { log(" -lib\n"); log(" only create empty blackbox modules\n"); log("\n"); + log(" -legalize\n"); + log(" prevent semantic errors (e.g. reference to unknown wire, redefinition of wire/cell)\n"); + log(" by deterministically rewriting the input into something valid. Useful when using\n"); + log(" fuzzing to generate random but valid RTLIL.\n"); + log("\n"); } void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { @@ -828,6 +925,10 @@ struct RTLILFrontend : public Frontend { worker.flag_lib = true; continue; } + if (arg == "-legalize") { + worker.flag_legalize = true; + continue; + } break; } extra_args(f, filename, args, argidx); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d92aec73b..a09f9497a 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3039,6 +3039,13 @@ void RTLIL::Module::remove(RTLIL::Cell *cell) } } +void RTLIL::Module::remove(RTLIL::Memory *memory) +{ + log_assert(memories.count(memory->name) != 0); + memories.erase(memory->name); + delete memory; +} + void RTLIL::Module::remove(RTLIL::Process *process) { log_assert(processes.count(process->name) != 0); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f841df1ed..163dbe5a8 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -2139,6 +2139,8 @@ public: } RTLIL::ObjRange wires() { return RTLIL::ObjRange(&wires_, &refcount_wires_); } + int wires_size() const { return wires_.size(); } + RTLIL::Wire* wire_at(int index) const { return wires_.element(index)->second; } RTLIL::ObjRange cells() { return RTLIL::ObjRange(&cells_, &refcount_cells_); } void add(RTLIL::Binding *binding); @@ -2146,6 +2148,7 @@ public: // Removing wires is expensive. If you have to remove wires, remove them all at once. void remove(const pool &wires); void remove(RTLIL::Cell *cell); + void remove(RTLIL::Memory *memory); void remove(RTLIL::Process *process); void rename(RTLIL::Wire *wire, RTLIL::IdString new_name); From 46cb05c4713ad057d10f435c5d40df811c76a54c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 22 Dec 2025 01:52:59 +0000 Subject: [PATCH 47/83] Pass IdString by value instead of by const reference. When IdString refcounting was expensive, it made sense to pass it by const reference instead of by value, to avoid refcount churn. Now that IdString is not refcounted, it's slightly more efficient to pass it by value. --- backends/cxxrtl/cxxrtl_backend.cc | 10 ++-- frontends/ast/simplify.cc | 2 +- kernel/celltypes.h | 8 +-- kernel/io.cc | 2 +- kernel/modtools.h | 2 +- kernel/rtlil.cc | 70 +++++++++++----------- kernel/rtlil.h | 98 +++++++++++++++---------------- kernel/rtlil_bufnorm.cc | 4 +- kernel/scopeinfo.cc | 4 +- kernel/scopeinfo.h | 4 +- passes/cmds/printattrs.cc | 2 +- passes/cmds/trace.cc | 2 +- passes/techmap/bufnorm.cc | 2 +- passes/techmap/simplemap.cc | 2 +- pyosys/wrappers_tpl.cc | 4 +- 15 files changed, 108 insertions(+), 108 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index d575b5879..71913d2db 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -756,7 +756,7 @@ struct CxxrtlWorker { // 1b. Generated identifiers for internal names (beginning with `$`) start with `i_`. // 2. An underscore is escaped with another underscore, i.e. `__`. // 3. Any other non-alnum character is escaped with underscores around its lowercase hex code, e.g. `@` as `_40_`. - std::string mangle_name(const RTLIL::IdString &name) + std::string mangle_name(RTLIL::IdString name) { std::string mangled; bool first = true; @@ -786,7 +786,7 @@ struct CxxrtlWorker { return mangled; } - std::string mangle_module_name(const RTLIL::IdString &name, bool is_blackbox = false) + std::string mangle_module_name(RTLIL::IdString name, bool is_blackbox = false) { // Class namespace. if (is_blackbox) @@ -794,19 +794,19 @@ struct CxxrtlWorker { return mangle_name(name); } - std::string mangle_memory_name(const RTLIL::IdString &name) + std::string mangle_memory_name(RTLIL::IdString name) { // Class member namespace. return "memory_" + mangle_name(name); } - std::string mangle_cell_name(const RTLIL::IdString &name) + std::string mangle_cell_name(RTLIL::IdString name) { // Class member namespace. return "cell_" + mangle_name(name); } - std::string mangle_wire_name(const RTLIL::IdString &name) + std::string mangle_wire_name(RTLIL::IdString name) { // Class member namespace. return mangle_name(name); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 83174e963..b1331420e 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -879,7 +879,7 @@ static void check_auto_nosync(AstNode *node) } // remove the attributes we've "consumed" - for (const RTLIL::IdString &str : attrs_to_drop) { + for (RTLIL::IdString str : attrs_to_drop) { auto it = node->attributes.find(str); node->attributes.erase(it); } diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 2c3535eac..34b013dd9 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -305,18 +305,18 @@ struct CellTypes cell_types.clear(); } - bool cell_known(const RTLIL::IdString &type) const + bool cell_known(RTLIL::IdString type) const { return cell_types.count(type) != 0; } - bool cell_output(const RTLIL::IdString &type, const RTLIL::IdString &port) const + bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(const RTLIL::IdString &type, const RTLIL::IdString &port) const + bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.inputs.count(port) != 0; @@ -332,7 +332,7 @@ struct CellTypes return RTLIL::PortDir(is_input + is_output * 2); } - bool cell_evaluable(const RTLIL::IdString &type) const + bool cell_evaluable(RTLIL::IdString type) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.is_evaluable; diff --git a/kernel/io.cc b/kernel/io.cc index 4f805e43b..078fa139c 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -602,7 +602,7 @@ void format_emit_string_view(std::string &result, std::string_view spec, int *dy } void format_emit_idstring(std::string &result, std::string_view spec, int *dynamic_ints, - DynamicIntCount num_dynamic_ints, const IdString &arg) + DynamicIntCount num_dynamic_ints, const RTLIL::IdString &arg) { if (spec == "%s") { // Format checking will have guaranteed num_dynamic_ints == 0. diff --git a/kernel/modtools.h b/kernel/modtools.h index 27ba98d7d..a081c7556 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -161,7 +161,7 @@ struct ModIndex : public RTLIL::Monitor #endif } - void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override + void notify_connect(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override { log_assert(module == cell->module); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d92aec73b..cdaaa97bb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1017,12 +1017,12 @@ RTLIL::Const RTLIL::Const::extract(int offset, int len, RTLIL::State padding) co } #undef check /* check(condition) for Const */ -bool RTLIL::AttrObject::has_attribute(const RTLIL::IdString &id) const +bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const { return attributes.count(id); } -void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value) +void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) { if (value) attributes[id] = RTLIL::Const(1); @@ -1030,7 +1030,7 @@ void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value attributes.erase(id); } -bool RTLIL::AttrObject::get_bool_attribute(const RTLIL::IdString &id) const +bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const { const auto it = attributes.find(id); if (it == attributes.end()) @@ -1038,7 +1038,7 @@ bool RTLIL::AttrObject::get_bool_attribute(const RTLIL::IdString &id) const return it->second.as_bool(); } -void RTLIL::AttrObject::set_string_attribute(const RTLIL::IdString& id, string value) +void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value) { if (value.empty()) attributes.erase(id); @@ -1046,7 +1046,7 @@ void RTLIL::AttrObject::set_string_attribute(const RTLIL::IdString& id, string v attributes[id] = value; } -string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const +string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const { std::string value; const auto it = attributes.find(id); @@ -1055,7 +1055,7 @@ string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const return value; } -void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const pool &data) +void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool &data) { string attrval; for (const auto &s : data) { @@ -1066,7 +1066,7 @@ void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const p set_string_attribute(id, attrval); } -void RTLIL::AttrObject::add_strpool_attribute(const RTLIL::IdString& id, const pool &data) +void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool &data) { pool union_data = get_strpool_attribute(id); union_data.insert(data.begin(), data.end()); @@ -1074,7 +1074,7 @@ void RTLIL::AttrObject::add_strpool_attribute(const RTLIL::IdString& id, const p set_strpool_attribute(id, union_data); } -pool RTLIL::AttrObject::get_strpool_attribute(const RTLIL::IdString &id) const +pool RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const { pool data; if (attributes.count(id) != 0) @@ -1099,7 +1099,7 @@ vector RTLIL::AttrObject::get_hdlname_attribute() const return split_tokens(get_string_attribute(ID::hdlname), " "); } -void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const vector &data) +void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector &data) { std::stringstream attrval; for (auto &i : data) { @@ -1110,7 +1110,7 @@ void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const ve attributes[id] = RTLIL::Const(attrval.str()); } -vector RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) const +vector RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const { vector data; auto it = attributes.find(id); @@ -1128,7 +1128,7 @@ vector RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) c return data; } -bool RTLIL::Selection::boxed_module(const RTLIL::IdString &mod_name) const +bool RTLIL::Selection::boxed_module(RTLIL::IdString mod_name) const { if (current_design != nullptr) { auto module = current_design->module(mod_name); @@ -1139,7 +1139,7 @@ bool RTLIL::Selection::boxed_module(const RTLIL::IdString &mod_name) const } } -bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const +bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const { if (complete_selection) return true; @@ -1154,7 +1154,7 @@ bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const return false; } -bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) const +bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const { if (complete_selection) return true; @@ -1167,7 +1167,7 @@ bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) co return false; } -bool RTLIL::Selection::selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const +bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const { if (complete_selection) return true; @@ -1294,12 +1294,12 @@ RTLIL::ObjRange RTLIL::Design::modules() return RTLIL::ObjRange(&modules_, &refcount_modules_); } -RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) +RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) { return modules_.count(name) ? modules_.at(name) : NULL; } -const RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) const +const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const { return modules_.count(name) ? modules_.at(name) : NULL; } @@ -1488,21 +1488,21 @@ void RTLIL::Design::optimize() it.second.optimize(this); } -bool RTLIL::Design::selected_module(const RTLIL::IdString& mod_name) const +bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; return selection().selected_module(mod_name); } -bool RTLIL::Design::selected_whole_module(const RTLIL::IdString& mod_name) const +bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; return selection().selected_whole_module(mod_name); } -bool RTLIL::Design::selected_member(const RTLIL::IdString& mod_name, const RTLIL::IdString& memb_name) const +bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const { if (!selected_active_module.empty() && mod_name != selected_active_module) return false; @@ -1693,7 +1693,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const dictname.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str()); } - int param(const RTLIL::IdString& name) + int param(RTLIL::IdString name) { auto it = cell->parameters.find(name); if (it == cell->parameters.end()) @@ -1727,7 +1727,7 @@ namespace { return it->second.as_int(); } - int param_bool(const RTLIL::IdString& name) + int param_bool(RTLIL::IdString name) { int v = param(name); if (GetSize(cell->parameters.at(name)) > 32) @@ -1737,7 +1737,7 @@ namespace { return v; } - int param_bool(const RTLIL::IdString& name, bool expected) + int param_bool(RTLIL::IdString name, bool expected) { int v = param_bool(name); if (v != expected) @@ -1745,20 +1745,20 @@ namespace { return v; } - void param_bits(const RTLIL::IdString& name, int width) + void param_bits(RTLIL::IdString name, int width) { param(name); if (GetSize(cell->parameters.at(name)) != width) error(__LINE__); } - std::string param_string(const RTLIL::IdString &name) + std::string param_string(RTLIL::IdString name) { param(name); return cell->parameters.at(name).decode_string(); } - void port(const RTLIL::IdString& name, int width) + void port(RTLIL::IdString name, int width) { auto it = cell->connections_.find(name); if (it == cell->connections_.end()) @@ -4366,14 +4366,14 @@ std::map *RTLIL::Cell::get_all_cells(void) } #endif -bool RTLIL::Cell::hasPort(const RTLIL::IdString& portname) const +bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const { return connections_.count(portname) != 0; } // bufnorm -const RTLIL::SigSpec &RTLIL::Cell::getPort(const RTLIL::IdString& portname) const +const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const { return connections_.at(portname); } @@ -4392,7 +4392,7 @@ bool RTLIL::Cell::known() const return false; } -bool RTLIL::Cell::input(const RTLIL::IdString& portname) const +bool RTLIL::Cell::input(RTLIL::IdString portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_input(type, portname); @@ -4404,7 +4404,7 @@ bool RTLIL::Cell::input(const RTLIL::IdString& portname) const return false; } -bool RTLIL::Cell::output(const RTLIL::IdString& portname) const +bool RTLIL::Cell::output(RTLIL::IdString portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_output(type, portname); @@ -4416,7 +4416,7 @@ bool RTLIL::Cell::output(const RTLIL::IdString& portname) const return false; } -RTLIL::PortDir RTLIL::Cell::port_dir(const RTLIL::IdString& portname) const +RTLIL::PortDir RTLIL::Cell::port_dir(RTLIL::IdString portname) const { if (yosys_celltypes.cell_known(type)) return yosys_celltypes.cell_port_dir(type, portname); @@ -4432,22 +4432,22 @@ RTLIL::PortDir RTLIL::Cell::port_dir(const RTLIL::IdString& portname) const return PortDir::PD_UNKNOWN; } -bool RTLIL::Cell::hasParam(const RTLIL::IdString& paramname) const +bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const { return parameters.count(paramname) != 0; } -void RTLIL::Cell::unsetParam(const RTLIL::IdString& paramname) +void RTLIL::Cell::unsetParam(RTLIL::IdString paramname) { parameters.erase(paramname); } -void RTLIL::Cell::setParam(const RTLIL::IdString& paramname, RTLIL::Const value) +void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value) { parameters[paramname] = std::move(value); } -const RTLIL::Const &RTLIL::Cell::getParam(const RTLIL::IdString& paramname) const +const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const { const auto &it = parameters.find(paramname); if (it != parameters.end()) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f841df1ed..3edf6b053 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -241,7 +241,7 @@ struct RTLIL::IdString *this = id; } - constexpr inline const IdString &id_string() const { return *this; } + constexpr inline IdString id_string() const { return *this; } inline const char *c_str() const { if (index_ >= 0) @@ -372,7 +372,7 @@ struct RTLIL::IdString return Substrings(global_autoidx_id_storage_.at(index_).prefix, -index_); } - inline bool lt_by_name(const IdString &rhs) const { + inline bool lt_by_name(IdString rhs) const { Substrings lhs_it = substrings(); Substrings rhs_it = rhs.substrings(); std::string_view lhs_substr = lhs_it.first(); @@ -399,12 +399,12 @@ struct RTLIL::IdString } } - inline bool operator<(const IdString &rhs) const { + inline bool operator<(IdString rhs) const { return index_ < rhs.index_; } - inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } - inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } + inline bool operator==(IdString rhs) const { return index_ == rhs.index_; } + inline bool operator!=(IdString rhs) const { return index_ != rhs.index_; } // The methods below are just convenience functions for better compatibility with std::string. @@ -528,7 +528,7 @@ struct RTLIL::IdString return (... || in(args)); } - bool in(const IdString &rhs) const { return *this == rhs; } + bool in(IdString rhs) const { return *this == rhs; } bool in(const char *rhs) const { return *this == rhs; } bool in(const std::string &rhs) const { return *this == rhs; } inline bool in(const pool &rhs) const; @@ -646,13 +646,13 @@ private: namespace hashlib { template <> struct hash_ops { - static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) { + static inline bool cmp(RTLIL::IdString a, RTLIL::IdString b) { return a == b; } - [[nodiscard]] static inline Hasher hash(const RTLIL::IdString &id) { + [[nodiscard]] static inline Hasher hash(RTLIL::IdString id) { return id.hash_top(); } - [[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString &id, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(RTLIL::IdString id, Hasher h) { return id.hash_into(h); } }; @@ -759,11 +759,11 @@ namespace RTLIL { return str.substr(1); } - static inline std::string unescape_id(const RTLIL::IdString &str) { + static inline std::string unescape_id(RTLIL::IdString str) { return unescape_id(str.str()); } - static inline const char *id2cstr(const RTLIL::IdString &str) { + static inline const char *id2cstr(RTLIL::IdString str) { return log_id(str); } @@ -780,7 +780,7 @@ namespace RTLIL { }; struct sort_by_id_str { - bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const { + bool operator()(RTLIL::IdString a, RTLIL::IdString b) const { return a.lt_by_name(b); } }; @@ -1246,22 +1246,22 @@ struct RTLIL::AttrObject { dict attributes; - bool has_attribute(const RTLIL::IdString &id) const; + bool has_attribute(RTLIL::IdString id) const; - void set_bool_attribute(const RTLIL::IdString &id, bool value=true); - bool get_bool_attribute(const RTLIL::IdString &id) const; + void set_bool_attribute(RTLIL::IdString id, bool value=true); + bool get_bool_attribute(RTLIL::IdString id) const; [[deprecated("Use Module::get_blackbox_attribute() instead.")]] bool get_blackbox_attribute(bool ignore_wb=false) const { return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox)); } - void set_string_attribute(const RTLIL::IdString& id, string value); - string get_string_attribute(const RTLIL::IdString &id) const; + void set_string_attribute(RTLIL::IdString id, string value); + string get_string_attribute(RTLIL::IdString id) const; - void set_strpool_attribute(const RTLIL::IdString& id, const pool &data); - void add_strpool_attribute(const RTLIL::IdString& id, const pool &data); - pool get_strpool_attribute(const RTLIL::IdString &id) const; + void set_strpool_attribute(RTLIL::IdString id, const pool &data); + void add_strpool_attribute(RTLIL::IdString id, const pool &data); + pool get_strpool_attribute(RTLIL::IdString id) const; void set_src_attribute(const std::string &src) { set_string_attribute(ID::src, src); @@ -1273,8 +1273,8 @@ struct RTLIL::AttrObject void set_hdlname_attribute(const vector &hierarchy); vector get_hdlname_attribute() const; - void set_intvec_attribute(const RTLIL::IdString& id, const vector &data); - vector get_intvec_attribute(const RTLIL::IdString &id) const; + void set_intvec_attribute(RTLIL::IdString id, const vector &data); + vector get_intvec_attribute(RTLIL::IdString id) const; }; struct RTLIL::NamedObject : public RTLIL::AttrObject @@ -1781,18 +1781,18 @@ struct RTLIL::Selection // checks if the given module exists in the current design and is a // boxed module, warning the user if the current design is not set - bool boxed_module(const RTLIL::IdString &mod_name) const; + bool boxed_module(RTLIL::IdString mod_name) const; // checks if the given module is included in this selection - bool selected_module(const RTLIL::IdString &mod_name) const; + bool selected_module(RTLIL::IdString mod_name) const; // checks if the given module is wholly included in this selection, // i.e. not partially selected - bool selected_whole_module(const RTLIL::IdString &mod_name) const; + bool selected_whole_module(RTLIL::IdString mod_name) const; // checks if the given member from the given module is included in this // selection - bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const; + bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; // optimizes this selection for the given design by: // - removing non-existent modules and members, any boxed modules and @@ -1862,7 +1862,7 @@ struct RTLIL::Monitor virtual ~Monitor() { } virtual void notify_module_add(RTLIL::Module*) { } virtual void notify_module_del(RTLIL::Module*) { } - virtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { } + virtual void notify_connect(RTLIL::Cell*, RTLIL::IdString, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { } virtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { } virtual void notify_connect(RTLIL::Module*, const std::vector&) { } virtual void notify_blackout(RTLIL::Module*) { } @@ -1897,11 +1897,11 @@ struct RTLIL::Design ~Design(); RTLIL::ObjRange modules(); - RTLIL::Module *module(const RTLIL::IdString &name); - const RTLIL::Module *module(const RTLIL::IdString &name) const; + RTLIL::Module *module(RTLIL::IdString name); + const RTLIL::Module *module(RTLIL::IdString name) const; RTLIL::Module *top_module() const; - bool has(const RTLIL::IdString &id) const { + bool has(RTLIL::IdString id) const { return modules_.count(id) != 0; } @@ -1928,15 +1928,15 @@ struct RTLIL::Design void optimize(); // checks if the given module is included in the current selection - bool selected_module(const RTLIL::IdString &mod_name) const; + bool selected_module(RTLIL::IdString mod_name) const; // checks if the given module is wholly included in the current // selection, i.e. not partially selected - bool selected_whole_module(const RTLIL::IdString &mod_name) const; + bool selected_whole_module(RTLIL::IdString mod_name) const; // checks if the given member from the given module is included in the // current selection - bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const; + bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; // checks if the given module is included in the current selection bool selected_module(RTLIL::Module *mod) const; @@ -2068,7 +2068,7 @@ public: virtual ~Module(); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail = false); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail = false); - virtual size_t count_id(const RTLIL::IdString& id); + virtual size_t count_id(RTLIL::IdString id); virtual void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces); virtual bool reprocess_if_necessary(RTLIL::Design *design); @@ -2120,20 +2120,20 @@ public: return design->selected_member(name, member->name); } - RTLIL::Wire* wire(const RTLIL::IdString &id) { + RTLIL::Wire* wire(RTLIL::IdString id) { auto it = wires_.find(id); return it == wires_.end() ? nullptr : it->second; } - RTLIL::Cell* cell(const RTLIL::IdString &id) { + RTLIL::Cell* cell(RTLIL::IdString id) { auto it = cells_.find(id); return it == cells_.end() ? nullptr : it->second; } - const RTLIL::Wire* wire(const RTLIL::IdString &id) const{ + const RTLIL::Wire* wire(RTLIL::IdString id) const{ auto it = wires_.find(id); return it == wires_.end() ? nullptr : it->second; } - const RTLIL::Cell* cell(const RTLIL::IdString &id) const { + const RTLIL::Cell* cell(RTLIL::IdString id) const { auto it = cells_.find(id); return it == cells_.end() ? nullptr : it->second; } @@ -2490,23 +2490,23 @@ public: dict parameters; // access cell ports - bool hasPort(const RTLIL::IdString &portname) const; - void unsetPort(const RTLIL::IdString &portname); - void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal); - const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const; + bool hasPort(RTLIL::IdString portname) const; + void unsetPort(RTLIL::IdString portname); + void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal); + const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const; const dict &connections() const; // information about cell ports bool known() const; - bool input(const RTLIL::IdString &portname) const; - bool output(const RTLIL::IdString &portname) const; - PortDir port_dir(const RTLIL::IdString &portname) const; + bool input(RTLIL::IdString portname) const; + bool output(RTLIL::IdString portname) const; + PortDir port_dir(RTLIL::IdString portname) const; // access cell parameters - bool hasParam(const RTLIL::IdString ¶mname) const; - void unsetParam(const RTLIL::IdString ¶mname); - void setParam(const RTLIL::IdString ¶mname, RTLIL::Const value); - const RTLIL::Const &getParam(const RTLIL::IdString ¶mname) const; + bool hasParam(RTLIL::IdString paramname) const; + void unsetParam(RTLIL::IdString paramname); + void setParam(RTLIL::IdString paramname, RTLIL::Const value); + const RTLIL::Const &getParam(RTLIL::IdString paramname) const; void sort(); void check(); diff --git a/kernel/rtlil_bufnorm.cc b/kernel/rtlil_bufnorm.cc index d0561f880..5f74b3380 100644 --- a/kernel/rtlil_bufnorm.cc +++ b/kernel/rtlil_bufnorm.cc @@ -526,7 +526,7 @@ void RTLIL::Module::bufNormalize() pending_deleted_cells.clear(); } -void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname) +void RTLIL::Cell::unsetPort(RTLIL::IdString portname) { RTLIL::SigSpec signal; auto conn_it = connections_.find(portname); @@ -586,7 +586,7 @@ void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname) } } -void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal) +void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) { auto r = connections_.insert(portname); auto conn_it = r.first; diff --git a/kernel/scopeinfo.cc b/kernel/scopeinfo.cc index 7ed9ebf33..59dd746b5 100644 --- a/kernel/scopeinfo.cc +++ b/kernel/scopeinfo.cc @@ -97,13 +97,13 @@ static const char *attr_prefix(ScopeinfoAttrs attrs) } } -bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id) +bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id) { log_assert(scopeinfo->type == ID($scopeinfo)); return scopeinfo->has_attribute(attr_prefix(attrs) + RTLIL::unescape_id(id)); } -RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id) +RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id) { log_assert(scopeinfo->type == ID($scopeinfo)); auto found = scopeinfo->attributes.find(attr_prefix(attrs) + RTLIL::unescape_id(id)); diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 3bc1a8162..a3939b903 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -433,10 +433,10 @@ enum class ScopeinfoAttrs { }; // Check whether the flattened module or flattened cell corresponding to a $scopeinfo cell had a specific attribute. -bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id); +bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id); // Get a specific attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell. -RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id); +RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id); // Get all attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell. dict scopeinfo_attributes(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs); diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc index e4e78b0ea..6a1fab072 100644 --- a/passes/cmds/printattrs.cc +++ b/passes/cmds/printattrs.cc @@ -45,7 +45,7 @@ struct PrintAttrsPass : public Pass { return stringf("%*s", indent, ""); } - static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) { + static void log_const(RTLIL::IdString s, const RTLIL::Const &x, const unsigned int indent) { if (x.flags & RTLIL::CONST_FLAG_STRING) log("%s(* %s=\"%s\" *)\n", get_indent_str(indent), log_id(s), x.decode_string()); else if (x.flags == RTLIL::CONST_FLAG_NONE || x.flags == RTLIL::CONST_FLAG_SIGNED) diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc index 39ed8e60e..df7b665d5 100644 --- a/passes/cmds/trace.cc +++ b/passes/cmds/trace.cc @@ -36,7 +36,7 @@ struct TraceMonitor : public RTLIL::Monitor log("#TRACE# Module delete: %s\n", log_id(module)); } - void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override + void notify_connect(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override { log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig)); } diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index a4552c71b..123687255 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -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(type, dst)); diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 938ed5355..0c7d1930e 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -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); } diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc index aa257e1b6..2e358029a 100644 --- a/pyosys/wrappers_tpl.cc +++ b/pyosys/wrappers_tpl.cc @@ -112,7 +112,7 @@ namespace pyosys { void notify_connect( RTLIL::Cell *cell, - const RTLIL::IdString &port, + RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig ) override { @@ -228,7 +228,7 @@ namespace pyosys { "notify_connect", py::overload_cast< RTLIL::Cell *, - const RTLIL::IdString &, + RTLIL::IdString, const RTLIL::SigSpec &, const RTLIL::SigSpec & >(&RTLIL::Monitor::notify_connect) From 48cdb499f2b6e097cdff6e2bad9492cfc3b022c1 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 22 Dec 2025 01:57:30 +0000 Subject: [PATCH 48/83] Remove `IdString::id_string()`. This was needed for the short time when `ID()` could return a value of `StaticIdString`. That is no longer a problem. --- kernel/rtlil.h | 2 -- passes/cmds/example_dt.cc | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 3edf6b053..ec47adb0e 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -241,8 +241,6 @@ struct RTLIL::IdString *this = id; } - constexpr inline IdString id_string() const { return *this; } - inline const char *c_str() const { if (index_ >= 0) return global_id_storage_.at(index_).buf; diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 7d1c42a79..b10f50502 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -77,7 +77,7 @@ struct ExampleDtPass : public Pass auto enqueue = [&](DriveSpec const &spec) { int index = queue(spec); if (index == GetSize(graph_nodes)) - graph_nodes.emplace_back(compute_graph.add(ID($pending).id_string(), index).index()); + graph_nodes.emplace_back(compute_graph.add(ID($pending), index).index()); //if (index >= GetSize(graph_nodes)) return compute_graph[graph_nodes[index]]; }; From 13030e43d469eda5755a9676749cdf40c65fc30b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 22 Dec 2025 12:31:58 +0100 Subject: [PATCH 49/83] Update ABC as per 2025-12-22 --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index bd05a6454..9182a8048 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit bd05a6454e8c157caaa58ceda676ae0249d8e27c +Subproject commit 9182a8048d0bc86b39a6cb6b0488a7e1d10b2607 From 9ee51c8f27164e85c15ccbfc18910169f6d647b8 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sun, 21 Dec 2025 22:45:06 +0000 Subject: [PATCH 50/83] Add AFL++ Grammar-Generator grammar for RTLIL fuzzing, and instructions for how to use it. --- tests/pass-fuzzing.md | 106 ++++++++++++++++++++++++++++ tests/tools/rtlil-fuzz-grammar.json | 104 +++++++++++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 tests/pass-fuzzing.md create mode 100644 tests/tools/rtlil-fuzz-grammar.json diff --git a/tests/pass-fuzzing.md b/tests/pass-fuzzing.md new file mode 100644 index 000000000..993f36078 --- /dev/null +++ b/tests/pass-fuzzing.md @@ -0,0 +1,106 @@ +Suppose you're making significant changes to a pass that should not change +the pass's output in any way. It might be useful to run a large number of +automatically generated tests to try to find bugs where the output has +changed. This document describes how to do that. + +Basically we're going to use [AFL++](https://github.com/AFLplusplus/AFLplusplus) with the +[Grammar-Mutator](https://github.com/AFLplusplus/Grammar-Mutator) plugin to generate +RTLIL testcases. For each testcase, we run a Yosys script that applies both the old and new +implementation of the pass to the same design and compares the results. Testcase +generation is coverage-guided, i.e. the fuzzer will try to find testcases that exercise all +code in the old and new implementation of the pass (and in the RTLIL parser). + +## Setup + +These instructions clone tools into subdirectories of your home directory. They assume +you have a Yosys checkout under `$HOME/yosys`, and that you're testing the `opt_merge` pass. +They have been tested with AFL++ revision 68b492b2c7725816068718ef9437b72b40e67519 and Grammar-Mutator revision 05d8f537f8d656f0754e7ad5dcc653c42cb4f8ff. + +Clone and build AFL++ and Grammar-Mutator: +``` +cd $HOME +git clone https://github.com/AFLplusplus/AFLplusplus.git +git -C AFLplusplus checkout stable +git clone https://github.com/AFLplusplus/Grammar-Mutator.git +git -C Grammar-Mutator checkout stable +``` + +Check that `rtlil-fuzz-grammar.json` generates RTLIL constructs relevant to your pass. +Currently it's quite simple and generates a limited set of cells and wires; you may need to +extend it to generate different kinds of cells and other RTLIL constructs (e.g. `proc`). + +Build AFL++ and Grammar-Mutator: +``` +make -C $HOME/AFLplusplus -j all +make -C $HOME/Grammar-Mutator -j GRAMMAR_FILE=$HOME/yosys/tests/tools/rtlil-fuzz-grammar.json +``` + +Create a Yosys commit that adds the old version of your pass as a new command, e.g. copy +`opt_merge.cc` into `old_opt_merge.cc` and change the name of the command to `old_opt_merge`. +[Here's](https://github.com/YosysHQ/yosys/commit/827cd8c998f3e455b14ac990a3159030ddc19b21) an example. + +You may also need to patch in [this commit](https://github.com/YosysHQ/yosys/commit/121c52f514c4ca282b4e6b3b14f71184f3849ddf) to work around a bug involving `std::reverse` on +empty vectors in the RTLIL parser when building with fuzzing instrumentation. +I think this is a clang++ bug so hopefully it will get fixed eventually and that patch will not be +necessary. + +Rebuild Yosys with the AFL++ compiler wrapper. This assumes your config builds Yosys with clang++. +``` +(cd $HOME/yosys; patch -lp1 << EOF) +diff --git a/Makefile b/Makefile +index 9c361294d..c9a98f74c 100644 +--- a/Makefile ++++ b/Makefile +@@ -238,7 +238,7 @@ + LTOFLAGS := $(GCC_LTO) + + ifeq ($(CONFIG),clang) +-CXX = clang++ ++CXX = $(HOME)/AFLplusplus/afl-c++ + CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) + ifeq ($(ENABLE_LTO),1) + LINKFLAGS += -fuse-ld=lld +EOF +make -C yosys clean && make -C yosys -j +``` + +You probably need to configure coredumps to work normally instead of going through some OS service: +``` +echo core | sudo tee /proc/sys/kernel/core_pattern +``` + +## Running the fuzzer + +Generate some initial testcases using Grammar-Mutator: +``` +(cd $HOME/Grammar-Mutator; rm -rf seeds trees; ./grammar_generator-rtlil 100 1000 ./seeds ./trees) +``` + +Now run AFL++. +``` +(cd $HOME/Grammar-Mutator; \ + AFL_CUSTOM_MUTATOR_LIBRARY=./libgrammarmutator-rtlil.so \ + AFL_CUSTOM_MUTATOR_ONLY=1 \ + AFL_BENCH_UNTIL_CRASH=1 \ + YOSYS_WORK_UNITS_PER_THREAD=1 \ + YOSYS_ABORT_ON_LOG_ERROR=1 \ + $HOME/AFLplusplus/afl-fuzz -t 5000 -m none -i seeds -o out -- \ + $HOME/yosys/yosys -p 'read_rtlil -legalize @@; design -save init; old_opt_merge; design -save old; design -load init; opt_merge; design_equal old' \ +) +``` +This will run the fuzzer until the first crash (including any pass output mismatches) and then stop. +Or if you're lucky, the fuzzer will run indefinitely. This uses very little parallelism; if it doesn't find any errors right away, you can increase the test throughput by running AFL++ in parallel using the instructions [here](https://aflplus.plus/docs/parallel_fuzzing). + +## Working with fuzz test failures + +Any failing testcases will be dropped in `$HOME/Grammar-Mutator/out/default/crashes`. +Run `yosys -p 'read_rtlil -legalize ... ; dump'` to get the testcase as legalized RTLIL. + +## Notes on generating semantically valid RTLIL + +`Grammar-Mutator` generates RTLIL files according to the context-free grammar in `rtlil-fuzz-grammar.json`. +However, the testcases must also be semantically valid, e.g. references to wires should only refer to +wires that actually exist. These constraints cannot reasonably be expresed in a CFG. Therefore we +have added a `-legalize` option to the `read_rtlil` command. When `-legalize` is set, when `read_rtlil` +detects a failed semantic check, instead of erroring out it emits a warning and patches the incoming RTLIL +to make it valid. diff --git a/tests/tools/rtlil-fuzz-grammar.json b/tests/tools/rtlil-fuzz-grammar.json new file mode 100644 index 000000000..c27b160f4 --- /dev/null +++ b/tests/tools/rtlil-fuzz-grammar.json @@ -0,0 +1,104 @@ +{ + "": [ + [ + "module \\test\n", + "", "", + "", + "", + "end\n" + ] + ], + "": [ [ " wire width ", "", " ", "", " ", "", "\n" ] ], + "": [ [ "1" ], [ "2" ], [ "3" ], [ "4" ], [ "32" ], [ "128" ] ], + "": [ [ "input ", "" ], [ "output ", "" ], [ "inout ", "" ], [] ], + "": [ + [ + " cell $not ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell $and ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\B_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\B_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell $or ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\B_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\B_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell $xor ", "", "\n", + " parameter \\A_SIGNED 0\n", + " parameter \\B_SIGNED 0\n", + " parameter \\A_WIDTH 0\n", + " parameter \\B_WIDTH 0\n", + " parameter \\Y_WIDTH 0\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell ", "", " ", "", "\n", + " connect \\A ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ], + [ + " cell ", "", " ", "", "\n", + " connect \\A ", "", "\n", + " connect \\B ", "", "\n", + " connect \\Y ", "", "\n", + " end\n" + ] + ], + "": [ [ "\\wire_a" ], [ "\\wire_b" ], [ "\\wire_c" ], [ "\\wire_d" ], [ "\\wire_e" ], [ "\\wire_f" ], [ "\\wire_g" ], [ "\\wire_h" ], [ "\\wire_i" ], [ "\\wire_j" ] ], + "": [ [ "\\cell_a" ], [ "\\cell_b" ], [ "\\cell_c" ], [ "\\cell_d" ], [ "\\cell_e" ], [ "\\cell_f" ], [ "\\cell_g" ], [ "\\cell_h" ], [ "\\cell_i" ], [ "\\cell_j" ] ], + "": [ [ "\\bb1" ], [ "\\bb2" ] ], + "": [ + [ "", " " ], + [ "{", "", " ", "", "}" ], + [ "" ], + [ "", "[", "", "]" ], + [ "", "[", "", ":", "", "]" ] + ], + "": [ + [ "0'", "" ], + [ "1'", "" ], + [ "2'", "" ], + [ "3'", "" ], + [ "4'", "" ], + [ "31'", "" ], + [ "32'", "" ], + [ "128'", "" ] + ], + "": [ [ "0" ], [ "1" ], [ "x" ], [ "z" ], [ "-" ], [ "m" ] ], + "": [ "0", "1", "2", "3", "31", "32" ], + "": [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ], + "": [ [ " connect ", "", " ", "", "\n" ] ], + + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", "" ] ], + "": [ [ ], [ "", " ", "" ] ] +} From 0e61f57458a1190bd9e0655ed965df8102daa963 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 22 Dec 2025 21:58:15 +0000 Subject: [PATCH 51/83] Print errno to help diagnose failure to spawn ABC --- passes/techmap/abc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index a25a79ae8..e25a6facd 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -253,7 +253,7 @@ std::optional spawn_abc(const char* abc_exe, DeferredLogs &logs) { char arg1[] = "-s"; char* argv[] = { strdup(abc_exe), arg1, nullptr }; if (0 != posix_spawnp(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) { - logs.log_error("posix_spawnp %s failed", abc_exe); + logs.log_error("posix_spawnp %s failed (errno=%s)", abc_exe, strerrorname_np(errno)); return std::nullopt; } free(argv[0]); From 31f355c5997e5d486d6f843f8771e900162c77d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Dec 2025 00:26:12 +0000 Subject: [PATCH 52/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9c361294d..41cacf4f6 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+51 +YOSYS_VER := 0.60+59 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 4bc4e4eb41ee8de4ea4b8cb2f12bcdd0c8093504 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 23 Dec 2025 15:47:35 +0100 Subject: [PATCH 53/83] remove unused variable --- passes/cmds/icell_liberty.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/passes/cmds/icell_liberty.cc b/passes/cmds/icell_liberty.cc index d49cd360a..a928e5d58 100644 --- a/passes/cmds/icell_liberty.cc +++ b/passes/cmds/icell_liberty.cc @@ -163,7 +163,6 @@ struct IcellLiberty : Pass { log_header(d, "Executing ICELL_LIBERTY pass.\n"); size_t argidx; - IdString naming_attr; std::string liberty_filename; auto liberty_file = std::make_unique(); From 17ca71e1ab493af12e438edfc40ed2239b06e785 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 24 Dec 2025 00:26:02 +0000 Subject: [PATCH 54/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 41cacf4f6..6bea3c7b2 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+59 +YOSYS_VER := 0.60+64 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 99d7ab9c429d88f8965ba5bf6c2601ae34cee569 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 29 Dec 2025 04:06:52 +0000 Subject: [PATCH 55/83] Increase test timeout to 10 seconds On my machine, this test regularly times out when doing "make -j" (which defaults to 128). The high degree of parallelism seems to slow down the spwaning of ABC processes. --- tests/techmap/bug5495.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/techmap/bug5495.sh b/tests/techmap/bug5495.sh index 64bf2ca99..476727755 100755 --- a/tests/techmap/bug5495.sh +++ b/tests/techmap/bug5495.sh @@ -5,7 +5,7 @@ if ! which timeout ; then exit 0 fi -if ! timeout 5 ../../yosys bug5495.v -p 'hierarchy; techmap; abc -script bug5495.abc' ; then +if ! timeout 10 ../../yosys bug5495.v -p 'hierarchy; techmap; abc -script bug5495.abc' ; then echo "Yosys failed to complete" exit 1 fi From 96549e551487fdad183e0581600155a96d0f4288 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:26:17 +0000 Subject: [PATCH 56/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6bea3c7b2..ecf6d7d2b 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+64 +YOSYS_VER := 0.60+67 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 55af32024de6e992bb97741b4a9f4beb1cd9409b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 30 Dec 2025 09:23:45 +0100 Subject: [PATCH 57/83] Update ABC as per 2025-12-29 --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index 9182a8048..ef74590eb 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 9182a8048d0bc86b39a6cb6b0488a7e1d10b2607 +Subproject commit ef74590ebd78b3b707eeba56d8284faf018affa6 From a6d696ba2b4abaf2e3941d884f7db989d6b09e8b Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 30 Dec 2025 03:53:02 +0000 Subject: [PATCH 58/83] Give `IdString` a default move constructor and make it a POD type. Now that we're not refcounting `IdString`, it can use the default move constructor. This lets us make `IdString` a POD type so it can be passed in registers in the standard C++ ABI. --- kernel/rtlil.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index ec47adb0e..6549c1760 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -223,8 +223,8 @@ struct RTLIL::IdString constexpr inline IdString() : index_(0) { } inline IdString(const char *str) : index_(insert(std::string_view(str))) { } - constexpr inline IdString(const IdString &str) : index_(str.index_) { } - inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } + constexpr IdString(const IdString &str) = default; + IdString(IdString &&str) = default; inline IdString(const std::string &str) : index_(insert(std::string_view(str))) { } inline IdString(std::string_view str) : index_(insert(str)) { } constexpr inline IdString(StaticId id) : index_(static_cast(id)) {} From 8101c87fab54a060852f672e3027f1ed937bcfad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 31 Dec 2025 00:27:01 +0000 Subject: [PATCH 59/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ecf6d7d2b..0008025ee 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+67 +YOSYS_VER := 0.60+70 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From ea90f54783ce8170b8485b9bf012c8de519635dd Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 3 Jan 2026 17:42:49 +1000 Subject: [PATCH 60/83] Gowin. Implement byte enable. Enable write port with byte enables for BSRAM primitives. Signed-off-by: YRabbit --- techlibs/gowin/brams.txt | 6 ++++++ techlibs/gowin/brams_map.v | 18 +++++++++++++----- techlibs/gowin/brams_map_gw5a.v | 18 +++++++++++++----- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/techlibs/gowin/brams.txt b/techlibs/gowin/brams.txt index ee76dd73a..6898c9bd9 100644 --- a/techlibs/gowin/brams.txt +++ b/techlibs/gowin/brams.txt @@ -2,6 +2,7 @@ ram block $__GOWIN_SP_ { abits 14; widths 1 2 4 9 18 36 per_port; cost 128; + byte 9; init no_undef; port srsw "A" { clock posedge; @@ -24,6 +25,7 @@ ram block $__GOWIN_SP_ { rdwr old; } } + wrbe_separate; } } @@ -31,6 +33,7 @@ ram block $__GOWIN_DP_ { abits 14; widths 1 2 4 9 18 per_port; cost 128; + byte 9; init no_undef; port srsw "A" "B" { clock posedge; @@ -53,6 +56,7 @@ ram block $__GOWIN_DP_ { rdwr old; } } + wrbe_separate; } } @@ -60,6 +64,7 @@ ram block $__GOWIN_SDP_ { abits 14; widths 1 2 4 9 18 36 per_port; cost 128; + byte 9; init no_undef; port sr "R" { clock posedge; @@ -75,5 +80,6 @@ ram block $__GOWIN_SDP_ { port sw "W" { clock posedge; clken; + wrbe_separate; } } diff --git a/techlibs/gowin/brams_map.v b/techlibs/gowin/brams_map.v index 8e6cc6140..5ffe13e11 100644 --- a/techlibs/gowin/brams_map.v +++ b/techlibs/gowin/brams_map.v @@ -14,7 +14,7 @@ `define x8_width(width) (width / 9 * 8 + width % 9) `define x8_rd_data(data) {1'bx, data[31:24], 1'bx, data[23:16], 1'bx, data[15:8], 1'bx, data[7:0]} `define x8_wr_data(data) {data[34:27], data[25:18], data[16:9], data[7:0]} -`define addrbe_always(width, addr) (width < 18 ? addr : width == 18 ? {addr[13:4], 4'b0011} : {addr[13:5], 5'b01111}) +`define addrbe(width, addr, w_be) (width < 18 ? addr : width == 18 ? {addr[13:4], 2'b00, w_be[1:0]} : {addr[13:5], 1'b0, w_be[3:0]}) `define INIT(func) \ @@ -90,6 +90,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 36; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -97,13 +98,14 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; -wire [13:0] AD = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); +wire [13:0] AD = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_A_WR_BE); generate @@ -173,9 +175,11 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 18; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; parameter PORT_B_WIDTH = 18; parameter PORT_B_OPTION_WRITE_MODE = 0; +parameter PORT_B_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -183,6 +187,7 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; @@ -192,6 +197,7 @@ input PORT_B_WR_EN; input PORT_B_RD_SRST; input PORT_B_RD_ARST; input [13:0] PORT_B_ADDR; +input [PORT_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE; input [PORT_A_WIDTH-1:0] PORT_B_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; @@ -199,8 +205,8 @@ output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; wire RSTA = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; wire RSTB = OPTION_RESET_MODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST; -wire [13:0] ADA = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); -wire [13:0] ADB = `addrbe_always(PORT_B_WIDTH, PORT_B_ADDR); +wire [13:0] ADA = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_B_WR_BE); +wire [13:0] ADB = `addrbe(PORT_B_WIDTH, PORT_B_ADDR, PORT_B_WR_BE); generate @@ -306,6 +312,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_R_WIDTH = 18; parameter PORT_W_WIDTH = 18; +parameter PORT_W_WR_BE_WIDTH=4; input PORT_R_CLK; input PORT_R_CLK_EN; @@ -318,12 +325,13 @@ input PORT_W_CLK; input PORT_W_CLK_EN; input PORT_W_WR_EN; input [13:0] PORT_W_ADDR; +input [PORT_W_WR_BE_WIDTH-1:0] PORT_W_WR_BE; input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST; -wire [13:0] ADW = `addrbe_always(PORT_W_WIDTH, PORT_W_ADDR); +wire [13:0] ADW = `addrbe(PORT_W_WIDTH, PORT_W_ADDR, PORT_W_WR_BE); wire WRE = PORT_W_CLK_EN & PORT_W_WR_EN; generate diff --git a/techlibs/gowin/brams_map_gw5a.v b/techlibs/gowin/brams_map_gw5a.v index 246146ee5..812f04edf 100644 --- a/techlibs/gowin/brams_map_gw5a.v +++ b/techlibs/gowin/brams_map_gw5a.v @@ -14,7 +14,7 @@ `define x8_width(width) (width / 9 * 8 + width % 9) `define x8_rd_data(data) {1'bx, data[31:24], 1'bx, data[23:16], 1'bx, data[15:8], 1'bx, data[7:0]} `define x8_wr_data(data) {data[34:27], data[25:18], data[16:9], data[7:0]} -`define addrbe_always(width, addr) (width < 18 ? addr : width == 18 ? {addr[13:4], 4'b0011} : {addr[13:5], 5'b01111}) +`define addrbe(width, addr, w_be) (width < 18 ? addr : width == 18 ? {addr[13:4], 2'b00, w_be[1:0]} : {addr[13:5], 1'b0, w_be[3:0]}) `define INIT(func) \ @@ -90,6 +90,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 36; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -97,13 +98,14 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; -wire [13:0] AD = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); +wire [13:0] AD = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_A_WR_BE); generate @@ -173,9 +175,11 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_A_WIDTH = 18; parameter PORT_A_OPTION_WRITE_MODE = 0; +parameter PORT_A_WR_BE_WIDTH = 4; parameter PORT_B_WIDTH = 18; parameter PORT_B_OPTION_WRITE_MODE = 0; +parameter PORT_B_WR_BE_WIDTH = 4; input PORT_A_CLK; input PORT_A_CLK_EN; @@ -183,6 +187,7 @@ input PORT_A_WR_EN; input PORT_A_RD_SRST; input PORT_A_RD_ARST; input [13:0] PORT_A_ADDR; +input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; @@ -192,6 +197,7 @@ input PORT_B_WR_EN; input PORT_B_RD_SRST; input PORT_B_RD_ARST; input [13:0] PORT_B_ADDR; +input [PORT_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE; input [PORT_A_WIDTH-1:0] PORT_B_WR_DATA; output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; @@ -199,8 +205,8 @@ output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; wire RSTA = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; wire RSTB = OPTION_RESET_MODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST; -wire [13:0] ADA = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); -wire [13:0] ADB = `addrbe_always(PORT_B_WIDTH, PORT_B_ADDR); +wire [13:0] ADA = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_B_WR_BE); +wire [13:0] ADB = `addrbe(PORT_B_WIDTH, PORT_B_ADDR, PORT_B_WR_BE); generate @@ -306,6 +312,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_R_WIDTH = 18; parameter PORT_W_WIDTH = 18; +parameter PORT_W_WR_BE_WIDTH=4; input PORT_R_CLK; input PORT_R_CLK_EN; @@ -318,12 +325,13 @@ input PORT_W_CLK; input PORT_W_CLK_EN; input PORT_W_WR_EN; input [13:0] PORT_W_ADDR; +input [PORT_W_WR_BE_WIDTH-1:0] PORT_W_WR_BE; input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; `DEF_FUNCS wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST; -wire [13:0] ADW = `addrbe_always(PORT_W_WIDTH, PORT_W_ADDR); +wire [13:0] ADW = `addrbe(PORT_W_WIDTH, PORT_W_ADDR, PORT_W_WR_BE); wire WRE = PORT_W_CLK_EN & PORT_W_WR_EN; generate From 8a78f2f7c594932769c6881f6460df5abed8d29f Mon Sep 17 00:00:00 2001 From: YRabbit Date: Mon, 5 Jan 2026 20:07:31 +1000 Subject: [PATCH 61/83] Gowin. Fix style. Signed-off-by: YRabbit --- techlibs/gowin/brams_map.v | 2 +- techlibs/gowin/brams_map_gw5a.v | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/gowin/brams_map.v b/techlibs/gowin/brams_map.v index 5ffe13e11..774896e79 100644 --- a/techlibs/gowin/brams_map.v +++ b/techlibs/gowin/brams_map.v @@ -312,7 +312,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_R_WIDTH = 18; parameter PORT_W_WIDTH = 18; -parameter PORT_W_WR_BE_WIDTH=4; +parameter PORT_W_WR_BE_WIDTH = 4; input PORT_R_CLK; input PORT_R_CLK_EN; diff --git a/techlibs/gowin/brams_map_gw5a.v b/techlibs/gowin/brams_map_gw5a.v index 812f04edf..547b0d1d1 100644 --- a/techlibs/gowin/brams_map_gw5a.v +++ b/techlibs/gowin/brams_map_gw5a.v @@ -312,7 +312,7 @@ parameter OPTION_RESET_MODE = "SYNC"; parameter PORT_R_WIDTH = 18; parameter PORT_W_WIDTH = 18; -parameter PORT_W_WR_BE_WIDTH=4; +parameter PORT_W_WR_BE_WIDTH = 4; input PORT_R_CLK; input PORT_R_CLK_EN; From 6e5a5160518d422cee7cae922e930b3dc27c124c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 5 Jan 2026 16:34:45 +0100 Subject: [PATCH 62/83] Update ABC as per 2026-01-05 --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index ef74590eb..799ba6322 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit ef74590ebd78b3b707eeba56d8284faf018affa6 +Subproject commit 799ba632239b2a4db2bacda81de4e6efdc486b0c From 1567526954905120629315c807957938721871e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 00:26:49 +0000 Subject: [PATCH 63/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0008025ee..c859422cd 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+70 +YOSYS_VER := 0.60+78 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 11b0e7ad92e883af05f68fd3f4a9cdebbe14b85d Mon Sep 17 00:00:00 2001 From: Natalia Date: Fri, 19 Dec 2025 02:18:27 -0800 Subject: [PATCH 64/83] add lut2bmux --- passes/techmap/Makefile.inc | 1 + passes/techmap/lut2bmux.cc | 58 +++++++++++++++++++++++++++++++++++++ tests/techmap/lut2bmux.ys | 24 +++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 passes/techmap/lut2bmux.cc create mode 100644 tests/techmap/lut2bmux.ys diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 91b3b563a..083778d3c 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -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 diff --git a/passes/techmap/lut2bmux.cc b/passes/techmap/lut2bmux.cc new file mode 100644 index 000000000..42042c942 --- /dev/null +++ b/passes/techmap/lut2bmux.cc @@ -0,0 +1,58 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * 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 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 diff --git a/tests/techmap/lut2bmux.ys b/tests/techmap/lut2bmux.ys new file mode 100644 index 000000000..2d7387fc1 --- /dev/null +++ b/tests/techmap/lut2bmux.ys @@ -0,0 +1,24 @@ +read_rtlil << EOT +module \top + wire width 4 input 0 \A + wire output 1 \Y + + cell $lut $0 + parameter \WIDTH 4 + parameter \LUT 16'0110100110010110 + connect \A \A + connect \Y \Y + end +end +EOT + +hierarchy -auto-top + + +equiv_opt -assert lut2bmux + + +lut2bmux + +select -assert-count 0 t:$lut +select -assert-count 1 t:$bmux r:WIDTH=1 r:S_WIDTH=4 %i From 042ec1cf6076155e6a8ffa9d006fac789e12145a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 19 Dec 2025 00:38:47 +0000 Subject: [PATCH 65/83] Defer redirecting cell outputs when merging cells in `opt_merge` until after we've done a full pass over the cells. This avoids changing `assign_map` and `initvals`, which are inputs to the hash function for `known_cells`, while `known_cells` exists. Changing the hash function for a hashtable while it exists leads to confusing behavior. That also means the exact behavior of `opt_merge` cannot be reproduced by a parallel implementation. --- passes/opt/opt_merge.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 6cdcbc822..2914debbc 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -284,6 +284,7 @@ struct OptMergeWorker CellPtrHash, CellPtrEqual> known_cells (0, CellPtrHash(*this), CellPtrEqual(*this)); + std::vector redirects; for (auto cell : cells) { auto [cell_in_map, inserted] = known_cells.insert(cell); @@ -305,12 +306,7 @@ struct OptMergeWorker RTLIL::SigSpec other_sig = other_cell->getPort(it.first); log_debug(" Redirecting output %s: %s = %s\n", it.first, log_signal(it.second), log_signal(other_sig)); - Const init = initvals(other_sig); - initvals.remove_init(it.second); - initvals.remove_init(other_sig); - module->connect(RTLIL::SigSig(it.second, other_sig)); - assign_map.add(it.second, other_sig); - initvals.set_init(other_sig, init); + redirects.push_back(RTLIL::SigSig(it.second, std::move(other_sig))); } } log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type, cell->name, module->name); @@ -318,6 +314,14 @@ struct OptMergeWorker total_count++; } } + for (const RTLIL::SigSig &redirect : redirects) { + module->connect(redirect); + Const init = initvals(redirect.second); + initvals.remove_init(redirect.first); + initvals.remove_init(redirect.second); + assign_map.add(redirect.first, redirect.second); + initvals.set_init(redirect.second, init); + } } log_suppressed(); From fcb8695261bd4ecd23f6c67701a49074eb08af63 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 7 Jan 2026 13:09:49 +1300 Subject: [PATCH 66/83] write_verilog: Skip empty switches --- backends/verilog/verilog_backend.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 8d77160fd..3d451117c 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2143,6 +2143,9 @@ void dump_case_actions(std::ostream &f, std::string indent, RTLIL::CaseRule *cs) bool dump_proc_switch_ifelse(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw) { + if (sw->cases.empty()) + return true; + for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { if ((*it)->compare.size() == 0) { break; From c0e29ef57c07da504038d2e3434f2937fc70dd26 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 7 Jan 2026 13:10:32 +1300 Subject: [PATCH 67/83] proc_clean: Removing an empty full_case is doing something --- passes/proc/proc_clean.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index 19c2be4ca..8cccb96c4 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc @@ -97,6 +97,7 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did all_empty = false; if (all_empty) { + did_something = true; for (auto cs : sw->cases) delete cs; sw->cases.clear(); From 9f774651707e3d62e3aee94b7adf9b114e59bae8 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 6 Jan 2026 16:19:04 -0800 Subject: [PATCH 68/83] Add test --- .../test_smtbmc_witness_mismatch.py | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 tests/functional/test_smtbmc_witness_mismatch.py diff --git a/tests/functional/test_smtbmc_witness_mismatch.py b/tests/functional/test_smtbmc_witness_mismatch.py new file mode 100644 index 000000000..f13620f1d --- /dev/null +++ b/tests/functional/test_smtbmc_witness_mismatch.py @@ -0,0 +1,190 @@ +import json +import shutil +import subprocess +from pathlib import Path + +import pytest + +base_path = Path(__file__).resolve().parent.parent.parent + +pytestmark = pytest.mark.skipif(shutil.which("z3") is None, reason="z3 not available") + +def run(cmd, **kwargs): + """Run a command and assert it succeeds.""" + status = subprocess.run(cmd, **kwargs) + assert status.returncode == 0, f"{cmd[0]} failed" + return status + + +def write_smt2(tmp_path, verilog_text): + """Write Verilog to temp and emit SMT2 via yosys.""" + vfile = tmp_path / "design.v" + smt2 = tmp_path / "design.smt2" + vfile.write_text(verilog_text) + run([base_path / "yosys", "-Q", "-p", + f"read_verilog {vfile}; prep -top top; write_smt2 {smt2}"]) + return smt2 + + +def witness_entries(smt2_path): + """Parse yosys-smt2-witness JSON records from an SMT2 file.""" + entries = [] + marker = "yosys-smt2-witness" + with open(smt2_path, "r") as f: + for line in f: + if marker not in line: + continue + payload = line.split(marker, 1)[1].strip() + entries.append(json.loads(payload)) + return entries + + +def find_entry(entries, entry_type): + """Return the first witness entry of the given type.""" + for entry in entries: + if entry.get("type") == entry_type: + return entry + return None + + +def write_yw(yw_path, signals, bits): + """Write a minimal Yosys witness file with one step of bits.""" + data = { + "format": "Yosys Witness Trace", + "clocks": [], + "signals": signals, + "steps": [{"bits": bits}], + } + yw_path.write_text(json.dumps(data)) + + +def run_smtbmc(smt2_path, yw_path): + """Run yosys-smtbmc on the SMT2 file with a witness trace.""" + cmd = [ + base_path / "yosys-smtbmc", + "-s", "z3", + "-m", "top", + "--check-witness", + "--yw", yw_path, + "-t", "1", + smt2_path, + ] + return subprocess.run(cmd, capture_output=True, text=True) + + +def assert_no_mismatch_message(result): + """Assert the mismatch error prefix is absent from outputs.""" + combined = (result.stderr or "") + (result.stdout or "") + assert "Yosys witness signal mismatch" not in combined + + +def assert_has_mismatch_message(result, msg): + """Assert the mismatch error prefix and substring are present.""" + combined = (result.stderr or "") + (result.stdout or "") + assert "Yosys witness signal mismatch" in combined + assert msg in combined + + +def test_missing_signal_path(tmp_path): + smt2 = write_smt2(tmp_path, "module top(input ok, output out); assign out = ok; endmodule") + yw_path = tmp_path / "trace.yw" + signals = [{"path": ["\\missing"], "offset": 0, "width": 1, "init_only": False}] + write_yw(yw_path, signals, "1") + result = run_smtbmc(smt2, yw_path) + assert result.returncode != 0 + assert_has_mismatch_message(result, "signal not found in design") + + +def test_width_mismatch(tmp_path): + smt2 = write_smt2(tmp_path, "module top(input ok, output out); assign out = ok; endmodule") + entries = witness_entries(smt2) + input_entry = find_entry(entries, "input") + assert input_entry is not None + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": input_entry["path"], + "offset": 0, + "width": 2, + "init_only": False, + }] + write_yw(yw_path, signals, "10") + result = run_smtbmc(smt2, yw_path) + assert result.returncode != 0 + assert_has_mismatch_message(result, "signal width/offset mismatch") + + +def test_memory_address_oob(tmp_path): + verilog = """ +module top(input ok, output [7:0] mem_out); + reg [7:0] mem [0:1]; + assign mem_out = mem[0] ^ {8{ok}}; +endmodule +""" + smt2 = write_smt2(tmp_path, verilog) + entries = witness_entries(smt2) + mem_entry = find_entry(entries, "mem") + assert mem_entry is not None + addr = mem_entry["size"] + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": mem_entry["path"] + [f"\\[{addr}]"], + "offset": 0, + "width": mem_entry["width"], + "init_only": False, + }] + bits = "0" * mem_entry["width"] + write_yw(yw_path, signals, bits) + result = run_smtbmc(smt2, yw_path) + assert result.returncode != 0 + assert_has_mismatch_message(result, "memory address out of bounds") + + +def test_allowed_extra_signal_in_design(tmp_path): + verilog = """ +module top(input ok, input extra, output [1:0] out); + assign out = {ok, extra}; +endmodule +""" + smt2 = write_smt2(tmp_path, verilog) + entries = witness_entries(smt2) + input_entry = find_entry(entries, "input") + assert input_entry is not None + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": input_entry["path"], + "offset": 0, + "width": input_entry["width"], + "init_only": False, + }] + bits = "0" * input_entry["width"] + write_yw(yw_path, signals, bits) + result = run_smtbmc(smt2, yw_path) + # With --check-witness and no assertions, smtbmc can still exit non-zero. + # Thus we don't check the result.returncode here and in the other success + # cases. + assert_no_mismatch_message(result) + + +def test_allowed_extra_memory_in_design(tmp_path): + verilog = """ +module top(input ok, output [7:0] out); + reg [7:0] mem0 [0:1]; + reg [7:0] mem1 [0:3]; + assign out = mem0[0] ^ mem1[0]; +endmodule +""" + smt2 = write_smt2(tmp_path, verilog) + entries = witness_entries(smt2) + input_entry = find_entry(entries, "input") + assert input_entry is not None + yw_path = tmp_path / "trace.yw" + signals = [{ + "path": input_entry["path"], + "offset": 0, + "width": input_entry["width"], + "init_only": False, + }] + bits = "1" * input_entry["width"] + write_yw(yw_path, signals, bits) + result = run_smtbmc(smt2, yw_path) + assert_no_mismatch_message(result) From 4d237bdd921e8c405722a148043731c63e0971db Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 6 Jan 2026 16:19:54 -0800 Subject: [PATCH 69/83] Deliver more helpful error messages --- backends/smt2/smtbmc.py | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 4e47117b3..9dfbd2a25 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -735,6 +735,12 @@ def ywfile_signal(sig, step, mask=None): output = [] + def ywfile_signal_error(reason, detail=None): + msg = f"Yosys witness signal mismatch for {sig.pretty()}: {reason}" + if detail: + msg += f" ({detail})" + raise ValueError(msg) + if sig.path in smt_wires: for wire in smt_wires[sig.path]: width, offset = wire["width"], wire["offset"] @@ -765,6 +771,12 @@ def ywfile_signal(sig, step, mask=None): for mem in smt_mems[sig.memory_path]: width, size, bv = mem["width"], mem["size"], mem["statebv"] + if sig.memory_addr is not None and sig.memory_addr >= size: + ywfile_signal_error( + "memory address out of bounds", + f"address={sig.memory_addr} size={size}", + ) + smt_expr = smt.net_expr(topmod, f"s{step}", mem["smtpath"]) if bv: @@ -781,18 +793,34 @@ def ywfile_signal(sig, step, mask=None): smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr) output.append((0, sig.width, smt_expr)) + else: + ywfile_signal_error("memory not found in design") output.sort() output = [chunk for chunk in output if chunk[0] != chunk[1]] + if not output: + if sig.memory_path: + ywfile_signal_error("memory signal has no matching bits in design") + else: + ywfile_signal_error("signal not found in design") + pos = 0 for start, end, smt_expr in output: - assert start == pos + if start != pos: + ywfile_signal_error( + "signal width/offset mismatch", + f"expected coverage at bit {pos}", + ) pos = end - assert pos == sig.width + if pos != sig.width: + ywfile_signal_error( + "signal width/offset mismatch", + f"covered {pos} of {sig.width} bits", + ) if len(output) == 1: return output[0][-1] From 9a09758f5683bacad0776d5cf2353c88f986751c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 7 Jan 2026 13:21:23 +1300 Subject: [PATCH 70/83] Test empty switches --- tests/proc/bug5572.ys | 19 +++++++++++++++++++ tests/verilog/.gitignore | 1 + tests/verilog/bug5572.ys | 15 +++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/proc/bug5572.ys create mode 100644 tests/verilog/bug5572.ys diff --git a/tests/proc/bug5572.ys b/tests/proc/bug5572.ys new file mode 100644 index 000000000..1d8f4e514 --- /dev/null +++ b/tests/proc/bug5572.ys @@ -0,0 +1,19 @@ +read_rtlil << EOT +attribute \top 1 +module \top + wire width 1 \sig + wire width 1 \val + + process $2 + switch \sig [0] + case 1'0 + case 1'1 + case + assign \val [0] 1'1 + end + end +end +EOT +proc_rmdead +proc_clean +select -assert-none p:* diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore index b16ed0890..6a226989c 100644 --- a/tests/verilog/.gitignore +++ b/tests/verilog/.gitignore @@ -1,3 +1,4 @@ +/bug5572.v /const_arst.v /const_sr.v /doubleslash.v diff --git a/tests/verilog/bug5572.ys b/tests/verilog/bug5572.ys new file mode 100644 index 000000000..3044e3572 --- /dev/null +++ b/tests/verilog/bug5572.ys @@ -0,0 +1,15 @@ +read_rtlil << EOT +module \top + wire \sig + wire \val + process $2 + attribute \full_case 1 + switch \sig + end + end +end +EOT + +write_verilog bug5572.v +design -reset +read_verilog bug5572.v From 35321cd292075daabe847589d32d1f8a6c4224ba Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 00:25:36 +0000 Subject: [PATCH 71/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c859422cd..3dc5f0fe0 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+78 +YOSYS_VER := 0.60+88 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 8da919587d75d0ac84b4ee5c54606cc2e387b808 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 25 Nov 2025 01:35:00 +0000 Subject: [PATCH 72/83] Parallelize `opt_merge`. I'm not sure why but this is actually faster than existing `opt_merge` even with YOSYS_MAX_THREADS=1, for the jpeg synthesis test. 16.0s before, 15.5s after for end-to-end synthesis. --- kernel/hashlib.h | 6 + kernel/rtlil.h | 2 + passes/opt/opt_merge.cc | 407 +++++++++++++++++++++++++++++----------- 3 files changed, 301 insertions(+), 114 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index ca600231a..b43a68abf 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -1321,6 +1321,12 @@ public: return i < 0 ? 0 : 1; } + int lookup(const K &key) const + { + Hasher::hash_t hash = database.do_hash(key); + return database.do_lookup_no_rehash(key, hash); + } + void expect(const K &key, int i) { int j = (*this)(key); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 1f1d8e0da..e3a5a3bf8 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -2140,6 +2140,8 @@ public: int wires_size() const { return wires_.size(); } RTLIL::Wire* wire_at(int index) const { return wires_.element(index)->second; } RTLIL::ObjRange cells() { return RTLIL::ObjRange(&cells_, &refcount_cells_); } + int cells_size() const { return cells_.size(); } + RTLIL::Cell* cell_at(int index) const { return cells_.element(index)->second; } void add(RTLIL::Binding *binding); diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 69474b5f9..a6121b268 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -22,6 +22,7 @@ #include "kernel/sigtools.h" #include "kernel/log.h" #include "kernel/celltypes.h" +#include "kernel/threading.h" #include "libs/sha1/sha1.h" #include #include @@ -37,16 +38,73 @@ PRIVATE_NAMESPACE_BEGIN template inline Hasher hash_pair(const T &t, const U &u) { return hash_ops>::hash(t, u); } -struct OptMergeWorker +// Some cell and its hash value. +struct CellHash { - RTLIL::Design *design; - RTLIL::Module *module; - SigMap assign_map; - FfInitVals initvals; - bool mode_share_all; + // Index of a cell in the module + int cell_index; + Hasher::hash_t hash_value; +}; - CellTypes ct; - int total_count; +// The algorithm: +// 1) Compute and store the hashes of all relevant cells, in parallel. +// 2) Given N = the number of threads, partition the cells into N buckets by hash value: +// bucket k contains the cells whose hash value mod N = k. +// 3) For each bucket in parallel, build a hashtable of that bucket’s cells (using the +// precomputed hashes) and record the duplicates found. +// 4) On the main thread, process the list of duplicates to remove cells. +// For efficiency we fuse the second step into the first step by having the parallel +// threads write the cells into buckets directly. +// To avoid synchronization overhead, we divide each bucket into N shards. Each +// thread j adds a cell to bucket k by writing to shard j of bucket k — +// no synchronization required. In the next phase, thread k builds the hashtable for +// bucket k by iterating over all shards of the bucket. + +// The input to each thread in the "compute cell hashes" phase. +struct CellRange +{ + int begin; + int end; +}; + +// The output from each thread in the "compute cell hashes" phase. +struct CellHashes +{ + // Entry i contains the hashes where hash_value % bucketed_cell_hashes.size() == i + std::vector> bucketed_cell_hashes; +}; + +// A duplicate cell that has been found. +struct DuplicateCell +{ + // Remove this cell from the design + int remove_cell; + // ... and use this cell instead. + int keep_cell; +}; + +// The input to each thread in the "find duplicate cells" phase. +// Shards of buckets of cell hashes +struct Shards +{ + std::vector>> &bucketed_cell_hashes; +}; + +// The output from each thread in the "find duplicate cells" phase. +struct FoundDuplicates +{ + std::vector duplicates; +}; + +struct OptMergeThreadWorker +{ + const RTLIL::Module *module; + const SigMap &assign_map; + const FfInitVals &initvals; + const CellTypes &ct; + int workers; + bool mode_share_all; + bool mode_keepdc; static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h) { @@ -62,8 +120,8 @@ struct OptMergeWorker static void sort_pmux_conn(dict &conn) { - SigSpec sig_s = conn.at(ID::S); - SigSpec sig_b = conn.at(ID::B); + const SigSpec &sig_s = conn.at(ID::S); + const SigSpec &sig_b = conn.at(ID::B); int s_width = GetSize(sig_s); int width = GetSize(sig_b) / s_width; @@ -144,7 +202,6 @@ struct OptMergeWorker if (cell1->parameters != cell2->parameters) return false; - if (cell1->connections_.size() != cell2->connections_.size()) return false; for (const auto &it : cell1->connections_) @@ -199,7 +256,7 @@ struct OptMergeWorker return conn1 == conn2; } - bool has_dont_care_initval(const RTLIL::Cell *cell) + bool has_dont_care_initval(const RTLIL::Cell *cell) const { if (!cell->is_builtin_ff()) return false; @@ -207,36 +264,134 @@ struct OptMergeWorker return !initvals(cell->getPort(ID::Q)).is_fully_def(); } - OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) : - design(design), module(module), mode_share_all(mode_share_all) + OptMergeThreadWorker(const RTLIL::Module *module, const FfInitVals &initvals, + const SigMap &assign_map, const CellTypes &ct, int workers, + bool mode_share_all, bool mode_keepdc) : + module(module), assign_map(assign_map), initvals(initvals), ct(ct), + workers(workers), mode_share_all(mode_share_all), mode_keepdc(mode_keepdc) { - total_count = 0; - ct.setup_internals(); - ct.setup_internals_mem(); - ct.setup_stdcells(); - ct.setup_stdcells_mem(); + } - if (mode_nomux) { - ct.cell_types.erase(ID($mux)); - ct.cell_types.erase(ID($pmux)); + CellHashes compute_cell_hashes(const CellRange &cell_range) const + { + std::vector> bucketed_cell_hashes(workers); + for (int cell_index = cell_range.begin; cell_index < cell_range.end; ++cell_index) { + const RTLIL::Cell *cell = module->cell_at(cell_index); + if (!module->selected(cell)) + continue; + if (cell->type.in(ID($meminit), ID($meminit_v2), ID($mem), ID($mem_v2))) { + // Ignore those for performance: meminit can have an excessively large port, + // mem can have an excessively large parameter holding the init data + continue; + } + if (cell->type == ID($scopeinfo)) + continue; + if (mode_keepdc && has_dont_care_initval(cell)) + continue; + if (!cell->known()) + continue; + if (!mode_share_all && !ct.cell_known(cell->type)) + continue; + + Hasher::hash_t h = hash_cell_function(cell, Hasher()).yield(); + int bucket_index = h % workers; + bucketed_cell_hashes[bucket_index].push_back({cell_index, h}); } + return {std::move(bucketed_cell_hashes)}; + } - ct.cell_types.erase(ID($tribuf)); - ct.cell_types.erase(ID($_TBUF_)); - ct.cell_types.erase(ID($anyseq)); - ct.cell_types.erase(ID($anyconst)); - ct.cell_types.erase(ID($allseq)); - ct.cell_types.erase(ID($allconst)); - ct.cell_types.erase(ID($check)); - ct.cell_types.erase(ID($assert)); - ct.cell_types.erase(ID($assume)); - ct.cell_types.erase(ID($live)); - ct.cell_types.erase(ID($cover)); + FoundDuplicates find_duplicate_cells(int index, const Shards &in) const + { + // We keep a set of known cells. They're hashed with our hash_cell_function + // and compared with our compare_cell_parameters_and_connections. + struct CellHashOp { + std::size_t operator()(const CellHash &c) const { + return (std::size_t)c.hash_value; + } + }; + struct CellEqualOp { + const OptMergeThreadWorker& worker; + CellEqualOp(const OptMergeThreadWorker& w) : worker(w) {} + bool operator()(const CellHash &lhs, const CellHash &rhs) const { + return worker.compare_cell_parameters_and_connections( + worker.module->cell_at(lhs.cell_index), + worker.module->cell_at(rhs.cell_index)); + } + }; + std::unordered_set< + CellHash, + CellHashOp, + CellEqualOp> known_cells(0, CellHashOp(), CellEqualOp(*this)); + + std::vector duplicates; + for (const std::vector> &buckets : in.bucketed_cell_hashes) { + // Clear out our buckets as we go. This keeps the work of deallocation + // off the main thread. + std::vector bucket = std::move(buckets[index]); + for (CellHash c : bucket) { + auto [cell_in_map, inserted] = known_cells.insert(c); + if (inserted) + continue; + CellHash map_c = *cell_in_map; + if (module->cell_at(c.cell_index)->has_keep_attr()) { + if (module->cell_at(map_c.cell_index)->has_keep_attr()) + continue; + known_cells.erase(map_c); + known_cells.insert(c); + std::swap(c, map_c); + } + duplicates.push_back({c.cell_index, map_c.cell_index}); + } + } + return {duplicates}; + } +}; + +template +void initialize_queues(std::vector> &queues, int size) { + queues.reserve(size); + for (int i = 0; i < size; ++i) + queues.emplace_back(1); +} + +struct OptMergeWorker +{ + int total_count; + + OptMergeWorker(RTLIL::Module *module, const CellTypes &ct, bool mode_share_all, bool mode_keepdc) : + total_count(0) + { + SigMap assign_map(module); + FfInitVals initvals; + initvals.set(&assign_map, module); log("Finding identical cells in module `%s'.\n", module->name); - assign_map.set(module); - initvals.set(&assign_map, module); + // Use no more than one worker per thousand cells, rounded down, so + // we only start multithreading with at least 2000 cells. + int num_worker_threads = ThreadPool::pool_size(0, module->cells_size()/1000); + int workers = std::max(1, num_worker_threads); + + // The main thread doesn't do any work, so if there is only one worker thread, + // just run everything on the main thread instead. + // This avoids creating and waiting on a thread, which is pretty high overhead + // for very small modules. + if (num_worker_threads == 1) + num_worker_threads = 0; + OptMergeThreadWorker thread_worker(module, initvals, assign_map, ct, workers, mode_share_all, mode_keepdc); + + std::vector> cell_ranges_queues(num_worker_threads); + std::vector> cell_hashes_queues(num_worker_threads); + std::vector> shards_queues(num_worker_threads); + std::vector> duplicates_queues(num_worker_threads); + + ThreadPool thread_pool(num_worker_threads, [&](int i) { + while (std::optional c = cell_ranges_queues[i].pop_front()) { + cell_hashes_queues[i].push_back(thread_worker.compute_cell_hashes(*c)); + std::optional shards = shards_queues[i].pop_front(); + duplicates_queues[i].push_back(thread_worker.find_duplicate_cells(i, *shards)); + } + }); bool did_something = true; // A cell may have to go through a lot of collisions if the hash @@ -244,91 +399,99 @@ struct OptMergeWorker // beyond the user's control. while (did_something) { - std::vector cells; - cells.reserve(module->cells().size()); - for (auto cell : module->cells()) { - if (!design->selected(module, cell)) - continue; - if (cell->type.in(ID($meminit), ID($meminit_v2), ID($mem), ID($mem_v2))) { - // Ignore those for performance: meminit can have an excessively large port, - // mem can have an excessively large parameter holding the init data - continue; - } - if (cell->type == ID($scopeinfo)) - continue; - if (mode_keepdc && has_dont_care_initval(cell)) - continue; - if (!cell->known()) - continue; - if (!mode_share_all && !ct.cell_known(cell->type)) - continue; - cells.push_back(cell); - } + int cells_size = module->cells_size(); + log("Computing hashes of %d cells of `%s'.\n", cells_size, module->name); + std::vector>> sharded_bucketed_cell_hashes(workers); - did_something = false; - - // We keep a set of known cells. They're hashed with our hash_cell_function - // and compared with our compare_cell_parameters_and_connections. - // Both need to capture OptMergeWorker to access initvals - struct CellPtrHash { - const OptMergeWorker& worker; - CellPtrHash(const OptMergeWorker& w) : worker(w) {} - std::size_t operator()(const Cell* c) const { - return (std::size_t)worker.hash_cell_function(c, Hasher()).yield(); - } - }; - struct CellPtrEqual { - const OptMergeWorker& worker; - CellPtrEqual(const OptMergeWorker& w) : worker(w) {} - bool operator()(const Cell* lhs, const Cell* rhs) const { - return worker.compare_cell_parameters_and_connections(lhs, rhs); - } - }; - std::unordered_set< - RTLIL::Cell*, - CellPtrHash, - CellPtrEqual> known_cells (0, CellPtrHash(*this), CellPtrEqual(*this)); - - std::vector redirects; - for (auto cell : cells) + int cell_index = 0; + int cells_size_mod_workers = cells_size % workers; { - auto [cell_in_map, inserted] = known_cells.insert(cell); - if (!inserted) { - // We've failed to insert since we already have an equivalent cell - Cell* other_cell = *cell_in_map; - if (cell->has_keep_attr()) { - if (other_cell->has_keep_attr()) - continue; - known_cells.erase(other_cell); - known_cells.insert(cell); - std::swap(other_cell, cell); - } - - did_something = true; - log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name, other_cell->name); - for (auto &it : cell->connections()) { - if (cell->output(it.first)) { - RTLIL::SigSpec other_sig = other_cell->getPort(it.first); - log_debug(" Redirecting output %s: %s = %s\n", it.first, - log_signal(it.second), log_signal(other_sig)); - redirects.push_back(RTLIL::SigSig(it.second, std::move(other_sig))); - } - } - log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type, cell->name, module->name); - module->remove(cell); - total_count++; + Multithreading multithreading; + for (int i = 0; i < workers; ++i) { + int num_cells = cells_size/workers + ((i < cells_size_mod_workers) ? 1 : 0); + CellRange c = { cell_index, cell_index + num_cells }; + cell_index += num_cells; + if (num_worker_threads > 0) + cell_ranges_queues[i].push_back(c); + else + sharded_bucketed_cell_hashes[i] = std::move(thread_worker.compute_cell_hashes(c).bucketed_cell_hashes); } + log_assert(cell_index == cells_size); + if (num_worker_threads > 0) + for (int i = 0; i < workers; ++i) + sharded_bucketed_cell_hashes[i] = std::move(cell_hashes_queues[i].pop_front()->bucketed_cell_hashes); } - for (const RTLIL::SigSig &redirect : redirects) { - module->connect(redirect); - Const init = initvals(redirect.second); - initvals.remove_init(redirect.first); - initvals.remove_init(redirect.second); - assign_map.add(redirect.first, redirect.second); - initvals.set_init(redirect.second, init); + + log("Finding duplicate cells in `%s'.\n", module->name); + std::vector merged_duplicates; + { + Multithreading multithreading; + for (int i = 0; i < workers; ++i) { + Shards thread_shards = { sharded_bucketed_cell_hashes }; + if (num_worker_threads > 0) + shards_queues[i].push_back(thread_shards); + else { + std::vector d = std::move(thread_worker.find_duplicate_cells(i, thread_shards).duplicates); + merged_duplicates.insert(merged_duplicates.end(), d.begin(), d.end()); + } + } + if (num_worker_threads > 0) + for (int i = 0; i < workers; ++i) { + std::vector d = std::move(duplicates_queues[i].pop_front()->duplicates); + merged_duplicates.insert(merged_duplicates.end(), d.begin(), d.end()); + } } + std::sort(merged_duplicates.begin(), merged_duplicates.end(), [](const DuplicateCell &lhs, const DuplicateCell &rhs) { + // Sort them by the order in which duplicates would have been detected in a single-threaded + // run. The cell at which the duplicate would have been detected is the latter of the two + // cells involved. + return std::max(lhs.remove_cell, lhs.keep_cell) < std::max(rhs.remove_cell, rhs.keep_cell); + }); + + // Convert to cell pointers because removing cells will invalidate the indices. + std::vector> cell_ptrs; + for (DuplicateCell dup : merged_duplicates) + cell_ptrs.push_back({module->cell_at(dup.remove_cell), module->cell_at(dup.keep_cell)}); + + for (auto [remove_cell, keep_cell] : cell_ptrs) + { + log_debug(" Cell `%s' is identical to cell `%s'.\n", remove_cell->name, keep_cell->name); + for (auto &it : remove_cell->connections()) { + if (remove_cell->output(it.first)) { + RTLIL::SigSpec keep_sig = keep_cell->getPort(it.first); + log_debug(" Redirecting output %s: %s = %s\n", it.first, + log_signal(it.second), log_signal(keep_sig)); + Const init = initvals(keep_sig); + initvals.remove_init(it.second); + initvals.remove_init(keep_sig); + module->connect(RTLIL::SigSig(it.second, keep_sig)); + auto keep_sig_it = keep_sig.begin(); + for (SigBit remove_sig_bit : it.second) { + assign_map.add(remove_sig_bit, *keep_sig_it); + ++keep_sig_it; + } + initvals.set_init(keep_sig, init); + } + } + log_debug(" Removing %s cell `%s' from module `%s'.\n", remove_cell->type, remove_cell->name, module->name); + module->remove(remove_cell); + total_count++; + } + did_something = !merged_duplicates.empty(); } + for (ConcurrentQueue &q : cell_ranges_queues) + q.close(); + + for (ConcurrentQueue &q : shards_queues) + q.close(); + + for (ConcurrentQueue &q : cell_ranges_queues) + q.close(); + + for (ConcurrentQueue &q : shards_queues) + q.close(); + log_suppressed(); } }; @@ -381,9 +544,25 @@ struct OptMergePass : public Pass { } extra_args(args, argidx, design); + CellTypes ct; + ct.setup_internals(); + ct.setup_internals_mem(); + ct.setup_stdcells(); + ct.setup_stdcells_mem(); + if (mode_nomux) { + ct.cell_types.erase(ID($mux)); + ct.cell_types.erase(ID($pmux)); + } + ct.cell_types.erase(ID($tribuf)); + ct.cell_types.erase(ID($_TBUF_)); + ct.cell_types.erase(ID($anyseq)); + ct.cell_types.erase(ID($anyconst)); + ct.cell_types.erase(ID($allseq)); + ct.cell_types.erase(ID($allconst)); + int total_count = 0; for (auto module : design->selected_modules()) { - OptMergeWorker worker(design, module, mode_nomux, mode_share_all, mode_keepdc); + OptMergeWorker worker(module, ct, mode_share_all, mode_keepdc); total_count += worker.total_count; } From 991e7048993735cb072b913994cf81759c19df64 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 00:26:46 +0000 Subject: [PATCH 73/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3dc5f0fe0..a7e2020a4 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+88 +YOSYS_VER := 0.60+95 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 37347aacb2fddd8a79dcb372f89a79e981a22c76 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 29 Dec 2025 05:32:55 +0000 Subject: [PATCH 74/83] Check for missing port in SDC code I am getting weird crashes on `main` in `tests/sdc/alu_sub.ys` which I traced to a null `Wire*` in `SdcObjects::constrained_ports`. The null `Wire*` is being set in the `SdcObjects` constructor. I don't understand what's going on here, so I added this check to detect the missing wire early ... and that made the crash go away. Compiler bug maybe? I have `Debian clang version 19.1.7 (3+build5)`, default build configuration. Anyway this code seems fine to have. --- passes/cmds/sdc/sdc.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/passes/cmds/sdc/sdc.cc b/passes/cmds/sdc/sdc.cc index fad001e50..635aad016 100644 --- a/passes/cmds/sdc/sdc.cc +++ b/passes/cmds/sdc/sdc.cc @@ -165,7 +165,12 @@ struct SdcObjects { if (!top) log_error("Top module couldn't be determined. Check 'top' attribute usage"); for (auto port : top->ports) { - design_ports.push_back(std::make_pair(port.str().substr(1), top->wire(port))); + RTLIL::Wire *wire = top->wire(port); + if (!wire) { + // This should not be possible. See https://github.com/YosysHQ/yosys/pull/5594#issue-3791198573 + log_error("Port %s doesn't exist", log_id(port)); + } + design_ports.push_back(std::make_pair(port.str().substr(1), wire)); } std::list hierarchy{}; sniff_module(hierarchy, top); From 2b12b74121d01772c207ee90608486c8321d8498 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 11 Jan 2026 15:23:38 +0100 Subject: [PATCH 75/83] musllinux fix so wheels build can work --- passes/techmap/abc.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index e25a6facd..88311fc2c 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -253,7 +253,11 @@ std::optional spawn_abc(const char* abc_exe, DeferredLogs &logs) { char arg1[] = "-s"; char* argv[] = { strdup(abc_exe), arg1, nullptr }; if (0 != posix_spawnp(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) { +#if defined(__GLIBC__) logs.log_error("posix_spawnp %s failed (errno=%s)", abc_exe, strerrorname_np(errno)); +#else + logs.log_error("posix_spawnp %s failed (errno=%s)", abc_exe, strerror(errno)); +#endif return std::nullopt; } free(argv[0]); From b3b71df07c38616e02cb4eab0757d6249dd6e12a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 12 Jan 2026 15:38:45 +0100 Subject: [PATCH 76/83] musllinux fix so wheels build can work --- passes/techmap/abc.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 88311fc2c..ad4dc5ccd 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -253,11 +253,7 @@ std::optional spawn_abc(const char* abc_exe, DeferredLogs &logs) { char arg1[] = "-s"; char* argv[] = { strdup(abc_exe), arg1, nullptr }; if (0 != posix_spawnp(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) { -#if defined(__GLIBC__) - logs.log_error("posix_spawnp %s failed (errno=%s)", abc_exe, strerrorname_np(errno)); -#else logs.log_error("posix_spawnp %s failed (errno=%s)", abc_exe, strerror(errno)); -#endif return std::nullopt; } free(argv[0]); From 78cbc21b94e5898bb6f9586e228d0d1c63668637 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 00:22:49 +0000 Subject: [PATCH 77/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a7e2020a4..3f287741f 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+95 +YOSYS_VER := 0.60+102 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 5ae48ee25f298f7b3c8c0de30bd2f85a94133031 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 13 Jan 2026 08:35:02 +0100 Subject: [PATCH 78/83] Release version 0.61 --- CHANGELOG | 12 +++++++++++- COPYING | 2 +- Makefile | 4 ++-- docs/source/conf.py | 4 ++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 69f8ab1ce..252189ce8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,18 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.60 .. Yosys 0.61-dev +Yosys 0.60 .. Yosys 0.61 -------------------------- + * Various + - Removed "cover" pass for coverage tracking. + - Avoid merging formal properties with "opt_merge" pass. + - Parallelize "opt_merge" pass. + + * New commands and options + - Added "design_equal" pass to support fuzz-test comparison. + - Added "lut2bmux" pass to convert $lut to $bmux. + - Added "-legalize" option to "read_rtlil" pass to prevent + semantic errors. Yosys 0.59 .. Yosys 0.60 -------------------------- diff --git a/COPYING b/COPYING index 2d962dddc..a3ca45b42 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ ISC License -Copyright (C) 2012 - 2025 Claire Xenia Wolf +Copyright (C) 2012 - 2026 Claire Xenia Wolf Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/Makefile b/Makefile index 3f287741f..db7a115e8 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.60+102 +YOSYS_VER := 0.61 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -186,7 +186,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5bafeb7.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5bafeb7.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) diff --git a/docs/source/conf.py b/docs/source/conf.py index 01bb620ea..34f8be029 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -5,8 +5,8 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' -copyright ='2025 YosysHQ GmbH' -yosys_ver = "0.60" +copyright ='2026 YosysHQ GmbH' +yosys_ver = "0.61" # select HTML theme html_theme = 'furo-ys' From b08e044994ffd32d94040931bc255313084d091d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 13 Jan 2026 09:24:49 +0100 Subject: [PATCH 79/83] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 252189ce8..73c1606da 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.61 .. Yosys 0.62-dev +-------------------------- + Yosys 0.60 .. Yosys 0.61 -------------------------- * Various diff --git a/Makefile b/Makefile index db7a115e8..f2fc3e545 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.61 +YOSYS_VER := 0.61+0 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -186,7 +186,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5bafeb7.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5ae48ee.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From 0e6973037d7ee6d216f3de2d5c17e34d48aa534b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 13 Jan 2026 14:23:51 +0100 Subject: [PATCH 80/83] Update year in banner and license --- kernel/register.cc | 2 +- kernel/yosys.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/register.cc b/kernel/register.cc index 3f5aa49ca..abde8f47e 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -1204,7 +1204,7 @@ struct LicensePass : public Pass { log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf |\n"); + log(" | Copyright (C) 2012 - 2026 Claire Xenia Wolf |\n"); log(" | |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n"); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 2c9b8304d..4264cb772 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -173,7 +173,7 @@ void yosys_banner() log("\n"); log(" /----------------------------------------------------------------------------\\\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); - log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf |\n"); + log(" | Copyright (C) 2012 - 2026 Claire Xenia Wolf |\n"); log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n"); log(" \\----------------------------------------------------------------------------/\n"); log(" %s\n", yosys_maybe_version()); From 21e6833010348920eec3ec1baed8a1a634da4bae Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 13 Jan 2026 16:33:11 +0100 Subject: [PATCH 81/83] Makefile: no longer install ast.h and ast_binding.h --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index f2fc3e545..2fcc2fd95 100644 --- a/Makefile +++ b/Makefile @@ -645,8 +645,6 @@ $(eval $(call add_include_file,libs/sha1/sha1.h)) $(eval $(call add_include_file,libs/json11/json11.hpp)) $(eval $(call add_include_file,passes/fsm/fsmdata.h)) $(eval $(call add_include_file,passes/techmap/libparse.h)) -$(eval $(call add_include_file,frontends/ast/ast.h)) -$(eval $(call add_include_file,frontends/ast/ast_binding.h)) $(eval $(call add_include_file,frontends/blif/blifparse.h)) $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) From 8e2038c4195e09b1002f3af61bbc0c6041510aea Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 24 Nov 2025 12:28:30 +0100 Subject: [PATCH 82/83] Use digit separators for large decimal integers --- kernel/log.cc | 6 +++--- passes/cmds/select.cc | 2 +- passes/opt/opt_muxtree.cc | 2 +- passes/techmap/extract_fa.cc | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 2a1261621..018a19081 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -90,11 +90,11 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&counter); - counter.QuadPart *= 1000000; + counter.QuadPart *= 1'000'000; counter.QuadPart /= freq.QuadPart; tv->tv_sec = long(counter.QuadPart / 1000000); - tv->tv_usec = counter.QuadPart % 1000000; + tv->tv_usec = counter.QuadPart % 1'000'000; return 0; } @@ -135,7 +135,7 @@ static void logv_string(std::string_view format, std::string str) { initial_tv = tv; if (tv.tv_usec < initial_tv.tv_usec) { tv.tv_sec--; - tv.tv_usec += 1000000; + tv.tv_usec += 1'000'000; } tv.tv_sec -= initial_tv.tv_sec; tv.tv_usec -= initial_tv.tv_usec; diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 6da15c19a..0df47664f 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -570,7 +570,7 @@ static void select_op_expand(RTLIL::Design *design, const std::string &arg, char ct.setup(design); if (pos < int(arg.size()) && arg[pos] == '*') { - levels = 1000000; + levels = 1'000'000; pos++; } else if (pos < int(arg.size()) && '0' <= arg[pos] && arg[pos] <= '9') { diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index 2f7d26dcf..0020af09f 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -64,7 +64,7 @@ struct OptMuxtreeWorker RTLIL::Module *module; SigMap assign_map; int removed_count; - int glob_evals_left = 10000000; + int glob_evals_left = 10'000'000; struct bitinfo_t { // Is bit directly used by non-mux cells or ports? diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc index 1984f82f5..46ab7e520 100644 --- a/passes/techmap/extract_fa.cc +++ b/passes/techmap/extract_fa.cc @@ -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; } From 83c1364eeb0e0c8c2771c5fefdbfad6645c6e282 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 13 Jan 2026 18:47:23 +0100 Subject: [PATCH 83/83] read_verilog: remove log I left behind by accident --- frontends/verilog/verilog_frontend.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 6c9e67dc5..29a739f81 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -500,7 +500,6 @@ struct VerilogFrontend : public Frontend { log("Parsing %s%s input from `%s' to AST representation.\n", parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); - log("verilog frontend filename %s\n", filename.c_str()); if (flag_relative_share) { auto share_path = proc_share_dirname(); if (filename.substr(0, share_path.length()) == share_path)