mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			267 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
Writing extensions
 | 
						|
==================
 | 
						|
 | 
						|
.. role:: yoscrypt(code)
 | 
						|
   :language: yoscrypt
 | 
						|
 | 
						|
.. todo:: check text is coherent
 | 
						|
 | 
						|
.. todo:: update to use :file:`/code_examples/extensions/test*.log`
 | 
						|
 | 
						|
This chapter contains some bits and pieces of information about programming
 | 
						|
yosys extensions. Don't be afraid to ask questions on the YosysHQ Discourse.
 | 
						|
 | 
						|
.. todo:: mention coding guide
 | 
						|
 | 
						|
Quick guide
 | 
						|
-----------
 | 
						|
 | 
						|
Code examples from this section are included in the |code_examples/extensions|_
 | 
						|
directory of the Yosys source code.
 | 
						|
 | 
						|
.. |code_examples/extensions| replace:: :file:`docs/source/code_examples/extensions`
 | 
						|
.. _code_examples/extensions: https://github.com/YosysHQ/yosys/tree/main/docs/source/code_examples/extensions
 | 
						|
 | 
						|
 | 
						|
Program components and data formats
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
See :doc:`/yosys_internals/formats/rtlil_rep` document for more information
 | 
						|
about the internal data storage format used in Yosys and the classes that it
 | 
						|
provides.
 | 
						|
 | 
						|
This document will focus on the much simpler version of RTLIL left after the
 | 
						|
commands `proc` and `memory` (or :yoscrypt:`memory -nomap`):
 | 
						|
 | 
						|
.. figure:: /_images/internals/simplified_rtlil.*
 | 
						|
    :class: width-helper invert-helper
 | 
						|
    :name: fig:Simplified_RTLIL
 | 
						|
 | 
						|
    Simplified RTLIL entity-relationship diagram without memories and processes
 | 
						|
 | 
						|
It is possible to only work on this simpler version:
 | 
						|
 | 
						|
.. todo:: consider replacing inline code
 | 
						|
 | 
						|
