From 583eb1addb82b033647aaee150ee02acd1d9e9fd Mon Sep 17 00:00:00 2001 From: George Rennie Date: Fri, 15 Nov 2024 15:15:42 +0100 Subject: [PATCH 01/51] pyosys: dereference cpp objects when constructing a tuple * This fixes a bug where when converting a tuple from python to c++, get_cpp_obj() was called (returning a pointer) without dereferencing the pointer to get the underlying object --- misc/py_wrap_generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py index b0ac1e82e..6715951fc 100644 --- a/misc/py_wrap_generator.py +++ b/misc/py_wrap_generator.py @@ -515,11 +515,11 @@ class TupleTranslator(PythonDictTranslator): if types[0].name.split(" ")[-1] in primitive_types: text += varname + "___tmp_0, " else: - text += varname + "___tmp_0.get_cpp_obj(), " + text += "*" + varname + "___tmp_0.get_cpp_obj(), " if types[1].name.split(" ")[-1] in primitive_types: text += varname + "___tmp_1);" else: - text += varname + "___tmp_1.get_cpp_obj());" + text += "*" + varname + "___tmp_1.get_cpp_obj());" return text #Generate c++ code to translate to a boost::python::tuple From 3001473ae5280469ad3e4a057d7a43f5482c1f36 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 21 May 2025 16:09:39 +1200 Subject: [PATCH 02/51] functional.cc: Maintain port ordering Based on #4753. --- kernel/functional.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/functional.cc b/kernel/functional.cc index adf7bfb0c..178995de8 100644 --- a/kernel/functional.cc +++ b/kernel/functional.cc @@ -518,10 +518,12 @@ public: if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($check))) queue.emplace_back(cell); } - for (auto wire : module->wires()) { - if (wire->port_input) + for (auto port : module->ports) { + auto *wire = module->wire(port); + if (wire && wire->port_input) { factory.add_input(wire->name, ID($input), Sort(wire->width)); - if (wire->port_output) { + } + if (wire && wire->port_output) { auto &output = factory.add_output(wire->name, ID($output), Sort(wire->width)); output.set_value(enqueue(DriveChunk(DriveChunkWire(wire, 0, wire->width)))); } From 847558547b04c309a6ebe350d2ae2bd4f01da60a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 21 May 2025 16:21:27 +1200 Subject: [PATCH 03/51] functional.cc: Reverse port iteration --- kernel/functional.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/functional.cc b/kernel/functional.cc index 178995de8..4983703e3 100644 --- a/kernel/functional.cc +++ b/kernel/functional.cc @@ -518,8 +518,8 @@ public: if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($check))) queue.emplace_back(cell); } - for (auto port : module->ports) { - auto *wire = module->wire(port); + for (auto riter = module->ports.rbegin(); riter != module->ports.rend(); ++riter) { + auto *wire = module->wire(*riter); if (wire && wire->port_input) { factory.add_input(wire->name, ID($input), Sort(wire->width)); } From 6e3922e1c76a8ea2c689daab4d04198af92a387f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 31 May 2025 09:57:43 +1200 Subject: [PATCH 04/51] functional.cc: Explicit unsorted-pool-as-LIFO --- kernel/functional.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/functional.cc b/kernel/functional.cc index 4983703e3..211527926 100644 --- a/kernel/functional.cc +++ b/kernel/functional.cc @@ -518,6 +518,7 @@ public: if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($check))) queue.emplace_back(cell); } + // we are relying here on unsorted pools iterating last-in-first-out for (auto riter = module->ports.rbegin(); riter != module->ports.rend(); ++riter) { auto *wire = module->wire(*riter); if (wire && wire->port_input) { From ca8af1f8c89910b9b3c9112d8e5efd6e031f53ec Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Mon, 21 Jul 2025 14:15:26 +0300 Subject: [PATCH 05/51] opt_dff: implement simplify_patterns --- passes/opt/opt_dff.cc | 60 ++++++++++++++++++++++++++++++-- tests/arch/quicklogic/pp3/fsm.ys | 6 ++-- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 4ed4b0cb6..b24616928 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -170,9 +170,65 @@ struct OptDffWorker return ret; } - void simplify_patterns(patterns_t&) + void simplify_patterns(patterns_t& patterns) { - // TBD + // remove complimentary patterns + + auto new_patterns = patterns; + bool optimized; + do { + optimized = false; + for (auto i = patterns.begin(); i != patterns.end(); i++) { + for (auto j = std::next(i, 1); j != patterns.end(); j++) { + const auto& smaller = (GetSize(*j) <= GetSize(*i)) ? *j : *i; + const auto& larger = (GetSize(*i) < GetSize(*j)) ? *j : *i; + auto left = std::move(smaller); + auto right = std::move(larger); + + std::optional complimentary_var; + + for (const auto &pt : left) + if (right.count(pt.first) == 0) + goto next; + else if (right[pt.first] == pt.second) + continue; + else + if (complimentary_var) + goto next; + else + complimentary_var = pt.first; + if (complimentary_var) { + new_patterns.erase(right); + right.erase(complimentary_var.value()); + new_patterns.insert(right); + optimized = true; + } + next: + continue; + } + } + patterns = new_patterns; + } while(optimized); + + // remove redundant patterns + + for (auto i = patterns.begin(); i != patterns.end(); ++i) { + for (auto j = std::next(i, 1); j != patterns.end(); ++j) { + const auto& smaller = (GetSize(*j) <= GetSize(*i)) ? *j : *i; + const auto& larger = (GetSize(*i) < GetSize(*j)) ? *j : *i; + auto left = std::move(smaller); + auto right = std::move(larger); + + bool redundant = true; + + for (const auto& pt : left) + if (right.count(pt.first) == 0 || right[pt.first] != pt.second) + redundant = false; + if (redundant) + new_patterns.erase(right); + } + } + patterns = std::move(new_patterns) } ctrl_t make_patterns_logic(const patterns_t &patterns, const ctrls_t &ctrls, bool make_gates) diff --git a/tests/arch/quicklogic/pp3/fsm.ys b/tests/arch/quicklogic/pp3/fsm.ys index 418db8025..9679628e9 100644 --- a/tests/arch/quicklogic/pp3/fsm.ys +++ b/tests/arch/quicklogic/pp3/fsm.ys @@ -11,8 +11,8 @@ sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd fsm # Constrain all select calls below inside the top module -select -assert-count 1 t:LUT2 -select -assert-count 9 t:LUT3 +select -assert-count 2 t:LUT2 +select -assert-count 4 t:LUT3 select -assert-count 4 t:dffepc select -assert-count 1 t:logic_0 select -assert-count 1 t:logic_1 @@ -20,4 +20,4 @@ select -assert-count 3 t:inpad select -assert-count 2 t:outpad select -assert-count 1 t:ckpad -select -assert-none t:LUT2 t:LUT3 t:dffepc t:logic_0 t:logic_1 t:inpad t:outpad t:ckpad %% t:* %D +select -assert-none t:LUT2 t:LUT3 t:LUT4 t:dffepc t:logic_0 t:logic_1 t:inpad t:outpad t:ckpad %% t:* %D From d9fc6dda9ec9354568f372f870af73ccffc6b652 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Mon, 21 Jul 2025 14:42:52 +0300 Subject: [PATCH 06/51] typo --- passes/opt/opt_dff.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index b24616928..def177133 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -228,7 +228,7 @@ struct OptDffWorker new_patterns.erase(right); } } - patterns = std::move(new_patterns) + patterns = std::move(new_patterns); } ctrl_t make_patterns_logic(const patterns_t &patterns, const ctrls_t &ctrls, bool make_gates) From 206d2a455374c1ff25402a6efdcf7e4b47d6d093 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Wed, 30 Jul 2025 21:31:34 +0300 Subject: [PATCH 07/51] opt_dff: refactor simplify_patterns --- passes/opt/opt_dff.cc | 53 ++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index def177133..036c1b917 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -172,60 +172,57 @@ struct OptDffWorker void simplify_patterns(patterns_t& patterns) { - // remove complimentary patterns - auto new_patterns = patterns; + auto find_comp = [](const auto& left, const auto& right) -> std::optional { + std::optional ret; + for (const auto &pt: left) + if (right.count(pt.first) == 0) + return {}; + else if (right.at(pt.first) == pt.second) + continue; + else + if (ret) + return {}; + else + ret = pt.first; + return ret; + }; + + // remove complimentary patterns bool optimized; do { optimized = false; for (auto i = patterns.begin(); i != patterns.end(); i++) { for (auto j = std::next(i, 1); j != patterns.end(); j++) { - const auto& smaller = (GetSize(*j) <= GetSize(*i)) ? *j : *i; - const auto& larger = (GetSize(*i) < GetSize(*j)) ? *j : *i; - auto left = std::move(smaller); - auto right = std::move(larger); + const auto& left = (GetSize(*j) <= GetSize(*i)) ? *j : *i; + auto right = (GetSize(*i) < GetSize(*j)) ? *j : *i; - std::optional complimentary_var; + const auto complimentary_var = find_comp(left, right); - for (const auto &pt : left) - if (right.count(pt.first) == 0) - goto next; - else if (right[pt.first] == pt.second) - continue; - else - if (complimentary_var) - goto next; - else - complimentary_var = pt.first; if (complimentary_var) { new_patterns.erase(right); right.erase(complimentary_var.value()); new_patterns.insert(right); optimized = true; } - next: - continue; } } patterns = new_patterns; } while(optimized); // remove redundant patterns - for (auto i = patterns.begin(); i != patterns.end(); ++i) { - for (auto j = std::next(i, 1); j != patterns.end(); ++j) { - const auto& smaller = (GetSize(*j) <= GetSize(*i)) ? *j : *i; - const auto& larger = (GetSize(*i) < GetSize(*j)) ? *j : *i; - auto left = std::move(smaller); - auto right = std::move(larger); + for (auto j = std::next(i, 1); j != patterns.end(); ++j) { + const auto& left = (GetSize(*j) <= GetSize(*i)) ? *j : *i; + const auto& right = (GetSize(*i) < GetSize(*j)) ? *j : *i; bool redundant = true; - for (const auto& pt : left) - if (right.count(pt.first) == 0 || right[pt.first] != pt.second) + for (const auto& pt : smaller) + if (larger.count(pt.first) == 0 || larger[pt.first] != pt.second) redundant = false; if (redundant) - new_patterns.erase(right); + new_patterns.erase(larger); } } patterns = std::move(new_patterns); From bfff7a47f17033e2d61c75a779d0078bc0f8cfcf Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Wed, 30 Jul 2025 21:34:42 +0300 Subject: [PATCH 08/51] typo --- passes/opt/opt_dff.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 036c1b917..2a9d67dd6 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -222,7 +222,7 @@ struct OptDffWorker if (larger.count(pt.first) == 0 || larger[pt.first] != pt.second) redundant = false; if (redundant) - new_patterns.erase(larger); + new_patterns.erase(right); } } patterns = std::move(new_patterns); From 85e0e8ca670333898e9cbbbd4f1bf94dc421ae9c Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Wed, 30 Jul 2025 21:40:20 +0300 Subject: [PATCH 09/51] typo --- passes/opt/opt_dff.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 2a9d67dd6..210c4828f 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -218,8 +218,8 @@ struct OptDffWorker bool redundant = true; - for (const auto& pt : smaller) - if (larger.count(pt.first) == 0 || larger[pt.first] != pt.second) + for (const auto& pt : left) + if (right.count(pt.first) == 0 || right.at(pt.first) != pt.second) redundant = false; if (redundant) new_patterns.erase(right); From ffd52a0d8e43aba34d8d87def77b073c9fd90a07 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 31 Jul 2025 10:19:44 +0000 Subject: [PATCH 10/51] Making `stringf()` use the format conversion specs as-is without widening them. And make sure our fast-path for `%d` and `%u` narrows to `int` correctly. Resolves #5260 --- kernel/io.cc | 34 ++---------------- kernel/io.h | 2 +- tests/unit/kernel/ioTest.cc | 72 +++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 32 deletions(-) create mode 100644 tests/unit/kernel/ioTest.cc diff --git a/kernel/io.cc b/kernel/io.cc index 3deb54d86..9811919ba 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -405,37 +405,9 @@ std::string unescape_format_string(std::string_view fmt) static std::string string_view_stringf(std::string_view spec, ...) { - std::string fmt(spec); - char format_specifier = fmt[fmt.size() - 1]; - switch (format_specifier) { - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': { - // Strip any length modifier off `fmt` - std::string long_fmt; - for (size_t i = 0; i + 1 < fmt.size(); ++i) { - char ch = fmt[i]; - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { - break; - } - long_fmt.push_back(ch); - } - // Add `lld` or whatever - long_fmt += "ll"; - long_fmt.push_back(format_specifier); - fmt = long_fmt; - break; - } - default: - break; - } - va_list ap; va_start(ap, spec); - std::string result = vstringf(fmt.c_str(), ap); + std::string result = vstringf(std::string(spec).c_str(), ap); va_end(ap); return result; } @@ -464,7 +436,7 @@ void format_emit_long_long(std::string &result, std::string_view spec, int *dyna { if (spec == "%d") { // Format checking will have guaranteed num_dynamic_ints == 0. - result += std::to_string(arg); + result += std::to_string(static_cast(arg)); return; } format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); @@ -475,7 +447,7 @@ void format_emit_unsigned_long_long(std::string &result, std::string_view spec, { if (spec == "%u") { // Format checking will have guaranteed num_dynamic_ints == 0. - result += std::to_string(arg); + result += std::to_string(static_cast(arg)); return; } if (spec == "%c") { diff --git a/kernel/io.h b/kernel/io.h index ea2499e43..dafef8bfa 100644 --- a/kernel/io.h +++ b/kernel/io.h @@ -62,7 +62,7 @@ enum ConversionSpecifier : uint8_t CONVSPEC_UNSIGNED_INT, // Consumes a "double" CONVSPEC_DOUBLE, - // Consumes a "const char*" + // Consumes a "const char*" or other string type CONVSPEC_CHAR_PTR, // Consumes a "void*" CONVSPEC_VOID_PTR, diff --git a/tests/unit/kernel/ioTest.cc b/tests/unit/kernel/ioTest.cc new file mode 100644 index 000000000..7cb8498cb --- /dev/null +++ b/tests/unit/kernel/ioTest.cc @@ -0,0 +1,72 @@ +#include + +#include "kernel/io.h" + +YOSYS_NAMESPACE_BEGIN + +TEST(KernelStringfTest, integerTruncation) +{ + EXPECT_EQ(stringf("%d", 1LL << 32), "0"); + EXPECT_EQ(stringf("%u", 1LL << 32), "0"); + EXPECT_EQ(stringf("%x", 0xff12345678LL), "12345678"); + EXPECT_EQ(stringf("%hu", 0xff12345678LL), "22136"); +} + +TEST(KernelStringfTest, charFormat) +{ + EXPECT_EQ(stringf("%c", 256), std::string_view("\0", 1)); + EXPECT_EQ(stringf("%c", -1), "\377"); +} + +TEST(KernelStringfTest, floatFormat) +{ + EXPECT_EQ(stringf("%g", 1.0), "1"); +} + +TEST(KernelStringfTest, intToFloat) +{ + EXPECT_EQ(stringf("%g", 1), "1"); +} + +TEST(KernelStringfTest, floatToInt) +{ + EXPECT_EQ(stringf("%d", 1.0), "1"); + EXPECT_EQ(stringf("%d", -1.6), "-1"); +} + +TEST(KernelStringfTest, stringParam) +{ + EXPECT_EQ(stringf("%s", std::string("hello")), "hello"); +} + +TEST(KernelStringfTest, stringViewParam) +{ + EXPECT_EQ(stringf("%s", std::string_view("hello")), "hello"); +} + +TEST(KernelStringfTest, escapePercent) +{ + EXPECT_EQ(stringf("%%"), "%"); +} + +TEST(KernelStringfTest, trailingPercent) +{ + EXPECT_EQ(stringf("%"), "%"); +} + +TEST(KernelStringfTest, dynamicWidth) +{ + EXPECT_EQ(stringf("%*s", 8, "hello"), " hello"); +} + +TEST(KernelStringfTest, dynamicPrecision) +{ + EXPECT_EQ(stringf("%.*f", 4, 1.0), "1.0000"); +} + +TEST(KernelStringfTest, dynamicWidthAndPrecision) +{ + EXPECT_EQ(stringf("%*.*f", 8, 4, 1.0), " 1.0000"); +} + +YOSYS_NAMESPACE_END From 75b62d01645bfb454a2e0452020938b598c0a02f Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 4 Aug 2025 15:38:19 +0200 Subject: [PATCH 11/51] verificsva: Fix typo in the cover only followed-by operator support --- frontends/verific/verificsva.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 6e87bd267..60d8292b8 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -1616,7 +1616,7 @@ struct VerificSvaImporter inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION || (mode_cover && ( inst->Type() == PRIM_SVA_OVERLAPPED_FOLLOWED_BY || - inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION))) + inst->Type() == PRIM_SVA_NON_OVERLAPPED_FOLLOWED_BY))) { Net *antecedent_net = inst->GetInput1(); Net *consequent_net = inst->GetInput2(); From 86ef7f7edee18c075197ba80a4d03cb45c641003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Mon, 4 Aug 2025 17:43:03 +0200 Subject: [PATCH 12/51] Update wheels to Trusted Publisher --- .github/workflows/wheels.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b01ce6b3a..d81e340aa 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -119,6 +119,11 @@ jobs: upload_wheels: name: Upload Wheels runs-on: ubuntu-latest + # Specifying a GitHub environment is optional, but strongly encouraged + environment: pypi + permissions: + # IMPORTANT: this permission is mandatory for Trusted Publishing + id-token: write needs: build_wheels steps: - uses: actions/download-artifact@v4 @@ -132,6 +137,3 @@ jobs: mv *.whl ./dist - name: Publish uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_TOKEN }} - repository-url: ${{ vars.PYPI_INDEX || 'https://upload.pypi.org/legacy/' }} From 074f5e7ea606564f782e78812d1e5f6a7ee45627 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:56 +1200 Subject: [PATCH 13/51] Docs: Initial outline of minimizing designs How to guide for using bugpoint, minimizing yosys scripts, and minimizing verilog code. AKA how to MVCE. --- docs/source/using_yosys/bugpoint.rst | 210 +++++++++++++++++++++++++++ docs/source/using_yosys/index.rst | 1 + 2 files changed, 211 insertions(+) create mode 100644 docs/source/using_yosys/bugpoint.rst diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst new file mode 100644 index 000000000..8c685c35c --- /dev/null +++ b/docs/source/using_yosys/bugpoint.rst @@ -0,0 +1,210 @@ +Minimizing failing (or bugged) designs +====================================== + +- how to guide +- assumes knowledge and familiarity with Yosys +- something is wrong with your design OR something is wrong with Yosys + + + how to work out which + +- *read* the error message +- is it a Yosys error? (starts with ERROR:) + + + does it give you a line number from your design + +- is it a runtime error, e.g. SEGFAULT +- are you using the latest release of Yosys + + + has your problem already been fixed + +- is your input design valid? + + + if you're using Verilog, try load it with `iverilog`_ or `verilator`_ + +.. _iverilog: https://steveicarus.github.io/iverilog/ +.. _verilator: https://www.veripool.org/verilator/ + +- make sure to back up your code (design source and yosys script(s)) before + making any modifications + + + even if the code itself isn't important, this can help avoid "losing" the + error while trying to debug it + + +.. _minimize your RTLIL: + +Minimizing RTLIL designs with bugpoint +-------------------------------------- + +- `bugpoint`, only usable on platforms where Yosys can spawn executables + + + unavailable on emscripten and wasm + + can test by running e.g. ``yosys -qqp '!echo test'`` + + * the ``-qq`` prevents Yosys from outputting non-error messages to the + console, so this will either display the text ``test``, or an error + message about ``Shell`` being unavailable + * be careful about using ``!`` in bash as it will perform a history + substitution if not escaped with single quotes (double quotes will not + escape it) + * ``!`` does not need to be escaped in *Yosys* scripts or when called within + the interactive Yosys shell, *only* when called on the command line with + ``-p`` + +- single command (``yosys -p "" design.il``) +- *or* multiple commands in a separate script file + + + script shouldn't load the design + + ``yosys -s design.il`` + + `minimize your script`_ to reduce the time needed by `bugpoint` + +- doesn't require design to be in RTLIL format + + + can e.g. ``read_verilog ; prep -top ;`` before `bugpoint` + + this method may be more useful if you are trying to find a bug in your + design rather than Yosys + + but, `bugpoint` itself calls the command/script with an RTLIL dump, so if it + isn't reproducible from RTLIL then `bugpoint` won't work + +- follow `bugpoint` instructions + + + output design after `bugpoint` with `write_rtlil` + + use ``-grep ""`` to only accept a minimized design that crashes + with the ```` in the log file + + ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those + parts of the design to be removed + + * use the ``bugpoint_keep`` attribute on objects you don't want to be + removed, usually because you already know they are related to the failure + * ``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in + RTLIL, or ``setattr -set bugpoint_keep 1 [selection]`` from script + + + ``-runner ""`` can allow running ``yosys`` wrapped by another + command + + can also use `setenv` before `bugpoint` to set environment variables for + the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) + +.. note:: + + Using `setenv` in this way **does not affect the current process**. Only + child processes will respect the assigned ``halt_on_error``. + + +.. _minimize your script: + +Minimizing scripts +------------------ + +- reminder to back up original code before modifying it +- if you're using command line, convert it to a script +- if you're using one of the :doc:`/using_yosys/synthesis/synth`, replace it + with its contents +- remove everything *after* the error occurs +- can use `log` command to print messages to help locate the failure point +- `echo` can also help (``echo on``) +- try ``write_rtlil ; design -reset; read_rtlil ;`` before + the failure point + + + ideally you now have a single command that is producing an error and can + `minimize your RTLIL`_ with the ```` output + + if not, try to move the write/reset/read earlier in the script until you can + reproduce the error + + if you have no idea where exactly you should put the reset, the best way is + to use a "binary search" type approach, reducing the possible options by + half after each attempt + + * for example, your script has 16 commands in it before failing on the 17th + * if resetting immediately before the 17th doesn't reproduce the error, try + between the 8th and 9th (8 is half of the total 16) + * if that produces the error then you can remove everything before the + `read_rtlil` and try reset again in the middle of what's left, making sure + to use a different name for the output file so that you don't overwrite + what you've already got + * if the error isn't produced then you need to go earlier still, so in this + case you would do between the 4th and 5th (4 is half of the previous 8) + * repeat this until you can't reduce the remaining commands any further + +.. TODO:: is it possible to dump scratchpad? + + is there anything else in the yosys/design state that doesn't get included in + `write_rtlil`? + +- you can also try to remove or comment out commands prior to the failing + command; just because the first and last commands are needed doesn't mean that + every command between them is + + +Minimizing Verilog designs +-------------------------- + +- manual process +- made easier if the error message is able to identify the source line or name + of the object +- reminder to back up original code before modifying it +- if a specific module is causing the problem, try to set that as the top + module, you can then remove + + + if the problem is parameter specific you may be able to change the default + parameters so that they match the problematic configuration + +- as with `minimize your script`_, if you have no idea what is or is not + relevant, try to follow a "binary search" type approach where you remove (or + comment out) roughly half of what's left at a time +- focusing on one type of object at a time simplifies the process, removing as + many as you can until the error disappears if any of the remaining objects are + removed +- periodically check if anything is totally disconnected (ports, wires, etc), if + it is then it can be removed too +- start by removing cells (instances of modules) + + + if a module has no more instances, remove it entirely + +- then processes +- try to remove or reduce assignments and operations + + + are there any wires/registers which get read but never written? + + * try removing the signal declaration and replacing references to it with + ``'0`` or ``'x`` + * try this with constants too + + + can you replace strings with numeric values? + + are you able to simplify any operations? like replacing ``a & '0`` with + ``'0`` + + if you have enable or reset logic, does the error still happen without that? + + can you reduce an ``if .. else`` to a single case? + +- if you're planning to share the minimized code: + + + make sure there is no sensitive or proprietary data in the design + + instead of a long string of numbers and letters that had some meaning (or + were randomly or sequentially generated), can you give it a single character + name like ``a`` or ``x`` + + please try to keep things in English, using the letters a-z and numbers 0-9 + (unless the error is arising because of the names used) + + +Creating an issue on GitHub +--------------------------- + +- "Reproduction Steps" is ideally a single code-block (starting and ending with + triple backquotes), containing the minimized yosys script file, which includes + the minimized design as a "here document" followed by the sequence of commands + which reproduce the error + +.. TODO:: https://tldp.org/LDP/abs/html/here-docs.html + + Actually fill out :doc:`/using_yosys/more_scripting/load_design` with here + docs info and then link to it from here + +.. code-block:: markdown + + ``` + read_rtlil < Date: Tue, 5 Aug 2025 09:53:56 +1200 Subject: [PATCH 14/51] docs: Outline loading a design page Talk about input files coming from command line, the `read` command, and features provided by `RTLIL::Frontend` (making note that `read_slang` is a subclass but `ghdl` isn't). --- .../more_scripting/load_design.rst | 119 +++++++++++++++--- 1 file changed, 101 insertions(+), 18 deletions(-) diff --git a/docs/source/using_yosys/more_scripting/load_design.rst b/docs/source/using_yosys/more_scripting/load_design.rst index bbc55a36b..964e9a7df 100644 --- a/docs/source/using_yosys/more_scripting/load_design.rst +++ b/docs/source/using_yosys/more_scripting/load_design.rst @@ -1,11 +1,88 @@ Loading a design -~~~~~~~~~~~~~~~~ +---------------- -keyword: Frontends +.. _input files: + +Input files on the command line +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- guesses frontend based on file extension + + + ``.v`` -> ``read -vlog2k`` + + ``.sv`` -> ``read -sv`` + + ``.vhd`` and ``.vhdl`` -> ``read -vhdl`` + + ``.blif`` and ``.eblif`` -> `read_blif` + + ``.json`` -> `read_json` + + ``.il`` -> `read_rtlil` (direct textual representation of Yosys internal + state) + +- command line also supports + + + ``.ys`` -> `script` + + ``.tcl`` -> `tcl` + + ``-`` -> reads stdin and treats it as a script + +The `read` command +~~~~~~~~~~~~~~~~~~ + +- standard method of loading designs +- also for defining macros and include directories +- uses `verific` command if available + + + ``-verific`` and ``-noverific`` options to enforce with/without Verific + + check ``help read`` for more about the options available and the filetypes + supported + +- fallback to `read_verilog` + +.. note:: + + The Verific frontend for Yosys, which provides the :cmd:ref:`verific` + command, requires Yosys to be built with Verific. For full functionality, + custom modifications to the Verific source code from YosysHQ are required, + but limited useability can be achieved with some stock Verific builds. Check + :doc:`/yosys_internals/extending_yosys/build_verific` for more. + +.. _Frontend: + +Yosys frontends +~~~~~~~~~~~~~~~ + +- typically start with ``read_`` +- built-in support for heredocs + + + in-line code with ``< Date: Tue, 5 Aug 2025 09:53:57 +1200 Subject: [PATCH 15/51] Docs: Bugpoint fixups from JF Also dropping the `autosectionlabel_maxdepth = 1` so that I can actually use the auto section labels. Adds warning on bash substitution on scripting intro page when talking about `yosys -p`. --- docs/source/conf.py | 1 - .../getting_started/scripting_intro.rst | 9 ++- docs/source/using_yosys/bugpoint.rst | 79 ++++++++++++------- .../more_scripting/load_design.rst | 18 ++++- 4 files changed, 74 insertions(+), 33 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 05dcb7d5f..e587b8d31 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -64,7 +64,6 @@ if os.getenv("READTHEDOCS"): # Ensure that autosectionlabel will produce unique names autosectionlabel_prefix_document = True -autosectionlabel_maxdepth = 1 # include todos for previews extensions.append('sphinx.ext.todo') diff --git a/docs/source/getting_started/scripting_intro.rst b/docs/source/getting_started/scripting_intro.rst index 01954c661..6a6e4ff51 100644 --- a/docs/source/getting_started/scripting_intro.rst +++ b/docs/source/getting_started/scripting_intro.rst @@ -26,7 +26,7 @@ of the comment is a semicolon ``;`` or a new line. .. code-block:: :caption: Using the ``-p`` option - $ yosys -p "read_verilog fifo.v; :this is a comment; prep" + $ yosys -p 'read_verilog fifo.v; :this is a comment; prep' .. warning:: @@ -42,6 +42,13 @@ will be raised by Yosys. `exec` provides a much more flexible way of executing commands, allowing the output to be logged and more control over when to generate errors. +.. warning:: + + Take care when using the ``yosys -p`` option. Some shells such as bash will + perform substitution options inside of a double quoted string, such as ``!`` + for history substitution and ``$`` for variable substitution; single quotes + should be used instead to pass the string to Yosys without substitution. + The synthesis starter script ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 8c685c35c..9b402858e 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -44,14 +44,10 @@ Minimizing RTLIL designs with bugpoint * the ``-qq`` prevents Yosys from outputting non-error messages to the console, so this will either display the text ``test``, or an error message about ``Shell`` being unavailable - * be careful about using ``!`` in bash as it will perform a history - substitution if not escaped with single quotes (double quotes will not - escape it) - * ``!`` does not need to be escaped in *Yosys* scripts or when called within - the interactive Yosys shell, *only* when called on the command line with - ``-p`` + * check :ref:`getting_started/scripting_intro:script parsing` for more about + the ``-p`` option and common pitfalls -- single command (``yosys -p "" design.il``) +- single command (``yosys -p '' design.il``) - *or* multiple commands in a separate script file + script shouldn't load the design @@ -68,26 +64,30 @@ Minimizing RTLIL designs with bugpoint - follow `bugpoint` instructions - + output design after `bugpoint` with `write_rtlil` - + use ``-grep ""`` to only accept a minimized design that crashes - with the ```` in the log file - + ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those - parts of the design to be removed + + output design after `bugpoint` with `write_rtlil` + + use ``-grep ""`` to only accept a minimized design that crashes + with the ```` in the log file + + ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those + parts of the design to be removed - * use the ``bugpoint_keep`` attribute on objects you don't want to be - removed, usually because you already know they are related to the failure - * ``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in - RTLIL, or ``setattr -set bugpoint_keep 1 [selection]`` from script + * use the ``bugpoint_keep`` attribute on objects you don't want to be + removed, usually because you already know they are related to the failure + * ``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in + RTLIL, or ``setattr -set bugpoint_keep 1 [selection]`` from script - + ``-runner ""`` can allow running ``yosys`` wrapped by another - command - + can also use `setenv` before `bugpoint` to set environment variables for - the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) + + ``-runner ""`` can allow running ``yosys`` wrapped by another + command + + can also use `setenv` before `bugpoint` to set environment variables for + the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) .. note:: - Using `setenv` in this way **does not affect the current process**. Only - child processes will respect the assigned ``halt_on_error``. + Using `setenv` in this way may not affect the current process as some + environment variables are only read on start up. For instance the + ``UBSAN_OPTIONS halt_on_error`` here only affects child processes, as does + the :doc:`Yosys environment variable` ``ABC``. While + others such as ``YOSYS_NOVERIFIC`` and ``HOME`` are evaluated each time they + are used. .. _minimize your script: @@ -187,15 +187,34 @@ Minimizing Verilog designs Creating an issue on GitHub --------------------------- -- "Reproduction Steps" is ideally a single code-block (starting and ending with - triple backquotes), containing the minimized yosys script file, which includes - the minimized design as a "here document" followed by the sequence of commands - which reproduce the error +- "Reproduction Steps" is ideally a code-block (starting and ending with triple + backquotes) containing the minimized design (Verilog or RTLIL), followed by a + code-block containing the minimized yosys script OR a command line call to + yosys with code-formatting (starting and ending with single backquotes) -.. TODO:: https://tldp.org/LDP/abs/html/here-docs.html +.. code-block:: markdown - Actually fill out :doc:`/using_yosys/more_scripting/load_design` with here - docs info and then link to it from here + min.v + ```verilog + // minimized Verilog design + ``` + + min.ys + ``` + read_verilog min.v + # minimum sequence of commands to reproduce error + ``` + + OR + + `yosys -p ': minimum sequence of commands;' min.v` + + +- alternatively can provide a single code-block which includes the minimized + design as a "here document" followed by the sequence of commands which + reproduce the error + + + see :doc:`/using_yosys/more_scripting/load_design` for more on heredocs. .. code-block:: markdown @@ -203,7 +222,7 @@ Creating an issue on GitHub read_rtlil <`` (or use + `hierarchy`) -- fallback to `read_verilog` +- fallback to `read_verilog` with ``-defer`` option + + + does not compile design until `hierarchy` command as discussed in + :doc:`/getting_started/example_synth` + + more similar to `verific` behaviour + +- ``read -define`` et al mapped to `verific` or `verilog_defines` +- similarly, ``read -incdir`` et al mapped to `verific` or `verilog_defaults` .. note:: @@ -129,3 +138,10 @@ Externally maintained plugins - both plugins above are included in `OSS CAD Suite`_ .. _OSS CAD Suite: https://github.com/YosysHQ/oss-cad-suite-build + +- `Synlig`_, which uses `Surelog`_ to provide SystemVerilog support + + + also implemented as a '`Frontend`_' + +.. _Synlig: https://github.com/chipsalliance/synlig +.. _Surelog: https://github.com/chipsalliance/Surelog From db3dc45bc68f97b244d0732260dbcd31094b1fc2 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:57 +1200 Subject: [PATCH 16/51] Docs: Tidying Fix error on duplicated heading. Drop `cmd_ref`_ link (everything already uses :doc:`cmd_ref`). --- docs/source/cmd_ref.rst | 2 -- .../using_yosys/more_scripting/interactive_investigation.rst | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/source/cmd_ref.rst b/docs/source/cmd_ref.rst index acf2d1d41..d2d59ba54 100644 --- a/docs/source/cmd_ref.rst +++ b/docs/source/cmd_ref.rst @@ -1,5 +1,3 @@ -.. _cmd_ref: - ================================================================================ Command line reference ================================================================================ diff --git a/docs/source/using_yosys/more_scripting/interactive_investigation.rst b/docs/source/using_yosys/more_scripting/interactive_investigation.rst index e9c9bc9ac..ca4c76ee7 100644 --- a/docs/source/using_yosys/more_scripting/interactive_investigation.rst +++ b/docs/source/using_yosys/more_scripting/interactive_investigation.rst @@ -311,8 +311,8 @@ cells, as the net-names are usually suppressed in the circuit diagram if they are auto-generated. Note that the output is in the RTLIL representation, described in :doc:`/yosys_internals/formats/rtlil_rep`. -Interactive Design Investigation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Design Investigation +~~~~~~~~~~~~~~~~~~~~ Yosys can also be used to investigate designs (or netlists created from other tools). From 6e1cc9c0cd278f30c1593e5d4a021de8ab578a53 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:57 +1200 Subject: [PATCH 17/51] docs: Some extra bugpoint bullets --- docs/source/using_yosys/bugpoint.rst | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 9b402858e..d292c2d32 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -67,8 +67,11 @@ Minimizing RTLIL designs with bugpoint + output design after `bugpoint` with `write_rtlil` + use ``-grep ""`` to only accept a minimized design that crashes with the ```` in the log file + + * only checks log file, will not match runtime errors + + ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those - parts of the design to be removed + parts of the design to be removed (default is allow removing all) * use the ``bugpoint_keep`` attribute on objects you don't want to be removed, usually because you already know they are related to the failure @@ -89,6 +92,23 @@ Minimizing RTLIL designs with bugpoint others such as ``YOSYS_NOVERIFIC`` and ``HOME`` are evaluated each time they are used. +- check minimized design still fails, especially if not using `write_rtlil` + + + e.g. if you ran :ref:`bugpoint_script` below, then calling ``yosys -s + min.v`` should still fail in the same way + + `write_rtlil` is more reliable since `bugpoint` will have run that exact + code through the failing script; other ``write_*`` commands convert from the + RTLIL and then back again during the ``read_*`` which can result in + differences which mean the design no longer fails + +.. code-block:: yoscrypt + :caption: example `bugpoint` minimizer + :name: bugpoint_script + + read_verilog design.v + bugpoint -script + write_verilog min.v + .. _minimize your script: From aefe3443aac9fbeb5549502893d12afdebc9f9a3 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:57 +1200 Subject: [PATCH 18/51] docs: Minimizing synth with -run bullets --- docs/source/using_yosys/bugpoint.rst | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index d292c2d32..804787df8 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -119,9 +119,44 @@ Minimizing scripts - if you're using command line, convert it to a script - if you're using one of the :doc:`/using_yosys/synthesis/synth`, replace it with its contents + + + can also do this piece-wise with the ``-run`` option + + e.g. replacing ``synth -top -lut`` with :ref:`replace_synth` + + the options ``-top -lut`` can be provided to each `synth` step, or + to just the step(s) where it is relevant, as done here + +.. code-block:: yoscrypt + :caption: example replacement script for `synth` command + :name: replace_synth + + synth -top -run :coarse + synth -lut -run coarse:fine + synth -lut -run fine:check + synth -run check: + - remove everything *after* the error occurs - can use `log` command to print messages to help locate the failure point - `echo` can also help (``echo on``) + + + if you used a ``-run`` option like in :ref:`replace_synth` above, you can + now replace the failing step with its contents and repeat the above if + needed + + checking the log should tell you the last command that ran which can make + this easier + + say we ran :ref:`replace_synth` and were able to remove the ``synth -run + check:`` and still got our error, then we check the log and we see the last + thing before the error was `7.2. Executing MEMORY_MAP pass (converting + memories to logic and flip-flops).` + + we can then update our script to the following: + +.. code-block:: yoscrypt + :caption: example replacement script for `synth` when `memory_map` is failing + + synth -top -run :fine + opt -fast -full + memory_map + + - try ``write_rtlil ; design -reset; read_rtlil ;`` before the failure point From 8ec3e3a1025943b45772644b0a2387e1c3a1f238 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:58 +1200 Subject: [PATCH 19/51] docs: Bullets for identifying issues Add a note on fuzzers, with a polite suggestion that if you're fuzzing you should put in the work of identifying the underlying issue so that you (and we) are confident you're not raising multiple issues for the same bug. --- docs/source/using_yosys/bugpoint.rst | 113 +++++++++++++++++++++------ 1 file changed, 89 insertions(+), 24 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 804787df8..abc6094a6 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -36,6 +36,11 @@ Minimizing failing (or bugged) designs Minimizing RTLIL designs with bugpoint -------------------------------------- +- what is `bugpoint` + +Can I use bugpoint? +~~~~~~~~~~~~~~~~~~~ + - `bugpoint`, only usable on platforms where Yosys can spawn executables + unavailable on emscripten and wasm @@ -62,26 +67,29 @@ Minimizing RTLIL designs with bugpoint + but, `bugpoint` itself calls the command/script with an RTLIL dump, so if it isn't reproducible from RTLIL then `bugpoint` won't work + +How do I use bugpoint? +~~~~~~~~~~~~~~~~~~~~~~ + - follow `bugpoint` instructions +- output design after `bugpoint` with `write_rtlil` +- use ``-grep ""`` to only accept a minimized design that crashes +- with the ```` in the log file - + output design after `bugpoint` with `write_rtlil` - + use ``-grep ""`` to only accept a minimized design that crashes - with the ```` in the log file + + only checks log file, will not match runtime errors - * only checks log file, will not match runtime errors +- ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those +- parts of the design to be removed (default is allow removing all) - + ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those - parts of the design to be removed (default is allow removing all) + + use the ``bugpoint_keep`` attribute on objects you don't want to be + removed, usually because you already know they are related to the failure + + ``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in + RTLIL, or ``setattr -set bugpoint_keep 1 [selection]`` from script - * use the ``bugpoint_keep`` attribute on objects you don't want to be - removed, usually because you already know they are related to the failure - * ``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in - RTLIL, or ``setattr -set bugpoint_keep 1 [selection]`` from script - - + ``-runner ""`` can allow running ``yosys`` wrapped by another - command - + can also use `setenv` before `bugpoint` to set environment variables for - the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) +- ``-runner ""`` can allow running ``yosys`` wrapped by another +- command +- can also use `setenv` before `bugpoint` to set environment variables for +- the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) .. note:: @@ -92,14 +100,13 @@ Minimizing RTLIL designs with bugpoint others such as ``YOSYS_NOVERIFIC`` and ``HOME`` are evaluated each time they are used. -- check minimized design still fails, especially if not using `write_rtlil` - + e.g. if you ran :ref:`bugpoint_script` below, then calling ``yosys -s - min.v`` should still fail in the same way - + `write_rtlil` is more reliable since `bugpoint` will have run that exact - code through the failing script; other ``write_*`` commands convert from the - RTLIL and then back again during the ``read_*`` which can result in - differences which mean the design no longer fails +What do I do with the minimized design? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- check minimized design still fails, especially if not using `write_rtlil` +- e.g. if you ran :ref:`bugpoint_script` below, then calling ``yosys -s + min.v`` should still fail in the same way .. code-block:: yoscrypt :caption: example `bugpoint` minimizer @@ -109,6 +116,12 @@ Minimizing RTLIL designs with bugpoint bugpoint -script write_verilog min.v +- `write_rtlil` is more reliable since `bugpoint` will have run that exact + code through the failing script; other ``write_*`` commands convert from the + RTLIL and then back again during the ``read_*`` which can result in + differences which mean the design no longer fails +- check out :ref:`using_yosys/bugpoint:identifying issues` for more on what to + do next .. _minimize your script: @@ -145,8 +158,8 @@ Minimizing scripts this easier + say we ran :ref:`replace_synth` and were able to remove the ``synth -run check:`` and still got our error, then we check the log and we see the last - thing before the error was `7.2. Executing MEMORY_MAP pass (converting - memories to logic and flip-flops).` + thing before the error was ``7.2. Executing MEMORY_MAP pass (converting + memories to logic and flip-flops).`` + we can then update our script to the following: .. code-block:: yoscrypt @@ -239,6 +252,58 @@ Minimizing Verilog designs (unless the error is arising because of the names used) +Identifying issues +------------------ + +- does the failing command indicate limited support, or does it mention some + other command that needs to be run first? +- if you're able to, try to match the minimized design back to its original + context + + + could you achieve the same thing a different way? + + and if so, does this other method have the same issue? + +- try to change the design in small ways and see what happens + + + `bugpoint` can reduce and simplify a design, but it doesn't *change* much + + what happens if you change operators, for example a left shift (or `$shl`) + to a right shift (or `$shr`)? + + is the issue tied to specific parameters, widths, or values? + +- if you're familiar with C/C++ you might try to have a look at the source + code of the command that's failing + + + even if you can't fix the problem yourself, it can be very helpful for + anyone else investigating if you're able to identify where exactly the + issue is + + if you're using a fuzzer to find issues in Yosys, you should be prepared to + do this step + +.. warning:: + + In the event that you are unable to identify the root cause of a fuzzer + generated issue, **do not** open more than one issue at a time. You have no + way of being able to tell if multiple fuzzer generated issues are simply + different cases of the same problem, and opening multiple issues for the same + problem means more time is spent on triaging and diagnosing bug reports and + less on fixing the problem. If you are found to be doing this, your issues + may be closed without further investigation. + +- search `the existing issues`_ and see if someone has already made a bug report + + + this is where changing the design and finding the limits of what causes the + failure really comes in handy + + if you're more familiar with how the problem can arise, you may be able to + find a related issue more easily + + if an issue already exists for one case of the problem but you've found + other cases, you can comment on the issue and help get it solved + +.. _the existing issues: https://github.com/YosysHQ/yosys/issues + +- if there are no existing or related issues already, the check out the steps + for :ref:`using_yosys/bugpoint:creating an issue on github` + + Creating an issue on GitHub --------------------------- From 385d58562d171f86884247a1ae1971666362df82 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:58 +1200 Subject: [PATCH 20/51] Docs: Move verilog.rst to using_yosys Was previously in yosys_internals which is more developer focused, rather than user focused. --- docs/source/using_yosys/index.rst | 1 + docs/source/{yosys_internals => using_yosys}/verilog.rst | 2 -- docs/source/yosys_internals/index.rst | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) rename docs/source/{yosys_internals => using_yosys}/verilog.rst (99%) diff --git a/docs/source/using_yosys/index.rst b/docs/source/using_yosys/index.rst index 0ea91fae7..b243d431e 100644 --- a/docs/source/using_yosys/index.rst +++ b/docs/source/using_yosys/index.rst @@ -16,3 +16,4 @@ ways Yosys can interact with designs for a deeper investigation. synthesis/index more_scripting/index bugpoint + verilog diff --git a/docs/source/yosys_internals/verilog.rst b/docs/source/using_yosys/verilog.rst similarity index 99% rename from docs/source/yosys_internals/verilog.rst rename to docs/source/using_yosys/verilog.rst index d67553aa9..1701458f7 100644 --- a/docs/source/yosys_internals/verilog.rst +++ b/docs/source/using_yosys/verilog.rst @@ -1,8 +1,6 @@ Notes on Verilog support in Yosys ================================= -.. TODO:: how much of this is specific to the read_verilog and should be in :doc:`/yosys_internals/flow/verilog_frontend`? - Unsupported Verilog-2005 Features --------------------------------- diff --git a/docs/source/yosys_internals/index.rst b/docs/source/yosys_internals/index.rst index 3dd4224fa..483cc2bf8 100644 --- a/docs/source/yosys_internals/index.rst +++ b/docs/source/yosys_internals/index.rst @@ -38,5 +38,4 @@ as reference to implement a similar system in any language. formats/index extending_yosys/index techmap - verilog hashing From be999219a2972acb6d1931c6c589d8dd5f02383a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:58 +1200 Subject: [PATCH 21/51] docs: User-defined failures in bugpoint Also some other tidy up and clarifications. --- docs/source/using_yosys/bugpoint.rst | 47 +++++++++++++++++++--------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index abc6094a6..a74693fa3 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -36,12 +36,16 @@ Minimizing failing (or bugged) designs Minimizing RTLIL designs with bugpoint -------------------------------------- -- what is `bugpoint` +Yosys provides the `bugpoint` command for reducing a failing design to the +smallest portion of that design which still results in failure. While initially +developed for Yosys crashes, `bugpoint` can also be used for designs that lead +to non-fatal errors, or even failures in other tools that use the output of a +Yosys script. Can I use bugpoint? ~~~~~~~~~~~~~~~~~~~ -- `bugpoint`, only usable on platforms where Yosys can spawn executables +- only usable on platforms where Yosys can spawn executables + unavailable on emscripten and wasm + can test by running e.g. ``yosys -qqp '!echo test'`` @@ -67,6 +71,18 @@ Can I use bugpoint? + but, `bugpoint` itself calls the command/script with an RTLIL dump, so if it isn't reproducible from RTLIL then `bugpoint` won't work +- works with user-defined failures in scripts + + + e.g. `select` command with ``-assert-*`` option + + or `equiv_opt` + + can even call another tool with `exec` + + * useful for when Yosys is outputting an invalid design + * use the ``-expect-*`` options to ensure the script correctly returns the + failure state to `bugpoint` + * can call shell scripts with e.g. ``exec -expect-return 1 -- bash + `` + How do I use bugpoint? ~~~~~~~~~~~~~~~~~~~~~~ @@ -74,31 +90,34 @@ How do I use bugpoint? - follow `bugpoint` instructions - output design after `bugpoint` with `write_rtlil` - use ``-grep ""`` to only accept a minimized design that crashes -- with the ```` in the log file + with the ```` in the log file + only checks log file, will not match runtime errors + + can be particularly important for scripts with multiple commands to avoid + unrelated failures + + call e.g. ``yosys -qqp '' design.il`` or ``yosys -qqs + design.il`` to print only the error message(s) and use that (or a portion of + that) as the ```` to search for - ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those -- parts of the design to be removed (default is allow removing all) + parts of the design to be removed (default is to allow removing all) + use the ``bugpoint_keep`` attribute on objects you don't want to be removed, usually because you already know they are related to the failure + ``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in RTLIL, or ``setattr -set bugpoint_keep 1 [selection]`` from script -- ``-runner ""`` can allow running ``yosys`` wrapped by another -- command +- ``-runner ""`` can allow running ``yosys`` wrapped by another command - can also use `setenv` before `bugpoint` to set environment variables for -- the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) + the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) .. note:: - Using `setenv` in this way may not affect the current process as some - environment variables are only read on start up. For instance the - ``UBSAN_OPTIONS halt_on_error`` here only affects child processes, as does - the :doc:`Yosys environment variable` ``ABC``. While - others such as ``YOSYS_NOVERIFIC`` and ``HOME`` are evaluated each time they - are used. + Using `setenv` in this way may or may not affect the current process. For + instance the ``UBSAN_OPTIONS halt_on_error`` here only affects child + processes, as does the :doc:`Yosys environment variable` + ``ABC`` because they are only read on start-up. While others, such as + ``YOSYS_NOVERIFIC`` and ``HOME``, are evaluated each time they are used. What do I do with the minimized design? @@ -300,7 +319,7 @@ Identifying issues .. _the existing issues: https://github.com/YosysHQ/yosys/issues -- if there are no existing or related issues already, the check out the steps +- if there are no existing or related issues already, then check out the steps for :ref:`using_yosys/bugpoint:creating an issue on github` From 47c89a61df5c85f60ff738e0340554e583597570 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:58 +1200 Subject: [PATCH 22/51] Docs: What is bugpoint in paragraphs --- docs/source/using_yosys/bugpoint.rst | 82 +++++++++++++++++----------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index a74693fa3..ffefcb144 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -45,43 +45,64 @@ Yosys script. Can I use bugpoint? ~~~~~~~~~~~~~~~~~~~ -- only usable on platforms where Yosys can spawn executables +The first thing to be aware of is that `bugpoint` is not available in every +build of Yosys. Because the command works by invoking external processes, it +requires that Yosys can spawn executables. Notably this means `bugpoint` is not +able to be used in WebAssembly builds such as that available via YoWASP. The +easiest way to check your build of Yosys is by running ``yosys -qq -p '!echo +test'``. If this echoes ``test`` in the console, then `bugpoint` will work as +expected. If instead if it displays the text ``ERROR: Shell is not available.`` +then `bugpoint` will not work either. - + unavailable on emscripten and wasm - + can test by running e.g. ``yosys -qqp '!echo test'`` +.. note:: - * the ``-qq`` prevents Yosys from outputting non-error messages to the - console, so this will either display the text ``test``, or an error - message about ``Shell`` being unavailable - * check :ref:`getting_started/scripting_intro:script parsing` for more about - the ``-p`` option and common pitfalls + The console command ``yosys -qq -p '!echo test'`` uses the ``-qq`` flag to + prevent Yosys from outputting non-error messages to the console. The ``-p`` + option executes ``!echo test`` as a Yosys command, attempting to pass ``echo + test`` to the shell for execution. For more about the ``-p`` option and + common pitfalls, check out :ref:`getting_started/scripting_intro:script + parsing` in the :doc:`/getting_started/index` section. -- single command (``yosys -p '' design.il``) -- *or* multiple commands in a separate script file +.. TODO:: Add ``YOSYS_DISABLE_SPAWN`` check in ``bugpoint.cc``. - + script shouldn't load the design - + ``yosys -s design.il`` - + `minimize your script`_ to reduce the time needed by `bugpoint` + At least in the help text, so that ``yosys -h bugpoint`` will correctly + indicate if the command will work instead of this roundabout method. -- doesn't require design to be in RTLIL format +Next you need to separate loading the design from the failure point; you should +be aiming to reproduce the failure by running ``yosys -s -s +``. If the failure occurs while loading the design, such as during +`read_verilog` you will instead have to minimize the input design yourself. +Check out the instructions for :ref:`using_yosys/bugpoint:minimizing verilog +designs` below. - + can e.g. ``read_verilog ; prep -top ;`` before `bugpoint` - + this method may be more useful if you are trying to find a bug in your - design rather than Yosys - + but, `bugpoint` itself calls the command/script with an RTLIL dump, so if it - isn't reproducible from RTLIL then `bugpoint` won't work +The commands in ```` only need to be run once, while those in +```` will be run on each iteration of `bugpoint`. If you haven't +already, following the instructions for :ref:`using_yosys/bugpoint:minimizing +scripts` will also help with identifying exactly which commands are needed to +produce the failure and which can be safely moved to the loading script. -- works with user-defined failures in scripts +.. note:: - + e.g. `select` command with ``-assert-*`` option - + or `equiv_opt` - + can even call another tool with `exec` - - * useful for when Yosys is outputting an invalid design - * use the ``-expect-*`` options to ensure the script correctly returns the - failure state to `bugpoint` - * can call shell scripts with e.g. ``exec -expect-return 1 -- bash - `` + You should also be able to run the two scripts separately, calling first + ``yosys -s -p 'write_rtlil design.il'`` and then ``yosys -s + design.il``. If this doesn't work then it may mean that the + failure isn't reproducible from RTLIL and `bugpoint` won't work either. + +When we talk about failure points here, it doesn't just mean crashes or errors +in Yosys. The ```` script can also be a user-defined failure such +as the `select` command with one of the ``-assert-*`` options; an example where +this might be useful is when a pass is supposed to remove a certain kind of +cell, but there is some edge case where the cell is not removed. Another +use-case would be minimizing a design which fails with the `equiv_opt` command, +suggesting that the optimization in question alters the circuit in some way. + +It is even possible to use `bugpoint` with failures *external* to Yosys, by +making use of the `exec` command in ````. This is especially useful +when Yosys is outputting an invalid design, or when some other tool is +incompatible with the design. Be sure to use the ``exec -expect-*`` options so +that the pass/fail can be detected correctly. Multiple calls to `exec` can be +made, or even entire shell scripts (e.g. ``exec -expect-return 1 -- bash +``). How do I use bugpoint? @@ -142,6 +163,7 @@ What do I do with the minimized design? - check out :ref:`using_yosys/bugpoint:identifying issues` for more on what to do next + .. _minimize your script: Minimizing scripts @@ -188,7 +210,6 @@ Minimizing scripts opt -fast -full memory_map - - try ``write_rtlil ; design -reset; read_rtlil ;`` before the failure point @@ -348,7 +369,6 @@ Creating an issue on GitHub `yosys -p ': minimum sequence of commands;' min.v` - - alternatively can provide a single code-block which includes the minimized design as a "here document" followed by the sequence of commands which reproduce the error From 2c534c88282e6d04760b0a09a7b76b697d6530f4 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:59 +1200 Subject: [PATCH 23/51] Docs: How to use bugpoint paragraphs --- docs/source/using_yosys/bugpoint.rst | 98 ++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index ffefcb144..7d38124bf 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -104,33 +104,75 @@ that the pass/fail can be detected correctly. Multiple calls to `exec` can be made, or even entire shell scripts (e.g. ``exec -expect-return 1 -- bash ``). +Our final failure we can use with `bugpoint` is one returned by a wrapper +process, such as ``valgrind`` or ``timeout``. In this case you will be calling +something like `` yosys -s design.il``. Here, Yosys is +run under a wrapper process which checks for some failure state, like a memory +leak or excessive runtime. Note however that unlike the `exec` command, there +is currently no way to check the return status or messages from the wrapper +process; only a binary pass/fail. + How do I use bugpoint? ~~~~~~~~~~~~~~~~~~~~~~ -- follow `bugpoint` instructions -- output design after `bugpoint` with `write_rtlil` -- use ``-grep ""`` to only accept a minimized design that crashes - with the ```` in the log file +At this point you should have: - + only checks log file, will not match runtime errors - + can be particularly important for scripts with multiple commands to avoid - unrelated failures - + call e.g. ``yosys -qqp '' design.il`` or ``yosys -qqs - design.il`` to print only the error message(s) and use that (or a portion of - that) as the ```` to search for +1. either an RTLIL file containing the design to minimize (referred to here as + ``design.il``), or a Yosys script, ````, which loads it; and +2. a Yosys script, ````, which produces the failure and returns a + non-zero return status. -- ``-modules``, ``-ports``, ``-cells``, and ``-processes`` will enable those - parts of the design to be removed (default is to allow removing all) +Now call ``yosys -qq -s design.il`` and take note of the error(s) +that get printed. A template script, ````, is provided here which +you can use. Make sure to configure it with the correct filenames and use only +one of the methods to load the design. Fill in the ``-grep`` option with the +error message printed just before. If you are using a wrapper process for your +failure state, add the ``-runner ""`` option to the `bugpoint` call. +For more about the options available, check ``help bugpoint`` or +:doc:`/cmd/bugpoint`. - + use the ``bugpoint_keep`` attribute on objects you don't want to be - removed, usually because you already know they are related to the failure - + ``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in - RTLIL, or ``setattr -set bugpoint_keep 1 [selection]`` from script +.. code-block:: yoscrypt + :caption: ```` template script -- ``-runner ""`` can allow running ``yosys`` wrapped by another command -- can also use `setenv` before `bugpoint` to set environment variables for - the spawned processes (e.g. ``setenv UBSAN_OPTIONS halt_on_error=1``) + # Load design + read_rtlil design.il + ## OR + script + + # Call bugpoint with failure + bugpoint -script -grep "" + + # Save minimized design + write_rtlil min.il + +.. note:: + + Using ``-grep ""`` with `bugpoint` is optional, but helps to ensure + that the minimized design is reproducing the right error, especially when + ```` contains more than one command. Unfortunately this does not + work with runtime errors such as a ``SEGFAULT`` as it is only able to match + strings from the log file. + +.. TODO:: Consider checking ``run_command`` return value for runtime errors. + + Currently ``BugpointPass::run_yosys`` returns ``run_command(yosys_cmdline) == + 0``, so it shouldn't be too hard to add an option for it. Could also be + used with the ``-runner`` option, which might give it a bit more flexibility. + +By default, `bugpoint` is able to remove any part of the design. In order to +keep certain parts, for instance because you already know they are related to +the failure, you can use the ``bugpoint_keep`` attribute. This can be done with +``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in RTLIL, or +``setattr -set bugpoint_keep 1 [selection]`` from a Yosys script. It is also +possible to limit `bugpoint` to only removing certain *kinds* of objects, such +as only removing entire modules or cells (instances of modules). For more about +the options available, check ``help bugpoint`` or :doc:`/cmd/bugpoint`. + +In some situations, it may also be helpful to use `setenv` before `bugpoint` to +set environment variables for the spawned processes. An example of this is +``setenv UBSAN_OPTIONS halt_on_error=1`` for where you are trying to raise an +error on undefined behaviour but only want the child process to halt on error. .. note:: @@ -140,6 +182,24 @@ How do I use bugpoint? ``ABC`` because they are only read on start-up. While others, such as ``YOSYS_NOVERIFIC`` and ``HOME``, are evaluated each time they are used. +Once you have finished configuration, you can now run ``yosys ``. +The first thing `bugpoint` will do is test the input design fails. If it +doesn't, make sure you are using the right ``yosys`` executable; unless the +``-yosys`` option is provided, it will use whatever the shell defaults to. If +you are using the ``-runner`` option, try replacing the `bugpoint` command with +``write_rtlil test.il`` and then on a new line, ``! yosys -s + test.il`` to check it works as expected and returns a non-zero +status. + +Depending on the size of your design, and the length of your ````, +`bugpoint` may take some time; remember, it will run ``yosys -s `` +on each iteration of the design. The bigger the design, the more iterations. +The longer the ````, the longer each iteration will take. As the +design shrinks and `bugpoint` converges, each iteration should take less and +less time. Once all simplifications are exhausted and there are no more objects +that can be removed, the script will continue and the minimized design can be +saved. + What do I do with the minimized design? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 9fa1f76cf2b364a825d98a0b9ef672f059965a94 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:59 +1200 Subject: [PATCH 24/51] bugpoint.rst: Why context matters (bullets) --- docs/source/using_yosys/bugpoint.rst | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 7d38124bf..54559de32 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -230,6 +230,10 @@ Minimizing scripts ------------------ - reminder to back up original code before modifying it + + + sometimes over-minimizing scripts can hide underlying issues, so maintaining + the original context is important + - if you're using command line, convert it to a script - if you're using one of the :doc:`/using_yosys/synthesis/synth`, replace it with its contents @@ -370,6 +374,18 @@ Identifying issues to a right shift (or `$shr`)? + is the issue tied to specific parameters, widths, or values? +- if the failing command was part of a larger script, such as one of the + :doc:`/using_yosys/synthesis/synth`, you could try to follow the design + through the script + + + sometimes when a command is raising an error, you're seeing a symptom rather + than the underlying issue + + an earlier command may be putting the design in an invalid state which isn't + picked up until the error is raised + + check out :ref:`using_yosys/bugpoint:Why context matters` + + if you're using a fuzzer to find issues in Yosys, you should be prepared to + do this step + - if you're familiar with C/C++ you might try to have a look at the source code of the command that's failing @@ -404,6 +420,40 @@ Identifying issues for :ref:`using_yosys/bugpoint:creating an issue on github` +Why context matters +------------------- + +- if you did `minimize your script`_, and removed commands prior to the failure + to get a smaller design, try to work backwards and find which commands may + have contributed to the design failing +- especially important when the bug is happening inside of a ``synth_*`` script +- example (#4590) + + + say you did all the minimization and found that the error occurs when a call + to ``techmap -map +/xilinx/cells_map.v`` with ``MIN_MUX_INPUTS`` defined + parses a `$_MUX16_` with all inputs set to ``1'x`` + + step through the original script, calling `stat` after each step to find + when the `$_MUX16_` is added + + find that the `$_MUX16_` is introduced by a call to `muxcover`, but all the + inputs are defined, so calling `techmap` now works as expected + + * and from running `bugpoint` with the failing techmap you know that the + cell with index ``2297`` will fail, so you can now call ``select + top/*$2297`` to limit to just that cell, and optionally call ``design + -save pre_bug`` or ``write_rtlil -selected pre_bug.il`` to save this state + + + next you step through the remaining commands and call `dump` after each to + find when the inputs are disconnected + + find that ``opt -full`` has optimized away portions of the circuit, leading + to `opt_expr` setting the undriven mux inputs to ``x``, but failing to + remove the now unnecessary `$_MUX16_` + +- in this example, you might've stopped with the minimal reproducer, fixed the + bug in ``+/xilinx/cells_map.v``, and carried on +- but by following the failure back you've managed to identify a problem with + `opt_expr` that could be causing other problems either now or in the future + + Creating an issue on GitHub --------------------------- From e776f1dca20d406097e47b230e247a23b4d59ddf Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:59 +1200 Subject: [PATCH 25/51] bugpoint.rst: More paragraphs What do I do with the minimized design and (the first half of) Minimizing scripts --- docs/source/using_yosys/bugpoint.rst | 107 ++++++++++++++++++--------- 1 file changed, 74 insertions(+), 33 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 54559de32..80694fd2d 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -204,9 +204,10 @@ saved. What do I do with the minimized design? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- check minimized design still fails, especially if not using `write_rtlil` -- e.g. if you ran :ref:`bugpoint_script` below, then calling ``yosys -s - min.v`` should still fail in the same way +First off, check the minimized design still fails. This is especially important +if you're not using `write_rtlil` to output the minimized design. For example, +if you ran :ref:`bugpoint_script` below, then calling ``yosys -s +min.v`` should still fail in the same way. .. code-block:: yoscrypt :caption: example `bugpoint` minimizer @@ -216,12 +217,21 @@ What do I do with the minimized design? bugpoint -script write_verilog min.v -- `write_rtlil` is more reliable since `bugpoint` will have run that exact - code through the failing script; other ``write_*`` commands convert from the - RTLIL and then back again during the ``read_*`` which can result in - differences which mean the design no longer fails -- check out :ref:`using_yosys/bugpoint:identifying issues` for more on what to - do next +The `write_rtlil` command is generally more reliable, since `bugpoint` will have +run that exact code through the failing script. Other ``write_*`` commands +convert from the RTLIL and then back again during the ``read_*`` which can +result in differences which mean the design no longer fails. + +.. note:: + + Simply calling Yosys with the output of ``write_*``, as in ``yosys -s + min.v``, does not guarantee that the corresponding ``read_*`` + will be used. For more about this, refer to + :doc:`/using_yosys/more_scripting/load_design`, or load the design explicitly + with ``yosys -p 'read_verilog min.v' -s ``. + +Once you've verified the failure still happens, check out +:ref:`using_yosys/bugpoint:identifying issues` for more on what to do next. .. _minimize your script: @@ -229,19 +239,43 @@ What do I do with the minimized design? Minimizing scripts ------------------ -- reminder to back up original code before modifying it +If you're using a command line prompt, such as ``yosys -p 'synth_xilinx' -o +design.json design.v``, consider converting it to a script. It's generally much +easier to iterate over changes to a script in a file rather than one on the +command line, as well as being better for sharing with others. - + sometimes over-minimizing scripts can hide underlying issues, so maintaining - the original context is important +.. code-block:: yoscrypt + :caption: example script, ``script.ys``, for prompt ``yosys -p 'synth_xilinx' -o design.json design.v`` -- if you're using command line, convert it to a script -- if you're using one of the :doc:`/using_yosys/synthesis/synth`, replace it - with its contents + read_verilog design.v + synth_xilinx + write_json design.json - + can also do this piece-wise with the ``-run`` option - + e.g. replacing ``synth -top -lut`` with :ref:`replace_synth` - + the options ``-top -lut`` can be provided to each `synth` step, or - to just the step(s) where it is relevant, as done here +Next up you want to remove everything *after* the error occurs. Using the +``-L`` flag can help here, allowing you to specify a file to log to, such as +``yosys -L out.log -s script.ys``. Most commands will print a header message +when they begin; something like ``2.48. Executing HIERARCHY pass (managing +design hierarchy).`` The last header message will usually be the failing +command. There are some commands which don't print a header message, so you may +want to add ``echo on`` to the start of your script. The `echo` command echoes +each command executed, along with any arguments given to it. For the +`hierarchy` example above this might be ``yosys> hierarchy -check``. + +.. note:: + + It may also be helpful to use the `log` command to add messages which you can + then search for either in the terminal or the logfile. This can be quite + useful if your script contains script-passes, like the + :doc:`/using_yosys/synthesis/synth`, which call many sub-commands and you're + not sure exactly which script-pass is calling the failing command. + +If your final command calls sub-commands, replace it with its contents and +repeat the previous step. In the case of the +:doc:`/using_yosys/synthesis/synth`, as well as certain other script-passes, you +can use the ``-run`` option to simplify this. For example we can replace +``synth -top -lut`` with the :ref:`replace_synth`. The options ``-top + -lut`` can be provided to each `synth` step, or to just the step(s) where +it is relevant, as done here. .. code-block:: yoscrypt :caption: example replacement script for `synth` command @@ -252,20 +286,12 @@ Minimizing scripts synth -lut -run fine:check synth -run check: -- remove everything *after* the error occurs -- can use `log` command to print messages to help locate the failure point -- `echo` can also help (``echo on``) - - + if you used a ``-run`` option like in :ref:`replace_synth` above, you can - now replace the failing step with its contents and repeat the above if - needed - + checking the log should tell you the last command that ran which can make - this easier - + say we ran :ref:`replace_synth` and were able to remove the ``synth -run - check:`` and still got our error, then we check the log and we see the last - thing before the error was ``7.2. Executing MEMORY_MAP pass (converting - memories to logic and flip-flops).`` - + we can then update our script to the following: +Say we ran :ref:`replace_synth` and were able to remove the ``synth -run +check:`` and still got our error, then we check the log and we see the last +thing before the error was ``7.2. Executing MEMORY_MAP pass (converting memories +to logic and flip-flops)``. By checking the output of ``yosys -h synth`` (or the +`synth` help page) we can see that the `memory_map` pass is called in the +``fine`` step. We can then update our script to the following: .. code-block:: yoscrypt :caption: example replacement script for `synth` when `memory_map` is failing @@ -274,6 +300,21 @@ Minimizing scripts opt -fast -full memory_map +By giving `synth` the option ``-run :fine``, we are telling it to run from the +beginning of the script until the ``fine`` step, where we then give it the exact +commands to run. There are some cases where the commands given in the help +output are not an exact match for what is being run, but are instead a +simplification. If you find that replacing the script-pass with its contents +causes the error to disappear, or change, try calling the script-pass with +``echo on`` to see exactly what commands are being called and what options are +used. + +.. warning:: + + Before continuing further, *back up your code*. The following steps can + remove context and lead to over-minimizing scripts, hiding underlying issues. + Check out :ref:`using_yosys/bugpoint:Why context matters` to learn more. + - try ``write_rtlil ; design -reset; read_rtlil ;`` before the failure point From c75b07820ffbd5f317a88c94e7bae77d2e4e63f4 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:53:59 +1200 Subject: [PATCH 26/51] Docs: More bugpoint bullets More info for creating GitHub issues and the different sections. Discuss additional details that can be included as comments on the issue. Also mention Gists for large files (preferable to downloading a .txt). Add a warning about external plugins/tools. Also add a note to `load_design.rst` about `Frontend`s and `-f` command line option. --- docs/source/using_yosys/bugpoint.rst | 102 ++++++++++++++++-- .../more_scripting/load_design.rst | 4 + 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 80694fd2d..2316510cf 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -498,10 +498,27 @@ Why context matters Creating an issue on GitHub --------------------------- -- "Reproduction Steps" is ideally a code-block (starting and ending with triple - backquotes) containing the minimized design (Verilog or RTLIL), followed by a - code-block containing the minimized yosys script OR a command line call to - yosys with code-formatting (starting and ending with single backquotes) +- use the `bug report template`_ + +.. _bug report template: https://github.com/YosysHQ/yosys/issues/new?template=bug_report.yml + +- short title briefly describing the issue, e.g. + + techmap of wide mux with undefined inputs raises error during synth_xilinx + + + tells us what's happening ("raises error") + + gives the command affected (`techmap`) + + an overview of the input design ("wide mux with undefined inputs") + + and some context where it was found ("during `synth_xilinx`") + + +Reproduction Steps +~~~~~~~~~~~~~~~~~~ + +- ideally a code-block (starting and ending with triple backquotes) containing + the minimized design (Verilog or RTLIL), followed by a code-block containing + the minimized yosys script OR a command line call to yosys with + code-formatting (starting and ending with single backquotes) .. code-block:: markdown @@ -535,5 +552,78 @@ Creating an issue on GitHub # minimum sequence of commands ``` -- any environment variables or command line options should also be mentioned in - the "Reproduction Steps" +- any environment variables or command line options should also be mentioned +- if the problem occurs for a range of values/designs, what is that range +- if you're using an external tool, such as ``valgrind``, to detect the issue, + what version of that tool are you using and what options are you giving it + +.. warning:: + + Please try to avoid the use of any external plugins/tools in the reproduction + steps if they are not directly related to the issue being raised. This + includes frontend plugins such as GHDL or slang; use `write_rtlil` on the + minimized design instead. This also includes tools which provide a wrapper + around Yosys such as OpenLane; you should instead minimize your input and + reproduction steps to just the Yosys part. + +"Expected Behaviour" +~~~~~~~~~~~~~~~~~~~~ + +- if you have a similar design/script that doesn't give the error, include it + here as a reference +- if the bug is that an error *should* be raised but isn't, are there any other + commands with similar error messages + + +"Actual Behaviour" +~~~~~~~~~~~~~~~~~~ + +- any error messages go here +- any details relevant to the crash that were found with ``--trace`` or + ``--debug`` flags +- if you identified the point of failure in the source code, you could mention + it here, or as a comment below + + + if possible, use a permalink to the source on GitHub + + you can browse the source repository for a certain commit with the failure + and open the source file, select the relevant lines (click on the line + number for the first relevant line, then while holding shift click on the + line number for the last relevant line), click on the `...` that appears and + select "Copy permalink" + + should look something like + ``https://github.com/YosysHQ/yosys/blob//path/to/file#L139-L147`` + + clicking on "Preview" should reveal a code block containing the lines of + source specified, with a link to the source file at the given commit + + +Additional details +~~~~~~~~~~~~~~~~~~ + +- once you have created the issue, any additional details can be added as a + comment on that issue +- could include any additional context as to what you were doing when you first + encountered the bug +- was this issue discovered through the use of a fuzzer +- if you've minimized the script, consider including the `bugpoint` script you + used, or the original script, e.g. + +.. code-block:: markdown + + Minimized with + ``` + read_verilog design.v + # original sequence of commands prior to error + bugpoint -script -grep "" + write_rtlil min.il + ``` + + OR + + Minimized from + `yosys -p ': original sequence of commands to produce error;' design.v` + +- if you're able to, it may also help to share the original un-minimized design + + + if the design is too big for a comment, consider turning it into a `Gist`_ + +.. _Gist: https://gist.github.com/ diff --git a/docs/source/using_yosys/more_scripting/load_design.rst b/docs/source/using_yosys/more_scripting/load_design.rst index 1c597bdfc..7e417eff9 100644 --- a/docs/source/using_yosys/more_scripting/load_design.rst +++ b/docs/source/using_yosys/more_scripting/load_design.rst @@ -68,6 +68,10 @@ Yosys frontends + executed as multiple successive calls to the frontend +- compatible with ``-f`` command line option, e.g. ``yosys -f verilog + design.txt`` will use the `read_verilog` frontend with the input file + ``design.txt`` + - `verific` and `read` commands are technically not 'Frontends', but their behaviour is kept in sync From 113a6f6e525f3fc98bac64c8fd6b65ae08ff12dd Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:00 +1200 Subject: [PATCH 27/51] bugpoint.rst: yosys -h bugpoint does work I just missed that it only gets included in the makefile if `DISABLE_SPAWN` is set, because I was looking for the C define `YOSYS_DISABLE_SPAWN`. --- docs/source/using_yosys/bugpoint.rst | 35 ++++++++++++---------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 2316510cf..e7bbfa665 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -49,24 +49,10 @@ The first thing to be aware of is that `bugpoint` is not available in every build of Yosys. Because the command works by invoking external processes, it requires that Yosys can spawn executables. Notably this means `bugpoint` is not able to be used in WebAssembly builds such as that available via YoWASP. The -easiest way to check your build of Yosys is by running ``yosys -qq -p '!echo -test'``. If this echoes ``test`` in the console, then `bugpoint` will work as -expected. If instead if it displays the text ``ERROR: Shell is not available.`` -then `bugpoint` will not work either. - -.. note:: - - The console command ``yosys -qq -p '!echo test'`` uses the ``-qq`` flag to - prevent Yosys from outputting non-error messages to the console. The ``-p`` - option executes ``!echo test`` as a Yosys command, attempting to pass ``echo - test`` to the shell for execution. For more about the ``-p`` option and - common pitfalls, check out :ref:`getting_started/scripting_intro:script - parsing` in the :doc:`/getting_started/index` section. - -.. TODO:: Add ``YOSYS_DISABLE_SPAWN`` check in ``bugpoint.cc``. - - At least in the help text, so that ``yosys -h bugpoint`` will correctly - indicate if the command will work instead of this roundabout method. +easiest way to check your build of Yosys is by running ``yosys -h bugpoint``. If +Yosys displays the help text for `bugpoint` then it is available for use, but if +it instead prints "No such command or cell type: bugpoint", then `bugpoint` is +not available. Next you need to separate loading the design from the failure point; you should be aiming to reproduce the failure by running ``yosys -s -s @@ -315,6 +301,15 @@ used. remove context and lead to over-minimizing scripts, hiding underlying issues. Check out :ref:`using_yosys/bugpoint:Why context matters` to learn more. +When a problem is occurring many steps into a script, minimizing the design at +the start of the script isn't always enough to identify the cause of the issue. +Each extra step of the script can lead to larger sections of the input design +being needed for the specific problem to be preserved until it causes a crash. +So to find the smallest possible reproducer it can sometimes be helpful to +remove commands prior to the failure point. + + + - try ``write_rtlil ; design -reset; read_rtlil ;`` before the failure point @@ -588,8 +583,8 @@ Reproduction Steps + you can browse the source repository for a certain commit with the failure and open the source file, select the relevant lines (click on the line number for the first relevant line, then while holding shift click on the - line number for the last relevant line), click on the `...` that appears and - select "Copy permalink" + line number for the last relevant line), click on the ``...`` that appears + and select "Copy permalink" + should look something like ``https://github.com/YosysHQ/yosys/blob//path/to/file#L139-L147`` + clicking on "Preview" should reveal a code block containing the lines of From 20a573953cbb483aec74e4f66d0cabe3463679c3 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:00 +1200 Subject: [PATCH 28/51] bugpoint.rst: Minimizing scripts part 2: electric boogaloo --- docs/source/using_yosys/bugpoint.rst | 66 ++++++++++++++++++---------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index e7bbfa665..ca54bc8f0 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -308,38 +308,60 @@ being needed for the specific problem to be preserved until it causes a crash. So to find the smallest possible reproducer it can sometimes be helpful to remove commands prior to the failure point. +The simplest way to do this is by writing out the design, resetting the current +state, and reading back the design: +.. code-block:: yoscrypt -- try ``write_rtlil ; design -reset; read_rtlil ;`` before - the failure point + write_rtlil ; design -reset; read_rtlil ; - + ideally you now have a single command that is producing an error and can - `minimize your RTLIL`_ with the ```` output - + if not, try to move the write/reset/read earlier in the script until you can - reproduce the error - + if you have no idea where exactly you should put the reset, the best way is - to use a "binary search" type approach, reducing the possible options by - half after each attempt +In most cases, this can be inserted immediately before the failing command while +still producing the error, allowing you to `minimize your RTLIL`_ with the +```` output. For our previous example with `memory_map`, if +:ref:`map_reset` still gives the same error, then we should now be able to call +``yosys design.il -p 'memory_map'`` to reproduce it. - * for example, your script has 16 commands in it before failing on the 17th - * if resetting immediately before the 17th doesn't reproduce the error, try - between the 8th and 9th (8 is half of the total 16) - * if that produces the error then you can remove everything before the - `read_rtlil` and try reset again in the middle of what's left, making sure - to use a different name for the output file so that you don't overwrite - what you've already got - * if the error isn't produced then you need to go earlier still, so in this - case you would do between the 4th and 5th (4 is half of the previous 8) - * repeat this until you can't reduce the remaining commands any further +.. code-block:: yoscrypt + :caption: resetting the design immediately before failure + :name: map_reset + + synth -top -run :fine + opt -fast -full + write_rtlil design.il; design -reset; read_rtlil design.il; + memory_map + +If that doesn't give the error (or doesn't give the same error), then you should +try to move the write/reset/read earlier in the script until it does. If you +have no idea where exactly you should put the reset, the best way is to use a +"binary search" type approach, reducing the possible options by half after each +attempt. + + As an example, your script has 16 commands in it before failing on the 17th. + If resetting immediately before the 17th doesn't reproduce the error, try + between the 8th and 9th (8 is half of the total 16). If that produces the + error then you can remove everything before the `read_rtlil` and try reset + again in the middle of what's left, making sure to use a different name for + the output file so that you don't overwrite what you've already got. If the + error isn't produced then you need to go earlier still, so in this case you + would do between the 4th and 5th (4 is half of the previous 8). Repeat this + until you can't reduce the remaining commands any further. .. TODO:: is it possible to dump scratchpad? is there anything else in the yosys/design state that doesn't get included in `write_rtlil`? -- you can also try to remove or comment out commands prior to the failing - command; just because the first and last commands are needed doesn't mean that - every command between them is +A more conservative, but more involved, method is to remove or comment out +commands prior to the failing command. Each command, or group of commands, can +be disabled one at a time while checking if the error still occurs, eventually +giving the smallest subset of commands needed to take the original input through +to the error. The difficulty with this method is that depending on your design, +some commands may be necessary even if they aren't needed to reproduce the +error. For example, if your design includes ``process`` blocks, many commands +will fail unless you run the `proc` command. While this approach can do a +better job of maintaining context, it is often easier to *recover* the context +after the design has been minimized for producing the error. For more on +recovering context, checkout :ref:`using_yosys/bugpoint:Why context matters`. Minimizing Verilog designs From f0b4f7012e689fcf98b991075e3cf67365504d5b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:00 +1200 Subject: [PATCH 29/51] bugpoint.rst: Extra notes Move `yosys -h bugpoint` failure into a code-block to break up text. Same for the `exec -expect-return` example. TODOs on #5068 being merged. --- docs/source/using_yosys/bugpoint.rst | 36 ++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index ca54bc8f0..6f58e3d5b 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -24,6 +24,13 @@ Minimizing failing (or bugged) designs .. _iverilog: https://steveicarus.github.io/iverilog/ .. _verilator: https://www.veripool.org/verilator/ +- are there any warnings before the error (either immediately before or in an + earlier command) that could be related? +- does calling `check` before the failure give any errors or warnings? +- did you call `hierarchy` before the failure? + + + can you call ``hierarchy -check``? + - make sure to back up your code (design source and yosys script(s)) before making any modifications @@ -50,9 +57,15 @@ build of Yosys. Because the command works by invoking external processes, it requires that Yosys can spawn executables. Notably this means `bugpoint` is not able to be used in WebAssembly builds such as that available via YoWASP. The easiest way to check your build of Yosys is by running ``yosys -h bugpoint``. If -Yosys displays the help text for `bugpoint` then it is available for use, but if -it instead prints "No such command or cell type: bugpoint", then `bugpoint` is -not available. +Yosys displays the help text for `bugpoint` then it is available for use. + +.. code-block:: console + :caption: `bugpoint` is unavailable + + $ yosys -h bugpoint + + -- Running command `help bugpoint' -- + No such command or cell type: bugpoint Next you need to separate loading the design from the failure point; you should be aiming to reproduce the failure by running ``yosys -s -s @@ -87,8 +100,11 @@ making use of the `exec` command in ````. This is especially useful when Yosys is outputting an invalid design, or when some other tool is incompatible with the design. Be sure to use the ``exec -expect-*`` options so that the pass/fail can be detected correctly. Multiple calls to `exec` can be -made, or even entire shell scripts (e.g. ``exec -expect-return 1 -- bash -``). +made, or even entire shell scripts: + +.. code-block:: yoscrypt + + exec -expect-return 1 --bash Our final failure we can use with `bugpoint` is one returned by a wrapper process, such as ``valgrind`` or ``timeout``. In this case you will be calling @@ -98,6 +114,8 @@ leak or excessive runtime. Note however that unlike the `exec` command, there is currently no way to check the return status or messages from the wrapper process; only a binary pass/fail. +.. TODO:: above note pending updated bugpoint #5068 + How do I use bugpoint? ~~~~~~~~~~~~~~~~~~~~~~ @@ -140,11 +158,7 @@ For more about the options available, check ``help bugpoint`` or work with runtime errors such as a ``SEGFAULT`` as it is only able to match strings from the log file. -.. TODO:: Consider checking ``run_command`` return value for runtime errors. - - Currently ``BugpointPass::run_yosys`` returns ``run_command(yosys_cmdline) == - 0``, so it shouldn't be too hard to add an option for it. Could also be - used with the ``-runner`` option, which might give it a bit more flexibility. +.. TODO:: above note pending updated bugpoint #5068 By default, `bugpoint` is able to remove any part of the design. In order to keep certain parts, for instance because you already know they are related to @@ -177,6 +191,8 @@ you are using the ``-runner`` option, try replacing the `bugpoint` command with test.il`` to check it works as expected and returns a non-zero status. +.. TODO:: note on ``!`` (link to :ref:`getting_started/scripting_intro:script parsing`) + Depending on the size of your design, and the length of your ````, `bugpoint` may take some time; remember, it will run ``yosys -s `` on each iteration of the design. The bigger the design, the more iterations. From 65b75049aa5da7683e576a2c7165f30c1560e885 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:00 +1200 Subject: [PATCH 30/51] docs: Shuffling bug reporting guidelines Move the "creating an issue" section from bugpoint.rst to "reporting bugs" in `contributing.rst`. Fix link to `CONTRIBUTING.md`. Update `CONTRIBUTING.md` to refer to the bugpoint guide instead of the stack overflow guide. --- CONTRIBUTING.md | 16 +-- docs/source/using_yosys/bugpoint.rst | 136 +----------------- .../extending_yosys/contributing.rst | 136 +++++++++++++++++- 3 files changed, 144 insertions(+), 144 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c4376cc4..74f9ab10d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,14 +19,14 @@ much easier for someone to respond and help. ### Bug reports -Before you submit an issue, please have a search of the existing issues in case -one already exists. Making sure that you have a minimal, complete and -verifiable example (MVCE) is a great way to quickly check an existing issue -against a new one. Stack overflow has a guide on [how to create an -MVCE](https://stackoverflow.com/help/minimal-reproducible-example). The -[`bugpoint` -command](https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/bugpoint.html) -in Yosys can be helpful for this process. +Before you submit an issue, please check out the [how-to guide for +`bugpoint`](https://yosys.readthedocs.io/en/latest/using_yosys/bugpoint.html). +This guide will take you through the process of using the [`bugpoint` +command](https://yosys.readthedocs.io/en/latest/cmd/bugpoint.html) in Yosys to +produce a [minimal, complete and verifiable +example](https://stackoverflow.com/help/minimal-reproducible-example) (MVCE). +Providing an MVCE with your bug report drastically increases the likelihood that +someone will be able to help resolve your issue. # Using pull requests diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 6f58e3d5b..89c58a8f4 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -491,7 +491,7 @@ Identifying issues .. _the existing issues: https://github.com/YosysHQ/yosys/issues - if there are no existing or related issues already, then check out the steps - for :ref:`using_yosys/bugpoint:creating an issue on github` + for :ref:`yosys_internals/extending_yosys/contributing:reporting bugs` Why context matters @@ -526,137 +526,3 @@ Why context matters bug in ``+/xilinx/cells_map.v``, and carried on - but by following the failure back you've managed to identify a problem with `opt_expr` that could be causing other problems either now or in the future - - -Creating an issue on GitHub ---------------------------- - -- use the `bug report template`_ - -.. _bug report template: https://github.com/YosysHQ/yosys/issues/new?template=bug_report.yml - -- short title briefly describing the issue, e.g. - - techmap of wide mux with undefined inputs raises error during synth_xilinx - - + tells us what's happening ("raises error") - + gives the command affected (`techmap`) - + an overview of the input design ("wide mux with undefined inputs") - + and some context where it was found ("during `synth_xilinx`") - - -Reproduction Steps -~~~~~~~~~~~~~~~~~~ - -- ideally a code-block (starting and ending with triple backquotes) containing - the minimized design (Verilog or RTLIL), followed by a code-block containing - the minimized yosys script OR a command line call to yosys with - code-formatting (starting and ending with single backquotes) - -.. code-block:: markdown - - min.v - ```verilog - // minimized Verilog design - ``` - - min.ys - ``` - read_verilog min.v - # minimum sequence of commands to reproduce error - ``` - - OR - - `yosys -p ': minimum sequence of commands;' min.v` - -- alternatively can provide a single code-block which includes the minimized - design as a "here document" followed by the sequence of commands which - reproduce the error - - + see :doc:`/using_yosys/more_scripting/load_design` for more on heredocs. - -.. code-block:: markdown - - ``` - read_rtlil </path/to/file#L139-L147`` - + clicking on "Preview" should reveal a code block containing the lines of - source specified, with a link to the source file at the given commit - - -Additional details -~~~~~~~~~~~~~~~~~~ - -- once you have created the issue, any additional details can be added as a - comment on that issue -- could include any additional context as to what you were doing when you first - encountered the bug -- was this issue discovered through the use of a fuzzer -- if you've minimized the script, consider including the `bugpoint` script you - used, or the original script, e.g. - -.. code-block:: markdown - - Minimized with - ``` - read_verilog design.v - # original sequence of commands prior to error - bugpoint -script -grep "" - write_rtlil min.il - ``` - - OR - - Minimized from - `yosys -p ': original sequence of commands to produce error;' design.v` - -- if you're able to, it may also help to share the original un-minimized design - - + if the design is too big for a comment, consider turning it into a `Gist`_ - -.. _Gist: https://gist.github.com/ diff --git a/docs/source/yosys_internals/extending_yosys/contributing.rst b/docs/source/yosys_internals/extending_yosys/contributing.rst index 69258aa5f..70170fc48 100644 --- a/docs/source/yosys_internals/extending_yosys/contributing.rst +++ b/docs/source/yosys_internals/extending_yosys/contributing.rst @@ -7,7 +7,7 @@ Contributing to Yosys |CONTRIBUTING|_ file. .. |CONTRIBUTING| replace:: :file:`CONTRIBUTING.md` -.. _CONTRIBUTING: https://github.com/YosysHQ/yosys/CONTRIBUTING.md +.. _CONTRIBUTING: https://github.com/YosysHQ/yosys/blob/main/CONTRIBUTING.md Coding Style ------------ @@ -42,3 +42,137 @@ for implicit type casts, always use ``GetSize(foobar)`` instead of ``foobar.size()``. (``GetSize()`` is defined in :file:`kernel/yosys.h`) Use range-based for loops whenever applicable. + + +Reporting bugs +-------------- + +- use the `bug report template`_ + +.. _bug report template: https://github.com/YosysHQ/yosys/issues/new?template=bug_report.yml + +- short title briefly describing the issue, e.g. + + techmap of wide mux with undefined inputs raises error during synth_xilinx + + + tells us what's happening ("raises error") + + gives the command affected (`techmap`) + + an overview of the input design ("wide mux with undefined inputs") + + and some context where it was found ("during `synth_xilinx`") + + +Reproduction Steps +~~~~~~~~~~~~~~~~~~ + +- ideally a code-block (starting and ending with triple backquotes) containing + the minimized design (Verilog or RTLIL), followed by a code-block containing + the minimized yosys script OR a command line call to yosys with + code-formatting (starting and ending with single backquotes) + +.. code-block:: markdown + + min.v + ```verilog + // minimized Verilog design + ``` + + min.ys + ``` + read_verilog min.v + # minimum sequence of commands to reproduce error + ``` + + OR + + `yosys -p ': minimum sequence of commands;' min.v` + +- alternatively can provide a single code-block which includes the minimized + design as a "here document" followed by the sequence of commands which + reproduce the error + + + see :doc:`/using_yosys/more_scripting/load_design` for more on heredocs. + +.. code-block:: markdown + + ``` + read_rtlil </path/to/file#L139-L147`` + + clicking on "Preview" should reveal a code block containing the lines of + source specified, with a link to the source file at the given commit + + +Additional details +~~~~~~~~~~~~~~~~~~ + +- once you have created the issue, any additional details can be added as a + comment on that issue +- could include any additional context as to what you were doing when you first + encountered the bug +- was this issue discovered through the use of a fuzzer +- if you've minimized the script, consider including the `bugpoint` script you + used, or the original script, e.g. + +.. code-block:: markdown + + Minimized with + ``` + read_verilog design.v + # original sequence of commands prior to error + bugpoint -script -grep "" + write_rtlil min.il + ``` + + OR + + Minimized from + `yosys -p ': original sequence of commands to produce error;' design.v` + +- if you're able to, it may also help to share the original un-minimized design + + + if the design is too big for a comment, consider turning it into a `Gist`_ + +.. _Gist: https://gist.github.com/ From c47b533a3da6a6938ea735a19f6c2ba578f80a30 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:01 +1200 Subject: [PATCH 31/51] docs: Split bugpoint.rst into user/developer Minimizing scripts (and more generally identifying root cause) isn't necessary for regular bug reports. Rather, it can be useful for developers working on *fixing* bugs, and also for fuzzers to avoid spam. Minor adjustments to `bugpoint.rst`. Add note to `advanced_bugpoint.rst` about primitives when minimizing scripts. --- docs/source/using_yosys/bugpoint.rst | 225 +----------------- .../extending_yosys/advanced_bugpoint.rst | 208 ++++++++++++++++ .../yosys_internals/extending_yosys/index.rst | 1 + 3 files changed, 217 insertions(+), 217 deletions(-) create mode 100644 docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 89c58a8f4..82eab3cfa 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -38,8 +38,6 @@ Minimizing failing (or bugged) designs error while trying to debug it -.. _minimize your RTLIL: - Minimizing RTLIL designs with bugpoint -------------------------------------- @@ -74,12 +72,6 @@ be aiming to reproduce the failure by running ``yosys -s -s Check out the instructions for :ref:`using_yosys/bugpoint:minimizing verilog designs` below. -The commands in ```` only need to be run once, while those in -```` will be run on each iteration of `bugpoint`. If you haven't -already, following the instructions for :ref:`using_yosys/bugpoint:minimizing -scripts` will also help with identifying exactly which commands are needed to -produce the failure and which can be safely moved to the loading script. - .. note:: You should also be able to run the two scripts separately, calling first @@ -236,150 +228,6 @@ Once you've verified the failure still happens, check out :ref:`using_yosys/bugpoint:identifying issues` for more on what to do next. -.. _minimize your script: - -Minimizing scripts ------------------- - -If you're using a command line prompt, such as ``yosys -p 'synth_xilinx' -o -design.json design.v``, consider converting it to a script. It's generally much -easier to iterate over changes to a script in a file rather than one on the -command line, as well as being better for sharing with others. - -.. code-block:: yoscrypt - :caption: example script, ``script.ys``, for prompt ``yosys -p 'synth_xilinx' -o design.json design.v`` - - read_verilog design.v - synth_xilinx - write_json design.json - -Next up you want to remove everything *after* the error occurs. Using the -``-L`` flag can help here, allowing you to specify a file to log to, such as -``yosys -L out.log -s script.ys``. Most commands will print a header message -when they begin; something like ``2.48. Executing HIERARCHY pass (managing -design hierarchy).`` The last header message will usually be the failing -command. There are some commands which don't print a header message, so you may -want to add ``echo on`` to the start of your script. The `echo` command echoes -each command executed, along with any arguments given to it. For the -`hierarchy` example above this might be ``yosys> hierarchy -check``. - -.. note:: - - It may also be helpful to use the `log` command to add messages which you can - then search for either in the terminal or the logfile. This can be quite - useful if your script contains script-passes, like the - :doc:`/using_yosys/synthesis/synth`, which call many sub-commands and you're - not sure exactly which script-pass is calling the failing command. - -If your final command calls sub-commands, replace it with its contents and -repeat the previous step. In the case of the -:doc:`/using_yosys/synthesis/synth`, as well as certain other script-passes, you -can use the ``-run`` option to simplify this. For example we can replace -``synth -top -lut`` with the :ref:`replace_synth`. The options ``-top - -lut`` can be provided to each `synth` step, or to just the step(s) where -it is relevant, as done here. - -.. code-block:: yoscrypt - :caption: example replacement script for `synth` command - :name: replace_synth - - synth -top -run :coarse - synth -lut -run coarse:fine - synth -lut -run fine:check - synth -run check: - -Say we ran :ref:`replace_synth` and were able to remove the ``synth -run -check:`` and still got our error, then we check the log and we see the last -thing before the error was ``7.2. Executing MEMORY_MAP pass (converting memories -to logic and flip-flops)``. By checking the output of ``yosys -h synth`` (or the -`synth` help page) we can see that the `memory_map` pass is called in the -``fine`` step. We can then update our script to the following: - -.. code-block:: yoscrypt - :caption: example replacement script for `synth` when `memory_map` is failing - - synth -top -run :fine - opt -fast -full - memory_map - -By giving `synth` the option ``-run :fine``, we are telling it to run from the -beginning of the script until the ``fine`` step, where we then give it the exact -commands to run. There are some cases where the commands given in the help -output are not an exact match for what is being run, but are instead a -simplification. If you find that replacing the script-pass with its contents -causes the error to disappear, or change, try calling the script-pass with -``echo on`` to see exactly what commands are being called and what options are -used. - -.. warning:: - - Before continuing further, *back up your code*. The following steps can - remove context and lead to over-minimizing scripts, hiding underlying issues. - Check out :ref:`using_yosys/bugpoint:Why context matters` to learn more. - -When a problem is occurring many steps into a script, minimizing the design at -the start of the script isn't always enough to identify the cause of the issue. -Each extra step of the script can lead to larger sections of the input design -being needed for the specific problem to be preserved until it causes a crash. -So to find the smallest possible reproducer it can sometimes be helpful to -remove commands prior to the failure point. - -The simplest way to do this is by writing out the design, resetting the current -state, and reading back the design: - -.. code-block:: yoscrypt - - write_rtlil ; design -reset; read_rtlil ; - -In most cases, this can be inserted immediately before the failing command while -still producing the error, allowing you to `minimize your RTLIL`_ with the -```` output. For our previous example with `memory_map`, if -:ref:`map_reset` still gives the same error, then we should now be able to call -``yosys design.il -p 'memory_map'`` to reproduce it. - -.. code-block:: yoscrypt - :caption: resetting the design immediately before failure - :name: map_reset - - synth -top -run :fine - opt -fast -full - write_rtlil design.il; design -reset; read_rtlil design.il; - memory_map - -If that doesn't give the error (or doesn't give the same error), then you should -try to move the write/reset/read earlier in the script until it does. If you -have no idea where exactly you should put the reset, the best way is to use a -"binary search" type approach, reducing the possible options by half after each -attempt. - - As an example, your script has 16 commands in it before failing on the 17th. - If resetting immediately before the 17th doesn't reproduce the error, try - between the 8th and 9th (8 is half of the total 16). If that produces the - error then you can remove everything before the `read_rtlil` and try reset - again in the middle of what's left, making sure to use a different name for - the output file so that you don't overwrite what you've already got. If the - error isn't produced then you need to go earlier still, so in this case you - would do between the 4th and 5th (4 is half of the previous 8). Repeat this - until you can't reduce the remaining commands any further. - -.. TODO:: is it possible to dump scratchpad? - - is there anything else in the yosys/design state that doesn't get included in - `write_rtlil`? - -A more conservative, but more involved, method is to remove or comment out -commands prior to the failing command. Each command, or group of commands, can -be disabled one at a time while checking if the error still occurs, eventually -giving the smallest subset of commands needed to take the original input through -to the error. The difficulty with this method is that depending on your design, -some commands may be necessary even if they aren't needed to reproduce the -error. For example, if your design includes ``process`` blocks, many commands -will fail unless you run the `proc` command. While this approach can do a -better job of maintaining context, it is often easier to *recover* the context -after the design has been minimized for producing the error. For more on -recovering context, checkout :ref:`using_yosys/bugpoint:Why context matters`. - - Minimizing Verilog designs -------------------------- @@ -393,9 +241,9 @@ Minimizing Verilog designs + if the problem is parameter specific you may be able to change the default parameters so that they match the problematic configuration -- as with `minimize your script`_, if you have no idea what is or is not - relevant, try to follow a "binary search" type approach where you remove (or - comment out) roughly half of what's left at a time +- if you have no idea what is or is not relevant, try to follow a "binary + search" type approach where you remove (or comment out) roughly half of what's + left at a time - focusing on one type of object at a time simplifies the process, removing as many as you can until the error disappears if any of the remaining objects are removed @@ -448,36 +296,13 @@ Identifying issues to a right shift (or `$shr`)? + is the issue tied to specific parameters, widths, or values? -- if the failing command was part of a larger script, such as one of the - :doc:`/using_yosys/synthesis/synth`, you could try to follow the design - through the script - - + sometimes when a command is raising an error, you're seeing a symptom rather - than the underlying issue - + an earlier command may be putting the design in an invalid state which isn't - picked up until the error is raised - + check out :ref:`using_yosys/bugpoint:Why context matters` - + if you're using a fuzzer to find issues in Yosys, you should be prepared to - do this step - -- if you're familiar with C/C++ you might try to have a look at the source - code of the command that's failing - - + even if you can't fix the problem yourself, it can be very helpful for - anyone else investigating if you're able to identify where exactly the - issue is - + if you're using a fuzzer to find issues in Yosys, you should be prepared to - do this step - .. warning:: - In the event that you are unable to identify the root cause of a fuzzer - generated issue, **do not** open more than one issue at a time. You have no - way of being able to tell if multiple fuzzer generated issues are simply - different cases of the same problem, and opening multiple issues for the same - problem means more time is spent on triaging and diagnosing bug reports and - less on fixing the problem. If you are found to be doing this, your issues - may be closed without further investigation. + If you are using a fuzzer to find bugs, follow the instructions for + :doc:`/yosys_internals/extending_yosys/advanced_bugpoint`. **Do not** open + more than one fuzzer generated issue at a time if you can not identify the + root cause. If you are found to be doing this, your issues may be closed + without further investigation. - search `the existing issues`_ and see if someone has already made a bug report @@ -492,37 +317,3 @@ Identifying issues - if there are no existing or related issues already, then check out the steps for :ref:`yosys_internals/extending_yosys/contributing:reporting bugs` - - -Why context matters -------------------- - -- if you did `minimize your script`_, and removed commands prior to the failure - to get a smaller design, try to work backwards and find which commands may - have contributed to the design failing -- especially important when the bug is happening inside of a ``synth_*`` script -- example (#4590) - - + say you did all the minimization and found that the error occurs when a call - to ``techmap -map +/xilinx/cells_map.v`` with ``MIN_MUX_INPUTS`` defined - parses a `$_MUX16_` with all inputs set to ``1'x`` - + step through the original script, calling `stat` after each step to find - when the `$_MUX16_` is added - + find that the `$_MUX16_` is introduced by a call to `muxcover`, but all the - inputs are defined, so calling `techmap` now works as expected - - * and from running `bugpoint` with the failing techmap you know that the - cell with index ``2297`` will fail, so you can now call ``select - top/*$2297`` to limit to just that cell, and optionally call ``design - -save pre_bug`` or ``write_rtlil -selected pre_bug.il`` to save this state - - + next you step through the remaining commands and call `dump` after each to - find when the inputs are disconnected - + find that ``opt -full`` has optimized away portions of the circuit, leading - to `opt_expr` setting the undriven mux inputs to ``x``, but failing to - remove the now unnecessary `$_MUX16_` - -- in this example, you might've stopped with the minimal reproducer, fixed the - bug in ``+/xilinx/cells_map.v``, and carried on -- but by following the failure back you've managed to identify a problem with - `opt_expr` that could be causing other problems either now or in the future diff --git a/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst b/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst new file mode 100644 index 000000000..32d334581 --- /dev/null +++ b/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst @@ -0,0 +1,208 @@ +Identifying the root cause of bugs +================================== + +This document references Yosys internals and is intended for people interested +in solving or investigating Yosys bugs. This also applies if you are using a +fuzzing tool; fuzzers have a tendency to find many variations of the same bug, +so identifying the root cause is important for avoiding issue spam. + +- if the failing command was part of a larger script, such as one of the + :doc:`/using_yosys/synthesis/synth`, you could try to follow the design + through the script + + + sometimes when a command is raising an error, you're seeing a symptom rather + than the underlying issue + + an earlier command may be putting the design in an invalid state which isn't + picked up until the error is raised + + check out :ref:`yosys_internals/extending_yosys/advanced_bugpoint:why context matters` + +- if you're familiar with C/C++ you might try to have a look at the source + code of the command that's failing + + + even if you can't fix the problem yourself, it can be very helpful for + anyone else investigating if you're able to identify where exactly the + issue is + +Minimizing scripts +------------------ + +.. TODO:: disclaimer this is intended as advanced usage, and generally not necessary for bug reports + +If you're using a command line prompt, such as ``yosys -p 'synth_xilinx' -o +design.json design.v``, consider converting it to a script. It's generally much +easier to iterate over changes to a script in a file rather than one on the +command line, as well as being better for sharing with others. + +.. code-block:: yoscrypt + :caption: example script, ``script.ys``, for prompt ``yosys -p 'synth_xilinx' -o design.json design.v`` + + read_verilog design.v + synth_xilinx + write_json design.json + +Next up you want to remove everything *after* the error occurs. Using the +``-L`` flag can help here, allowing you to specify a file to log to, such as +``yosys -L out.log -s script.ys``. Most commands will print a header message +when they begin; something like ``2.48. Executing HIERARCHY pass (managing +design hierarchy).`` The last header message will usually be the failing +command. There are some commands which don't print a header message, so you may +want to add ``echo on`` to the start of your script. The `echo` command echoes +each command executed, along with any arguments given to it. For the +`hierarchy` example above this might be ``yosys> hierarchy -check``. + +.. note:: + + It may also be helpful to use the `log` command to add messages which you can + then search for either in the terminal or the logfile. This can be quite + useful if your script contains script-passes, like the + :doc:`/using_yosys/synthesis/synth`, which call many sub-commands and you're + not sure exactly which script-pass is calling the failing command. + +If your final command calls sub-commands, replace it with its contents and +repeat the previous step. In the case of the +:doc:`/using_yosys/synthesis/synth`, as well as certain other script-passes, you +can use the ``-run`` option to simplify this. For example we can replace +``synth -top -lut`` with the :ref:`replace_synth`. The options ``-top + -lut`` can be provided to each `synth` step, or to just the step(s) where +it is relevant, as done here. + +.. code-block:: yoscrypt + :caption: example replacement script for `synth` command + :name: replace_synth + + synth -top -run :coarse + synth -lut -run coarse:fine + synth -lut -run fine:check + synth -run check: + +Say we ran :ref:`replace_synth` and were able to remove the ``synth -run +check:`` and still got our error, then we check the log and we see the last +thing before the error was ``7.2. Executing MEMORY_MAP pass (converting memories +to logic and flip-flops)``. By checking the output of ``yosys -h synth`` (or the +`synth` help page) we can see that the `memory_map` pass is called in the +``fine`` step. We can then update our script to the following: + +.. code-block:: yoscrypt + :caption: example replacement script for `synth` when `memory_map` is failing + + synth -top -run :fine + opt -fast -full + memory_map + +By giving `synth` the option ``-run :fine``, we are telling it to run from the +beginning of the script until the ``fine`` step, where we then give it the exact +commands to run. There are some cases where the commands given in the help +output are not an exact match for what is being run, but are instead a +simplification. If you find that replacing the script-pass with its contents +causes the error to disappear, or change, try calling the script-pass with +``echo on`` to see exactly what commands are being called and what options are +used. + +.. warning:: + + Before continuing further, *back up your code*. The following steps can + remove context and lead to over-minimizing scripts, hiding underlying issues. + Check out :ref:`yosys_internals/extending_yosys/advanced_bugpoint:Why + context matters` to learn more. + +When a problem is occurring many steps into a script, minimizing the design at +the start of the script isn't always enough to identify the cause of the issue. +Each extra step of the script can lead to larger sections of the input design +being needed for the specific problem to be preserved until it causes a crash. +So to find the smallest possible reproducer it can sometimes be helpful to +remove commands prior to the failure point. + +The simplest way to do this is by writing out the design, resetting the current +state, and reading back the design: + +.. code-block:: yoscrypt + + write_rtlil ; design -reset; read_rtlil ; + +In most cases, this can be inserted immediately before the failing command while +still producing the error, allowing you to :ref:`minimize your +RTLIL` with the +```` output. For our previous example with `memory_map`, if +:ref:`map_reset` still gives the same error, then we should now be able to call +``yosys design.il -p 'memory_map'`` to reproduce it. + +.. code-block:: yoscrypt + :caption: resetting the design immediately before failure + :name: map_reset + + synth -top -run :fine + opt -fast -full + write_rtlil design.il; design -reset; read_rtlil design.il; + memory_map + +If that doesn't give the error (or doesn't give the same error), then you should +try to move the write/reset/read earlier in the script until it does. If you +have no idea where exactly you should put the reset, the best way is to use a +"binary search" type approach, reducing the possible options by half after each +attempt. + +.. note:: + + By default, `write_rtlil` doesn't include platform specific IP blocks and + other primitive cell models which are typically loaded with a ``read_verilog + -lib`` command at the start of the synthesis script. You may have to + duplicate these commands *after* the call to ``design -reset``. It is also + possible to write out *everything* with ``select =*; write_rtlil -selected + ``. + +As an example, your script has 16 commands in it before failing on the 17th. If +resetting immediately before the 17th doesn't reproduce the error, try between +the 8th and 9th (8 is half of the total 16). If that produces the error then +you can remove everything before the `read_rtlil` and try reset again in the +middle of what's left, making sure to use a different name for the output file +so that you don't overwrite what you've already got. If the error isn't +produced then you need to go earlier still, so in this case you would do between +the 4th and 5th (4 is half of the previous 8). Repeat this until you can't +reduce the remaining commands any further. + +A more conservative, but more involved, method is to remove or comment out +commands prior to the failing command. Each command, or group of commands, can +be disabled one at a time while checking if the error still occurs, eventually +giving the smallest subset of commands needed to take the original input through +to the error. The difficulty with this method is that depending on your design, +some commands may be necessary even if they aren't needed to reproduce the +error. For example, if your design includes ``process`` blocks, many commands +will fail unless you run the `proc` command. While this approach can do a +better job of maintaining context, it is often easier to *recover* the context +after the design has been minimized for producing the error. For more on +recovering context, checkout +:ref:`yosys_internals/extending_yosys/advanced_bugpoint:Why context matters`. + + +Why context matters +------------------- + +- if you did minimized your script, and removed commands prior to the failure + to get a smaller design, try to work backwards and find which commands may + have contributed to the design failing +- especially important when the bug is happening inside of a ``synth_*`` script +- example (#4590) + + + say you did all the minimization and found that the error occurs when a call + to ``techmap -map +/xilinx/cells_map.v`` with ``MIN_MUX_INPUTS`` defined + parses a `$_MUX16_` with all inputs set to ``1'x`` + + step through the original script, calling `stat` after each step to find + when the `$_MUX16_` is added + + find that the `$_MUX16_` is introduced by a call to `muxcover`, but all the + inputs are defined, so calling `techmap` now works as expected + + * and from running `bugpoint` with the failing techmap you know that the + cell with index ``2297`` will fail, so you can now call ``select + top/*$2297`` to limit to just that cell, and optionally call ``design + -save pre_bug`` or ``write_rtlil -selected pre_bug.il`` to save this state + + + next you step through the remaining commands and call `dump` after each to + find when the inputs are disconnected + + find that ``opt -full`` has optimized away portions of the circuit, leading + to `opt_expr` setting the undriven mux inputs to ``x``, but failing to + remove the now unnecessary `$_MUX16_` + +- in this example, you might've stopped with the minimal reproducer, fixed the + bug in ``+/xilinx/cells_map.v``, and carried on +- but by following the failure back you've managed to identify a problem with + `opt_expr` that could be causing other problems either now or in the future diff --git a/docs/source/yosys_internals/extending_yosys/index.rst b/docs/source/yosys_internals/extending_yosys/index.rst index 4ee21517b..72843ecd6 100644 --- a/docs/source/yosys_internals/extending_yosys/index.rst +++ b/docs/source/yosys_internals/extending_yosys/index.rst @@ -11,6 +11,7 @@ of interest for developers looking to customise Yosys builds. extensions build_verific functional_ir + advanced_bugpoint contributing test_suites From aa6c6fd2832bfb59acf84e7822aea919b2ac2440 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:01 +1200 Subject: [PATCH 32/51] bugpoint.rst: Some paragraphs on verilog --- docs/source/using_yosys/bugpoint.rst | 57 ++++++++++++++++++---------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 82eab3cfa..a2d0b901e 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -231,29 +231,47 @@ Once you've verified the failure still happens, check out Minimizing Verilog designs -------------------------- -- manual process -- made easier if the error message is able to identify the source line or name - of the object -- reminder to back up original code before modifying it -- if a specific module is causing the problem, try to set that as the top - module, you can then remove +Unlike RTLIL designs where we can use `bugpoint`, minimizing Verilog designs is +a much more manual, iterative process. Be sure to check any errors or warnings +for messages that might identify source lines or object names that might be +causing the failure, and back up your source code before modifying it. At any +point in the process, you can check for anything that is unused or totally +disconnected (ports, wires, etc) and remove them too. - + if the problem is parameter specific you may be able to change the default - parameters so that they match the problematic configuration +.. note:: -- if you have no idea what is or is not relevant, try to follow a "binary - search" type approach where you remove (or comment out) roughly half of what's - left at a time -- focusing on one type of object at a time simplifies the process, removing as - many as you can until the error disappears if any of the remaining objects are - removed -- periodically check if anything is totally disconnected (ports, wires, etc), if - it is then it can be removed too -- start by removing cells (instances of modules) + If a specific module is causing the problem, try to set that as the top + module instead. Any parameters should have their default values changed to + match the failing usage. - + if a module has no more instances, remove it entirely +As a rule of thumb, try to split things roughly in half at each step; similar to +a "binary search". If you have 10 cells (instances of modules) in your top +module, and have no idea what is causing the issue, split them into two groups +of 5 cells. For each group of cells, try remove them and see if the failure +still happens. If the error still occurs with the first group removed, but +disappears when the second group is removed, then the first group can be safely +removed. If a module has no more instances, remove it entirely. Repeat this +for each remaining group of cells until each group only has 1 cell in it and no +more cells can be removed without making the error disappear. You can also +repeat this for each module still in your design. + +After minimizing the number of cells, do the same for the process blocks in your +top module. And again for any generate blocks and combinational blocks. +Remember to check for any ports or signals which are no longer used and remove +those too. Any signals which are written but never read can also be removed. + +.. note:: + + Depending on where the design is failing, there are some commands which may + help in identifying unused objects in the design. `hierarchy` will identify + which modules are used and which are not, but check for `$paramod` modules + before removing unused ones. ``debug clean`` will list all unused wires in + each module, as well as unused cells which were automatically generated + (giving the line number of the source that generated them). Adding the + ``-purge`` flag will also include named wires that would normally be ignored + by `clean`. Though when there are large numbers of unused wires it is often + easier to just delete sections of the code and see what happens. -- then processes - try to remove or reduce assignments and operations + are there any wires/registers which get read but never written? @@ -267,6 +285,7 @@ Minimizing Verilog designs ``'0`` + if you have enable or reset logic, does the error still happen without that? + can you reduce an ``if .. else`` to a single case? + + can you remove states from a ``case`` block? - if you're planning to share the minimized code: From 6b7756b67a3226cc84d7473add7167d771b3ad30 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:01 +1200 Subject: [PATCH 33/51] bugpoint.rst: Finish paragraphs Update text to assume bugpoint PR changes. --- docs/source/using_yosys/bugpoint.rst | 221 ++++++++++++++++----------- 1 file changed, 131 insertions(+), 90 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index a2d0b901e..38a978695 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -1,41 +1,62 @@ Minimizing failing (or bugged) designs ====================================== -- how to guide -- assumes knowledge and familiarity with Yosys -- something is wrong with your design OR something is wrong with Yosys +.. TODO:: pending merge of https://github.com/YosysHQ/yosys/pull/5068 - + how to work out which +This document is a how-to guide for reducing problematic designs to the bare +minimum needed for reproducing the issue. This is a Yosys specific alternative +to the Stack Overflow article: `How to create a Minimal, Reproducible Example`_, +and is intended to help when there's something wrong with your design, or with +Yosys itself. -- *read* the error message -- is it a Yosys error? (starts with ERROR:) +.. _How to create a Minimal, Reproducible Example: https://stackoverflow.com/help/minimal-reproducible-example - + does it give you a line number from your design +.. note:: -- is it a runtime error, e.g. SEGFAULT -- are you using the latest release of Yosys + This guide assumes a moderate degree of familiarity with Yosys and requires + some amount of problem solving ability. - + has your problem already been fixed -- is your input design valid? +Before you start +---------------- - + if you're using Verilog, try load it with `iverilog`_ or `verilator`_ +The first (and often overlooked) step, is to check for and *read* any error +messages or warnings. Passing the ``-q`` flag when running Yosys will make it +so that only warnings and error messages are written to the console. Don't just +read the last message either, there may be warnings that indicate a problem +before it happens. While some things may only be regarded as warnings, such as +multiple drivers for the same signal or logic loops, these can cause problems in +some synthesis flows but not others. + +A Yosys error (one that starts with ``ERROR:``) may give you a line number from +your design, or the name of the object causing issues. If so, you may already +have enough information to resolve the problem, or at least understand why it's +happening. + +.. note:: + + If you're not already, try using the latest version from the `Yosys GitHub`_. + You may find that your issue has already been fixed! And even if it isn't, + testing with two different versions is a good way to ensure reproducibility. + +.. _Yosys GitHub: https://github.com/YosysHQ/yosys + +Another thing to be aware of is that Yosys generally doesn't perform rigorous +checking of input designs to ensure they are valid. This is especially true for +the `read_verilog` frontend. It is instead recommended that you try load it +with `iverilog`_ or `verilator`_ first, as an invalid design can often lead to +unexpected issues. .. _iverilog: https://steveicarus.github.io/iverilog/ .. _verilator: https://www.veripool.org/verilator/ -- are there any warnings before the error (either immediately before or in an - earlier command) that could be related? -- does calling `check` before the failure give any errors or warnings? -- did you call `hierarchy` before the failure? - - + can you call ``hierarchy -check``? - -- make sure to back up your code (design source and yosys script(s)) before - making any modifications - - + even if the code itself isn't important, this can help avoid "losing" the - error while trying to debug it +If you're using a custom synthesis script, try take a bit of time to figure out +which command is failing. Calling ``echo on`` at the start of your script will +`echo` each command executed; the last echo before the error should then be +where the error has come from. Check the help message for the failing command; +does it indicate limited support, or mention some other command that needs to be +run first? You can also try to call `check` and/or ``hierarchy -check`` before +the failure to see if they report and errors or warnings. Minimizing RTLIL designs with bugpoint @@ -47,6 +68,12 @@ developed for Yosys crashes, `bugpoint` can also be used for designs that lead to non-fatal errors, or even failures in other tools that use the output of a Yosys script. +.. note:: + + Make sure to back up your code (design source and yosys script(s)) before + making any modifications. Even if the code itself isn't important, this can + help avoid "losing" the error while trying to debug it. + Can I use bugpoint? ~~~~~~~~~~~~~~~~~~~ @@ -102,11 +129,7 @@ Our final failure we can use with `bugpoint` is one returned by a wrapper process, such as ``valgrind`` or ``timeout``. In this case you will be calling something like `` yosys -s design.il``. Here, Yosys is run under a wrapper process which checks for some failure state, like a memory -leak or excessive runtime. Note however that unlike the `exec` command, there -is currently no way to check the return status or messages from the wrapper -process; only a binary pass/fail. - -.. TODO:: above note pending updated bugpoint #5068 +leak or excessive runtime. How do I use bugpoint? @@ -125,8 +148,6 @@ you can use. Make sure to configure it with the correct filenames and use only one of the methods to load the design. Fill in the ``-grep`` option with the error message printed just before. If you are using a wrapper process for your failure state, add the ``-runner ""`` option to the `bugpoint` call. -For more about the options available, check ``help bugpoint`` or -:doc:`/cmd/bugpoint`. .. code-block:: yoscrypt :caption: ```` template script @@ -142,15 +163,17 @@ For more about the options available, check ``help bugpoint`` or # Save minimized design write_rtlil min.il +The ``-grep`` option is used to search the log file generated by the Yosys under +test. If the error message is generated by something else, such as a wrapper +process or compiler sanitizer, then you should instead use ``-err_grep``. For +an OS error, like a SEGFAULT, you can also use ``-expect-return`` to check the +error code returned. + .. note:: - Using ``-grep ""`` with `bugpoint` is optional, but helps to ensure - that the minimized design is reproducing the right error, especially when - ```` contains more than one command. Unfortunately this does not - work with runtime errors such as a ``SEGFAULT`` as it is only able to match - strings from the log file. - -.. TODO:: above note pending updated bugpoint #5068 + Checking the error message or return status with is optional, but helps to + ensure that the minimized design is reproducing the right error, especially + when ```` contains more than one command. By default, `bugpoint` is able to remove any part of the design. In order to keep certain parts, for instance because you already know they are related to @@ -177,13 +200,16 @@ error on undefined behaviour but only want the child process to halt on error. Once you have finished configuration, you can now run ``yosys ``. The first thing `bugpoint` will do is test the input design fails. If it doesn't, make sure you are using the right ``yosys`` executable; unless the -``-yosys`` option is provided, it will use whatever the shell defaults to. If -you are using the ``-runner`` option, try replacing the `bugpoint` command with -``write_rtlil test.il`` and then on a new line, ``! yosys -s - test.il`` to check it works as expected and returns a non-zero -status. +``-yosys`` option is provided, it will use whatever the shell defaults to, *not* +the current ``yosys``. If you are using the ``-runner`` option, try replacing +the `bugpoint` command with ``write_rtlil test.il`` and then on a new line, +``! yosys -s test.il`` to check it works as expected and +returns a non-zero status. -.. TODO:: note on ``!`` (link to :ref:`getting_started/scripting_intro:script parsing`) +.. seealso:: + + For more on script parsing and the use of ``!``, check out + :ref:`getting_started/scripting_intro:script parsing`. Depending on the size of your design, and the length of your ````, `bugpoint` may take some time; remember, it will run ``yosys -s `` @@ -231,12 +257,19 @@ Once you've verified the failure still happens, check out Minimizing Verilog designs -------------------------- +.. seealso:: + + This section is not specific to Yosys, so feel free to use another guide such + as Stack Overflow's `How to create a Minimal, Reproducible Example`_. + Unlike RTLIL designs where we can use `bugpoint`, minimizing Verilog designs is a much more manual, iterative process. Be sure to check any errors or warnings for messages that might identify source lines or object names that might be causing the failure, and back up your source code before modifying it. At any point in the process, you can check for anything that is unused or totally -disconnected (ports, wires, etc) and remove them too. +disconnected (ports, wires, etc) and remove them too. If you have multiple +source files, try to reduce them down to a single file; either by removing files +or combining them. .. note:: @@ -264,7 +297,7 @@ those too. Any signals which are written but never read can also be removed. Depending on where the design is failing, there are some commands which may help in identifying unused objects in the design. `hierarchy` will identify - which modules are used and which are not, but check for `$paramod` modules + which modules are used and which are not, but check for ``$paramod`` modules before removing unused ones. ``debug clean`` will list all unused wires in each module, as well as unused cells which were automatically generated (giving the line number of the source that generated them). Adding the @@ -272,48 +305,70 @@ those too. Any signals which are written but never read can also be removed. by `clean`. Though when there are large numbers of unused wires it is often easier to just delete sections of the code and see what happens. -- try to remove or reduce assignments and operations +Next, try to remove or reduce assignments (``a = b``) and operations (``a + +b``). A good place to start is by checking for any wires/registers which are +read but never written. Try removing the signal declaration and replacing +references to it with ``'0`` or ``'x``. Do this with any constants too. Try to +replace strings with numeric values, and wide signals with smaller ones, then +see if the error persists. - + are there any wires/registers which get read but never written? +Check if there are any operations that you can simplify, like replacing ``a & +'0`` with ``'0``. If you have enable or reset logic, try removing it and see if +the error still occurs. Try reducing ``if .. else`` and ``case`` blocks to a +single case. Even if that doesn't work, you may still be able to remove some +paths; start with cases that appear to be unreachable and go from there. - * try removing the signal declaration and replacing references to it with - ``'0`` or ``'x`` - * try this with constants too +If you're planning to share the minimized code, remember to make sure there is +no sensitive or proprietary data in the design. Maybe rename that +``ibex_prefetch_buffer`` module to ``buf``, and ``very_important_signal_name`` +could just as easily be ``sig``. The point here isn't to make names as small as +possible, but rather to remove the context that is no longer necessary. Calling +something ``multiplier_output_value`` doesn't mean as much if you no longer have +the multiplier being referred to; but if the name does still make sense then +it's fine to leave it as-is. - + can you replace strings with numeric values? - + are you able to simplify any operations? like replacing ``a & '0`` with - ``'0`` - + if you have enable or reset logic, does the error still happen without that? - + can you reduce an ``if .. else`` to a single case? - + can you remove states from a ``case`` block? +.. note:: -- if you're planning to share the minimized code: - - + make sure there is no sensitive or proprietary data in the design - + instead of a long string of numbers and letters that had some meaning (or - were randomly or sequentially generated), can you give it a single character - name like ``a`` or ``x`` - + please try to keep things in English, using the letters a-z and numbers 0-9 - (unless the error is arising because of the names used) + When sharing code on the `Yosys GitHub`_, please try to keep things in + English. Declarations and strings should stick to the letters a-z and + numbers 0-9, unless the error is arising because of the names/characters + used. Identifying issues ------------------ -- does the failing command indicate limited support, or does it mention some - other command that needs to be run first? -- if you're able to, try to match the minimized design back to its original - context +When identifying issues, it is quite useful to understand the conditions under +which the issue is occurring. While there are occasionally bugs that affect a +significant number of designs, Yosys changes are tested on a variety of designs +and operating systems which typically catch any such issues before they make it +into the main branch. So what is is it about your situation that makes it +unusual? - + could you achieve the same thing a different way? - + and if so, does this other method have the same issue? +.. note:: -- try to change the design in small ways and see what happens + If you have access to a different platform you could also check if your issue + is reproducible there. Some issues may be specific to the platform or build + of Yosys. - + `bugpoint` can reduce and simplify a design, but it doesn't *change* much - + what happens if you change operators, for example a left shift (or `$shl`) - to a right shift (or `$shr`)? - + is the issue tied to specific parameters, widths, or values? +Try to match the minimized design back to its original context. Could you +achieve the same thing a different way, and if so, does this other method have +the same issue? Try to change the design in small ways and see what happens; +while `bugpoint` can reduce and simplify a design, it doesn't *change* much. +What happens if you change operators, for example a left shift (or `$shl`) to a +right shift (or `$shr`)? Try to see if the issue is tied to specific +parameters, widths, or values. + +Search `the existing issues`_ and see if someone has already made a bug report. +This is where changing the design and finding the limits of what causes the +failure really comes in handy. If you're more familiar with how the problem can +arise, you may be able to find a related issue more easily. If an issue already +exists for one case of the problem but you've found other cases, you can comment +on the issue and help get it solved. If there are no existing or related issues +already, then check out the steps for +:ref:`yosys_internals/extending_yosys/contributing:reporting bugs`. + +.. _the existing issues: https://github.com/YosysHQ/yosys/issues .. warning:: @@ -322,17 +377,3 @@ Identifying issues more than one fuzzer generated issue at a time if you can not identify the root cause. If you are found to be doing this, your issues may be closed without further investigation. - -- search `the existing issues`_ and see if someone has already made a bug report - - + this is where changing the design and finding the limits of what causes the - failure really comes in handy - + if you're more familiar with how the problem can arise, you may be able to - find a related issue more easily - + if an issue already exists for one case of the problem but you've found - other cases, you can comment on the issue and help get it solved - -.. _the existing issues: https://github.com/YosysHQ/yosys/issues - -- if there are no existing or related issues already, then check out the steps - for :ref:`yosys_internals/extending_yosys/contributing:reporting bugs` From c994b59ac6a0a87df33fe5ace0a162571329d2e2 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:01 +1200 Subject: [PATCH 34/51] advanced_bugpoint.rst: Paragraphing --- .../extending_yosys/advanced_bugpoint.rst | 170 +++++++++++------- 1 file changed, 109 insertions(+), 61 deletions(-) diff --git a/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst b/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst index 32d334581..570155c61 100644 --- a/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst +++ b/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst @@ -6,27 +6,40 @@ in solving or investigating Yosys bugs. This also applies if you are using a fuzzing tool; fuzzers have a tendency to find many variations of the same bug, so identifying the root cause is important for avoiding issue spam. -- if the failing command was part of a larger script, such as one of the - :doc:`/using_yosys/synthesis/synth`, you could try to follow the design - through the script +If you're familiar with C/C++, you might try to have a look at the source code +of the command that's failing. Even if you can't fix the problem yourself, it +can be very helpful for anyone else investigating if you're able to identify +where the issue is arising. - + sometimes when a command is raising an error, you're seeing a symptom rather - than the underlying issue - + an earlier command may be putting the design in an invalid state which isn't - picked up until the error is raised - + check out :ref:`yosys_internals/extending_yosys/advanced_bugpoint:why context matters` -- if you're familiar with C/C++ you might try to have a look at the source - code of the command that's failing +Finding the failing command +--------------------------- + +Using the ``-L`` flag can help here, allowing you to specify a file to log to, +such as ``yosys -L out.log -s script.ys``. Most commands will print a header +message when they begin; something like ``2.48. Executing HIERARCHY pass +(managing design hierarchy).`` The last header message will usually be the +failing command. There are some commands which don't print a header message, so +you may want to add ``echo on`` to the start of your script. The `echo` command +echoes each command executed, along with any arguments given to it. For the +`hierarchy` example above this might be ``yosys> hierarchy -check``. + +.. note:: + + It may also be helpful to use the `log` command to add messages which you can + then search for either in the terminal or the logfile. This can be quite + useful if your script contains script-passes, like the + :doc:`/using_yosys/synthesis/synth`, which call many sub-commands and you're + not sure exactly which script-pass is calling the failing command. - + even if you can't fix the problem yourself, it can be very helpful for - anyone else investigating if you're able to identify where exactly the - issue is Minimizing scripts ------------------ -.. TODO:: disclaimer this is intended as advanced usage, and generally not necessary for bug reports +.. warning:: + + This section is intended as **advanced usage**, and generally not necessary + for normal bug reports. If you're using a command line prompt, such as ``yosys -p 'synth_xilinx' -o design.json design.v``, consider converting it to a script. It's generally much @@ -40,28 +53,10 @@ command line, as well as being better for sharing with others. synth_xilinx write_json design.json -Next up you want to remove everything *after* the error occurs. Using the -``-L`` flag can help here, allowing you to specify a file to log to, such as -``yosys -L out.log -s script.ys``. Most commands will print a header message -when they begin; something like ``2.48. Executing HIERARCHY pass (managing -design hierarchy).`` The last header message will usually be the failing -command. There are some commands which don't print a header message, so you may -want to add ``echo on`` to the start of your script. The `echo` command echoes -each command executed, along with any arguments given to it. For the -`hierarchy` example above this might be ``yosys> hierarchy -check``. - -.. note:: - - It may also be helpful to use the `log` command to add messages which you can - then search for either in the terminal or the logfile. This can be quite - useful if your script contains script-passes, like the - :doc:`/using_yosys/synthesis/synth`, which call many sub-commands and you're - not sure exactly which script-pass is calling the failing command. - -If your final command calls sub-commands, replace it with its contents and -repeat the previous step. In the case of the -:doc:`/using_yosys/synthesis/synth`, as well as certain other script-passes, you -can use the ``-run`` option to simplify this. For example we can replace +Next up you want to remove everything *after* the error occurs. If your final +command calls sub-commands, replace it with its contents first. In the case of +the :doc:`/using_yosys/synthesis/synth`, as well as certain other script-passes, +you can use the ``-run`` option to simplify this. For example we can replace ``synth -top -lut`` with the :ref:`replace_synth`. The options ``-top -lut`` can be provided to each `synth` step, or to just the step(s) where it is relevant, as done here. @@ -177,32 +172,85 @@ recovering context, checkout Why context matters ------------------- -- if you did minimized your script, and removed commands prior to the failure - to get a smaller design, try to work backwards and find which commands may - have contributed to the design failing -- especially important when the bug is happening inside of a ``synth_*`` script -- example (#4590) +Sometimes when a command is raising an error, you're seeing a symptom rather +than the underlying issue. It's possible that an earlier command may be putting +the design in an invalid state, which isn't picked up until the error is raised. +This is particularly true for the pre-packaged +:doc:`/using_yosys/synthesis/synth`, which rely on a combination of generic and +architecture specific passes. As new features are added to Yosys and more +designs are supported, the types of cells output by a pass can grow and change; +and sometimes this leads to a mismatch in what a pass is intended to handle. + +If you minimized your script, and removed commands prior to the failure to get a +smaller reproducer, try to work backwards and find which commands may have +contributed to the design failing. From the minimized design you should have +some understanding of the cell or cells which are producing the error; but where +did those cells come from? The name and/or type of the cell can often point you +in the right direction: + +.. code-block:: + + # internal cell types start with a $ + # lowercase for word-level, uppercase for bit-level + $and + $_AND_ + + # cell types with $__ are typically intermediate cells used in techmapping + $__MUL16X16 + + # cell types without a $ are either user-defined or architecture specific + my_module + SB_MAC16 + + # object names might give you the name of the pass that created them + $procdff$1204 + $memory\rom$rdmux[0][0][0]$a$1550 + + # or even the line number in the Yosys source + $auto$muxcover.cc:557:implement_best_cover$2152 + $auto$alumacc.cc:495:replace_alu$1209 + +Try running the unminimized script and search the log for the names of the +objects in your minimized design. In the case of cells you can also search for +the type of the cell. Remember that calling `stat` will list all the types of +cells currently used in the design, and `select -list =*` will list the names of +of all the current objects. You can add these commands to your script, or use +an interactive terminal to run each command individually. Adding them to the +script can be more repeatable, but if it takes a long time to run to the point +you're interested in then an interactive shell session can give you more +flexibility once you reach that point. You can also add a call to the `shell` +command at any point in a script to start an interactive session at a given +point; allowing you to script any preparation steps, then come back once it's +done. + +A worked example +~~~~~~~~~~~~~~~~ - + say you did all the minimization and found that the error occurs when a call - to ``techmap -map +/xilinx/cells_map.v`` with ``MIN_MUX_INPUTS`` defined - parses a `$_MUX16_` with all inputs set to ``1'x`` - + step through the original script, calling `stat` after each step to find - when the `$_MUX16_` is added - + find that the `$_MUX16_` is introduced by a call to `muxcover`, but all the - inputs are defined, so calling `techmap` now works as expected +Say you did all the minimization and found that an error in `synth_xilinx` +occurs when a call to ``techmap -map +/xilinx/cells_map.v`` with +``MIN_MUX_INPUTS`` defined parses a `$_MUX16_` with all inputs set to ``1'x``. +You could fix the bug in ``+/xilinx/cells_map.v``, but that might only solve +this one case while leaving other problems that haven't been found yet. So you +step through the original script, calling `stat` after each step to find when +the `$_MUX16_` is added. - * and from running `bugpoint` with the failing techmap you know that the - cell with index ``2297`` will fail, so you can now call ``select - top/*$2297`` to limit to just that cell, and optionally call ``design - -save pre_bug`` or ``write_rtlil -selected pre_bug.il`` to save this state +You find that the `$_MUX16_` is introduced by a call to `muxcover`, but all the +inputs are defined, so calling `techmap` now works as expected. From running +`bugpoint` with the failing techmap you know that the cell with index ``2297`` +will fail, so you call ``select top/*$2297`` to limit to just that cell. This +can then be saved with ``design -save pre_bug`` or ``write_rtlil -selected +pre_bug.il``, so that you don't have to re-run all the earlier steps to get back +here. - + next you step through the remaining commands and call `dump` after each to - find when the inputs are disconnected - + find that ``opt -full`` has optimized away portions of the circuit, leading - to `opt_expr` setting the undriven mux inputs to ``x``, but failing to - remove the now unnecessary `$_MUX16_` +Next you step through the remaining commands and call `dump` after each to find +when the inputs are disconnected. You find that ``opt -full`` has optimized +away portions of the circuit, leading to `opt_expr` setting the undriven mux +inputs to ``x``, but failing to remove the now unnecessary `$_MUX16_`. Now +you've identified a problem in `opt_expr` that affects all of the wide muxes, +and could happen in any synthesis flow, not just `synth_xilinx`. -- in this example, you might've stopped with the minimal reproducer, fixed the - bug in ``+/xilinx/cells_map.v``, and carried on -- but by following the failure back you've managed to identify a problem with - `opt_expr` that could be causing other problems either now or in the future +.. seealso:: + + This example is taken from `YosysHQ/yosys#4590 + `_ and can be reproduced with a + version of Yosys between 0.45 and 0.51. From 29d334186c8acc0329eb9b6cf06ac686d71e514e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:01 +1200 Subject: [PATCH 35/51] bugpoint.rst: How to creduce --- docs/source/using_yosys/bugpoint.rst | 87 +++++++++++++++++++++------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 38a978695..5c4bf3ae7 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -262,20 +262,74 @@ Minimizing Verilog designs This section is not specific to Yosys, so feel free to use another guide such as Stack Overflow's `How to create a Minimal, Reproducible Example`_. -Unlike RTLIL designs where we can use `bugpoint`, minimizing Verilog designs is -a much more manual, iterative process. Be sure to check any errors or warnings -for messages that might identify source lines or object names that might be -causing the failure, and back up your source code before modifying it. At any -point in the process, you can check for anything that is unused or totally -disconnected (ports, wires, etc) and remove them too. If you have multiple -source files, try to reduce them down to a single file; either by removing files -or combining them. +Be sure to check any errors or warnings for messages that might identify source +lines or object names that might be causing the failure, and back up your source +code before modifying it. If you have multiple source files, you should start +by reducing them down to a single file. If a specific file is failing to read, +try removing everything else and just focus on that one. If your source uses +the `include` directive, replace it with the contents of the file referenced. -.. note:: +Unlike RTLIL designs where we can use `bugpoint`, Yosys does not provide any +tools for minimizing Verilog designs. Instead, you should use an external tool +like `C-Reduce`_ (with the ``--not-c`` flag) or `sv-bugpoint`_. - If a specific module is causing the problem, try to set that as the top - module instead. Any parameters should have their default values changed to - match the failing usage. +.. _C-Reduce: https://github.com/csmith-project/creduce +.. _sv-bugpoint: https://github.com/antmicro/sv-bugpoint + +C-Reduce +~~~~~~~~ + +As a very brief overview for using C-Reduce, you want your failing source design +(``test.v``), and some shell script which checks for the error being +investigated (``test.sh``). Below is an :ref:`egtest` which uses `logger` and +the ``-expect error "" 1`` option to perform a similar role to +``bugpoint -grep``, along with ``verilator`` to lint the code and make sure it +is still valid. + +.. code-block:: bash + :caption: Example test.sh + :name: egtest + + #!/bin/bash + verilator --lint-only test.v &&/ + yosys -p 'logger -expect error "unsupported" 1; read_verilog test.v' + +.. code-block:: verilog + :caption: input test.v + + module top(input clk, a, b, c, output x, y, z); + always @(posedge clk) begin + if (a == 1'b1) + $stop; + end + assign x = a; + assign y = a ^ b; + assign z = c; + endmodule + +In this example ``read_verilog test.v`` is giving an error message that contains +the string "unsupported" because the ``$stop`` system task is only supported in +``initial`` blocks. By calling ``creduce ./test.sh test.v --not-c`` we can +minimize the design to just the failing code, while still being valid Verilog. + +.. code-block:: verilog + :caption: output test.v + + module a; + always begin $stop; + end endmodule + + +Doing it manually +~~~~~~~~~~~~~~~~~ + +If for some reason you are unable to use a tool to minimize your code, you can +still do it manually. But it can be a time consuming process and requires a lot +of iteration. At any point in the process, you can check for anything that is +unused or totally disconnected (ports, wires, etc) and remove them. If a +specific module is causing the problem, try to set that as the top module +instead. Any parameters should have their default values changed to match the +failing usage. As a rule of thumb, try to split things roughly in half at each step; similar to a "binary search". If you have 10 cells (instances of modules) in your top @@ -318,15 +372,6 @@ the error still occurs. Try reducing ``if .. else`` and ``case`` blocks to a single case. Even if that doesn't work, you may still be able to remove some paths; start with cases that appear to be unreachable and go from there. -If you're planning to share the minimized code, remember to make sure there is -no sensitive or proprietary data in the design. Maybe rename that -``ibex_prefetch_buffer`` module to ``buf``, and ``very_important_signal_name`` -could just as easily be ``sig``. The point here isn't to make names as small as -possible, but rather to remove the context that is no longer necessary. Calling -something ``multiplier_output_value`` doesn't mean as much if you no longer have -the multiplier being referred to; but if the name does still make sense then -it's fine to leave it as-is. - .. note:: When sharing code on the `Yosys GitHub`_, please try to keep things in From 4924670325f0768cb71f5072e300a874d1bef02e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:02 +1200 Subject: [PATCH 36/51] bugpoint.rst: How to sv-bugpoint --- docs/source/using_yosys/bugpoint.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 5c4bf3ae7..41fc60cdb 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -287,7 +287,7 @@ the ``-expect error "" 1`` option to perform a similar role to is still valid. .. code-block:: bash - :caption: Example test.sh + :caption: Example test.sh for C-Reduce :name: egtest #!/bin/bash @@ -320,6 +320,25 @@ minimize the design to just the failing code, while still being valid Verilog. end endmodule +sv-bugpoint +~~~~~~~~~~~ + +sv-bugpoint works quite similarly to C-Reduce, except it requires an output +directory to be provided and the check script needs to accept the target file as +an input argument: ``sv-bugpoint outDir/ test.sh test.v`` + +.. code-block:: bash + :caption: Example test.sh for sv-bugpoint + + #!/bin/bash + verilator --lint-only $1 &&/ + yosys -p "logger -expect error \"unsupported\" 1; read_verilog $1" + +Notice that the commands for ``yosys -p`` are now in double quotes (``"``), and +the quotes around the error string are escaped (``\"``). This is necessary for +the ``$1`` argument subsitution to work correctly. + + Doing it manually ~~~~~~~~~~~~~~~~~ From 96b072aeb31ae6e476d419b1eb814febf75b31c6 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:02 +1200 Subject: [PATCH 37/51] advanced_bugpoint.rst: --dump-design Also fix missing double backtick. --- .../extending_yosys/advanced_bugpoint.rst | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst b/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst index 570155c61..22e4b1b7a 100644 --- a/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst +++ b/docs/source/yosys_internals/extending_yosys/advanced_bugpoint.rst @@ -213,16 +213,31 @@ in the right direction: Try running the unminimized script and search the log for the names of the objects in your minimized design. In the case of cells you can also search for the type of the cell. Remember that calling `stat` will list all the types of -cells currently used in the design, and `select -list =*` will list the names of -of all the current objects. You can add these commands to your script, or use -an interactive terminal to run each command individually. Adding them to the -script can be more repeatable, but if it takes a long time to run to the point -you're interested in then an interactive shell session can give you more +cells currently used in the design, and ``select -list =*`` will list the names +of of all the current objects. You can add these commands to your script, or +use an interactive terminal to run each command individually. Adding them to +the script can be more repeatable, but if it takes a long time to run to the +point you're interested in then an interactive shell session can give you more flexibility once you reach that point. You can also add a call to the `shell` command at any point in a script to start an interactive session at a given point; allowing you to script any preparation steps, then come back once it's done. +The ``--dump-design`` option +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Yosys provides the ``--dump-design`` option (or ``-P`` for short) for dumping +the design at specific steps of the script based on the log header. If the last +step before an error is ``7.2. Executing MEMORY_MAP pass (converting memories to +logic and flip-flops)``, then calling Yosys with ``--dump-design 7.2:bad.il`` +will save the design *before* this command runs, in the file ``bad.il``. + +It is also possible to use this option multiple times, e.g. ``-P2:hierarchy.il +-P7 -P7.2:bad.il``, to get multiple dumps in the same run. This can make it +easier to follow the design through each step to find where certain cells or +connections are coming from. ``--dump-design ALL`` is also allowed, writing out +the design at each log header. + A worked example ~~~~~~~~~~~~~~~~ From bfe2418a67ea6f586c4b99a094c871f19c2a9871 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:02 +1200 Subject: [PATCH 38/51] bugpoint.rst: Expand note on checking errors --- docs/source/using_yosys/bugpoint.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 41fc60cdb..ce84fd285 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -171,9 +171,12 @@ error code returned. .. note:: - Checking the error message or return status with is optional, but helps to - ensure that the minimized design is reproducing the right error, especially - when ```` contains more than one command. + Checking the error message or return status is optional, but highly + recommended. `bugpoint` can quite easily introduce bugs by creating + malformed designs that commands were not intended to handle. By having some + way to check the error, `bugpoint` can ensure that it is the *right* error + being reproduced. This is even more important when ```` contains + more than one command. By default, `bugpoint` is able to remove any part of the design. In order to keep certain parts, for instance because you already know they are related to From 8750ca42d38883030c703d31213cfcaeacf28b82 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:54:02 +1200 Subject: [PATCH 39/51] docs: Fix formatting --- docs/source/using_yosys/bugpoint.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index ce84fd285..60cabd879 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -270,7 +270,7 @@ lines or object names that might be causing the failure, and back up your source code before modifying it. If you have multiple source files, you should start by reducing them down to a single file. If a specific file is failing to read, try removing everything else and just focus on that one. If your source uses -the `include` directive, replace it with the contents of the file referenced. +the ``include`` directive, replace it with the contents of the file referenced. Unlike RTLIL designs where we can use `bugpoint`, Yosys does not provide any tools for minimizing Verilog designs. Instead, you should use an external tool From f22fe912379aee2a7263896d984a1cdc7fa0d5fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 00:27:22 +0000 Subject: [PATCH 40/51] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c828aa2d5..e5f23a0fd 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.55+150 +YOSYS_VER := 0.55+158 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 f769e6e24524ebde9fec4cf0fddcf6910a51170f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 5 Aug 2025 12:27:10 +0200 Subject: [PATCH 41/51] Update ABC --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index fcd8ac34d..fa7fa163d 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit fcd8ac34d6105b48f32dfaf31983b071c46fb7b9 +Subproject commit fa7fa163dacdf81bdcb72b2d2713fbe9984b62bb From 2ad3532a557de0ee512b5a6ec6fe3b8fd8efca7d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 00:27:13 +0000 Subject: [PATCH 42/51] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e5f23a0fd..283040755 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.55+158 +YOSYS_VER := 0.55+194 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 3959d19291c68a521b8d332c253d4f20356e3879 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:52:12 +1200 Subject: [PATCH 43/51] Reapply "Add groups to command reference" This reverts commit 81f87ce6ede480de2c976938921eef8b9e79f9db. --- .github/workflows/prepare-docs.yml | 1 - Makefile | 36 +- backends/functional/test_generic.cc | 4 +- docs/.gitignore | 1 - docs/Makefile | 2 +- docs/source/_static/custom.css | 5 + docs/source/appendix/auxlibs.rst | 5 +- docs/source/cmd/index_backends.rst | 5 + docs/source/cmd/index_formal.rst | 5 + docs/source/cmd/index_frontends.rst | 5 + docs/source/cmd/index_internal.rst | 152 ++++++ docs/source/cmd/index_kernel.rst | 5 + docs/source/cmd/index_other.rst | 9 + docs/source/cmd/index_passes.rst | 14 + docs/source/cmd/index_passes_cmds.rst | 5 + docs/source/cmd/index_passes_equiv.rst | 5 + docs/source/cmd/index_passes_fsm.rst | 5 + docs/source/cmd/index_passes_hierarchy.rst | 5 + docs/source/cmd/index_passes_memory.rst | 5 + docs/source/cmd/index_passes_opt.rst | 5 + docs/source/cmd/index_passes_proc.rst | 5 + docs/source/cmd/index_passes_sat.rst | 5 + docs/source/cmd/index_passes_status.rst | 5 + docs/source/cmd/index_passes_techmap.rst | 7 + docs/source/cmd/index_techlibs.rst | 11 + docs/source/cmd/index_techlibs_achronix.rst | 5 + docs/source/cmd/index_techlibs_anlogic.rst | 5 + docs/source/cmd/index_techlibs_common.rst | 5 + .../source/cmd/index_techlibs_coolrunner2.rst | 5 + docs/source/cmd/index_techlibs_easic.rst | 5 + docs/source/cmd/index_techlibs_ecp5.rst | 5 + docs/source/cmd/index_techlibs_fabulous.rst | 5 + docs/source/cmd/index_techlibs_gatemate.rst | 5 + docs/source/cmd/index_techlibs_gowin.rst | 5 + docs/source/cmd/index_techlibs_greenpak4.rst | 5 + docs/source/cmd/index_techlibs_ice40.rst | 5 + docs/source/cmd/index_techlibs_intel.rst | 5 + docs/source/cmd/index_techlibs_intel_alm.rst | 5 + docs/source/cmd/index_techlibs_lattice.rst | 5 + .../cmd/index_techlibs_lattice_nexus.rst | 5 + docs/source/cmd/index_techlibs_microchip.rst | 5 + .../cmd/index_techlibs_microchip_sf2.rst | 5 + docs/source/cmd/index_techlibs_nanoxplore.rst | 5 + docs/source/cmd/index_techlibs_quicklogic.rst | 5 + docs/source/cmd/index_techlibs_xilinx.rst | 5 + docs/source/cmd_ref.rst | 33 +- .../code_examples/macro_commands/prep.ys | 23 + docs/source/conf.py | 12 +- docs/source/getting_started/example_synth.rst | 63 ++- .../getting_started/scripting_intro.rst | 4 +- docs/source/index.rst | 2 +- .../interactive_investigation.rst | 10 +- .../more_scripting/load_design.rst | 2 +- .../using_yosys/more_scripting/selections.rst | 6 +- docs/source/using_yosys/synthesis/fsm.rst | 2 +- docs/source/using_yosys/synthesis/memory.rst | 2 +- docs/source/using_yosys/synthesis/opt.rst | 8 +- docs/source/using_yosys/synthesis/proc.rst | 2 +- docs/source/using_yosys/synthesis/synth.rst | 33 +- .../using_yosys/synthesis/techmap_synth.rst | 6 +- docs/source/using_yosys/verilog.rst | 2 +- docs/source/yosys_internals/hashing.rst | 2 +- docs/util/{cellref.py => cell_documenter.py} | 0 docs/util/cmd_documenter.py | 443 ++++++++++++++++++ docs/util/{cmdref.py => custom_directives.py} | 152 +++++- kernel/json.h | 4 +- kernel/log_help.cc | 151 ++++++ kernel/log_help.h | 132 ++++++ kernel/register.cc | 438 +++++++++-------- kernel/register.h | 46 +- passes/cmds/check.cc | 6 + passes/cmds/chformal.cc | 109 ++--- passes/cmds/cover.cc | 14 +- passes/cmds/dft_tag.cc | 6 + passes/cmds/edgetypes.cc | 6 + passes/cmds/example_dt.cc | 8 +- passes/cmds/exec.cc | 9 +- passes/cmds/future.cc | 6 + passes/cmds/glift.cc | 11 +- passes/cmds/internal_stats.cc | 7 +- passes/cmds/logcmd.cc | 10 +- passes/cmds/logger.cc | 9 +- passes/cmds/ltp.cc | 6 + passes/cmds/plugin.cc | 6 + passes/cmds/portarcs.cc | 6 + passes/cmds/portlist.cc | 6 + passes/cmds/printattrs.cc | 6 + passes/cmds/scc.cc | 11 +- passes/cmds/scratchpad.cc | 10 +- passes/cmds/select.cc | 18 +- passes/cmds/setenv.cc | 11 +- passes/cmds/show.cc | 10 +- passes/cmds/sta.cc | 6 + passes/cmds/stat.cc | 6 + passes/cmds/tee.cc | 10 +- passes/cmds/torder.cc | 6 + passes/cmds/trace.cc | 11 + passes/cmds/viz.cc | 6 + passes/cmds/write_file.cc | 6 + passes/cmds/xprop.cc | 6 + passes/hierarchy/Makefile.inc | 1 + passes/{techmap => hierarchy}/flatten.cc | 0 passes/opt/rmports.cc | 11 +- passes/pmgen/test_pmgen.cc | 4 +- passes/sat/assertpmux.cc | 6 + passes/sat/async2sync.cc | 6 + passes/sat/clk2fflogic.cc | 6 + passes/sat/cutpoint.cc | 6 + passes/sat/expose.cc | 10 +- passes/sat/fmcombine.cc | 6 + passes/sat/fminit.cc | 6 + passes/sat/formalff.cc | 6 + passes/sat/freduce.cc | 14 +- passes/sat/miter.cc | 10 +- passes/sat/mutate.cc | 6 + passes/sat/qbfsat.cc | 6 + passes/sat/recover_names.cc | 6 + passes/sat/sat.cc | 14 +- passes/sat/supercover.cc | 6 + passes/sat/synthprop.cc | 12 +- passes/techmap/Makefile.inc | 1 - passes/tests/test_abcloop.cc | 4 +- passes/tests/test_autotb.cc | 4 +- passes/tests/test_cell.cc | 4 +- 124 files changed, 2030 insertions(+), 463 deletions(-) create mode 100644 docs/source/cmd/index_backends.rst create mode 100644 docs/source/cmd/index_formal.rst create mode 100644 docs/source/cmd/index_frontends.rst create mode 100644 docs/source/cmd/index_internal.rst create mode 100644 docs/source/cmd/index_kernel.rst create mode 100644 docs/source/cmd/index_other.rst create mode 100644 docs/source/cmd/index_passes.rst create mode 100644 docs/source/cmd/index_passes_cmds.rst create mode 100644 docs/source/cmd/index_passes_equiv.rst create mode 100644 docs/source/cmd/index_passes_fsm.rst create mode 100644 docs/source/cmd/index_passes_hierarchy.rst create mode 100644 docs/source/cmd/index_passes_memory.rst create mode 100644 docs/source/cmd/index_passes_opt.rst create mode 100644 docs/source/cmd/index_passes_proc.rst create mode 100644 docs/source/cmd/index_passes_sat.rst create mode 100644 docs/source/cmd/index_passes_status.rst create mode 100644 docs/source/cmd/index_passes_techmap.rst create mode 100644 docs/source/cmd/index_techlibs.rst create mode 100644 docs/source/cmd/index_techlibs_achronix.rst create mode 100644 docs/source/cmd/index_techlibs_anlogic.rst create mode 100644 docs/source/cmd/index_techlibs_common.rst create mode 100644 docs/source/cmd/index_techlibs_coolrunner2.rst create mode 100644 docs/source/cmd/index_techlibs_easic.rst create mode 100644 docs/source/cmd/index_techlibs_ecp5.rst create mode 100644 docs/source/cmd/index_techlibs_fabulous.rst create mode 100644 docs/source/cmd/index_techlibs_gatemate.rst create mode 100644 docs/source/cmd/index_techlibs_gowin.rst create mode 100644 docs/source/cmd/index_techlibs_greenpak4.rst create mode 100644 docs/source/cmd/index_techlibs_ice40.rst create mode 100644 docs/source/cmd/index_techlibs_intel.rst create mode 100644 docs/source/cmd/index_techlibs_intel_alm.rst create mode 100644 docs/source/cmd/index_techlibs_lattice.rst create mode 100644 docs/source/cmd/index_techlibs_lattice_nexus.rst create mode 100644 docs/source/cmd/index_techlibs_microchip.rst create mode 100644 docs/source/cmd/index_techlibs_microchip_sf2.rst create mode 100644 docs/source/cmd/index_techlibs_nanoxplore.rst create mode 100644 docs/source/cmd/index_techlibs_quicklogic.rst create mode 100644 docs/source/cmd/index_techlibs_xilinx.rst create mode 100644 docs/source/code_examples/macro_commands/prep.ys rename docs/util/{cellref.py => cell_documenter.py} (100%) create mode 100644 docs/util/cmd_documenter.py rename docs/util/{cmdref.py => custom_directives.py} (81%) create mode 100644 kernel/log_help.cc create mode 100644 kernel/log_help.h rename passes/{techmap => hierarchy}/flatten.cc (100%) diff --git a/.github/workflows/prepare-docs.yml b/.github/workflows/prepare-docs.yml index fb1fab426..b47f5f3dd 100644 --- a/.github/workflows/prepare-docs.yml +++ b/.github/workflows/prepare-docs.yml @@ -59,7 +59,6 @@ jobs: with: name: cmd-ref-${{ github.sha }} path: | - docs/source/cmd docs/source/generated docs/source/_images docs/source/code_examples diff --git a/Makefile b/Makefile index 283040755..ce438f5db 100644 --- a/Makefile +++ b/Makefile @@ -115,12 +115,6 @@ BISON ?= bison STRIP ?= strip AWK ?= awk -ifneq ($(shell :; command -v rsync),) -RSYNC_CP ?= rsync -rc -else -RSYNC_CP ?= cp -ru -endif - ifeq ($(OS), Darwin) PLUGIN_LINKFLAGS += -undefined dynamic_lookup LINKFLAGS += -rdynamic @@ -532,7 +526,6 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE endif endif - ifeq ($(ENABLE_COVER),1) CXXFLAGS += -DYOSYS_ENABLE_COVER endif @@ -634,6 +627,7 @@ $(eval $(call add_include_file,frontends/blif/blifparse.h)) $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/io.o kernel/gzip.o +OBJS += kernel/log_help.o OBJS += kernel/binding.o kernel/tclapi.o OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o OBJS += kernel/drivertools.o kernel/functional.o @@ -1035,19 +1029,8 @@ ifeq ($(ENABLE_PYOSYS),1) endif endif -# also others, but so long as it doesn't fail this is enough to know we tried -docs/source/cmd/abc.rst: $(TARGETS) $(EXTRA_TARGETS) - $(Q) mkdir -p docs/source/cmd - $(Q) mkdir -p temp/docs/source/cmd - $(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-command-reference-manual' - $(Q) $(RSYNC_CP) temp/docs/source/cmd docs/source - $(Q) rm -rf temp -docs/source/cell/word_add.rst: $(TARGETS) $(EXTRA_TARGETS) - $(Q) mkdir -p docs/source/cell - $(Q) mkdir -p temp/docs/source/cell - $(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-cells-manual' - $(Q) $(RSYNC_CP) temp/docs/source/cell docs/source - $(Q) rm -rf temp +docs/source/generated/cmds.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) + $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cmds-json $@' docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@' @@ -1064,6 +1047,15 @@ docs/source/generated/functional/rosette.diff: backends/functional/smtlib.cc bac PHONY: docs/gen/functional_ir docs/gen/functional_ir: docs/source/generated/functional/smtlib.cc docs/source/generated/functional/rosette.diff +docs/source/generated/%.log: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) + $(Q) ./$(PROGRAM_PREFIX)yosys -qQT -h '$*' -l $@ + +docs/source/generated/chformal.cc: passes/cmds/chformal.cc docs/source/generated + $(Q) cp $< $@ + +PHONY: docs/gen/chformal +docs/gen/chformal: docs/source/generated/chformal.log docs/source/generated/chformal.cc + PHONY: docs/gen docs/usage docs/reqs docs/gen: $(TARGETS) $(Q) $(MAKE) -C docs gen @@ -1099,7 +1091,7 @@ docs/reqs: $(Q) $(MAKE) -C docs reqs .PHONY: docs/prep -docs/prep: docs/source/cmd/abc.rst docs/source/generated/cells.json docs/gen docs/usage docs/gen/functional_ir +docs/prep: docs/source/generated/cells.json docs/source/generated/cmds.json docs/gen docs/usage docs/gen/functional_ir docs/gen/chformal DOC_TARGET ?= html docs: docs/prep @@ -1123,7 +1115,7 @@ clean: rm -f tests/tools/cmp_tbdata rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS)) -$(MAKE) -C docs clean - rm -rf docs/source/cmd docs/util/__pycache__ + rm -rf docs/util/__pycache__ rm -f *.whl rm -f libyosys.so diff --git a/backends/functional/test_generic.cc b/backends/functional/test_generic.cc index a9dfd0c70..42d6c2b95 100644 --- a/backends/functional/test_generic.cc +++ b/backends/functional/test_generic.cc @@ -116,7 +116,9 @@ struct MemContentsTest { struct FunctionalTestGeneric : public Pass { - FunctionalTestGeneric() : Pass("test_generic", "test the generic compute graph") {} + FunctionalTestGeneric() : Pass("test_generic", "test the generic compute graph") { + internal(); + } void help() override { diff --git a/docs/.gitignore b/docs/.gitignore index 65bbcdeae..09bb59048 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,5 +1,4 @@ /build/ -/source/cmd /source/generated /source/_images/**/*.log /source/_images/**/*.aux diff --git a/docs/Makefile b/docs/Makefile index a8874bb83..fb3e03b79 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -47,7 +47,7 @@ help: .PHONY: clean clean: clean-examples rm -rf $(BUILDDIR)/* - rm -rf source/cmd util/__pycache__ + rm -rf util/__pycache__ rm -rf source/generated $(MAKE) -C source/_images clean diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css index b08194c05..60faf6812 100644 --- a/docs/source/_static/custom.css +++ b/docs/source/_static/custom.css @@ -18,3 +18,8 @@ .literal-block-wrapper .code-block-caption .caption-number { padding-right: 0.5em } + +/* Don't double shrink text in a literal in an optionlist */ +kbd .option>.literal { + font-size: revert; +} diff --git a/docs/source/appendix/auxlibs.rst b/docs/source/appendix/auxlibs.rst index 8c78ed6b3..192ac0944 100644 --- a/docs/source/appendix/auxlibs.rst +++ b/docs/source/appendix/auxlibs.rst @@ -29,8 +29,7 @@ ezSAT The files in ``libs/ezsat`` provide a library for simplifying generating CNF formulas for SAT solvers. It also contains bindings of MiniSAT. The ezSAT -library is written by C. Wolf. It is used by the `sat` pass (see -:doc:`/cmd/sat`). +library is written by C. Wolf. It is used by the `sat` pass. fst --- @@ -78,4 +77,4 @@ SubCircuit The files in ``libs/subcircuit`` provide a library for solving the subcircuit isomorphism problem. It is written by C. Wolf and based on the Ullmann Subgraph Isomorphism Algorithm :cite:p:`UllmannSubgraphIsomorphism`. It is used by the -extract pass (see :doc:`../cmd/extract`). +`extract` pass. diff --git a/docs/source/cmd/index_backends.rst b/docs/source/cmd/index_backends.rst new file mode 100644 index 000000000..373c26def --- /dev/null +++ b/docs/source/cmd/index_backends.rst @@ -0,0 +1,5 @@ +Writing output files +-------------------- + +.. autocmdgroup:: backends + :members: diff --git a/docs/source/cmd/index_formal.rst b/docs/source/cmd/index_formal.rst new file mode 100644 index 000000000..b8b134c17 --- /dev/null +++ b/docs/source/cmd/index_formal.rst @@ -0,0 +1,5 @@ +Formal verification +------------------- + +.. autocmdgroup:: formal + :members: diff --git a/docs/source/cmd/index_frontends.rst b/docs/source/cmd/index_frontends.rst new file mode 100644 index 000000000..b64fdc9b9 --- /dev/null +++ b/docs/source/cmd/index_frontends.rst @@ -0,0 +1,5 @@ +Reading input files +------------------- + +.. autocmdgroup:: frontends + :members: diff --git a/docs/source/cmd/index_internal.rst b/docs/source/cmd/index_internal.rst new file mode 100644 index 000000000..bfb369dde --- /dev/null +++ b/docs/source/cmd/index_internal.rst @@ -0,0 +1,152 @@ +Internal commands for developers +-------------------------------- + +.. autocmdgroup:: internal + :members: + +Writing command help +-------------------- + +- use `chformal` as an example +- generated help content below + +.. _chformal autocmd: + +.. autocmd:: chformal + :noindex: + +The ``formatted_help()`` method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``PrettyHelp::get_current()`` +- ``PrettyHelp::set_group()`` + + + used with ``.. autocmdgroup:: `` + + can assign group and return false + + if no group is set, will try to use ``source_location`` and assign group + from path to source file + +- return value + + + true means help content added to current ``PrettyHelp`` + + false to use ``Pass::help()`` + +- adding content + + + help content is a list of ``ContentListing`` nodes, each one having a type, + body, and its own list of children ``ContentListing``\ s + + ``PrettyHelp::get_root()`` returns the root ``ContentListing`` (``type="root"``) + + ``ContentListing::{usage, option, codeblock, paragraph}`` each add a + ``ContentListing`` to the current node, with type the same as the method + + * the first argument is the body of the new node + * ``usage`` shows how to call the command (i.e. its "signature") + * ``paragraph`` content is formatted as a paragraph of text with line breaks + added automatically + * ``codeblock`` content is displayed verbatim, use line breaks as desired; + takes an optional ``language`` argument for assigning the language in RST + output for code syntax highlighting (use ``yoscrypt`` for yosys script + syntax highlighting) + * ``option`` lists a single option for the command, usually starting with a + dash (``-``); takes an optional second argument which adds a paragraph + node as a means of description + + + ``ContentListing::open_usage`` creates and returns a new usage node, can be + used to e.g. add text/options specific to a given usage of the command + + ``ContentListing::open_option`` creates and returns a new option node, can + be used to e.g. add multiple paragraphs to an option's description + + paragraphs are treated as raw RST, allowing for inline formatting and + references as if it were written in the RST file itself + +.. literalinclude:: /generated/chformal.cc + :language: c++ + :start-at: bool formatted_help() + :end-before: void execute + :caption: ``ChformalPass::formatted_help()`` from :file:`passes/cmds/chformal.cc` + +Dumping command help to json +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- `help -dump-cells-json cmds.json` + + + generates a ``ContentListing`` for each command registered in Yosys + + tries to parse unformatted ``Pass::help()`` output if + ``Pass::formatted_help()`` is unimplemented or returns false + + * if a line starts with four spaces followed by the name of the command then + a space, it is parsed as a signature (usage node) + * if a line is indented and starts with a dash (``-``), it is parsed as an + option + * anything else is parsed as a codeblock and added to either the root node + or the current option depending on the indentation + + + dictionary of command name to ``ContentListing`` + + * uses ``ContentListing::to_json()`` recursively for each node in root + * root node used for source location of class definition + * includes flags set during pass constructor (e.g. ``experimental_flag`` set + by ``Pass::experimental()``) + * also title (``short_help`` argument in ``Pass::Pass``), group, and class + name + + + dictionary of group name to list of commands in that group + +- used by sphinx autodoc to generate help content + +.. literalinclude:: /generated/cmds.json + :language: json + :start-at: "chformal": { + :end-before: "chparam": { + :caption: `chformal` in generated :file:`cmds.json` + +.. note:: Synthesis command scripts are special cased + + If the final block of help output starts with the string `"The following + commands are executed by this synthesis command:\n"`, then the rest of the + code block is formatted as ``yoscrypt`` (e.g. `synth_ice40`). The caveat + here is that if the ``script()`` calls ``run()`` on any commands *prior* to + the first ``check_label`` then the auto detection will break and revert to + unformatted code (e.g. `synth_fabulous`). + +Command line rendering +~~~~~~~~~~~~~~~~~~~~~~ + +- if ``Pass::formatted_help()`` returns true, will call + ``PrettyHelp::log_help()`` + + + traverse over the children of the root node and render as plain text + + effectively the reverse of converting unformatted ``Pass::help()`` text + + lines are broken at 80 characters while maintaining indentation (controlled + by ``MAX_LINE_LEN`` in :file:`kernel/log_help.cc`) + + each line is broken into words separated by spaces, if a given word starts + and ends with backticks they will be stripped + +- if it returns false it will call ``Pass::help()`` which should call ``log()`` + directly to print and format help text + + + if ``Pass::help()`` is not overridden then a default message about missing + help will be displayed + +.. literalinclude:: /generated/chformal.log + :lines: 2- + +RST generated from autocmd +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- below is the raw RST output from ``autocmd`` (``YosysCmdDocumenter`` class in + :file:`docs/util/cmd_documenter.py`) for `chformal` command +- heading will be rendered as a subheading of the most recent heading (see + `chformal autocmd`_ above rendered under `Writing command help`_) +- ``.. cmd:def:: `` line is indexed for cross references with ``:cmd:ref:`` + directive (`chformal autocmd`_ above uses ``:noindex:`` option so that + `chformal` still links to the correct location) + + + ``:title:`` option controls text that appears when hovering over the + `chformal` link + +- commands with warning flags (experimental or internal) add a ``.. warning`` + block before any of the help content +- if a command has no ``source_location`` the ``.. note`` at the bottom will + instead link to :doc:`/cmd/index_other` + +.. autocmd_rst:: chformal diff --git a/docs/source/cmd/index_kernel.rst b/docs/source/cmd/index_kernel.rst new file mode 100644 index 000000000..c6891b5e5 --- /dev/null +++ b/docs/source/cmd/index_kernel.rst @@ -0,0 +1,5 @@ +Yosys kernel commands +--------------------- + +.. autocmdgroup:: kernel + :members: diff --git a/docs/source/cmd/index_other.rst b/docs/source/cmd/index_other.rst new file mode 100644 index 000000000..540cf9e49 --- /dev/null +++ b/docs/source/cmd/index_other.rst @@ -0,0 +1,9 @@ +:orphan: + +Other commands +============== + +Unknown source location + +.. autocmdgroup:: unknown + :members: diff --git a/docs/source/cmd/index_passes.rst b/docs/source/cmd/index_passes.rst new file mode 100644 index 000000000..b652be004 --- /dev/null +++ b/docs/source/cmd/index_passes.rst @@ -0,0 +1,14 @@ +Passes +------ + +.. toctree:: + :maxdepth: 2 + :glob: + + /cmd/index_passes_hierarchy + /cmd/index_passes_proc + /cmd/index_passes_fsm + /cmd/index_passes_memory + /cmd/index_passes_opt + /cmd/index_passes_techmap + /cmd/index_passes_* diff --git a/docs/source/cmd/index_passes_cmds.rst b/docs/source/cmd/index_passes_cmds.rst new file mode 100644 index 000000000..d7b448f07 --- /dev/null +++ b/docs/source/cmd/index_passes_cmds.rst @@ -0,0 +1,5 @@ +Design modification +------------------- + +.. autocmdgroup:: passes/cmds + :members: diff --git a/docs/source/cmd/index_passes_equiv.rst b/docs/source/cmd/index_passes_equiv.rst new file mode 100644 index 000000000..6ed2c3c18 --- /dev/null +++ b/docs/source/cmd/index_passes_equiv.rst @@ -0,0 +1,5 @@ +Equivalence checking +-------------------- + +.. autocmdgroup:: passes/equiv + :members: diff --git a/docs/source/cmd/index_passes_fsm.rst b/docs/source/cmd/index_passes_fsm.rst new file mode 100644 index 000000000..43af5dce6 --- /dev/null +++ b/docs/source/cmd/index_passes_fsm.rst @@ -0,0 +1,5 @@ +FSM handling +------------ + +.. autocmdgroup:: passes/fsm + :members: diff --git a/docs/source/cmd/index_passes_hierarchy.rst b/docs/source/cmd/index_passes_hierarchy.rst new file mode 100644 index 000000000..27a0faeb7 --- /dev/null +++ b/docs/source/cmd/index_passes_hierarchy.rst @@ -0,0 +1,5 @@ +Working with hierarchy +---------------------- + +.. autocmdgroup:: passes/hierarchy + :members: diff --git a/docs/source/cmd/index_passes_memory.rst b/docs/source/cmd/index_passes_memory.rst new file mode 100644 index 000000000..b4edb88e7 --- /dev/null +++ b/docs/source/cmd/index_passes_memory.rst @@ -0,0 +1,5 @@ +Memory handling +--------------- + +.. autocmdgroup:: passes/memory + :members: diff --git a/docs/source/cmd/index_passes_opt.rst b/docs/source/cmd/index_passes_opt.rst new file mode 100644 index 000000000..ddeb5ce10 --- /dev/null +++ b/docs/source/cmd/index_passes_opt.rst @@ -0,0 +1,5 @@ +Optimization passes +------------------- + +.. autocmdgroup:: passes/opt + :members: diff --git a/docs/source/cmd/index_passes_proc.rst b/docs/source/cmd/index_passes_proc.rst new file mode 100644 index 000000000..1ad8d85b4 --- /dev/null +++ b/docs/source/cmd/index_passes_proc.rst @@ -0,0 +1,5 @@ +Converting process blocks +------------------------- + +.. autocmdgroup:: passes/proc + :members: diff --git a/docs/source/cmd/index_passes_sat.rst b/docs/source/cmd/index_passes_sat.rst new file mode 100644 index 000000000..a2571fedb --- /dev/null +++ b/docs/source/cmd/index_passes_sat.rst @@ -0,0 +1,5 @@ +Simulating circuits +------------------- + +.. autocmdgroup:: passes/sat + :members: diff --git a/docs/source/cmd/index_passes_status.rst b/docs/source/cmd/index_passes_status.rst new file mode 100644 index 000000000..a157ed840 --- /dev/null +++ b/docs/source/cmd/index_passes_status.rst @@ -0,0 +1,5 @@ +Design status +------------- + +.. autocmdgroup:: passes/status + :members: diff --git a/docs/source/cmd/index_passes_techmap.rst b/docs/source/cmd/index_passes_techmap.rst new file mode 100644 index 000000000..1682cd181 --- /dev/null +++ b/docs/source/cmd/index_passes_techmap.rst @@ -0,0 +1,7 @@ +Technology mapping +------------------ + +.. seealso:: :doc:`/cmd/index_techlibs` + +.. autocmdgroup:: passes/techmap + :members: diff --git a/docs/source/cmd/index_techlibs.rst b/docs/source/cmd/index_techlibs.rst new file mode 100644 index 000000000..043620a3b --- /dev/null +++ b/docs/source/cmd/index_techlibs.rst @@ -0,0 +1,11 @@ +Technology libraries +==================== + +Listed in alphabetical order. + +.. toctree:: + :maxdepth: 2 + :glob: + + /cmd/index_techlibs_common + /cmd/index_techlibs_* diff --git a/docs/source/cmd/index_techlibs_achronix.rst b/docs/source/cmd/index_techlibs_achronix.rst new file mode 100644 index 000000000..d4d96d24a --- /dev/null +++ b/docs/source/cmd/index_techlibs_achronix.rst @@ -0,0 +1,5 @@ +Achronix +------------------ + +.. autocmdgroup:: techlibs/achronix + :members: diff --git a/docs/source/cmd/index_techlibs_anlogic.rst b/docs/source/cmd/index_techlibs_anlogic.rst new file mode 100644 index 000000000..8a2e6b577 --- /dev/null +++ b/docs/source/cmd/index_techlibs_anlogic.rst @@ -0,0 +1,5 @@ +Anlogic +------------------ + +.. autocmdgroup:: techlibs/anlogic + :members: diff --git a/docs/source/cmd/index_techlibs_common.rst b/docs/source/cmd/index_techlibs_common.rst new file mode 100644 index 000000000..532f4291e --- /dev/null +++ b/docs/source/cmd/index_techlibs_common.rst @@ -0,0 +1,5 @@ +Generic +------------------ + +.. autocmdgroup:: techlibs/common + :members: diff --git a/docs/source/cmd/index_techlibs_coolrunner2.rst b/docs/source/cmd/index_techlibs_coolrunner2.rst new file mode 100644 index 000000000..23d91a500 --- /dev/null +++ b/docs/source/cmd/index_techlibs_coolrunner2.rst @@ -0,0 +1,5 @@ +CoolRunner-II +------------------ + +.. autocmdgroup:: techlibs/coolrunner2 + :members: diff --git a/docs/source/cmd/index_techlibs_easic.rst b/docs/source/cmd/index_techlibs_easic.rst new file mode 100644 index 000000000..c6398ddf3 --- /dev/null +++ b/docs/source/cmd/index_techlibs_easic.rst @@ -0,0 +1,5 @@ +eASIC +------------------ + +.. autocmdgroup:: techlibs/easic + :members: diff --git a/docs/source/cmd/index_techlibs_ecp5.rst b/docs/source/cmd/index_techlibs_ecp5.rst new file mode 100644 index 000000000..29fd309cf --- /dev/null +++ b/docs/source/cmd/index_techlibs_ecp5.rst @@ -0,0 +1,5 @@ +ECP5 +------------------ + +.. autocmdgroup:: techlibs/ecp5 + :members: diff --git a/docs/source/cmd/index_techlibs_fabulous.rst b/docs/source/cmd/index_techlibs_fabulous.rst new file mode 100644 index 000000000..96f04f40a --- /dev/null +++ b/docs/source/cmd/index_techlibs_fabulous.rst @@ -0,0 +1,5 @@ +FABulous +------------------ + +.. autocmdgroup:: techlibs/fabulous + :members: diff --git a/docs/source/cmd/index_techlibs_gatemate.rst b/docs/source/cmd/index_techlibs_gatemate.rst new file mode 100644 index 000000000..951d0000b --- /dev/null +++ b/docs/source/cmd/index_techlibs_gatemate.rst @@ -0,0 +1,5 @@ +Gatemate +------------------ + +.. autocmdgroup:: techlibs/gatemate + :members: diff --git a/docs/source/cmd/index_techlibs_gowin.rst b/docs/source/cmd/index_techlibs_gowin.rst new file mode 100644 index 000000000..cdcb1c2ee --- /dev/null +++ b/docs/source/cmd/index_techlibs_gowin.rst @@ -0,0 +1,5 @@ +Gowin +------------------ + +.. autocmdgroup:: techlibs/gowin + :members: diff --git a/docs/source/cmd/index_techlibs_greenpak4.rst b/docs/source/cmd/index_techlibs_greenpak4.rst new file mode 100644 index 000000000..add1ab102 --- /dev/null +++ b/docs/source/cmd/index_techlibs_greenpak4.rst @@ -0,0 +1,5 @@ +GreenPAK4 +------------------ + +.. autocmdgroup:: techlibs/greenpak4 + :members: diff --git a/docs/source/cmd/index_techlibs_ice40.rst b/docs/source/cmd/index_techlibs_ice40.rst new file mode 100644 index 000000000..1c4b2d07a --- /dev/null +++ b/docs/source/cmd/index_techlibs_ice40.rst @@ -0,0 +1,5 @@ +iCE40 +------------------ + +.. autocmdgroup:: techlibs/ice40 + :members: diff --git a/docs/source/cmd/index_techlibs_intel.rst b/docs/source/cmd/index_techlibs_intel.rst new file mode 100644 index 000000000..6b3a26222 --- /dev/null +++ b/docs/source/cmd/index_techlibs_intel.rst @@ -0,0 +1,5 @@ +Intel (MAX10, Cyclone IV) +------------------------- + +.. autocmdgroup:: techlibs/intel + :members: diff --git a/docs/source/cmd/index_techlibs_intel_alm.rst b/docs/source/cmd/index_techlibs_intel_alm.rst new file mode 100644 index 000000000..afadfc13e --- /dev/null +++ b/docs/source/cmd/index_techlibs_intel_alm.rst @@ -0,0 +1,5 @@ +Intel ALM (Cyclone V, Arria V, Cyclone 10 GX) +--------------------------------------------- + +.. autocmdgroup:: techlibs/intel_alm + :members: diff --git a/docs/source/cmd/index_techlibs_lattice.rst b/docs/source/cmd/index_techlibs_lattice.rst new file mode 100644 index 000000000..985bf0bbd --- /dev/null +++ b/docs/source/cmd/index_techlibs_lattice.rst @@ -0,0 +1,5 @@ +Lattice +------------------ + +.. autocmdgroup:: techlibs/lattice + :members: diff --git a/docs/source/cmd/index_techlibs_lattice_nexus.rst b/docs/source/cmd/index_techlibs_lattice_nexus.rst new file mode 100644 index 000000000..d5ac4184c --- /dev/null +++ b/docs/source/cmd/index_techlibs_lattice_nexus.rst @@ -0,0 +1,5 @@ +Lattice Nexus +------------------ + +.. autocmdgroup:: techlibs/nexus + :members: diff --git a/docs/source/cmd/index_techlibs_microchip.rst b/docs/source/cmd/index_techlibs_microchip.rst new file mode 100644 index 000000000..06613a59c --- /dev/null +++ b/docs/source/cmd/index_techlibs_microchip.rst @@ -0,0 +1,5 @@ +Microchip +------------------ + +.. autocmdgroup:: techlibs/microchip + :members: diff --git a/docs/source/cmd/index_techlibs_microchip_sf2.rst b/docs/source/cmd/index_techlibs_microchip_sf2.rst new file mode 100644 index 000000000..4ebe47f33 --- /dev/null +++ b/docs/source/cmd/index_techlibs_microchip_sf2.rst @@ -0,0 +1,5 @@ +Microchip - SmartFusion2/IGLOO2 +----------------------------------- + +.. autocmdgroup:: techlibs/sf2 + :members: diff --git a/docs/source/cmd/index_techlibs_nanoxplore.rst b/docs/source/cmd/index_techlibs_nanoxplore.rst new file mode 100644 index 000000000..9eff4681c --- /dev/null +++ b/docs/source/cmd/index_techlibs_nanoxplore.rst @@ -0,0 +1,5 @@ +NanoXplore +------------------ + +.. autocmdgroup:: techlibs/nanoxplore + :members: diff --git a/docs/source/cmd/index_techlibs_quicklogic.rst b/docs/source/cmd/index_techlibs_quicklogic.rst new file mode 100644 index 000000000..54d199eb0 --- /dev/null +++ b/docs/source/cmd/index_techlibs_quicklogic.rst @@ -0,0 +1,5 @@ +QuickLogic +------------------ + +.. autocmdgroup:: techlibs/quicklogic + :members: diff --git a/docs/source/cmd/index_techlibs_xilinx.rst b/docs/source/cmd/index_techlibs_xilinx.rst new file mode 100644 index 000000000..df5112b7e --- /dev/null +++ b/docs/source/cmd/index_techlibs_xilinx.rst @@ -0,0 +1,5 @@ +Xilinx +------------------ + +.. autocmdgroup:: techlibs/xilinx + :members: diff --git a/docs/source/cmd_ref.rst b/docs/source/cmd_ref.rst index d2d59ba54..668516a0b 100644 --- a/docs/source/cmd_ref.rst +++ b/docs/source/cmd_ref.rst @@ -5,10 +5,31 @@ Command line reference .. literalinclude:: /generated/yosys :start-at: Usage -.. toctree:: - :caption: Command reference - :maxdepth: 1 - :glob: +.. _cmd_ref: - /appendix/env_vars - /cmd/* +Command reference +----------------- + +.. todo:: Can we warn on command groups that aren't included anywhere? + +:ref:`List of all commands` + +.. toctree:: + :maxdepth: 2 + + /appendix/env_vars + /cmd/index_frontends + /cmd/index_backends + /cmd/index_kernel + /cmd/index_formal + +.. toctree:: + :maxdepth: 3 + + /cmd/index_passes + /cmd/index_techlibs + +.. toctree:: + :maxdepth: 2 + + /cmd/index_internal diff --git a/docs/source/code_examples/macro_commands/prep.ys b/docs/source/code_examples/macro_commands/prep.ys new file mode 100644 index 000000000..1bec907f6 --- /dev/null +++ b/docs/source/code_examples/macro_commands/prep.ys @@ -0,0 +1,23 @@ +#start:The following commands are executed by this synthesis command: +#end:$ +begin: + hierarchy -check [-top | -auto-top] + +coarse: + proc [-ifx] + flatten (if -flatten) + future + opt_expr -keepdc + opt_clean + check + opt -noff -keepdc + wreduce -keepdc [-memx] + memory_dff (if -rdff) + memory_memx (if -memx) + opt_clean + memory_collect + opt -noff -keepdc -fast + +check: + stat + check diff --git a/docs/source/conf.py b/docs/source/conf.py index e587b8d31..7cdea5df1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -43,8 +43,12 @@ html_static_path = ['_static', "_images"] # default to no highlight highlight_language = 'none' -# default single quotes to attempt auto reference, or fallback to code +# default single quotes to attempt auto reference, or fallback to yoscrypt default_role = 'autoref' +rst_prolog = """ +.. role:: yoscrypt(code) + :language: yoscrypt +""" extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex'] @@ -105,12 +109,14 @@ latex_elements = { # custom cmd-ref parsing/linking sys.path += [os.path.dirname(__file__) + "/../"] -extensions.append('util.cmdref') +extensions.append('util.custom_directives') # use autodocs extensions.append('sphinx.ext.autodoc') -extensions.append('util.cellref') +extensions.append('util.cell_documenter') cells_json = Path(__file__).parent / 'generated' / 'cells.json' +extensions.append('util.cmd_documenter') +cmds_json = Path(__file__).parent / 'generated' / 'cmds.json' from sphinx.application import Sphinx def setup(app: Sphinx) -> None: diff --git a/docs/source/getting_started/example_synth.rst b/docs/source/getting_started/example_synth.rst index e215586cc..ccf0d252b 100644 --- a/docs/source/getting_started/example_synth.rst +++ b/docs/source/getting_started/example_synth.rst @@ -70,7 +70,7 @@ At the bottom of the `help` output for `synth_ice40` is the complete list of commands called by this script. Let's start with the section labeled ``begin``: -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: begin: :end-before: flatten: @@ -143,8 +143,8 @@ line refers to the line numbers of the start/end of the corresponding ``always @`` block. In the case of an ``initial`` block, we instead see the ``PROC`` referring to line 0. -To handle these, let us now introduce the next command: :doc:`/cmd/proc`. `proc` -is a macro command like `synth_ice40`. Rather than modifying the design +To handle these, let us now introduce the next command: :cmd:title:`proc`. +`proc` is a macro command like `synth_ice40`. Rather than modifying the design directly, it instead calls a series of other commands. In the case of `proc`, these sub-commands work to convert the behavioral logic of processes into multiplexers and registers. Let's see what happens when we run it. For now, we @@ -188,7 +188,7 @@ opt_expr `. .. note:: - :doc:`/cmd/clean` can also be called with two semicolons after any command, + :cmd:title:`clean` can also be called with two semicolons after any command, for example we could have called :yoscrypt:`opt_expr;;` instead of :yoscrypt:`opt_expr; clean`. You may notice some scripts will end each line with ``;;``. It is beneficial to run `clean` before inspecting intermediate @@ -215,8 +215,8 @@ Note that if we tried to run this command now then we would get an error. This is because we already removed all of the modules other than ``addr_gen``. We could restart our shell session, but instead let's use two new commands: -- :doc:`/cmd/design`, and -- :doc:`/cmd/read_verilog`. +- :cmd:title:`design`, and +- :cmd:title:`read_verilog`. .. literalinclude:: /code_examples/fifo/fifo.out :language: doscon @@ -251,7 +251,7 @@ our design won't run into this issue, we can skip the ``-defer``. We can also run `proc` now to finish off the full :ref:`synth_begin`. Because the design schematic is quite large, we will be showing just the data path for the ``rdata`` output. If you would like to see the entire design for yourself, -you can do so with :doc:`/cmd/show`. Note that the `show` command only works +you can do so with :cmd:title:`show`. Note that the `show` command only works with a single module, so you may need to call it with :yoscrypt:`show fifo`. :ref:`show_intro` section in :doc:`/getting_started/scripting_intro` has more on how to use `show`. @@ -283,7 +283,7 @@ Flattening At this stage of a synthesis flow there are a few other commands we could run. In `synth_ice40` we get these: -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: flatten: :end-before: coarse: @@ -355,7 +355,7 @@ Part 1 In the iCE40 flow, we start with the following commands: -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: coarse: :end-before: wreduce @@ -371,7 +371,7 @@ wasting time on something we know is impossible. Next up is :yoscrypt:`opt -nodffe -nosdff` performing a set of simple optimizations on the design. This command also ensures that only a specific subset of FF types are included, in preparation for the next command: -:doc:`/cmd/fsm`. Both `opt` and `fsm` are macro commands which are explored in +:cmd:title:`fsm`. Both `opt` and `fsm` are macro commands which are explored in more detail in :doc:`/using_yosys/synthesis/opt` and :doc:`/using_yosys/synthesis/fsm` respectively. @@ -403,7 +403,7 @@ Part 2 The next group of commands performs a series of optimizations: -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-at: wreduce :end-before: t:$mul @@ -411,7 +411,7 @@ The next group of commands performs a series of optimizations: :caption: ``coarse`` section (part 2) :name: synth_coarse2 -First up is :doc:`/cmd/wreduce`. If we run this we get the following: +First up is :cmd:title:`wreduce`. If we run this we get the following: .. literalinclude:: /code_examples/fifo/fifo.out :language: doscon @@ -432,7 +432,7 @@ the schematic and see the output of that cell has now changed. ``rdata`` output after `wreduce` -The next two (new) commands are :doc:`/cmd/peepopt` and :doc:`/cmd/share`. +The next two (new) commands are :cmd:title:`peepopt` and :cmd:title:`share`. Neither of these affect our design, and they're explored in more detail in :doc:`/using_yosys/synthesis/opt`, so let's skip over them. :yoscrypt:`techmap -map +/cmp2lut.v -D LUT_WIDTH=4` optimizes certain comparison operators by @@ -440,7 +440,7 @@ converting them to LUTs instead. The usage of `techmap` is explored more in :doc:`/using_yosys/synthesis/techmap_synth`. Our next command to run is -:doc:`/cmd/memory_dff`. +:cmd:title:`memory_dff`. .. literalinclude:: /code_examples/fifo/fifo.out :language: doscon @@ -475,7 +475,7 @@ will only be performed if called with the ``-dsp`` flag: :yoscrypt:`synth_ice40 -dsp`. While our example has nothing that could be mapped to DSPs we can still take a quick look at the commands here and describe what they do. -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-at: t:$mul :end-before: alumacc @@ -514,7 +514,7 @@ Part 4 That brings us to the fourth and final part for the iCE40 synthesis flow: -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-at: alumacc :end-before: map_ram: @@ -543,7 +543,7 @@ Once these cells have been inserted, the call to `opt` can combine cells which are now identical but may have been missed due to e.g. the difference between `$add` and `$sub`. -The other new command in this part is :doc:`/cmd/memory`. `memory` is another +The other new command in this part is :cmd:title:`memory`. `memory` is another macro command which we examine in more detail in :doc:`/using_yosys/synthesis/memory`. For this document, let us focus just on the step most relevant to our example: `memory_collect`. Up until this point, @@ -594,7 +594,7 @@ Memory blocks Mapping to hard memory blocks uses a combination of `memory_libmap` and `techmap`. -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: map_ram: :end-before: map_ffram: @@ -636,7 +636,7 @@ into flip flops (the ``logic fallback``) with `memory_map`. .. |techlibs/ice40/brams_map.v| replace:: :file:`techlibs/ice40/brams_map.v` .. _techlibs/ice40/brams_map.v: https://github.com/YosysHQ/yosys/tree/main/techlibs/ice40/brams_map.v -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: map_ffram: :end-before: map_gates: @@ -671,7 +671,7 @@ an explosion in cells as multi-bit `$mux` and `$adffe` are replaced with single-bit `$_MUX_` and `$_DFFE_PP0P_` cells, while the `$alu` is replaced with primitive `$_OR_` and `$_NOT_` gates and a `$lut` cell. -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: map_gates: :end-before: map_ffs: @@ -700,7 +700,7 @@ mapped to hardware into gate-level primitives. This includes optimizing `$_MUX_` cells where one of the inputs is a constant ``1'0``, replacing it instead with an `$_AND_` cell. -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: map_ffs: :end-before: map_luts: @@ -725,7 +725,7 @@ LUTs `abc`. For more on what these do, and what the difference between these two commands are, refer to :doc:`/using_yosys/synthesis/abc`. -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: map_luts: :end-before: map_cells: @@ -742,7 +742,7 @@ commands are, refer to :doc:`/using_yosys/synthesis/abc`. Finally we use `techmap` to map the generic `$lut` cells to iCE40 ``SB_LUT4`` cells. -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: map_cells: :end-before: check: @@ -784,19 +784,18 @@ Final steps The next section of the iCE40 synth flow performs some sanity checking and final tidy up: -.. literalinclude:: /cmd/synth_ice40.rst +.. literalinclude:: /code_examples/macro_commands/synth_ice40.ys :language: yoscrypt :start-after: check: - :end-before: blif: :dedent: :name: check :caption: ``check`` section The new commands here are: -- :doc:`/cmd/autoname`, -- :doc:`/cmd/stat`, and -- :doc:`/cmd/blackbox`. +- :cmd:title:`autoname`, +- :cmd:title:`stat`, and +- :cmd:title:`blackbox`. The output from `stat` is useful for checking resource utilization; providing a list of cells used in the design and the number of each, as well as the number @@ -835,9 +834,9 @@ Synthesis output The iCE40 synthesis flow has the following output modes available: -- :doc:`/cmd/write_blif`, -- :doc:`/cmd/write_edif`, and -- :doc:`/cmd/write_json`. +- `write_blif`, +- `write_edif`, and +- `write_json`. As an example, if we called :yoscrypt:`synth_ice40 -top fifo -json fifo.json`, our synthesized ``fifo`` design will be output as :file:`fifo.json`. We can @@ -848,4 +847,4 @@ is beyond the scope of this documentation. .. _nextpnr: https://github.com/YosysHQ/nextpnr -.. seealso:: :doc:`/cmd/synth_ice40` +.. seealso:: :cmd:title:`synth_ice40` diff --git a/docs/source/getting_started/scripting_intro.rst b/docs/source/getting_started/scripting_intro.rst index 6a6e4ff51..c44ce82a8 100644 --- a/docs/source/getting_started/scripting_intro.rst +++ b/docs/source/getting_started/scripting_intro.rst @@ -129,7 +129,7 @@ module. Detailed documentation of the select framework can be found under :doc:`/using_yosys/more_scripting/selections` or in the command reference at -:doc:`/cmd/select`. +:cmd:title:`select`. .. _show_intro: @@ -226,7 +226,7 @@ those used in options, must be a single expression instead. .. _GraphViz color docs: https://graphviz.org/doc/info/colors For all of the options available to `show`, check the command reference at -:doc:`/cmd/show`. +:cmd:title:`show`. .. seealso:: :ref:`interactive_show` on the :doc:`/using_yosys/more_scripting/interactive_investigation` page. diff --git a/docs/source/index.rst b/docs/source/index.rst index 61dc114ef..403100093 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -5,7 +5,7 @@ Yosys Open SYnthesis Suite Yosys is an open source framework for RTL synthesis. To learn more about Yosys, see :doc:`/introduction`. For a quick guide on how to get started using Yosys, check out :doc:`/getting_started/index`. For the complete list of commands -available, go to :ref:`commandindex`. +available, go to :ref:`cmd_ref`. .. todo:: look into command ref improvements diff --git a/docs/source/using_yosys/more_scripting/interactive_investigation.rst b/docs/source/using_yosys/more_scripting/interactive_investigation.rst index ca4c76ee7..0d1a17503 100644 --- a/docs/source/using_yosys/more_scripting/interactive_investigation.rst +++ b/docs/source/using_yosys/more_scripting/interactive_investigation.rst @@ -323,10 +323,10 @@ tools). design into an equivalent design that is easier to analyse. - Commands such as `eval` and `sat` can be used to investigate the behavior of the circuit. -- :doc:`/cmd/show`. -- :doc:`/cmd/dump`. -- :doc:`/cmd/add` and :doc:`/cmd/delete` can be used to modify and reorganize a - design dynamically. +- :cmd:title:`show`. +- :cmd:title:`dump`. +- :cmd:title:`add` and :cmd:title:`delete` can be used to modify and reorganize + a design dynamically. The code used is included in the Yosys code base under |code_examples/scrambler|_. @@ -358,7 +358,7 @@ reorganizing a module in Yosys and checking the resulting circuit. .. figure:: /_images/code_examples/scrambler/scrambler_p02.* :class: width-helper invert-helper -Analyzing the resulting circuit with :doc:`/cmd/eval`: +Analyzing the resulting circuit with :cmd:title:`eval`: .. todo:: replace inline code diff --git a/docs/source/using_yosys/more_scripting/load_design.rst b/docs/source/using_yosys/more_scripting/load_design.rst index 7e417eff9..e5006c16e 100644 --- a/docs/source/using_yosys/more_scripting/load_design.rst +++ b/docs/source/using_yosys/more_scripting/load_design.rst @@ -86,7 +86,7 @@ Yosys frontends The `read_verilog` command """""""""""""""""""""""""" -- :doc:`/cmd/read_verilog` +- :doc:`/cmd/index_frontends` - supports most of Verilog-2005 - limited support for SystemVerilog - some non-standard features/extensions for enabling formal verification diff --git a/docs/source/using_yosys/more_scripting/selections.rst b/docs/source/using_yosys/more_scripting/selections.rst index e82f23497..1f3912956 100644 --- a/docs/source/using_yosys/more_scripting/selections.rst +++ b/docs/source/using_yosys/more_scripting/selections.rst @@ -93,7 +93,7 @@ Special patterns can be used to select by object property or type. For example: A:blabla` - select all `$add` cells from the module foo: :yoscrypt:`select foo/t:$add` -A complete list of pattern expressions can be found in :doc:`/cmd/select`. +A complete list of pattern expressions can be found in :cmd:title:`select`. Operations on selections ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -141,7 +141,7 @@ Some of the special ``%``-codes: - ``%i``: intersection of top two elements on stack -- pop 2, push 1 - ``%n``: inverse of top element on stack -- pop 1, push 1 -See :doc:`/cmd/select` for the full list. +See :cmd:title:`select` for the full list. Expanding selections ^^^^^^^^^^^^^^^^^^^^ @@ -354,7 +354,7 @@ boolean operations such as intersection (``%i``) and difference (``%d``) are powerful tools for extracting the relevant portions of the circuit under investigation. -Again, see :doc:`/cmd/select` for full documentation of these expressions. +Again, see :cmd:title:`select` for full documentation of these expressions. Incremental selection ^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/using_yosys/synthesis/fsm.rst b/docs/source/using_yosys/synthesis/fsm.rst index 6fad81d54..07a3cc9cc 100644 --- a/docs/source/using_yosys/synthesis/fsm.rst +++ b/docs/source/using_yosys/synthesis/fsm.rst @@ -10,7 +10,7 @@ other commands: :start-after: #end: :caption: Passes called by `fsm` -See also :doc:`/cmd/fsm`. +See also :doc:`/cmd/index_passes_fsm`. The algorithms used for FSM detection and extraction are influenced by a more general reported technique :cite:p:`fsmextract`. diff --git a/docs/source/using_yosys/synthesis/memory.rst b/docs/source/using_yosys/synthesis/memory.rst index a8f2280f7..9b81fb6dc 100644 --- a/docs/source/using_yosys/synthesis/memory.rst +++ b/docs/source/using_yosys/synthesis/memory.rst @@ -26,7 +26,7 @@ Some quick notes: decoder logic and registers. For more information about `memory`, such as disabling certain sub commands, see -:doc:`/cmd/memory`. +:doc:`/cmd/index_passes_memory`. Example ------- diff --git a/docs/source/using_yosys/synthesis/opt.rst b/docs/source/using_yosys/synthesis/opt.rst index 43b558739..56330bc37 100644 --- a/docs/source/using_yosys/synthesis/opt.rst +++ b/docs/source/using_yosys/synthesis/opt.rst @@ -11,8 +11,8 @@ The `opt` macro command The Yosys pass `opt` runs a number of simple optimizations. This includes removing unused signals and cells and const folding. It is recommended to run -this pass after each major step in the synthesis script. As listed in -:doc:`/cmd/opt`, this macro command calls the following ``opt_*`` commands: +this pass after each major step in the synthesis script. This macro command +calls the following ``opt_*`` commands: .. literalinclude:: /code_examples/macro_commands/opt.ys :language: yoscrypt @@ -233,7 +233,5 @@ Other optimizations .. todo:: more on the other optimizations -- :doc:`/cmd/wreduce` -- :doc:`/cmd/peepopt` -- :doc:`/cmd/share` +- Check :doc:`/cmd/index_passes_opt` for more. - `abc` and `abc9`, see also: :doc:`abc`. diff --git a/docs/source/using_yosys/synthesis/proc.rst b/docs/source/using_yosys/synthesis/proc.rst index b7cd348d7..c4ab0f0ea 100644 --- a/docs/source/using_yosys/synthesis/proc.rst +++ b/docs/source/using_yosys/synthesis/proc.rst @@ -17,7 +17,7 @@ commands in a sensible order: After all the ``proc_*`` commands, `opt_expr` is called. This can be disabled by calling :yoscrypt:`proc -noopt`. For more information about `proc`, such as -disabling certain sub commands, see :doc:`/cmd/proc`. +disabling certain sub commands, see :doc:`/cmd/index_passes_proc`. Many commands can not operate on modules with "processess" in them. Usually a call to `proc` is the first command in the actual synthesis procedure after diff --git a/docs/source/using_yosys/synthesis/synth.rst b/docs/source/using_yosys/synthesis/synth.rst index e3d82931b..db81d0790 100644 --- a/docs/source/using_yosys/synthesis/synth.rst +++ b/docs/source/using_yosys/synthesis/synth.rst @@ -6,44 +6,23 @@ Synth commands Packaged ``synth_*`` commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The following is a list of all synth commands included in Yosys for different -platforms. Each command runs a script of sub commands specific to the platform -being targeted. Note that not all of these scripts are actively maintained and -may not be up-to-date. - -- :doc:`/cmd/synth_achronix` -- :doc:`/cmd/synth_anlogic` -- :doc:`/cmd/synth_coolrunner2` -- :doc:`/cmd/synth_easic` -- :doc:`/cmd/synth_ecp5` -- :doc:`/cmd/synth_efinix` -- :doc:`/cmd/synth_fabulous` -- :doc:`/cmd/synth_gatemate` -- :doc:`/cmd/synth_gowin` -- :doc:`/cmd/synth_greenpak4` -- :doc:`/cmd/synth_ice40` -- :doc:`/cmd/synth_intel` (MAX10, Cyclone IV) -- :doc:`/cmd/synth_intel_alm` (Cyclone V, Arria V, Cyclone 10 GX) -- :doc:`/cmd/synth_lattice` -- :doc:`/cmd/synth_nexus` -- :doc:`/cmd/synth_quicklogic` -- :doc:`/cmd/synth_sf2` -- :doc:`/cmd/synth_xilinx` +A list of all synth commands included in Yosys for different platforms can be +found under :doc:`/cmd/index_techlibs`. Each command runs a script of sub +commands specific to the platform being targeted. Note that not all of these +scripts are actively maintained and may not be up-to-date. General synthesis ~~~~~~~~~~~~~~~~~ In addition to the above hardware-specific synth commands, there is also -:doc:`/cmd/prep`. This command is limited to coarse-grain synthesis, without +:cmd:title:`prep`. This command is limited to coarse-grain synthesis, without getting into any architecture-specific mappings or optimizations. Among other things, this is useful for design verification. The following commands are executed by the `prep` command: -.. literalinclude:: /cmd/prep.rst +.. literalinclude:: /code_examples/macro_commands/prep.ys :start-at: begin: - :end-before: .. only:: latex - :dedent: :doc:`/getting_started/example_synth` covers most of these commands and what they do. diff --git a/docs/source/using_yosys/synthesis/techmap_synth.rst b/docs/source/using_yosys/synthesis/techmap_synth.rst index 9e9d42df5..54a715342 100644 --- a/docs/source/using_yosys/synthesis/techmap_synth.rst +++ b/docs/source/using_yosys/synthesis/techmap_synth.rst @@ -33,9 +33,9 @@ reader may find this map file as :file:`techlibs/common/techmap.v` in the Yosys source tree. Additional features have been added to techmap to allow for conditional mapping -of cells (see :doc:`/cmd/techmap`). This can for example be useful if the target -architecture supports hardware multipliers for certain bit-widths but not for -others. +of cells (see :doc:`/cmd/index_passes_techmap`). This can for example be useful +if the target architecture supports hardware multipliers for certain bit-widths +but not for others. A usual synthesis flow would first use the techmap pass to directly map some RTL cells to coarse-grain cells provided by the target architecture (if any) and diff --git a/docs/source/using_yosys/verilog.rst b/docs/source/using_yosys/verilog.rst index 1701458f7..92f223e49 100644 --- a/docs/source/using_yosys/verilog.rst +++ b/docs/source/using_yosys/verilog.rst @@ -94,7 +94,7 @@ Verilog Attributes and non-standard features - The ``keep_hierarchy`` attribute on cells and modules keeps the `flatten` command from flattening the indicated cells and modules. -- The `gate_cost_equivalent` attribute on a module can be used to specify +- The ``gate_cost_equivalent`` attribute on a module can be used to specify the estimated cost of the module as a number of basic gate instances. See the help message of command `keep_hierarchy` which interprets this attribute. diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index c6e22c0cf..b9608d99e 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -138,7 +138,7 @@ Previously, the interface to implement hashing on custom types was just independently and then ad-hoc combined with the hash function with some xorshift operations thrown in to mix bits together somewhat. A plugin can stay compatible with both versions prior and after the break by implementing both interfaces -based on the existance and value of `YS_HASHING_VERSION`. +based on the existance and value of ``YS_HASHING_VERSION``. .. code-block:: cpp :caption: Example hash compatibility wrapper diff --git a/docs/util/cellref.py b/docs/util/cell_documenter.py similarity index 100% rename from docs/util/cellref.py rename to docs/util/cell_documenter.py diff --git a/docs/util/cmd_documenter.py b/docs/util/cmd_documenter.py new file mode 100644 index 000000000..9347d8ffd --- /dev/null +++ b/docs/util/cmd_documenter.py @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +from dataclasses import dataclass +import json +from pathlib import Path, PosixPath, WindowsPath +import re + +from typing import Any +from sphinx.application import Sphinx +from sphinx.ext import autodoc +from sphinx.ext.autodoc import Documenter +from sphinx.util import logging + +logger = logging.getLogger(__name__) + +# cmd signature +cmd_ext_sig_re = re.compile( + r'''^ ([\w/]+::)? # optional group + ([\w$._]+?) # module name + (?:\.([\w_]+))? # optional: thing name + (::[\w_]+)? # attribute + \s* $ # and nothing more + ''', re.VERBOSE) + +class YosysCmdContentListing: + type: str + body: str + source_file: str + source_line: int + options: dict[str, str] + content: list[YosysCmdContentListing] + + def __init__( + self, + type: str = "", + body: str = "", + source_file: str = "unknown", + source_line: int = 0, + options: dict[str, str] = {}, + content: list[dict[str]] = [], + ): + self.type = type + self.body = body + self.source_file = source_file + self.source_line = source_line + self.options = options + self.content = [YosysCmdContentListing(**c) for c in content] + +class YosysCmd: + name: str + title: str + content: list[YosysCmdContentListing] + group: str + source_file: str + source_line: int + source_func: str + experimental_flag: bool + internal_flag: bool + + def __init__( + self, + name:str = "", title:str = "", + content: list[dict[str]] = [], + group: str = 'unknown', + source_file: str = "", + source_line: int = 0, + source_func: str = "", + experimental_flag: bool = False, + internal_flag: bool = False, + ) -> None: + self.name = name + self.title = title + self.content = [YosysCmdContentListing(**c) for c in content] + self.group = group + self.source_file = source_file + self.source_line = source_line + self.source_func = source_func + self.experimental_flag = experimental_flag + self.internal_flag = internal_flag + +class YosysCmdGroupDocumenter(Documenter): + objtype = 'cmdgroup' + priority = 10 + object: tuple[str, list[str]] + lib_key = 'groups' + + option_spec = Documenter.option_spec.copy() + option_spec.update({ + 'caption': autodoc.annotation_option, + 'members': autodoc.members_option, + 'source': autodoc.bool_option, + 'linenos': autodoc.bool_option, + }) + + __cmd_lib: dict[str, list[str] | dict[str]] | None = None + @property + def cmd_lib(self) -> dict[str, list[str] | dict[str]]: + if not self.__cmd_lib: + self.__cmd_lib = {} + cmds_obj: dict[str, dict[str, dict[str]]] + try: + with open(self.config.cmds_json, "r") as f: + cmds_obj = json.loads(f.read()) + except FileNotFoundError: + logger.warning( + f"unable to find cmd lib at {self.config.cmds_json}", + type = 'cmdref', + subtype = 'cmd_lib' + ) + cmds_obj = {} + for (name, obj) in cmds_obj.get(self.lib_key, {}).items(): + self.__cmd_lib[name] = obj + return self.__cmd_lib + + @classmethod + def can_document_member( + cls, + member: Any, + membername: str, + isattr: bool, + parent: Any + ) -> bool: + return False + + def parse_name(self) -> bool: + if not self.options.caption: + self.content_indent = '' + self.fullname = self.modname = self.name + return True + + def import_object(self, raiseerror: bool = False) -> bool: + # get cmd + try: + self.object = (self.modname, self.cmd_lib[self.modname]) + except KeyError: + if raiseerror: + raise + return False + + self.real_modname = self.modname + return True + + def get_sourcename(self) -> str: + return self.env.doc2path(self.env.docname) + + def format_name(self) -> str: + return self.options.caption or '' + + def format_signature(self, **kwargs: Any) -> str: + return self.modname + + def add_directive_header(self, sig: str) -> None: + pass + + def add_content(self, more_content: Any | None) -> None: + pass + + def filter_members( + self, + members: list[tuple[str, Any]], + want_all: bool + ) -> list[tuple[str, Any, bool]]: + return [(x[0], x[1], False) for x in members] + + def get_object_members( + self, + want_all: bool + ) -> tuple[bool, list[tuple[str, Any]]]: + ret: list[tuple[str, str]] = [] + + if want_all: + for member in self.object[1]: + ret.append((member, self.modname)) + else: + memberlist = self.options.members or [] + for name in memberlist: + if name in self.object: + ret.append((name, self.modname)) + else: + logger.warning(('unknown module mentioned in :members: option: ' + f'group {self.modname}, module {name}'), + type='cmdref') + + return False, ret + + def document_members(self, all_members: bool = False) -> None: + want_all = (all_members or + self.options.inherited_members or + self.options.members is autodoc.ALL) + # find out which members are documentable + members_check_module, members = self.get_object_members(want_all) + + # document non-skipped members + memberdocumenters: list[tuple[Documenter, bool]] = [] + for (mname, member, isattr) in self.filter_members(members, want_all): + classes = [cls for cls in self.documenters.values() + if cls.can_document_member(member, mname, isattr, self)] + if not classes: + # don't know how to document this member + continue + # prefer the documenter with the highest priority + classes.sort(key=lambda cls: cls.priority) + # give explicitly separated module name, so that members + # of inner classes can be documented + full_mname = self.format_signature() + '::' + mname + documenter = classes[-1](self.directive, full_mname, self.indent) + memberdocumenters.append((documenter, isattr)) + + member_order = self.options.member_order or self.config.autodoc_member_order + memberdocumenters = self.sort_members(memberdocumenters, member_order) + + for documenter, isattr in memberdocumenters: + documenter.generate( + all_members=True, real_modname=self.real_modname, + check_module=members_check_module and not isattr) + + def generate( + self, + more_content: Any | None = None, + real_modname: str | None = None, + check_module: bool = False, + all_members: bool = False + ) -> None: + if not self.parse_name(): + # need a cmd lib to import from + logger.warning( + f"don't know which cmd lib to import for autodocumenting {self.name}", + type = 'cmdref' + ) + return + + sourcename = self.get_sourcename() + + imported_object = self.import_object(); + if self.lib_key == 'groups' and self.name == 'unknown': + if imported_object: + logger.warning(f"Found commands assigned to group {self.name}: {[x[0] for x in self.object]}", type='cmdref') + else: + return + elif not imported_object: + log_msg = f"unable to load {self.name} with {type(self)}" + if self.lib_key == 'groups': + logger.info(log_msg, type = 'cmdref') + self.add_line(f'.. warning:: No commands found for group {self.name!r}', sourcename) + self.add_line('', sourcename) + self.add_line(' Documentation may have been built without ``source_location`` support.', sourcename) + self.add_line(' Try check :doc:`/cmd/index_other`.', sourcename) + else: + logger.warning(log_msg, type = 'cmdref') + return + + # check __module__ of object (for members not given explicitly) + # if check_module: + # if not self.check_module(): + # return + + self.add_line('', sourcename) + + # format the object's signature, if any + try: + sig = self.format_signature() + except Exception as exc: + logger.warning(('error while formatting signature for %s: %s'), + self.fullname, exc, type='cmdref') + return + + # generate the directive header and options, if applicable + self.add_directive_header(sig) + self.add_line('', sourcename) + + # e.g. the module directive doesn't have content + self.indent += self.content_indent + + # add all content (from docstrings, attribute docs etc.) + self.add_content(more_content) + + # document members, if possible + self.document_members(all_members) + +class YosysCmdDocumenter(YosysCmdGroupDocumenter): + objtype = 'cmd' + priority = 15 + object: YosysCmd + lib_key = 'cmds' + + @classmethod + def can_document_member( + cls, + member: Any, + membername: str, + isattr: bool, + parent: Any + ) -> bool: + if membername.startswith('$'): + return False + return isinstance(parent, YosysCmdGroupDocumenter) + + def parse_name(self) -> bool: + try: + matched = cmd_ext_sig_re.match(self.name) + group, modname, thing, attribute = matched.groups() + except AttributeError: + logger.warning(('invalid signature for auto%s (%r)') % (self.objtype, self.name), + type='cmdref') + return False + + self.modname = modname + self.groupname = group or '' + self.attribute = attribute or '' + self.fullname = ((self.modname) + (thing or '')) + + return True + + def import_object(self, raiseerror: bool = False) -> bool: + if super().import_object(raiseerror): + self.object = YosysCmd(self.modname, **self.object[1]) + return True + return False + + def get_sourcename(self) -> str: + try: + return self.object.source_file + except AttributeError: + return super().get_sourcename() + + def format_name(self) -> str: + return self.object.name + + def format_signature(self, **kwargs: Any) -> str: + return self.fullname + self.attribute + + def add_directive_header(self, sig: str) -> None: + domain = getattr(self, 'domain', self.objtype) + directive = getattr(self, 'directivetype', 'def') + source_name = self.object.source_file + source_line = self.object.source_line + + title = f'{self.object.name} - {self.object.title}' + self.add_line(title, source_name, source_line) + self.add_line('#' * len(title), source_name, source_line) + + # cmd definition + self.add_line(f'.. {domain}:{directive}:: {sig}', source_name, source_line) + if self.object.title: + self.add_line(f' :title: {self.object.title}', source_name, source_line) + + if self.options.noindex: + self.add_line(' :noindex:', source_name) + + def add_content(self, more_content: Any | None) -> None: + # set sourcename and add content from attribute documentation + domain = getattr(self, 'domain', self.objtype) + source_name = self.object.source_file + source_line = self.object.source_line + + if self.object.experimental_flag: + self.add_line(f'.. warning:: This command is experimental', source_name, source_line) + self.add_line('\n', source_name) + + if self.object.internal_flag: + self.add_line(f'.. warning:: This command is intended for internal developer use only', source_name, source_line) + self.add_line('\n', source_name) + + def render(content_list: YosysCmdContentListing, indent: int=0): + content_source = content_list.source_file or source_name + indent_str = ' '*indent + if content_list.type == 'usage': + if content_list.body: + self.add_line(f'{indent_str}.. {domain}:{content_list.type}:: {self.name}::{content_list.body}', content_source) + else: + self.add_line(f'{indent_str}.. {domain}:{content_list.type}:: {self.name}::', content_source) + self.add_line(f'{indent_str} :noindex:', source_name) + self.add_line('', source_name) + elif content_list.type == 'option': + self.add_line(f'{indent_str}:{content_list.type} {content_list.body}:', content_source) + elif content_list.type == 'text': + self.add_line(f'{indent_str}{content_list.body}', content_source) + self.add_line('', source_name) + elif content_list.type == 'code': + language_str = content_list.options.get('language', '') + self.add_line(f'{indent_str}.. code-block:: {language_str}', source_name) + self.add_line('', source_name) + for body_line in content_list.body.splitlines(): + self.add_line(f'{indent_str} {body_line}', content_source) + self.add_line('', source_name) + else: + logger.warning(f"unknown content type '{content_list.type}'") + for content in content_list.content: + render(content, indent+1) + + for content in self.object.content: + render(content) + + if self.get_sourcename() != 'unknown': + self.add_line('\n', source_name) + self.add_line(f'.. note:: Help text automatically generated from :file:`{source_name}:{source_line}`', source_name) + + # add additional content (e.g. from document), if present + if more_content: + for line, src in zip(more_content.data, more_content.items): + self.add_line(line, src[0], src[1]) + + def get_object_members( + self, + want_all: bool + ) -> tuple[bool, list[tuple[str, Any]]]: + + return False, [] + +class YosysCmdRstDocumenter(YosysCmdDocumenter): + objtype = 'cmd_rst' + priority = 0 + + @classmethod + def can_document_member(cls, *args) -> bool: + return False + + def add_directive_header(self, sig): + source_name = self.object.source_file + cmd = self.object.name + self.add_line(f'.. code-block:: rst', source_name) + self.add_line(f' :caption: Generated rst for ``.. autocmd:: {cmd}``', source_name) + + def add_content(self, more_content): + source_name = self.object.source_file + cmd = self.object.name + self.domain = 'cmd' + super().add_directive_header(cmd) + self.add_line('', source_name) + self.indent += self.content_indent + super().add_content(more_content) + +def setup(app: Sphinx) -> dict[str, Any]: + app.add_config_value('cmds_json', False, 'html', [Path, PosixPath, WindowsPath]) + app.setup_extension('sphinx.ext.autodoc') + app.add_autodocumenter(YosysCmdGroupDocumenter) + app.add_autodocumenter(YosysCmdDocumenter) + app.add_autodocumenter(YosysCmdRstDocumenter) + return { + 'version': '2', + 'parallel_read_safe': True, + } diff --git a/docs/util/cmdref.py b/docs/util/custom_directives.py similarity index 81% rename from docs/util/cmdref.py rename to docs/util/custom_directives.py index a31b08e0d..b90584aa7 100644 --- a/docs/util/cmdref.py +++ b/docs/util/custom_directives.py @@ -4,20 +4,21 @@ from __future__ import annotations import re from typing import cast +import warnings from docutils import nodes -from docutils.nodes import Node, Element, system_message +from docutils.nodes import Node, Element, Text from docutils.parsers.rst import directives from docutils.parsers.rst.states import Inliner from sphinx.application import Sphinx from sphinx.domains import Domain, Index from sphinx.domains.std import StandardDomain from sphinx.environment import BuildEnvironment -from sphinx.roles import XRefRole +from sphinx.roles import XRefRole, SphinxRole from sphinx.directives import ObjectDescription from sphinx.directives.code import container_wrapper from sphinx.util.nodes import make_refnode -from sphinx.util.docfields import Field +from sphinx.util.docfields import Field, GroupedField from sphinx import addnodes class TocNode(ObjectDescription): @@ -31,7 +32,7 @@ class TocNode(ObjectDescription): signode['ids'].append(idx) def _object_hierarchy_parts(self, sig_node: addnodes.desc_signature) -> tuple[str, ...]: - if 'fullname' not in sig_node: + if 'tocname' not in sig_node: return () modname = sig_node.get('module') @@ -57,16 +58,56 @@ class TocNode(ObjectDescription): return '.'.join(parents + [name]) return '' -class CommandNode(TocNode): +class NodeWithOptions(TocNode): + """A custom node with options.""" + + doc_field_types = [ + GroupedField('opts', label='Options', names=('option', 'options', 'opt', 'opts')), + ] + + def transform_content(self, contentnode: addnodes.desc_content) -> None: + """hack `:option -thing: desc` into a proper option list with yoscrypt highlighting""" + newchildren = [] + for node in contentnode: + newnode = node + if isinstance(node, nodes.field_list): + newnode = nodes.option_list() + for field in node: + is_option = False + option_list_item = nodes.option_list_item() + for child in field: + if isinstance(child, nodes.field_name): + option_group = nodes.option_group() + option_list_item += option_group + option = nodes.option() + option_group += option + name, text = child.rawsource.split(' ', 1) + is_option = name == 'option' + literal = nodes.literal(text=text) + literal['classes'] += ['code', 'highlight', 'yoscrypt'] + literal['language'] = 'yoscrypt' + option += literal + if not is_option: warnings.warn(f'unexpected option \'{name}\' in {field.source}') + elif isinstance(child, nodes.field_body): + description = nodes.description() + description += child.children + option_list_item += description + if is_option: + newnode += option_list_item + newchildren.append(newnode) + contentnode.children = newchildren + +class CommandNode(NodeWithOptions): """A custom node that describes a command.""" name = 'cmd' required_arguments = 1 - option_spec = { + option_spec = NodeWithOptions.option_spec.copy() + option_spec.update({ 'title': directives.unchanged, 'tags': directives.unchanged - } + }) def handle_signature(self, sig, signode: addnodes.desc_signature): signode['fullname'] = sig @@ -93,6 +134,46 @@ class CommandNode(TocNode): idx, 0)) +class CommandUsageNode(NodeWithOptions): + """A custom node that describes command usages""" + + name = 'cmdusage' + + option_spec = NodeWithOptions.option_spec + option_spec.update({ + 'usage': directives.unchanged, + }) + + def handle_signature(self, sig: str, signode: addnodes.desc_signature): + parts = sig.split('::') + if len(parts) > 2: parts.pop(0) + use = parts[-1] + signode['fullname'] = '::'.join(parts) + usage = self.options.get('usage', use) + if usage: + signode['tocname'] = usage + signode += addnodes.desc_name(text=usage) + return signode['fullname'] + + def add_target_and_index( + self, + name: str, + sig: str, + signode: addnodes.desc_signature + ) -> None: + idx = ".".join(name.split("::")) + signode['ids'].append(idx) + if 'noindex' not in self.options: + tocname: str = signode.get('tocname', name) + objs = self.env.domaindata[self.domain]['objects'] + # (name, sig, typ, docname, anchor, prio) + objs.append((name, + tocname, + type(self).name, + self.env.docname, + idx, + 1)) + class PropNode(TocNode): name = 'prop' fieldname = 'props' @@ -393,7 +474,7 @@ class TagIndex(Index): lis.append(( dispname, 0, docname, anchor, - docname, '', typ + '', '', '' )) ret = [(k, v) for k, v in sorted(content.items())] @@ -432,18 +513,19 @@ class CommandIndex(Index): Qualifier and description are not rendered e.g. in LaTeX output. """ - content = {} + content: dict[str, list[tuple]] = {} items = ((name, dispname, typ, docname, anchor) for name, dispname, typ, docname, anchor, prio in self.domain.get_objects() if typ == self.name) items = sorted(items, key=lambda item: item[0]) for name, dispname, typ, docname, anchor in items: + title = self.domain.data['obj2title'].get(name) lis = content.setdefault(self.shortname, []) lis.append(( dispname, 0, docname, anchor, - '', '', typ + '', '', title )) ret = [(k, v) for k, v in sorted(content.items())] @@ -507,16 +589,27 @@ class PropIndex(TagIndex): return (ret, True) +class TitleRefRole(XRefRole): + """XRefRole used which has the cmd title as the displayed text.""" + pass + +class OptionRole(SphinxRole): + def run(self) -> tuple[list[Node], list]: + return self.inliner.interpreted(self.rawtext, self.text, 'yoscrypt', self.lineno) + class CommandDomain(Domain): name = 'cmd' label = 'Yosys commands' roles = { - 'ref': XRefRole() + 'ref': XRefRole(), + 'title': TitleRefRole(), + 'option': OptionRole(), } directives = { 'def': CommandNode, + 'usage': CommandUsageNode, } indices = { @@ -542,7 +635,7 @@ class CommandDomain(Domain): def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - + match = [(docname, anchor, name) for name, sig, typ, docname, anchor, prio in self.get_objects() if sig == target] @@ -552,9 +645,17 @@ class CommandDomain(Domain): targ = match[0][1] qual_name = match[0][2] title = self.data['obj2title'].get(qual_name, targ) - - return make_refnode(builder,fromdocname,todocname, - targ, contnode, title) + + if typ == 'title': + # caller wants the title in the content of the node + cmd = contnode.astext() + contnode = Text(f'{cmd} - {title}') + return make_refnode(builder, fromdocname, todocname, + targ, contnode) + else: + # cmd title as hover text + return make_refnode(builder, fromdocname, todocname, + targ, contnode, title) else: print(f"Missing ref for {target} in {fromdocname} ") return None @@ -592,10 +693,18 @@ class CellDomain(CommandDomain): def autoref(name, rawtext: str, text: str, lineno, inliner: Inliner, options=None, content=None): - role = 'cell:ref' if text[0] == '$' else 'cmd:ref' - if text.startswith("help ") and text.count(' ') == 1: - _, cmd = text.split(' ', 1) - text = f'{text} <{cmd}>' + words = text.split(' ') + if len(words) == 2 and words[0] == "help": + IsLinkable = True + thing = words[1] + else: + IsLinkable = len(words) == 1 and words[0][0] != '-' + thing = words[0] + if IsLinkable: + role = 'cell:ref' if thing[0] == '$' else 'cmd:ref' + text = f'{text} <{thing}>' + else: + role = 'yoscrypt' return inliner.interpreted(rawtext, text, role, lineno) def setup(app: Sphinx): @@ -622,4 +731,7 @@ def setup(app: Sphinx): app.add_role('autoref', autoref) - return {'version': '0.2'} + return { + 'version': '0.3', + 'parallel_read_safe': False, + } diff --git a/kernel/json.h b/kernel/json.h index c9aa0e045..e8905c8e1 100644 --- a/kernel/json.h +++ b/kernel/json.h @@ -90,10 +90,10 @@ public: template void array(const T &&values) { - begin_object(); + begin_array(); for (auto &item : values) value(item); - end_object(); + end_array(); } }; diff --git a/kernel/log_help.cc b/kernel/log_help.cc new file mode 100644 index 000000000..45228b024 --- /dev/null +++ b/kernel/log_help.cc @@ -0,0 +1,151 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2025 Krystine Dawn + * + * 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/log_help.h" + +USING_YOSYS_NAMESPACE + +Json ContentListing::to_json() { + Json::object object; + object["type"] = type; + if (body.length()) object["body"] = body; + if (strcmp(source_file, "unknown") != 0) object["source_file"] = source_file; + if (source_line != 0) object["source_line"] = source_line; + object["options"] = Json(options); + Json::array content_array; + for (auto child : _content) content_array.push_back(child->to_json()); + object["content"] = content_array; + return object; +} + +void ContentListing::usage(const string &text, + const source_location location) +{ + log_assert(type.compare("root") == 0); + add_content("usage", text, location); +} + +void ContentListing::option(const string &text, const string &description, + const source_location location) +{ + auto option = open_option(text); + if (description.length()) + option->add_content("text", description, location); +} + +void ContentListing::codeblock(const string &code, const string &language, + const source_location location) +{ + add_content("code", code, location); + back()->set_option("language", language); +} + +void ContentListing::paragraph(const string &text, + const source_location location) +{ + add_content("text", text, location); +} + +ContentListing* ContentListing::open_usage(const string &text, + const source_location location) +{ + usage(text, location); + return back(); +} + +ContentListing* ContentListing::open_option(const string &text, + const source_location location) +{ + log_assert(type.compare("root") == 0 || type.compare("usage") == 0); + auto option = new ContentListing("option", text, location); + add_content(option); + return option; +} + +#define MAX_LINE_LEN 80 +void log_pass_str(const std::string &pass_str, std::string indent_str, bool leading_newline=false) { + if (pass_str.empty()) + return; + std::istringstream iss(pass_str); + if (leading_newline) + log("\n"); + for (std::string line; std::getline(iss, line);) { + log("%s", indent_str.c_str()); + auto curr_len = indent_str.length(); + std::istringstream lss(line); + for (std::string word; std::getline(lss, word, ' ');) { + while (word[0] == '`' && word.back() == '`') + word = word.substr(1, word.length()-2); + if (curr_len + word.length() >= MAX_LINE_LEN-1) { + curr_len = 0; + log("\n%s", indent_str.c_str()); + } + if (word.length()) { + log("%s ", word.c_str()); + curr_len += word.length() + 1; + } + } + log("\n"); + } +} +void log_pass_str(const std::string &pass_str, int indent=0, bool leading_newline=false) { + std::string indent_str(indent*4, ' '); + log_pass_str(pass_str, indent_str, leading_newline); +} + +PrettyHelp *current_help = nullptr; + +PrettyHelp::PrettyHelp() +{ + _prior = current_help; + _root_listing = ContentListing("root", ""); + + current_help = this; +} + +PrettyHelp::~PrettyHelp() +{ + current_help = _prior; +} + +PrettyHelp *PrettyHelp::get_current() +{ + if (current_help == nullptr) + new PrettyHelp(); + return current_help; +} + +void PrettyHelp::log_help() +{ + for (auto content : _root_listing.get_content()) { + if (content->type.compare("usage") == 0) { + log_pass_str(content->body, 1, true); + log("\n"); + } else if (content->type.compare("option") == 0) { + log_pass_str(content->body, 1); + for (auto text : content->get_content()) { + log_pass_str(text->body, 2); + log("\n"); + } + } else { + log_pass_str(content->body, 0); + log("\n"); + } + } +} diff --git a/kernel/log_help.h b/kernel/log_help.h new file mode 100644 index 000000000..0a40fc531 --- /dev/null +++ b/kernel/log_help.h @@ -0,0 +1,132 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2025 Krystine Dawn + * + * 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. + * + */ + +#ifndef LOG_HELP_H +#define LOG_HELP_H + +#include "kernel/yosys_common.h" +#include "kernel/json.h" + +YOSYS_NAMESPACE_BEGIN + +class ContentListing { + vector _content; +public: + string type; + string body; + const char* source_file; + int source_line; + std::map options; + + ContentListing( + string type = "root", string body = "", + const char* source_file = "unknown", int source_line = 0 + ) : type(type), body(body), source_file(source_file), source_line(source_line) { + _content = {}; + options = {}; + } + + ContentListing(string type, string body, source_location location) : + ContentListing(type, body, location.file_name(), location.line()) { } + + void add_content(ContentListing *new_content) { + _content.push_back(new_content); + } + + void add_content(string type, string body, source_location location) { + auto new_content = new ContentListing(type, body, location); + add_content(new_content); + } + + bool has_content() { return _content.size() != 0; } + const vector get_content() { + const vector content = _content; + return content; + } + ContentListing* back() { + return _content.back(); + } + + void set_option(string key, string val = "") { + options[key] = val; + } + + void usage( + const string &text, + const source_location location = source_location::current() + ); + void option( + const string &text, + const string &description = "", + const source_location location = source_location::current() + ); + void codeblock( + const string &code, + const string &language = "none", + const source_location location = source_location::current() + ); + void paragraph( + const string &text, + const source_location location = source_location::current() + ); + + ContentListing* open_usage( + const string &text, + const source_location location = source_location::current() + ); + ContentListing* open_option( + const string &text, + const source_location location = source_location::current() + ); + + Json to_json(); +}; + +class PrettyHelp +{ +public: + string group = "unknown"; + +private: + PrettyHelp *_prior; + ContentListing _root_listing; + +public: + PrettyHelp(); + ~PrettyHelp(); + + static PrettyHelp *get_current(); + + bool has_content() { return _root_listing.has_content(); } + const vector get_content() { + return _root_listing.get_content(); + } + ContentListing* get_root() { + return &_root_listing; + } + + void set_group(const string g) { group = g; } + bool has_group() { return group.compare("unknown") != 0; } + + void log_help(); +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/register.cc b/kernel/register.cc index af1823b5b..ea2a2624f 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -21,6 +21,7 @@ #include "kernel/satgen.h" #include "kernel/json.h" #include "kernel/gzip.h" +#include "kernel/log_help.h" #include #include @@ -41,7 +42,8 @@ std::map backend_register; std::vector Frontend::next_args; -Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help) +Pass::Pass(std::string name, std::string short_help, source_location location) : + pass_name(name), short_help(short_help), location(location) { next_queued_pass = first_queued_pass; first_queued_pass = this; @@ -116,9 +118,19 @@ void Pass::post_execute(Pass::pre_post_exec_state_t state) void Pass::help() { - log("\n"); - log("No help message for command `%s'.\n", pass_name.c_str()); - log("\n"); + auto prettyHelp = PrettyHelp(); + if (formatted_help()) { + prettyHelp.log_help(); + } else { + log("\n"); + log("No help message for command `%s'.\n", pass_name.c_str()); + log("\n"); + } +} + +bool Pass::formatted_help() +{ + return false; } void Pass::clear_flags() @@ -381,8 +393,8 @@ void ScriptPass::help_script() script(); } -Frontend::Frontend(std::string name, std::string short_help) : - Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help), +Frontend::Frontend(std::string name, std::string short_help, source_location location) : + Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help, location), frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) { } @@ -527,8 +539,8 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string } } -Backend::Backend(std::string name, std::string short_help) : - Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help), +Backend::Backend(std::string name, std::string short_help, source_location location) : + Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help, location), backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) { } @@ -681,6 +693,23 @@ static string get_cell_name(string name) { return is_code_getter(name) ? name.substr(0, name.length()-1) : name; } +static void log_warning_flags(Pass *pass) { + bool has_warnings = false; + const string name = pass->pass_name; + if (pass->experimental_flag) { + if (!has_warnings) log("\n"); + has_warnings = true; + log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", name.c_str()); + } + if (pass->internal_flag) { + if (!has_warnings) log("\n"); + has_warnings = true; + log("WARNING: THE '%s' COMMAND IS INTENDED FOR INTERNAL DEVELOPER USE ONLY.\n", name.c_str()); + } + if (has_warnings) + log("\n"); +} + static struct CellHelpMessages { dict cell_help; CellHelpMessages() { @@ -706,155 +735,211 @@ struct HelpPass : public Pass { log(" help + .... print verilog code for given cell type\n"); log("\n"); } - void write_cmd_rst(std::string cmd, std::string title, std::string text) - { - FILE *f = fopen(stringf("docs/source/cmd/%s.rst", cmd.c_str()).c_str(), "wt"); - // make header - size_t char_len = cmd.length() + 3 + title.length(); - std::string title_line = "\n"; - title_line.insert(0, char_len, '='); - fprintf(f, "%s", title_line.c_str()); - fprintf(f, "%s - %s\n", cmd.c_str(), title.c_str()); - fprintf(f, "%s\n", title_line.c_str()); + bool dump_cmds_json(PrettyJson &json) { + // init json + json.begin_object(); + json.entry("version", "Yosys command reference"); + json.entry("generator", yosys_version_str); - // render html - fprintf(f, ".. cmd:def:: %s\n", cmd.c_str()); - fprintf(f, " :title: %s\n\n", title.c_str()); - fprintf(f, " .. only:: html\n\n"); - std::stringstream ss; - std::string textcp = text; - ss << text; - bool IsUsage = true; - int blank_count = 0; - size_t def_strip_count = 0; - bool WasDefinition = false; - for (std::string line; std::getline(ss, line, '\n');) { - // find position of first non space character - std::size_t first_pos = line.find_first_not_of(" \t"); - std::size_t last_pos = line.find_last_not_of(" \t"); - if (first_pos == std::string::npos) { - // skip formatting empty lines - if (!WasDefinition) - fputc('\n', f); - blank_count += 1; - continue; + bool raise_error = false; + std::map> groups; + + json.name("cmds"); json.begin_object(); + // iterate over commands + for (auto &it : pass_register) { + auto name = it.first; + auto pass = it.second; + auto title = pass->short_help; + + auto cmd_help = PrettyHelp(); + auto has_pretty_help = pass->formatted_help(); + + if (!has_pretty_help) { + enum PassUsageState { + PUState_none, + PUState_signature, + PUState_options, + PUState_optionbody, + }; + + source_location null_source; + string current_buffer = ""; + auto root_listing = cmd_help.get_root(); + auto current_listing = root_listing; + + // dump command help + std::ostringstream buf; + log_streams.push_back(&buf); + pass->help(); + log_streams.pop_back(); + std::stringstream ss; + ss << buf.str(); + + // parse command help + size_t def_strip_count = 0; + auto current_state = PUState_none; + auto catch_verific = false; + auto blank_lines = 2; + for (string line; std::getline(ss, line, '\n');) { + // find position of first non space character + std::size_t first_pos = line.find_first_not_of(" \t"); + std::size_t last_pos = line.find_last_not_of(" \t"); + if (first_pos == std::string::npos) { + switch (current_state) + { + case PUState_signature: + root_listing->usage(current_buffer, null_source); + current_listing = root_listing; + current_state = PUState_none; + current_buffer = ""; + break; + case PUState_none: + case PUState_optionbody: + blank_lines += 1; + break; + default: + break; + } + // skip empty lines + continue; + } + + // strip leading and trailing whitespace + std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1); + bool IsDefinition = stripped_line[0] == '-'; + IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>'; + bool IsDedent = def_strip_count && first_pos < def_strip_count; + bool IsIndent = def_strip_count < first_pos; + + // line looks like a signature + bool IsSignature = stripped_line.find(name) == 0 && (stripped_line.length() == name.length() || stripped_line.at(name.size()) == ' '); + + if (IsSignature && first_pos <= 4 && (blank_lines >= 2 || current_state == PUState_signature)) { + if (current_state == PUState_options || current_state == PUState_optionbody) { + current_listing->codeblock(current_buffer, "none", null_source); + current_buffer = ""; + } else if (current_state == PUState_signature) { + root_listing->usage(current_buffer, null_source); + current_buffer = ""; + } else if (current_state == PUState_none && !current_buffer.empty()) { + current_listing->codeblock(current_buffer, "none", null_source); + current_buffer = ""; + } + current_listing = root_listing; + current_state = PUState_signature; + def_strip_count = first_pos; + catch_verific = false; + } else if (IsDedent) { + def_strip_count = first_pos; + if (current_state == PUState_optionbody) { + if (!current_buffer.empty()) { + current_listing->codeblock(current_buffer, "none", null_source); + current_buffer = ""; + } + if (IsIndent) { + current_state = PUState_options; + current_listing = root_listing->back(); + } else { + current_state = PUState_none; + current_listing = root_listing; + } + } else { + current_state = PUState_none; + } + } + + if (IsDefinition && !catch_verific && current_state != PUState_signature) { + if (!current_buffer.empty()) { + current_listing->codeblock(current_buffer, "none", null_source); + current_buffer = ""; + } + current_state = PUState_options; + current_listing = root_listing->open_option(stripped_line, null_source); + def_strip_count = first_pos; + } else { + if (current_state == PUState_options) { + current_state = PUState_optionbody; + } + if (current_buffer.empty()) + current_buffer = stripped_line; + else if (current_state == PUState_signature && IsIndent) + current_buffer += stripped_line; + else if (current_state == PUState_none) { + current_buffer += (blank_lines > 0 ? "\n\n" : "\n") + line; + } else + current_buffer += (blank_lines > 0 ? "\n\n" : "\n") + stripped_line; + if (stripped_line.compare("Command file parser supports following commands in file:") == 0) + catch_verific = true; + } + blank_lines = 0; + } + + if (!current_buffer.empty()) { + if (current_buffer.size() > 64 && current_buffer.substr(0, 64).compare("The following commands are executed by this synthesis command:\n\n") == 0) { + current_listing->paragraph(current_buffer.substr(0, 62), null_source); + current_listing->codeblock(current_buffer.substr(64), "yoscrypt", null_source); + } else + current_listing->codeblock(current_buffer, "none", null_source); + current_buffer = ""; + } } - // strip leading and trailing whitespace - std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1); - bool IsDefinition = stripped_line[0] == '-'; - IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>'; - bool IsDedent = def_strip_count && first_pos <= def_strip_count; - bool IsIndent = first_pos == 2 || first_pos == 4; - if (cmd.compare(0, 7, "verific") == 0) - // verific.cc has strange and different formatting from the rest - IsIndent = false; - - // another usage block - bool NewUsage = stripped_line.find(cmd) == 0; - - if (IsUsage) { - if (stripped_line.compare(0, 4, "See ") == 0) { - // description refers to another function - fprintf(f, "\n %s\n", stripped_line.c_str()); - } else { - // usage should be the first line of help output - fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str()); - WasDefinition = true; + // attempt auto group + if (!cmd_help.has_group()) { + string source_file = pass->location.file_name(); + bool has_source = source_file.compare("unknown") != 0; + if (pass->internal_flag) + cmd_help.group = "internal"; + else if (source_file.find("backends/") == 0 || (!has_source && name.find("read_") == 0)) + cmd_help.group = "backends"; + else if (source_file.find("frontends/") == 0 || (!has_source && name.find("write_") == 0)) + cmd_help.group = "frontends"; + else if (has_source) { + auto last_slash = source_file.find_last_of('/'); + if (last_slash != string::npos) { + auto parent_path = source_file.substr(0, last_slash); + cmd_help.group = parent_path; + } } - IsUsage = false; - } else if (IsIndent && NewUsage && (blank_count >= 2 || WasDefinition)) { - // another usage block - fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str()); - WasDefinition = true; - def_strip_count = 0; - } else if (IsIndent && IsDefinition && (blank_count || WasDefinition)) { - // format definition term - fprintf(f, "\n\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str()); - WasDefinition = true; - def_strip_count = first_pos; - } else { - if (IsDedent) { - fprintf(f, "\n\n ::\n"); - def_strip_count = first_pos; - } else if (WasDefinition) { - fprintf(f, "::\n"); - WasDefinition = false; - } - fprintf(f, "\n %s", line.substr(def_strip_count, std::string::npos).c_str()); + // implicit !has_source + else if (name.find("equiv") == 0) + cmd_help.group = "passes/equiv"; + else if (name.find("fsm") == 0) + cmd_help.group = "passes/fsm"; + else if (name.find("memory") == 0) + cmd_help.group = "passes/memory"; + else if (name.find("opt") == 0) + cmd_help.group = "passes/opt"; + else if (name.find("proc") == 0) + cmd_help.group = "passes/proc"; } - blank_count = 0; + if (groups.count(cmd_help.group) == 0) { + groups[cmd_help.group] = vector(); + } + groups[cmd_help.group].push_back(name); + + // write to json + json.name(name.c_str()); json.begin_object(); + json.entry("title", title); + json.name("content"); json.begin_array(); + for (auto content : cmd_help.get_content()) + json.value(content->to_json()); + json.end_array(); + json.entry("group", cmd_help.group); + json.entry("source_file", pass->location.file_name()); + json.entry("source_line", pass->location.line()); + json.entry("source_func", pass->location.function_name()); + json.entry("experimental_flag", pass->experimental_flag); + json.entry("internal_flag", pass->internal_flag); + json.end_object(); } - fputc('\n', f); + json.end_object(); - // render latex - fprintf(f, ".. only:: latex\n\n"); - fprintf(f, " ::\n\n"); - std::stringstream ss2; - ss2 << textcp; - for (std::string line; std::getline(ss2, line, '\n');) { - fprintf(f, " %s\n", line.c_str()); - } - fclose(f); - } - void write_cell_rst(Yosys::SimHelper cell, Yosys::CellType ct) - { - // open - FILE *f = fopen(stringf("docs/source/cell/%s.rst", cell.filesafe_name().c_str()).c_str(), "wt"); + json.entry("groups", groups); - // make header - string title_line; - if (cell.title.length()) - title_line = stringf("%s - %s", cell.name.c_str(), cell.title.c_str()); - else title_line = cell.name; - string underline = "\n"; - underline.insert(0, title_line.length(), '='); - fprintf(f, "%s\n", title_line.c_str()); - fprintf(f, "%s\n", underline.c_str()); - - // help text, with cell def for links - fprintf(f, ".. cell:def:: %s\n", cell.name.c_str()); - if (cell.title.length()) - fprintf(f, " :title: %s\n\n", cell.title.c_str()); - else - fprintf(f, " :title: %s\n\n", cell.name.c_str()); - std::stringstream ss; - ss << cell.desc; - for (std::string line; std::getline(ss, line, '\n');) { - fprintf(f, " %s\n", line.c_str()); - } - - // properties - fprintf(f, "\nProperties"); - fprintf(f, "\n----------\n\n"); - dict prop_dict = { - {"is_evaluable", ct.is_evaluable}, - {"is_combinatorial", ct.is_combinatorial}, - {"is_synthesizable", ct.is_synthesizable}, - }; - for (auto &it : prop_dict) { - fprintf(f, "- %s: %s\n", it.first.c_str(), it.second ? "true" : "false"); - } - - // source code - fprintf(f, "\nSimulation model (Verilog)"); - fprintf(f, "\n--------------------------\n\n"); - fprintf(f, ".. code-block:: verilog\n"); - fprintf(f, " :caption: %s\n\n", cell.source.c_str()); - std::stringstream ss2; - ss2 << cell.code; - for (std::string line; std::getline(ss2, line, '\n');) { - fprintf(f, " %s\n", line.c_str()); - } - - // footer - fprintf(f, "\n.. note::\n\n"); - fprintf(f, " This page was auto-generated from the output of\n"); - fprintf(f, " ``help %s``.\n", cell.name.c_str()); - - // close - fclose(f); + json.end_object(); + return raise_error; } bool dump_cells_json(PrettyJson &json) { // init json @@ -960,11 +1045,7 @@ struct HelpPass : public Pass { log("="); log("\n"); it.second->help(); - if (it.second->experimental_flag) { - log("\n"); - log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str()); - log("\n"); - } + log_warning_flags(it.second); } } else if (args[1] == "-cells") { @@ -978,44 +1059,9 @@ struct HelpPass : public Pass { log("\n"); return; } - // this option is undocumented as it is for internal use only - else if (args[1] == "-write-rst-command-reference-manual") { - for (auto &it : pass_register) { - std::ostringstream buf; - log_streams.push_back(&buf); - it.second->help(); - if (it.second->experimental_flag) { - log("\n"); - log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str()); - log("\n"); - } - log_streams.pop_back(); - write_cmd_rst(it.first, it.second->short_help, buf.str()); - } - } - // this option is also undocumented as it is for internal use only - else if (args[1] == "-write-rst-cells-manual") { - bool raise_error = false; - for (auto &it : yosys_celltypes.cell_types) { - auto name = it.first.str(); - if (cell_help_messages.contains(name)) { - write_cell_rst(cell_help_messages.get(name), it.second); - } else { - log("ERROR: Missing cell help for cell '%s'.\n", name.c_str()); - raise_error |= true; - } - } - if (raise_error) { - log_error("One or more cells defined in celltypes.h are missing help documentation.\n"); - } - } else if (pass_register.count(args[1])) { pass_register.at(args[1])->help(); - if (pass_register.at(args[1])->experimental_flag) { - log("\n"); - log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", args[1].c_str()); - log("\n"); - } + log_warning_flags(pass_register.at(args[1])); } else if (cell_help_messages.contains(args[1])) { auto help_cell = cell_help_messages.get(args[1]); @@ -1044,7 +1090,17 @@ struct HelpPass : public Pass { log("No such command or cell type: %s\n", args[1].c_str()); return; } else if (args.size() == 3) { - if (args[1] == "-dump-cells-json") { + // this option is undocumented as it is for internal use only + if (args[1] == "-dump-cmds-json") { + PrettyJson json; + if (!json.write_to_file(args[2])) + log_error("Can't open file `%s' for writing: %s\n", args[2].c_str(), strerror(errno)); + if (dump_cmds_json(json)) { + log_abort(); + } + } + // this option is undocumented as it is for internal use only + else if (args[1] == "-dump-cells-json") { PrettyJson json; if (!json.write_to_file(args[2])) log_error("Can't open file `%s' for writing: %s\n", args[2].c_str(), strerror(errno)); @@ -1052,6 +1108,8 @@ struct HelpPass : public Pass { log_error("One or more cells defined in celltypes.h are missing help documentation.\n"); } } + else + log("Unknown help command: `%s %s'\n", args[1].c_str(), args[2].c_str()); return; } diff --git a/kernel/register.h b/kernel/register.h index f4e2127e1..e8c017c1d 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -23,27 +23,62 @@ #include "kernel/yosys_common.h" #include "kernel/yosys.h" +#include +#if __cpp_lib_source_location == 201907L + #include + using std::source_location; +#elif defined(__has_include) +# if __has_include() + #include + using std::experimental::source_location; +# else + #define SOURCE_FALLBACK +# endif +#else + #define SOURCE_FALLBACK +#endif + +#ifdef SOURCE_FALLBACK +struct source_location { // dummy placeholder + int line() const { return 0; } + int column() const { return 0; } + const char* file_name() const { return "unknown"; } + const char* function_name() const { return "unknown"; } + static const source_location current(...) { return source_location(); } +}; +#endif + YOSYS_NAMESPACE_BEGIN struct Pass { std::string pass_name, short_help; - Pass(std::string name, std::string short_help = "** document me **"); + source_location location; + Pass(std::string name, std::string short_help = "** document me **", + source_location location = source_location::current()); // Prefer overriding 'Pass::on_shutdown()' if possible virtual ~Pass(); + // Makes calls to log() to generate help message virtual void help(); + // Uses PrettyHelp::get_current() to produce a more portable formatted help message + virtual bool formatted_help(); virtual void clear_flags(); virtual void execute(std::vector args, RTLIL::Design *design) = 0; int call_counter; int64_t runtime_ns; bool experimental_flag = false; + bool internal_flag = false; void experimental() { experimental_flag = true; } + void internal() { + internal_flag = true; + } + struct pre_post_exec_state_t { Pass *parent_pass; int64_t begin_ns; @@ -81,7 +116,8 @@ struct ScriptPass : Pass RTLIL::Design *active_design; std::string active_run_from, active_run_to; - ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { } + ScriptPass(std::string name, std::string short_help = "** document me **", source_location location = source_location::current()) : + Pass(name, short_help, location) { } virtual void script() = 0; @@ -99,7 +135,8 @@ struct Frontend : Pass static std::string last_here_document; std::string frontend_name; - Frontend(std::string name, std::string short_help = "** document me **"); + Frontend(std::string name, std::string short_help = "** document me **", + source_location location = source_location::current()); void run_register() override; ~Frontend() override; void execute(std::vector args, RTLIL::Design *design) override final; @@ -115,7 +152,8 @@ struct Frontend : Pass struct Backend : Pass { std::string backend_name; - Backend(std::string name, std::string short_help = "** document me **"); + Backend(std::string name, std::string short_help = "** document me **", + source_location location = source_location::current()); void run_register() override; ~Backend() override; void execute(std::vector args, RTLIL::Design *design) override final; diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 83fe781a0..8bbcb8da0 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -22,12 +22,18 @@ #include "kernel/celledges.h" #include "kernel/celltypes.h" #include "kernel/utils.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct CheckPass : public Pass { CheckPass() : Pass("check", "check for obvious problems in the design") { } + 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---| diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc index 572ed2153..ccda023c0 100644 --- a/passes/cmds/chformal.cc +++ b/passes/cmds/chformal.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -70,62 +71,62 @@ static bool is_triggered_check_cell(RTLIL::Cell * cell) } struct ChformalPass : public Pass { - ChformalPass() : Pass("chformal", "change formal constraints of the design") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" chformal [types] [mode] [options] [selection]\n"); - log("\n"); - log("Make changes to the formal constraints of the design. The [types] options\n"); - log("the type of constraint to operate on. If none of the following options are\n"); - log("given, the command will operate on all constraint types:\n"); - log("\n"); - log(" -assert $assert cells, representing assert(...) constraints\n"); - log(" -assume $assume cells, representing assume(...) constraints\n"); - log(" -live $live cells, representing assert(s_eventually ...)\n"); - log(" -fair $fair cells, representing assume(s_eventually ...)\n"); - log(" -cover $cover cells, representing cover() statements\n"); - log("\n"); - log(" Additionally chformal will operate on $check cells corresponding to the\n"); - log(" selected constraint types.\n"); - log("\n"); - log("Exactly one of the following modes must be specified:\n"); - log("\n"); - log(" -remove\n"); - log(" remove the cells and thus constraints from the design\n"); - log("\n"); - log(" -early\n"); - log(" bypass FFs that only delay the activation of a constraint. When inputs\n"); - log(" of the bypassed FFs do not remain stable between clock edges, this may\n"); - log(" result in unexpected behavior.\n"); - log("\n"); - log(" -delay \n"); - log(" delay activation of the constraint by clock cycles\n"); - log("\n"); - log(" -skip \n"); - log(" ignore activation of the constraint in the first clock cycles\n"); - log("\n"); - log(" -coverenable\n"); - log(" add cover statements for the enable signals of the constraints\n"); - log("\n"); + ChformalPass() : Pass("chformal", "change formal constraints of the design") {} + + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + + auto content_root = help->get_root(); + + content_root->usage("chformal [types] [mode] [options] [selection]"); + content_root->paragraph( + "Make changes to the formal constraints of the design. The [types] options " + "the type of constraint to operate on. If none of the following options are " + "given, the command will operate on all constraint types:" + ); + + content_root->option("-assert", "`$assert` cells, representing ``assert(...)`` constraints"); + content_root->option("-assume", "`$assume` cells, representing ``assume(...)`` constraints"); + content_root->option("-live", "`$live` cells, representing ``assert(s_eventually ...)``"); + content_root->option("-fair", "`$fair` cells, representing ``assume(s_eventually ...)``"); + content_root->option("-cover", "`$cover` cells, representing ``cover()`` statements"); + content_root->paragraph( + "Additionally chformal will operate on `$check` cells corresponding to the " + "selected constraint types." + ); + + content_root->paragraph("Exactly one of the following modes must be specified:"); + + content_root->option("-remove", "remove the cells and thus constraints from the design"); + content_root->option("-early", + "bypass FFs that only delay the activation of a constraint. When inputs " + "of the bypassed FFs do not remain stable between clock edges, this may " + "result in unexpected behavior." + ); + content_root->option("-delay ", "delay activation of the constraint by clock cycles"); + content_root->option("-skip ", "ignore activation of the constraint in the first clock cycles"); + auto cover_option = content_root->open_option("-coverenable"); + cover_option->paragraph( + "add cover statements for the enable signals of the constraints" + ); #ifdef YOSYS_ENABLE_VERIFIC - log(" Note: For the Verific frontend it is currently not guaranteed that a\n"); - log(" reachable SVA statement corresponds to an active enable signal.\n"); - log("\n"); + cover_option->paragraph( + "Note: For the Verific frontend it is currently not guaranteed that a " + "reachable SVA statement corresponds to an active enable signal." + ); #endif - log(" -assert2assume\n"); - log(" -assert2cover\n"); - log(" -assume2assert\n"); - log(" -live2fair\n"); - log(" -fair2live\n"); - log(" change the roles of cells as indicated. these options can be combined\n"); - log("\n"); - log(" -lower\n"); - log(" convert each $check cell into an $assert, $assume, $live, $fair or\n"); - log(" $cover cell. If the $check cell contains a message, also produce a\n"); - log(" $print cell.\n"); - log("\n"); + content_root->option("-assert2assume"); + content_root->option("-assert2cover"); + content_root->option("-assume2assert"); + content_root->option("-live2fair"); + content_root->option("-fair2live", "change the roles of cells as indicated. these options can be combined"); + content_root->option("-lower", + "convert each $check cell into an $assert, $assume, $live, $fair or " + "$cover cell. If the $check cell contains a message, also produce a " + "$print cell." + ); + return true; } void execute(std::vector args, RTLIL::Design *design) override { diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc index 1db3e2ca0..47354f1d5 100644 --- a/passes/cmds/cover.cc +++ b/passes/cmds/cover.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include #ifndef _WIN32 @@ -26,15 +27,18 @@ # include #endif -#include "kernel/register.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" - USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct CoverPass : public Pass { - CoverPass() : Pass("cover", "print code coverage counters") { } + 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---| diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index b6afe6f89..347c8efa4 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -22,6 +22,7 @@ #include "kernel/modtools.h" #include "kernel/sigtools.h" #include "kernel/yosys.h" +#include "kernel/log_help.h" #include USING_YOSYS_NAMESPACE @@ -952,6 +953,11 @@ struct DftTagWorker { struct DftTagPass : public Pass { DftTagPass() : Pass("dft_tag", "create tagging logic for data flow tracking") {} + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/cmds/edgetypes.cc b/passes/cmds/edgetypes.cc index 5b53f50cc..933bd457f 100644 --- a/passes/cmds/edgetypes.cc +++ b/passes/cmds/edgetypes.cc @@ -19,12 +19,18 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct EdgetypePass : public Pass { EdgetypePass() : Pass("edgetypes", "list all types of edges in selection") { } + 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---| diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 2870e062b..b10f50502 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -21,15 +21,17 @@ struct ExampleWorker struct ExampleDtPass : public Pass { - ExampleDtPass() : Pass("example_dt", "drivertools example") {} + ExampleDtPass() : Pass("example_dt", "drivertools example") { + internal(); + } - void help() override + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log("TODO: add help message\n"); log("\n"); - } + } void execute(std::vector args, RTLIL::Design *design) override diff --git a/passes/cmds/exec.cc b/passes/cmds/exec.cc index e9cc34b30..486fa1c2b 100644 --- a/passes/cmds/exec.cc +++ b/passes/cmds/exec.cc @@ -17,8 +17,8 @@ * */ -#include "kernel/register.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/log_help.h" #include #if defined(_WIN32) @@ -38,6 +38,11 @@ PRIVATE_NAMESPACE_BEGIN struct ExecPass : public Pass { ExecPass() : Pass("exec", "execute commands in the operating system shell") { } + 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---| diff --git a/passes/cmds/future.cc b/passes/cmds/future.cc index b03613c9b..5dcf46bcf 100644 --- a/passes/cmds/future.cc +++ b/passes/cmds/future.cc @@ -24,6 +24,7 @@ #include "kernel/sigtools.h" #include "kernel/utils.h" #include "kernel/yosys.h" +#include "kernel/log_help.h" #include USING_YOSYS_NAMESPACE @@ -110,6 +111,11 @@ struct FutureWorker { struct FuturePass : public Pass { FuturePass() : Pass("future", "resolve future sampled value functions") {} + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/cmds/glift.cc b/passes/cmds/glift.cc index 6a7d070d7..0c321eba6 100644 --- a/passes/cmds/glift.cc +++ b/passes/cmds/glift.cc @@ -17,10 +17,9 @@ * */ -#include "kernel/register.h" -#include "kernel/rtlil.h" #include "kernel/utils.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -425,6 +424,12 @@ public: struct GliftPass : public Pass { GliftPass() : Pass("glift", "create GLIFT models and optimization problems") {} + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/cmds/internal_stats.cc b/passes/cmds/internal_stats.cc index 28822f237..00456b8f9 100644 --- a/passes/cmds/internal_stats.cc +++ b/passes/cmds/internal_stats.cc @@ -18,8 +18,6 @@ */ #include -#include -#include #include "kernel/yosys.h" #include "kernel/celltypes.h" @@ -71,7 +69,10 @@ std::optional current_mem_bytes() { } struct InternalStatsPass : public Pass { - InternalStatsPass() : Pass("internal_stats", "print internal statistics") { } + InternalStatsPass() : Pass("internal_stats", "print internal statistics") { + experimental(); + internal(); + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc index 3b82ac48c..0238627d1 100644 --- a/passes/cmds/logcmd.cc +++ b/passes/cmds/logcmd.cc @@ -18,15 +18,19 @@ * */ -#include "kernel/register.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct LogPass : public Pass { LogPass() : Pass("log", "print text and log files") { } + 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---| diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 241a8799f..276810201 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -17,14 +17,19 @@ * */ -#include "kernel/register.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct LoggerPass : public Pass { LoggerPass() : Pass("logger", "set logger properties") { } + 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---| diff --git a/passes/cmds/ltp.cc b/passes/cmds/ltp.cc index 22bdaab44..b3134b110 100644 --- a/passes/cmds/ltp.cc +++ b/passes/cmds/ltp.cc @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "kernel/celltypes.h" #include "kernel/sigtools.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -141,6 +142,11 @@ struct LtpWorker struct LtpPass : public Pass { LtpPass() : Pass("ltp", "print longest topological path") { } + 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---| diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc index 4ad7c165b..a653844b7 100644 --- a/passes/cmds/plugin.cc +++ b/passes/cmds/plugin.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #ifdef YOSYS_ENABLE_PLUGINS # include @@ -122,6 +123,11 @@ void load_plugin(std::string, std::vector) struct PluginPass : public Pass { PluginPass() : Pass("plugin", "load and list loaded plugins") { } + 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---| diff --git a/passes/cmds/portarcs.cc b/passes/cmds/portarcs.cc index a6ed75de3..97682efbb 100644 --- a/passes/cmds/portarcs.cc +++ b/passes/cmds/portarcs.cc @@ -22,6 +22,7 @@ #include "kernel/rtlil.h" #include "kernel/utils.h" #include "kernel/celltypes.h" +#include "kernel/log_help.h" PRIVATE_NAMESPACE_BEGIN USING_YOSYS_NAMESPACE @@ -38,6 +39,11 @@ static RTLIL::SigBit canonical_bit(RTLIL::SigBit bit) struct PortarcsPass : Pass { PortarcsPass() : Pass("portarcs", "derive port arcs for propagation delay") {} + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("passes/status"); + return false; + } void help() override { diff --git a/passes/cmds/portlist.cc b/passes/cmds/portlist.cc index 03048422d..f78d9d3b6 100644 --- a/passes/cmds/portlist.cc +++ b/passes/cmds/portlist.cc @@ -19,12 +19,18 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct PortlistPass : public Pass { PortlistPass() : Pass("portlist", "list (top-level) ports") { } + 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---| diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc index 2a5034c13..c8b0a1d1f 100644 --- a/passes/cmds/printattrs.cc +++ b/passes/cmds/printattrs.cc @@ -18,12 +18,18 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct PrintAttrsPass : public Pass { PrintAttrsPass() : Pass("printattrs", "print attributes of selected objects") { } + 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---| diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 0f988e57a..e55e63828 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -21,12 +21,10 @@ // Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010 // http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm -#include "kernel/register.h" +#include "kernel/yosys.h" #include "kernel/celltypes.h" #include "kernel/sigtools.h" -#include "kernel/log.h" -#include -#include +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -252,6 +250,11 @@ struct SccWorker struct SccPass : public Pass { SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { } + 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---| diff --git a/passes/cmds/scratchpad.cc b/passes/cmds/scratchpad.cc index aecc4c17d..4a63f2f60 100644 --- a/passes/cmds/scratchpad.cc +++ b/passes/cmds/scratchpad.cc @@ -18,15 +18,19 @@ * */ -#include "kernel/register.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct ScratchpadPass : public Pass { ScratchpadPass() : Pass("scratchpad", "get/set values in the scratchpad") { } + 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---| diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 1d75091af..901f923f8 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -20,8 +20,7 @@ #include "kernel/yosys.h" #include "kernel/celltypes.h" #include "kernel/sigtools.h" -#include -#include +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -1085,6 +1084,11 @@ PRIVATE_NAMESPACE_BEGIN struct SelectPass : public Pass { SelectPass() : Pass("select", "modify and view the list of selected objects") { } + 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---| @@ -1664,6 +1668,11 @@ struct SelectPass : public Pass { struct CdPass : public Pass { CdPass() : Pass("cd", "a shortcut for 'select -module '") { } + 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---| @@ -1776,6 +1785,11 @@ static void log_matches(const char *title, Module *module, const T &list) struct LsPass : public Pass { LsPass() : Pass("ls", "list modules or objects in modules") { } + 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---| diff --git a/passes/cmds/setenv.cc b/passes/cmds/setenv.cc index 27f2eea28..850d7c961 100644 --- a/passes/cmds/setenv.cc +++ b/passes/cmds/setenv.cc @@ -17,15 +17,18 @@ * */ -#include "kernel/register.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" -#include +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct SetenvPass : public Pass { SetenvPass() : Pass("setenv", "set an environment variable") { } + 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---| diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 8a1bd58c4..4eb6569e6 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -17,10 +17,9 @@ * */ -#include "kernel/register.h" +#include "kernel/yosys.h" #include "kernel/celltypes.h" -#include "kernel/log.h" -#include +#include "kernel/log_help.h" #ifndef _WIN32 # include @@ -658,6 +657,11 @@ struct ShowWorker struct ShowPass : public Pass { ShowPass() : Pass("show", "generate schematics using graphviz") { } + 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---| diff --git a/passes/cmds/sta.cc b/passes/cmds/sta.cc index 4ad0e96be..5dfac1575 100644 --- a/passes/cmds/sta.cc +++ b/passes/cmds/sta.cc @@ -21,6 +21,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" #include "kernel/timinginfo.h" +#include "kernel/log_help.h" #include USING_YOSYS_NAMESPACE @@ -275,6 +276,11 @@ struct StaWorker struct StaPass : public Pass { StaPass() : Pass("sta", "perform static timing analysis") { } + 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---| diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 6b93621f1..af7023bdd 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -25,6 +25,7 @@ #include "kernel/cost.h" #include "kernel/gzip.h" #include "libs/json11/json11.hpp" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -367,6 +368,11 @@ void read_liberty_cellarea(dict &cell_area, string libert struct StatPass : public Pass { StatPass() : Pass("stat", "print some statistics") { } + 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---| diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc index 853f1bad3..fbd42e311 100644 --- a/passes/cmds/tee.cc +++ b/passes/cmds/tee.cc @@ -18,15 +18,19 @@ * */ -#include "kernel/register.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct TeePass : public Pass { TeePass() : Pass("tee", "redirect command output to file") { } + 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---| diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc index 1620c0bca..537b6793d 100644 --- a/passes/cmds/torder.cc +++ b/passes/cmds/torder.cc @@ -21,12 +21,18 @@ #include "kernel/celltypes.h" #include "kernel/sigtools.h" #include "kernel/utils.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct TorderPass : public Pass { TorderPass() : Pass("torder", "print cells in topological order") { } + 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---| diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc index 400542776..39ed8e60e 100644 --- a/passes/cmds/trace.cc +++ b/passes/cmds/trace.cc @@ -19,6 +19,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -60,6 +61,11 @@ struct TraceMonitor : public RTLIL::Monitor struct TracePass : public Pass { TracePass() : Pass("trace", "redirect command output to file") { } + 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---| @@ -96,6 +102,11 @@ struct TracePass : public Pass { struct DebugPass : public Pass { DebugPass() : Pass("debug", "run command with debug log messages enabled") { } + 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---| diff --git a/passes/cmds/viz.cc b/passes/cmds/viz.cc index 131e799ab..4c73b4d71 100644 --- a/passes/cmds/viz.cc +++ b/passes/cmds/viz.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/log_help.h" #ifndef _WIN32 # include @@ -817,6 +818,11 @@ struct VizWorker struct VizPass : public Pass { VizPass() : Pass("viz", "visualize data flow graph") { } + 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---| diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc index ea9b3f556..a22fdaf2a 100644 --- a/passes/cmds/write_file.cc +++ b/passes/cmds/write_file.cc @@ -19,12 +19,18 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct WriteFileFrontend : public Frontend { WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { } + 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---| diff --git a/passes/cmds/xprop.cc b/passes/cmds/xprop.cc index dc5befc27..d2d0c4d8e 100644 --- a/passes/cmds/xprop.cc +++ b/passes/cmds/xprop.cc @@ -24,6 +24,7 @@ #include "kernel/sigtools.h" #include "kernel/utils.h" #include "kernel/yosys.h" +#include "kernel/log_help.h" #include USING_YOSYS_NAMESPACE @@ -1100,6 +1101,11 @@ struct XpropWorker struct XpropPass : public Pass { XpropPass() : Pass("xprop", "formal x propagation") {} + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/hierarchy/Makefile.inc b/passes/hierarchy/Makefile.inc index 3cd1b6180..ff1a2fcc5 100644 --- a/passes/hierarchy/Makefile.inc +++ b/passes/hierarchy/Makefile.inc @@ -1,4 +1,5 @@ +OBJS += passes/hierarchy/flatten.o OBJS += passes/hierarchy/hierarchy.o OBJS += passes/hierarchy/uniquify.o OBJS += passes/hierarchy/submod.o diff --git a/passes/techmap/flatten.cc b/passes/hierarchy/flatten.cc similarity index 100% rename from passes/techmap/flatten.cc rename to passes/hierarchy/flatten.cc diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc index 9fa9f5c2d..0ac391790 100644 --- a/passes/opt/rmports.cc +++ b/passes/opt/rmports.cc @@ -17,17 +17,20 @@ * */ -#include "kernel/register.h" #include "kernel/sigtools.h" -#include "kernel/log.h" -#include -#include +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct RmportsPassPass : public Pass { RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("techlibs/greenpak4"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc index fc41848f7..892500850 100644 --- a/passes/pmgen/test_pmgen.cc +++ b/passes/pmgen/test_pmgen.cc @@ -117,7 +117,9 @@ void opt_eqpmux(test_pmgen_pm &pm) } struct TestPmgenPass : public Pass { - TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { } + TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { + internal(); + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc index 991977ab9..7b3357f82 100644 --- a/passes/sat/assertpmux.cc +++ b/passes/sat/assertpmux.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" #include "kernel/utils.h" @@ -182,6 +183,11 @@ struct AssertpmuxWorker struct AssertpmuxPass : public Pass { AssertpmuxPass() : Pass("assertpmux", "adds asserts for parallel muxes") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index 93c7e96c8..e86a78d81 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" @@ -27,6 +28,11 @@ PRIVATE_NAMESPACE_BEGIN struct Async2syncPass : public Pass { Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index 348bab727..6b94cbe19 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" @@ -33,6 +34,11 @@ struct SampledSig { struct Clk2fflogicPass : public Pass { Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index dcd399a57..485e44fd6 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" USING_YOSYS_NAMESPACE @@ -25,6 +26,11 @@ PRIVATE_NAMESPACE_BEGIN struct CutpointPass : public Pass { CutpointPass() : Pass("cutpoint", "adds formal cut points to the design") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc index 9afe00d5c..1e975db0f 100644 --- a/passes/sat/expose.cc +++ b/passes/sat/expose.cc @@ -17,11 +17,10 @@ * */ -#include "kernel/register.h" +#include "kernel/yosys.h" #include "kernel/celltypes.h" #include "kernel/sigtools.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -217,6 +216,11 @@ RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width struct ExposePass : public Pass { ExposePass() : Pass("expose", "convert internal signals to module ports") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("passes/cmds"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc index 220cf5c52..575b2f40d 100644 --- a/passes/sat/fmcombine.cc +++ b/passes/sat/fmcombine.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" @@ -237,6 +238,11 @@ struct FmcombineWorker struct FmcombinePass : public Pass { FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/fminit.cc b/passes/sat/fminit.cc index 5f4ec0068..547082164 100644 --- a/passes/sat/fminit.cc +++ b/passes/sat/fminit.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" USING_YOSYS_NAMESPACE @@ -25,6 +26,11 @@ PRIVATE_NAMESPACE_BEGIN struct FminitPass : public Pass { FminitPass() : Pass("fminit", "set init values/sequences for formal") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc index 1d87fcc3b..286bf2976 100644 --- a/passes/sat/formalff.cc +++ b/passes/sat/formalff.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" @@ -486,6 +487,11 @@ void HierarchyWorker::propagate() struct FormalFfPass : public Pass { FormalFfPass() : Pass("formalff", "prepare FFs for formal") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index 52e80f667..6063c5ab9 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -17,17 +17,12 @@ * */ -#include "kernel/register.h" #include "kernel/celltypes.h" #include "kernel/consteval.h" #include "kernel/sigtools.h" -#include "kernel/log.h" #include "kernel/satgen.h" -#include -#include -#include -#include -#include +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -761,6 +756,11 @@ struct FreduceWorker struct FreducePass : public Pass { FreducePass() : Pass("freduce", "perform functional reduction") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc index 8f27c4c6f..9bcf25547 100644 --- a/passes/sat/miter.cc +++ b/passes/sat/miter.cc @@ -17,9 +17,8 @@ * */ -#include "kernel/register.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -395,6 +394,11 @@ void create_miter_assert(struct Pass *that, std::vector args, RTLIL struct MiterPass : public Pass { MiterPass() : Pass("miter", "automatically create a miter circuit") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 3075ef3f0..43373ce0e 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" USING_YOSYS_NAMESPACE @@ -728,6 +729,11 @@ void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one) struct MutatePass : public Pass { MutatePass() : Pass("mutate", "generate or apply design mutations") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index db6836ea1..7a7a31806 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/consteval.h" #include "qbfsat.h" @@ -504,6 +505,11 @@ QbfSolveOptions parse_args(const std::vector &args) { struct QbfSatPass : public Pass { QbfSatPass() : Pass("qbfsat", "solve a 2QBF-SAT problem in the circuit") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index cddd8771c..7ed8b1304 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -23,6 +23,7 @@ #include "kernel/celltypes.h" #include "kernel/utils.h" #include "kernel/satgen.h" +#include "kernel/log_help.h" #include #include @@ -690,6 +691,11 @@ struct RecoverNamesWorker { struct RecoverNamesPass : public Pass { RecoverNamesPass() : Pass("recover_names", "Execute a lossy mapping command and recover original netnames") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("passes/opt"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 0c2143fc9..2f20880cb 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -21,17 +21,12 @@ // Niklas Een and Niklas Sörensson (2003) // http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.8161 -#include "kernel/register.h" #include "kernel/celltypes.h" #include "kernel/consteval.h" #include "kernel/sigtools.h" -#include "kernel/log.h" #include "kernel/satgen.h" -#include -#include -#include -#include -#include +#include "kernel/yosys.h" +#include "kernel/log_help.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -902,6 +897,11 @@ void print_qed() struct SatPass : public Pass { SatPass() : Pass("sat", "solve a SAT problem in the circuit") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/supercover.cc b/passes/sat/supercover.cc index 38dbd3cf9..f1b3ad09c 100644 --- a/passes/sat/supercover.cc +++ b/passes/sat/supercover.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/log_help.h" #include "kernel/sigtools.h" USING_YOSYS_NAMESPACE @@ -25,6 +26,11 @@ PRIVATE_NAMESPACE_BEGIN struct SupercoverPass : public Pass { SupercoverPass() : Pass("supercover", "add hi/lo cover cells for each wire bit") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/sat/synthprop.cc b/passes/sat/synthprop.cc index 5553abec2..4703e4ad7 100644 --- a/passes/sat/synthprop.cc +++ b/passes/sat/synthprop.cc @@ -18,7 +18,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ + #include "kernel/yosys.h" +#include "kernel/log_help.h" YOSYS_NAMESPACE_BEGIN @@ -179,7 +181,13 @@ void SynthPropWorker::run() struct SyntProperties : public Pass { SyntProperties() : Pass("synthprop", "synthesize SVA properties") { } - virtual void help() + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("formal"); + return false; + } + + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -208,7 +216,7 @@ struct SyntProperties : public Pass { log("\n"); } - virtual void execute(std::vector args, RTLIL::Design* design) + void execute(std::vector args, RTLIL::Design* design) override { log_header(design, "Executing SYNTHPROP pass.\n"); SynthPropWorker worker(design); diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index c9fe98a74..91b3b563a 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -1,5 +1,4 @@ -OBJS += passes/techmap/flatten.o OBJS += passes/techmap/techmap.o OBJS += passes/techmap/simplemap.o OBJS += passes/techmap/dfflibmap.o diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc index 9e7adaab1..ed54ce164 100644 --- a/passes/tests/test_abcloop.cc +++ b/passes/tests/test_abcloop.cc @@ -243,7 +243,9 @@ static void test_abcloop() } struct TestAbcloopPass : public Pass { - TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { } + TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { + internal(); + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index 404d1e48d..306e760ee 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -326,7 +326,9 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s } struct TestAutotbBackend : public Backend { - TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { } + TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { + internal(); + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index a34eafc2f..b6385766c 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -705,7 +705,9 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std:: } struct TestCellPass : public Pass { - TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { } + TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { + internal(); + } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| From 7fe4ae45fd8f60dddb6c4a48eb8844c44ced9351 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:52:12 +1200 Subject: [PATCH 44/51] log_help: Fix mem leaks `_content` vector owns elements so that when the `ContentListing` is deleted so is the content. Remove `get_content()` method in favour of `begin()` and `end()` const iterators. More `const` in general, and iterations over `ContentListing` use `&content` to avoid copying data. --- kernel/log_help.cc | 27 +++++++++++++-------------- kernel/log_help.h | 36 ++++++++++++++++-------------------- kernel/register.cc | 4 ++-- 3 files changed, 31 insertions(+), 36 deletions(-) diff --git a/kernel/log_help.cc b/kernel/log_help.cc index 45228b024..30c06a7c3 100644 --- a/kernel/log_help.cc +++ b/kernel/log_help.cc @@ -21,7 +21,7 @@ USING_YOSYS_NAMESPACE -Json ContentListing::to_json() { +Json ContentListing::to_json() const { Json::object object; object["type"] = type; if (body.length()) object["body"] = body; @@ -29,7 +29,7 @@ Json ContentListing::to_json() { if (source_line != 0) object["source_line"] = source_line; object["options"] = Json(options); Json::array content_array; - for (auto child : _content) content_array.push_back(child->to_json()); + for (auto child : _content) content_array.push_back(child.to_json()); object["content"] = content_array; return object; } @@ -73,9 +73,8 @@ ContentListing* ContentListing::open_option(const string &text, const source_location location) { log_assert(type.compare("root") == 0 || type.compare("usage") == 0); - auto option = new ContentListing("option", text, location); - add_content(option); - return option; + add_content("option", text, location); + return back(); } #define MAX_LINE_LEN 80 @@ -131,20 +130,20 @@ PrettyHelp *PrettyHelp::get_current() return current_help; } -void PrettyHelp::log_help() +void PrettyHelp::log_help() const { - for (auto content : _root_listing.get_content()) { - if (content->type.compare("usage") == 0) { - log_pass_str(content->body, 1, true); + for (auto &content : _root_listing) { + if (content.type.compare("usage") == 0) { + log_pass_str(content.body, 1, true); log("\n"); - } else if (content->type.compare("option") == 0) { - log_pass_str(content->body, 1); - for (auto text : content->get_content()) { - log_pass_str(text->body, 2); + } else if (content.type.compare("option") == 0) { + log_pass_str(content.body, 1); + for (auto text : content) { + log_pass_str(text.body, 2); log("\n"); } } else { - log_pass_str(content->body, 0); + log_pass_str(content.body, 0); log("\n"); } } diff --git a/kernel/log_help.h b/kernel/log_help.h index 0a40fc531..3ce0ac7aa 100644 --- a/kernel/log_help.h +++ b/kernel/log_help.h @@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN class ContentListing { - vector _content; + vector _content; public: string type; string body; @@ -45,22 +45,17 @@ public: ContentListing(string type, string body, source_location location) : ContentListing(type, body, location.file_name(), location.line()) { } - void add_content(ContentListing *new_content) { - _content.push_back(new_content); - } - void add_content(string type, string body, source_location location) { - auto new_content = new ContentListing(type, body, location); - add_content(new_content); + _content.push_back({type, body, location}); } - bool has_content() { return _content.size() != 0; } - const vector get_content() { - const vector content = _content; - return content; - } + bool has_content() const { return _content.size() != 0; } + + vector::const_iterator begin() const { return _content.cbegin(); } + vector::const_iterator end() const { return _content.cend(); } + ContentListing* back() { - return _content.back(); + return &_content.back(); } void set_option(string key, string val = "") { @@ -95,7 +90,7 @@ public: const source_location location = source_location::current() ); - Json to_json(); + Json to_json() const; }; class PrettyHelp @@ -113,18 +108,19 @@ public: static PrettyHelp *get_current(); - bool has_content() { return _root_listing.has_content(); } - const vector get_content() { - return _root_listing.get_content(); - } + bool has_content() const { return _root_listing.has_content(); } + + vector::const_iterator begin() const { return _root_listing.begin(); } + vector::const_iterator end() const { return _root_listing.end(); } + ContentListing* get_root() { return &_root_listing; } void set_group(const string g) { group = g; } - bool has_group() { return group.compare("unknown") != 0; } + bool has_group() const { return group.compare("unknown") != 0; } - void log_help(); + void log_help() const; }; YOSYS_NAMESPACE_END diff --git a/kernel/register.cc b/kernel/register.cc index ea2a2624f..0b02a6aa5 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -923,8 +923,8 @@ struct HelpPass : public Pass { json.name(name.c_str()); json.begin_object(); json.entry("title", title); json.name("content"); json.begin_array(); - for (auto content : cmd_help.get_content()) - json.value(content->to_json()); + for (auto &content : cmd_help) + json.value(content.to_json()); json.end_array(); json.entry("group", cmd_help.group); json.entry("source_file", pass->location.file_name()); From 891a907a3005fdb0f154f93d79943e563d8454c6 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:52:13 +1200 Subject: [PATCH 45/51] Add and use ENABLE_HELP_SOURCE Conditionally include help source tracking to preserve ABI. Docs builds can (and should) use `ENABLE_HELP_SOURCE` so that the generated sphinx docs can perform default grouping and link to source files. Regular user-builds don't need the source tracking. --- .github/workflows/prepare-docs.yml | 1 + Makefile | 5 +++++ README.md | 6 ++++++ kernel/register.h | 28 ++++++++++++++-------------- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.github/workflows/prepare-docs.yml b/.github/workflows/prepare-docs.yml index b47f5f3dd..a02febb3b 100644 --- a/.github/workflows/prepare-docs.yml +++ b/.github/workflows/prepare-docs.yml @@ -47,6 +47,7 @@ jobs: echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf echo "ENABLE_CCACHE := 1" >> Makefile.conf + echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf make -j$procs ENABLE_LTO=1 - name: Prepare docs diff --git a/Makefile b/Makefile index ce438f5db..1463055bd 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ ENABLE_VERIFIC_LIBERTY := 0 ENABLE_COVER := 1 ENABLE_LIBYOSYS := 0 ENABLE_ZLIB := 1 +ENABLE_HELP_SOURCE := 0 # python wrappers ENABLE_PYOSYS := 0 @@ -109,6 +110,10 @@ PLUGIN_LINKFLAGS += -L"$(LIBDIR)" PLUGIN_LIBS := -lyosys_exe endif +ifeq ($(ENABLE_HELP_SOURCE),1) +CXXFLAGS += -DYOSYS_ENABLE_HELP_SOURCE +endif + PKG_CONFIG ?= pkg-config SED ?= sed BISON ?= bison diff --git a/README.md b/README.md index 6c576f682..78b8bfc51 100644 --- a/README.md +++ b/README.md @@ -276,3 +276,9 @@ From the root of the repository, run `make docs`. This will build/rebuild yosys as necessary before generating the website documentation from the yosys help commands. To build for pdf instead of html, call `make docs DOC_TARGET=latexpdf`. + +It is recommended to use the `ENABLE_HELP_SOURCE` make option for Yosys builds +that will be used to build the documentation. This option enables source +location tracking for passes and improves the command reference through grouping +related commands and allowing for the documentation to link to the corresponding +source files. diff --git a/kernel/register.h b/kernel/register.h index e8c017c1d..fba72538f 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -23,22 +23,22 @@ #include "kernel/yosys_common.h" #include "kernel/yosys.h" -#include -#if __cpp_lib_source_location == 201907L - #include - using std::source_location; -#elif defined(__has_include) -# if __has_include() - #include - using std::experimental::source_location; -# else - #define SOURCE_FALLBACK -# endif -#else - #define SOURCE_FALLBACK +#ifdef YOSYS_ENABLE_HELP_SOURCE + #include +# if __cpp_lib_source_location == 201907L + #include + using std::source_location; + #define HAS_SOURCE_LOCATION +# elif defined(__has_include) +# if __has_include() + #include + using std::experimental::source_location; + #define HAS_SOURCE_LOCATION +# endif +# endif #endif -#ifdef SOURCE_FALLBACK +#ifndef HAS_SOURCE_LOCATION struct source_location { // dummy placeholder int line() const { return 0; } int column() const { return 0; } From ab403635e317619c23606b0aa31befe819c19fdb Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:52:13 +1200 Subject: [PATCH 46/51] CI: Enable source tracking for reusable build The `test-docs-build` jobs require source tracking enabled to prevent warnings-as-errors. Also add an extra note to the readme in case users run into the same. --- .github/workflows/test-build.yml | 1 + README.md | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 22d3a94f8..bdd290189 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -225,6 +225,7 @@ jobs: run: | make config-clang echo "ENABLE_CCACHE := 1" >> Makefile.conf + echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf make -j$procs - name: Install doc prereqs diff --git a/README.md b/README.md index 78b8bfc51..e5b8d1072 100644 --- a/README.md +++ b/README.md @@ -281,4 +281,6 @@ It is recommended to use the `ENABLE_HELP_SOURCE` make option for Yosys builds that will be used to build the documentation. This option enables source location tracking for passes and improves the command reference through grouping related commands and allowing for the documentation to link to the corresponding -source files. +source files. Without this, a warning will be raised during the Sphinx build +about `Found commands assigned to group unknown` and `make docs` is configured +to fail on warnings by default. From 20a51742f4bdbf4f6c70950f41e91b2e1fd95710 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:52:13 +1200 Subject: [PATCH 47/51] Docs: Fix cmd links from bugpoint docs --- docs/source/using_yosys/bugpoint.rst | 2 +- .../more_scripting/load_design.rst | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/source/using_yosys/bugpoint.rst b/docs/source/using_yosys/bugpoint.rst index 60cabd879..c524470af 100644 --- a/docs/source/using_yosys/bugpoint.rst +++ b/docs/source/using_yosys/bugpoint.rst @@ -185,7 +185,7 @@ the failure, you can use the ``bugpoint_keep`` attribute. This can be done with ``setattr -set bugpoint_keep 1 [selection]`` from a Yosys script. It is also possible to limit `bugpoint` to only removing certain *kinds* of objects, such as only removing entire modules or cells (instances of modules). For more about -the options available, check ``help bugpoint`` or :doc:`/cmd/bugpoint`. +the options available, check ``help bugpoint`` or :cmd:title:`bugpoint`. In some situations, it may also be helpful to use `setenv` before `bugpoint` to set environment variables for the spawned processes. An example of this is diff --git a/docs/source/using_yosys/more_scripting/load_design.rst b/docs/source/using_yosys/more_scripting/load_design.rst index e5006c16e..9aa028418 100644 --- a/docs/source/using_yosys/more_scripting/load_design.rst +++ b/docs/source/using_yosys/more_scripting/load_design.rst @@ -57,6 +57,7 @@ The `read` command Yosys frontends ~~~~~~~~~~~~~~~ +- :doc:`/cmd/index_frontends` - typically start with ``read_`` - built-in support for heredocs @@ -86,7 +87,12 @@ Yosys frontends The `read_verilog` command """""""""""""""""""""""""" -- :doc:`/cmd/index_frontends` +- :cmd:title:`read_verilog`; also + + + :cmd:title:`verilog_defaults`, + + :cmd:title:`verilog_defines`, and + + :cmd:title:`read_verilog_file_list` + - supports most of Verilog-2005 - limited support for SystemVerilog - some non-standard features/extensions for enabling formal verification @@ -117,12 +123,12 @@ The `read_verilog` command Other built-in ``read_*`` commands """""""""""""""""""""""""""""""""" -- :doc:`/cmd/read_rtlil` -- :doc:`/cmd/read_aiger` -- :doc:`/cmd/read_blif` -- :doc:`/cmd/read_json` -- :doc:`/cmd/read_liberty` -- :doc:`/cmd/read_xaiger2` +- :cmd:title:`read_rtlil` +- :cmd:title:`read_aiger` +- :cmd:title:`read_blif` +- :cmd:title:`read_json` +- :cmd:title:`read_liberty` +- :cmd:title:`read_xaiger2` .. TODO:: does `write_file` count? From 96108ad8b42ddd002fa43ecf25673998fc95eaf9 Mon Sep 17 00:00:00 2001 From: George Rennie Date: Wed, 6 Aug 2025 21:34:37 +0100 Subject: [PATCH 48/51] kernel/register.h: whitespace --- kernel/register.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/register.h b/kernel/register.h index fba72538f..534cfbc28 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -116,7 +116,7 @@ struct ScriptPass : Pass RTLIL::Design *active_design; std::string active_run_from, active_run_to; - ScriptPass(std::string name, std::string short_help = "** document me **", source_location location = source_location::current()) : + ScriptPass(std::string name, std::string short_help = "** document me **", source_location location = source_location::current()) : Pass(name, short_help, location) { } virtual void script() = 0; From b610afbc1bbbd73d4d4cdd7eb2d873c58b97445f Mon Sep 17 00:00:00 2001 From: George Rennie Date: Wed, 6 Aug 2025 21:37:28 +0100 Subject: [PATCH 49/51] py_wrap_generator.py: whitespace --- misc/py_wrap_generator.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py index 4857a9dc3..b9af5fe70 100644 --- a/misc/py_wrap_generator.py +++ b/misc/py_wrap_generator.py @@ -200,7 +200,7 @@ class WType: t.cont = candidate if(t.name not in known_containers): - return None + return None return t prefix = "" @@ -447,7 +447,7 @@ class PythonDictTranslator(Translator): if types[0].attr_type != attr_types.star: text += "*" text += key_tmp_name + "->get_cpp_obj()" - + text += ", " if types[1].name not in classnames: text += val_tmp_name @@ -457,7 +457,7 @@ class PythonDictTranslator(Translator): text += val_tmp_name + "->get_cpp_obj()" text += "));\n" + prefix + "}" return text - + #Generate c++ code to translate to a boost::python::dict @classmethod def translate_cpp(c, varname, types, prefix, ref): @@ -498,7 +498,7 @@ class DictTranslator(PythonDictTranslator): #Sub_type for std::map class MapTranslator(PythonDictTranslator): insert_name = "insert" - orig_name = "std::map" + orig_name = "std::map" #Translator for std::pair. Derived from PythonDictTranslator because the #gen_type function is the same (because both have two template parameters) @@ -684,7 +684,7 @@ class Attribute: if self.wtype.name in known_containers: return known_containers[self.wtype.name].typename return prefix + self.wtype.name - + #Generate Translation code for the attribute def gen_translation(self): if self.wtype.name in known_containers: @@ -948,7 +948,7 @@ class WClass: text = "\n\t\tclass_<" + self.name + base_info + ">(\"" + self.name + "\"" text += body return text - + def contains_default_constr(self): for c in self.found_constrs: @@ -1773,7 +1773,7 @@ class WMember: if self.wtype.name in classnames: text += ")" text += ";" - + if self.wtype.name in classnames: text += "\n\t\treturn *ret_;" elif self.wtype.name in known_containers: @@ -1795,12 +1795,12 @@ class WMember: text += "\n\t{" text += ret.gen_translation() text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";" - text += "\n\t}\n" + text += "\n\t}\n" return text; def gen_boost_py(self): - text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name + text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name if not self.is_const: text += ", &" + self.member_of.name + "::set_var_py_" + self.name text += ")" @@ -1926,7 +1926,7 @@ class WGlobal: if self.wtype.name in classnames: text += ")" text += ";" - + if self.wtype.name in classnames: text += "\n\t\treturn *ret_;" elif self.wtype.name in known_containers: @@ -1948,12 +1948,12 @@ class WGlobal: text += "\n\t{" text += ret.gen_translation() text += "\n\t\t" + self.namespace + "::" + self.name + " = " + ret.gen_call() + ";" - text += "\n\t}\n" + text += "\n\t}\n" return text; def gen_boost_py(self): - text = "\n\t\t\t.add_static_property(\"" + self.name + "\", &" + "YOSYS_PYTHON::get_var_py_" + self.name + text = "\n\t\t\t.add_static_property(\"" + self.name + "\", &" + "YOSYS_PYTHON::get_var_py_" + self.name if not self.is_const: text += ", &YOSYS_PYTHON::set_var_py_" + self.name text += ")" From 46a711d56695d7468e209f4bd104d0c1c271312a Mon Sep 17 00:00:00 2001 From: George Rennie Date: Wed, 6 Aug 2025 21:38:03 +0100 Subject: [PATCH 50/51] py_wrap_generator.py: support srd::source_location as trailing default argument --- misc/py_wrap_generator.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py index b9af5fe70..9de34e74e 100644 --- a/misc/py_wrap_generator.py +++ b/misc/py_wrap_generator.py @@ -71,7 +71,7 @@ keyword_aliases = { #These can be used without any explicit conversion primitive_types = ["void", "bool", "int", "double", "size_t", "std::string", - "string", "State", "char_p"] + "string", "State", "char_p", "std::source_location", "source_location"] from enum import Enum @@ -1137,10 +1137,18 @@ class WConstructor: str_def = str_def[0:found].strip() if len(str_def) == 0: return con - for arg in split_list(str_def, ","): + args = split_list(str_def, ",") + for i, arg in enumerate(args): parsed = Attribute.from_string(arg.strip(), containing_file, line_number) if parsed == None: return None + # Only allow std::source_location as defaulted last argument, and + # don't append so it takes default value + if parsed.wtype.name in ["std::source_location", "source_location"]: + if parsed.default_value is None or i != len(args) - 1: + debug("std::source_location not defaulted last arg of " + class_.name + " is unsupported", 2) + return None + continue con.args.append(parsed) return con @@ -1379,12 +1387,20 @@ class WFunction: str_def = str_def[:found].strip() if(len(str_def) == 0): return func - for arg in split_list(str_def, ","): + args = split_list(str_def, ",") + for i, arg in enumerate(args): if arg.strip() == "...": continue parsed = Attribute.from_string(arg.strip(), containing_file, line_number) if parsed == None: return None + # Only allow std::source_location as defaulted last argument, and + # don't append so it takes default value + if parsed.wtype.name in ["std::source_location", "source_location"]: + if parsed.default_value is None or i != len(args) - 1: + debug("std::source_location not defaulted last arg of " + func.name + " is unsupported", 2) + return None + continue func.args.append(parsed) return func From ab66d8b814edd60dc3f4fa51819889d84023411d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 00:27:08 +0000 Subject: [PATCH 51/51] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1463055bd..506f6a99c 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.55+194 +YOSYS_VER := 0.55+209 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)