Contributing to Yosys ===================== Reporting bugs -------------- A good bug report includes the following information: Title ~~~~~ briefly describe the issue, for example: 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 ~~~~~~~~~~~~~~~~~~ The reproduction steps should be a minimal, complete and verifiable example `MVCE`_. Providing an MVCE with your bug report drastically increases the likelihood that someone will be able to help resolve your issue. One way to minimize a design is to use the `bugpoint_` command. You can learn more in the `how-to guide for bugpoint_`. The reproduction steps are 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, you 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 ~~~~~~~~~~~~~~~~~~ Anything else you think might be helpful or relevant when verifying or fixing the bug. Once you have created the issue, any additional details can be added as a comment on that issue. You can include any additional context as to what you were doing when you first encountered the bug. If this issue discovered through the use of a fuzzer, ALWAYS declare that. If you've minimized the script, consider including the `bugpoint` script you used, or the original script, for example: .. 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 possible, 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/ Contributing code ----------------- Code that matters ~~~~~~~~~~~~~~~~~ If you're adding complex functionality, or modifying core parts of yosys, we highly recommend discussing your motivation and approach ahead of time on the `Discourse forum`_. Please, be as explicit and concrete as possible when explaining the motivation for what you're building. Additionally, if you do so on the forum first before you starting hacking away at C++, you might solve your problem without writing a single line of code! PRs are considered for relevance, priority, and quality based on their descriptions first, code second. Before you build or fix something, also search for existing `issues`_. .. _`Discourse forum`: https://yosyshq.discourse.group/ .. _`issues`: https://github.com/YosysHQ/yosys/issues Making sense ~~~~~~~~~~~~ Given enough effort, the behavior of any code can be figured out to any desired extent. However, the author of the code is by far in the best position to make this as easy as possible. Yosys is a long-standing project and has accumulated a lot of C-style code that's not written to be read, just written to run. We improve this bit by bit when opportunities arise, but it is what it is. New additions are expected to be a lot cleaner. The purpose and behavior of the code changed should be described clearly. Your change should contain exactly what it needs to match that description. This means: * nothing more than that - no dead code, no undocumented features * nothing missing - if something is partially built, that's fine, but you have to make that clear. For example, some passes only support some types of cells Here are some software engineering approaches that help: * Use abstraction to model the problem and hide details * Maximize the usage of types (structs over loose variables), not necessarily in an object-oriented way * Use functions, scopes, type aliases * In new passes, make sure the logic behind how and why it works is actually provided in coherent comments, and that variable and type naming is consistent with the terms you use in the description. * The logic of the implementation should be described in mathematical or algorithm theory terms. Correctness, termination, computational complexity. Make it clear if you're re-implementing a classic data structure for logic synthesis or graph traversal etc. * There's various ways of traversing the design with use-def indices (for getting drivers and driven signals) available in Yosys. They have advantages and sometimes disadvantages. Prefer not re-implementing these * Prefer references over pointers, and smart pointers over raw pointers * Aggressively deduplicate code. Within functions, within passes, across passes, even against existing code * Prefer declaring things ``const`` * Prefer range-based for loops over C-style Common mistakes ~~~~~~~~~~~~~~~ * Deleting design objects invalidates iterators. Defer deletions or hold a copy of the list of pointers to design objects * Deleting wires can get sketchy and is intended to be done solely by the ``opt_clean`` pass so just don't do it * Iterating over an entire design and checking if things are selected is more inefficient than using the ``selected_*`` methods * Remember to call ``fixup_ports`` at the end if you're modifying module interfaces Testing your change ~~~~~~~~~~~~~~~~~~~ Untested code can't be maintained. Inevitable codebase-wide changes are likely to break anything untested. Tests also help reviewers understand the purpose of the code change in practice. Your code needs to come with tests. If it's a feature, a test that covers representative examples of the added behavior. If it's a bug fix, it should reproduce the original isolated bug. But in some situations, adding a test isn't viable. If you can't provide a test, explain this decision. Prefer writing unit tests (:file:`tests/unit`) for isolated tests to the internals of more serious code changes, like those to the core of yosys, or more algorithmic ones. The rest of the test suite is mostly based on running Yosys on various Yosys and Tcl scripts that manually call Yosys commands. See :doc:`/yosys_internals/extending_yosys/test_suites` for more information about how our test suite is structured. The basic test writing approach is checking for the presence of some kind of object or pattern with ``-assert-count`` in :doc:`/using_yosys/more_scripting/selections`. It's often best to use equivalence checking with ``equiv_opt -assert`` or similar to prove that the changes done to the design by a modified pass preserve equivalence. But some code isn't meant to preserve equivalence. Sometimes proving equivalence takes an impractically long time for larger inputs. Also beware, the ``equiv_`` passes are a bit quirky and might even have incorrect results in unusual situations. .. Changes to core parts of Yosys or passes that are included in synthesis flows .. can change runtime and memory usage - for the better or for worse. This strongly .. depends on the design involved. Such risky changes should then be benchmarked .. with various designs. .. TODO Emil benchmarking Coding style ~~~~~~~~~~~~ Yosys is written in C++17. In general Yosys uses ``int`` instead of ``size_t``. To avoid compiler warnings for implicit type casts, always use ``GetSize(foobar)`` instead of ``foobar.size()``. (``GetSize()`` is defined in :file:`kernel/yosys.h`) For auto formatting code, a :file:`.clang-format` file is present top-level. Yosys code is using tabs for indentation. A tab is 8 characters wide, but prefer not relying on it. A continuation of a statement in the following line is indented by two additional tabs. Lines are as long as you want them to be. A good rule of thumb is to break lines at about column 150. Opening braces can be put on the same or next line as the statement opening the block (if, switch, for, while, do). Put the opening brace on its own line for larger blocks, especially blocks that contains blank lines. Remove trailing whitespace on sight. Otherwise stick to the `Linux Kernel Coding Style`_. .. _Linux Kernel Coding Style: https://www.kernel.org/doc/Documentation/process/coding-style.rst Git style ~~~~~~~~~ We don't have a strict commit message style. Some style hints: * Refactor and document existing code if you touch it, but in separate commits from your functional changes * Prefer smaller commits organized by good chunks. Git has a lot of features like fixup commits, interactive rebase with autosquash Reviewing PRs ------------- Reviewing PRs is a totally valid form of external contributing to the project! Who's the reviewer? ~~~~~~~~~~~~~~~~~~~ Yosys HQ is a company with the inherited mandate to make decisions on behalf of the open source project. As such, we at HQ are collectively the maintainers. Within HQ, we allocate reviews based on expertise with the topic at hand as well as member time constraints. If you're intimately acquainted with a part of the codebase, we will be happy to defer to your experience and have you review PRs. The official way we like is our CODEOWNERS file in the git repository. What we're looking for in code owners is activity and trust. For activity, if you're only interested in a yosys pass for example for the time you spend writing a thesis, it might be better to focus on writing good tests and docs in the PRs you submit rather than to commit to code ownership and therefore to be responsible for fixing things and reviewing other people's PRs at various unexpected points later. If you're prolific in some part of the codebase and not a code owner, we still value your experience and may tag you in PRs. As a matter of fact, the purpose of code ownership is to avoid maintainer burnout by removing orphaned parts of the codebase. If you become a code owner and stop being responsive, in the future, we might decide to remove such code if convenient and costly to maintain. It's simply more respectful of the users' time to explicitly cut something out than let it "bitrot". Larger projects like LLVM or linux could not survive without such things, but Yosys is far smaller, and there are expectations .. TODO this deserves its own section elsewhere I think? But it would be distracting elsewhere Sometimes, multiple maintainers may add review comments. This is considered healthy collaborative even if it might create disagreement at times. If somebody is already reviewing a PR, others, even non-maintainers are free to leave comments with extra observations and alternate perspectives in a collaborative spirit. How to review ~~~~~~~~~~~~~ First, read everything above about contributing. Those are the values you should gently enforce as a reviewer. They're ordered by importance, but explicitly, descriptions are more important than code, long-form comments describing the design are more important than piecemeal comments, etc. If a PR is poorly described, incomplete, tests are broken, or if the author is not responding, please don't feel pressured to take over their role by reverse engineering the code or fixing things for them, unless there are good reasons to do so. If a PR author submits LLM outputs they haven't understood themselves, they will not be able to implement feedback. Take this into consideration as well. We do not ban LLM code from the codebase, we ban bad code. Reviewers may have diverse styles of communication while reviewing - one may do one thorough review, another may prefer a back and forth with the basics out the way before digging into the code. Generally, PRs may have several requests for modifications and long discussions, but often they just are good enough to merge as-is. The CI is required to go green for merging. New contributors need a CI run to be triggered by a maintainer before their PRs take up computing resources. It's a single click from the github web interface.