.. code:: c++
 | 
						|
 | 
						|
    for (RTLIL::Module *module : design->selected_modules() {
 | 
						|
        if (module->has_memories_warn() || module->has_processes_warn())
 | 
						|
            continue;
 | 
						|
        ....
 | 
						|
    }
 | 
						|
 | 
						|
When trying to understand what a command does, creating a small test case to
 | 
						|
look at the output of `dump` and `show` before and after the command has been
 | 
						|
executed can be helpful. :doc:`/using_yosys/more_scripting/selections` has more
 | 
						|
information on using these commands.
 | 
						|
 | 
						|
Creating a command
 | 
						|
~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
.. todo:: add/expand supporting text
 | 
						|
 | 
						|
Let's create a very simple test command which prints the arguments we called it
 | 
						|
with, and lists off the current design's modules.
 | 
						|
 | 
						|
.. literalinclude:: /code_examples/extensions/my_cmd.cc
 | 
						|
   :language: c++
 | 
						|
   :lines: 1, 4, 6, 7-20
 | 
						|
   :caption: Example command :yoscrypt:`my_cmd` from :file:`my_cmd.cc`
 | 
						|
   
 | 
						|
Note that we are making a global instance of a class derived from
 | 
						|
``Yosys::Pass``, which we get by including :file:`kernel/yosys.h`.
 | 
						|
 | 
						|
Compiling to a plugin
 | 
						|
~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Yosys can be extended by adding additional C++ code to the Yosys code base, or
 | 
						|
by loading plugins into Yosys.  For maintainability it is generally recommended
 | 
						|
to create plugins.
 | 
						|
 | 
						|
The following command compiles our example :yoscrypt:`my_cmd` to a Yosys plugin:
 | 
						|
 | 
						|
.. todo:: replace inline code
 | 
						|
 | 
						|
.. code:: shell
 | 
						|
 | 
						|
   yosys-config --exec --cxx --cxxflags --ldflags \
 | 
						|
   -o my_cmd.so -shared my_cmd.cc --ldlibs
 | 
						|
 | 
						|
Or shorter:
 | 
						|
 | 
						|
.. code:: shell
 | 
						|
 | 
						|
   yosys-config --build my_cmd.so my_cmd.cc
 | 
						|
 | 
						|
Running Yosys with the ``-m`` option allows the plugin to be used.  Here's a
 | 
						|
quick example that also uses the ``-p`` option to run :yoscrypt:`my_cmd foo
 | 
						|
bar`.
 | 
						|
 | 
						|
.. code:: shell-session
 | 
						|
 | 
						|
   $ yosys -m ./my_cmd.so -p 'my_cmd foo bar'
 | 
						|
 | 
						|
   -- Running command `my_cmd foo bar' --
 | 
						|
   Arguments to my_cmd:
 | 
						|
     my_cmd
 | 
						|
     foo
 | 
						|
     bar
 | 
						|
   Modules in current design:
 | 
						|
 | 
						|
Creating modules from scratch
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Let's create the following module using the RTLIL API:
 | 
						|
 | 
						|
.. literalinclude:: /code_examples/extensions/absval_ref.v
 | 
						|
   :language: Verilog
 | 
						|
   :caption: absval_ref.v
 | 
						|
 | 
						|
We'll do the same as before and format it as a a ``Yosys::Pass``.
 | 
						|
 | 
						|
.. literalinclude:: /code_examples/extensions/my_cmd.cc
 | 
						|
   :language: c++
 | 
						|
   :lines: 23-47
 | 
						|
   :caption: :yoscrypt:`test1` - creating the absval module, from :file:`my_cmd.cc`
 | 
						|
 | 
						|
.. code:: shell-session
 | 
						|
 | 
						|
   $ yosys -m ./my_cmd.so -p 'test1' -Q
 | 
						|
 | 
						|
   -- Running command `test1' --
 | 
						|
   Name of this module: absval
 | 
						|
 | 
						|
And if we look at the schematic for this new module we see the following:
 | 
						|
 | 
						|
.. figure:: /_images/code_examples/extensions/test1.*
 | 
						|
   :class: width-helper invert-helper
 | 
						|
 | 
						|
   Output of ``yosys -m ./my_cmd.so -p 'test1; show'``
 | 
						|
 | 
						|
Modifying modules
 | 
						|
~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Most commands modify existing modules, not create new ones.
 | 
						|
 | 
						|
When modifying existing modules, stick to the following DOs and DON'Ts:
 | 
						|
 | 
						|
- Do not remove wires. Simply disconnect them and let a successive `clean`
 | 
						|
  command worry about removing it.
 | 
						|
- Use ``module->fixup_ports()`` after changing the ``port_*`` properties of
 | 
						|
  wires.
 | 
						|
- You can safely remove cells or change the ``connections`` property of a cell,
 | 
						|
  but be careful when changing the size of the ``SigSpec`` connected to a cell
 | 
						|
  port.
 | 
						|
- Use the ``SigMap`` helper class (see next section) when you need a unique
 | 
						|
  handle for each signal bit.
 | 
						|
 | 
						|
Using the SigMap helper class
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Consider the following module:
 | 
						|
 | 
						|
.. literalinclude:: /code_examples/extensions/sigmap_test.v
 | 
						|
   :language: Verilog
 | 
						|
   :caption: :file:`sigmap_test.v`
 | 
						|
 | 
						|
In this case ``a``, ``x``, and ``y`` are all different names for the same
 | 
						|
signal. However:
 | 
						|
 | 
						|
.. todo:: use my_cmd.cc literalincludes
 | 
						|
 | 
						|
.. code:: C++
 | 
						|
 | 
						|
    RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")),
 | 
						|
                                           y(module->wire("\\y"));
 | 
						|
    log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
 | 
						|
 | 
						|
The ``SigMap`` helper class can be used to map all such aliasing signals to a
 | 
						|
unique signal from the group (usually the wire that is directly driven by a cell
 | 
						|
or port).
 | 
						|
 | 
						|
.. code:: C++
 | 
						|
 | 
						|
    SigMap sigmap(module);
 | 
						|
    log("%d %d %d\n", sigmap(a) == sigmap(x), sigmap(x) == sigmap(y),
 | 
						|
                      sigmap(y) == sigmap(a)); // will print "1 1 1"
 | 
						|
 | 
						|
Printing log messages
 | 
						|
~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
The ``log()`` function is a ``printf()``-like function that can be used to
 | 
						|
create log messages.
 | 
						|
 | 
						|
Use ``log_signal()`` to create a C-string for a SigSpec object:
 | 
						|
 | 
						|
.. code:: C++
 | 
						|
 | 
						|
    log("Mapped signal x: %s\n", log_signal(sigmap(x)));
 | 
						|
 | 
						|
The pointer returned by ``log_signal()`` is automatically freed by the log
 | 
						|
framework at a later time.
 | 
						|
 | 
						|
Use ``log_id()`` to create a C-string for an ``RTLIL::IdString``:
 | 
						|
 | 
						|
.. code:: C++
 | 
						|
 | 
						|
    log("Name of this module: %s\n", log_id(module->name));
 | 
						|
 | 
						|
Use ``log_header()`` and ``log_push()``/\ ``log_pop()`` to structure log
 | 
						|
messages:
 | 
						|
 | 
						|
.. todo:: replace inline code
 | 
						|
 | 
						|
.. code:: C++
 | 
						|
 | 
						|
    log_header(design, "Doing important stuff!\n");
 | 
						|
    log_push();
 | 
						|
    for (int i = 0; i < 10; i++)
 | 
						|
        log("Log message #%d.\n", i);
 | 
						|
    log_pop();
 | 
						|
 | 
						|
Error handling
 | 
						|
~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Use ``log_error()`` to report a non-recoverable error:
 | 
						|
 | 
						|
.. todo:: replace inline code
 | 
						|
 | 
						|
.. code:: C++
 | 
						|
 | 
						|
    if (design->modules.count(module->name) != 0)
 | 
						|
        log_error("A module with the name %s already exists!\n",
 | 
						|
                   RTLIL::id2cstr(module->name));
 | 
						|
 | 
						|
Use ``log_cmd_error()`` to report a recoverable error:
 | 
						|
 | 
						|
.. code:: C++
 | 
						|
 | 
						|
    if (design->selection().empty())
 | 
						|
        log_cmd_error("This command can't operator on an empty selection!\n");
 | 
						|
 | 
						|
Use ``log_assert()`` and ``log_abort()`` instead of ``assert()`` and ``abort()``.
 | 
						|
 | 
						|
The "stubnets" example module
 | 
						|
------------------------------
 | 
						|
 | 
						|
The following is the complete code of the "stubnets" example module. It is
 | 
						|
included in the Yosys source distribution under |code_examples/stubnets|_.
 | 
						|
 | 
						|
.. |code_examples/stubnets| replace:: :file:`docs/source/code_examples/stubnets`
 | 
						|
.. _code_examples/stubnets: https://github.com/YosysHQ/yosys/tree/main/docs/source/code_examples/stubnets
 | 
						|
 | 
						|
.. literalinclude:: /code_examples/stubnets/stubnets.cc
 | 
						|
    :language: c++
 | 
						|
    :linenos:
 | 
						|
    :caption: :file:`stubnets.cc`
 | 
						|
 | 
						|
.. literalinclude:: /code_examples/stubnets/Makefile
 | 
						|
    :language: makefile
 | 
						|
    :linenos:
 | 
						|
    :caption: :file:`Makefile`
 | 
						|
 | 
						|
.. literalinclude:: /code_examples/stubnets/test.v
 | 
						|
    :language: verilog
 | 
						|
    :linenos:
 | 
						|
    :caption: :file:`test.v`
 |