docs/functional: Minimal backend paragraphs

I was thinking about compiling the dummy example and including a simple example usage, but it turns out functional.h isn't (currently) available for extensions.
This commit is contained in:
Krystine Sherwin 2025-03-01 16:15:54 +13:00
parent 3c493d2bef
commit b56e3ec6e4
No known key found for this signature in database
1 changed files with 36 additions and 31 deletions

View File

@ -149,44 +149,49 @@ S-expressions can be constructed with ``SExpr::list``, for example ``SExpr expr
Example: A minimal functional backend Example: A minimal functional backend
------------------------------------- -------------------------------------
At its most basic, there are three steps we need to accomplish for a minimal
functional backend. First, we need to convert our design into FunctionalIR.
This is most easily done by calling the ``Functional::IR::from_module()`` static
method with our top-level module, or iterating over and converting each of the
modules in our design. Second, we need to handle each of the
``Functional::Node``\ s in our design. Iterating over the ``Functional::IR``
includes reading the module inputs and current state, but not writing the
results. So our final step is to handle the outputs and next state.
In order to add an output command to Yosys, we implement the ``Yosys::Backend``
class and provide an instance of it:
.. literalinclude:: /code_examples/functional/dummy.cc .. literalinclude:: /code_examples/functional/dummy.cc
:language: c++ :language: c++
:caption: Example source code for a minimal functional backend :caption: Example source code for a minimal functional backend, ``dummy.cc``
- three main steps needed Because we are using the ``Backend`` class, our ``"functional_dummy"`` is
registered as the ``write_functional_dummy`` command. The ``execute`` method is
the part that runs when the user calls the command, handling any options,
preparing the output file for writing, and iterating over selected modules in
the design. Since we don't have any options here, we set ``argidx = 1`` and
call the ``extra_args()`` method. This method will read the command arguments,
raising an error if there are any unexpected ones. It will also assign the
pointer ``f`` to the output file, or stdout if none is given.
+ convert to FunctionalIR .. note::
+ handle nodes
+ handle outputs and next state
- backend pass boiler plate gives us ``write_functional_dummy`` command For more on adding new commands to Yosys and how they work, refer to
:doc:`/yosys_internals/extending_yosys/extensions`.
The final part is the ``Backend`` itself, which registers the command in Yosys. For this minimal example all we are doing is printing out each node. The
The ``execute`` method is the part that runs when the user calls the command, ``node.name()`` method returns an ``RTLIL::IdString``, which we convert for
handling any options, preparing the output file for writing, and iterating over printing with ``id2cstr()``. Then, to print the function of the node, we use
selected modules in the design. For more on adding new commands to Yosys and ``node.to_string()`` which gives us a string of the form ``function(args)``. The
how they work, refer to :doc:`/yosys_internals/extending_yosys/extensions`. ``function`` part is the result of ``Functional::IR::fn_to_string(node.fn())``;
while ``args`` is the zero or more arguments passed to the function, most
commonly the name of another node. Behind the scenes, the ``node.to_string()``
method actually wraps ``node.visit(visitor)`` with a private visitor whose
return type is ``std::string``.
- pointer ``f`` is a ``std::ostream`` we can write to, being either a file or Finally we iterate over the module's outputs and states, using
stdout ``Functional::IROutput::value()`` and ``Functional::IRState::next_value()``
- FunctionalIR conversion done by ``Functional::IR::from_module()`` respectively in order to get the results of the transfer function.
- each node performs some function or operation (including reading input/current
state)
+ each variable is assigned exactly once before being used
+ ``node.name()`` returns a ``RTLIL::IdString``, which we convert for
printing with ``id2cstr()``
+ ``node.to_string()`` converts the node into a string of the form
``function(args)``
* ``function`` is the result of ``Functional::IR::fn_to_string(node.fn())``
* ``args`` are the zero or more arguments passed to the function, most
commonly the name of another node
* wraps ``node.visit()`` with a private visitor with return type
``std::string``
- ``Functional::IROutput::value()`` and ``Functional::IRState::next_value()``
represent the outputs of our function
Example: Adapting SMT-LIB backend for Rosette Example: Adapting SMT-LIB backend for Rosette
--------------------------------------------- ---------------------------------------------