mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									3c493d2bef
								
							
						
					
					
						commit
						b56e3ec6e4
					
				
					 1 changed files with 36 additions and 31 deletions
				
			
		|  | @ -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 | ||||||
| --------------------------------------------- | --------------------------------------------- | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue