3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-12-14 07:36:24 +00:00

Merge remote-tracking branch 'origin/main' into gussmith23-rosette-backend-updates

This commit is contained in:
Gus Smith 2025-11-29 14:20:36 -08:00
commit 6fe35fa46c
694 changed files with 33466 additions and 17901 deletions

2
docs/.gitignore vendored
View file

@ -1,5 +1,4 @@
/build/
/source/cmd
/source/generated
/source/_images/**/*.log
/source/_images/**/*.aux
@ -7,3 +6,4 @@
/source/_images/**/*.svg
/source/_images/**/*.dot
/source/_images/code_examples
/venv

View file

@ -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

View file

@ -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;
}

View file

@ -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.

View file

@ -72,7 +72,7 @@ circuits.
Tools exist to synthesize high level code (usually in the form of C/C++/SystemC
code with additional metadata) to behavioural HDL code (usually in the form of
Verilog or VHDL code). Aside from the many commercial tools for high level
synthesis there are also a number of FOSS tools for high level synthesis .
synthesis there are also a number of FOSS tools for high level synthesis.
Behavioural level
~~~~~~~~~~~~~~~~~
@ -185,7 +185,7 @@ advantage that it has a unique normalized form. The latter has much better worst
case performance and is therefore better suited for the synthesis of large logic
functions.
Good FOSS tools exists for multi-level logic synthesis .
Good FOSS tools exists for multi-level logic synthesis.
Yosys contains basic logic synthesis functionality but can also use ABC for the
logic synthesis step. Using ABC is recommended.
@ -221,7 +221,7 @@ design description as input and generates an RTL, logical gate or physical gate
level description of the design as output. Yosys' main strengths are behavioural
and RTL synthesis. A wide range of commands (synthesis passes) exist within
Yosys that can be used to perform a wide range of synthesis tasks within the
domain of behavioural, rtl and logic synthesis. Yosys is designed to be
domain of behavioural, RTL and logic synthesis. Yosys is designed to be
extensible and therefore is a good basis for implementing custom synthesis tools
for specialised tasks.
@ -572,7 +572,7 @@ of lexical tokens given in :numref:`Tab. %s <tab:Basics_tokens>`.
TOK_SEMICOLON \-
============== ===============
The lexer is usually generated by a lexer generator (e.g. flex ) from a
The lexer is usually generated by a lexer generator (e.g. flex) from a
description file that is using regular expressions to specify the text pattern
that should match the individual tokens.

View file

@ -63,6 +63,10 @@ significant bit first. Bits may be any of:
- ``m``: A marked bit (internal use only)
- ``-``: A don't care value
When the bit representation has fewer bits than the width, it is padded to the width with
the most significant explicit bit, or ``0`` if the most significant explicit bit is ``1``,
or ``x`` if there are no explicit bits.
An *integer* is simply a signed integer value in decimal format. **Warning:**
Integer constants are limited to 32 bits. That is, they may only be in the range
:math:`[-2147483648, 2147483648)`. Integers outside this range will result in an
@ -133,6 +137,7 @@ wires, memories, cells, processes, and connections.
<module> ::= <attr-stmt>* <module-stmt> <module-body> <module-end-stmt>
<module-stmt> ::= module <id> <eol>
<module-body> ::= (<param-stmt>
| <conn-stmt>
| <wire>
| <memory>
| <cell>
@ -170,6 +175,11 @@ See :ref:`sec:rtlil_sigspec` for an overview of signal specifications.
| <sigspec> [ <integer> (:<integer>)? ]
| { <sigspec>* }
When a ``<wire-id>`` is specified, the wire must have been previously declared.
When a signal slice is specified, the left-hand integer must be greather than or
equal to the right-hand integer.
Connections
^^^^^^^^^^^
@ -268,7 +278,7 @@ may have zero or more attributes.
.. code:: BNF
<switch> ::= <switch-stmt> <case>* <switch-end-stmt>
<switch-stmt> := <attr-stmt>* switch <sigspec> <eol>
<switch-stmt> ::= <attr-stmt>* switch <sigspec> <eol>
<case> ::= <attr-stmt>* <case-stmt> <case-body>
<case-stmt> ::= case <compare>? <eol>
<compare> ::= <sigspec> (, <sigspec>)*
@ -295,3 +305,4 @@ be:
| sync always <eol>
<sync-type> ::= low | high | posedge | negedge | edge
<update-stmt> ::= update <dest-sigspec> <src-sigspec> <eol>
| <attr-stmt>* memwr <id> <sigspec> <sigspec> <sigspec> <constant> <eol>

View file

@ -24,8 +24,8 @@ are zero, the value from ``A`` input is sent to the output. If the :math:`n`\
'th bit from ``S`` is set, the value :math:`n`\ 'th ``WIDTH`` bits wide slice of
the ``B`` input is sent to the output. When more than one bit from ``S`` is set
the output is undefined. Cells of this type are used to model "parallel cases"
(defined by using the ``parallel_case`` attribute or detected by an
optimization).
(defined by using the ``parallel_case`` attribute, the ``unique`` or ``unique0``
SystemVerilog keywords, or detected by an optimization).
The `$tribuf` cell is used to implement tristate logic. Cells of this type have
a ``WIDTH`` parameter and inputs ``A`` and ``EN`` and an output ``Y``. The ``A``

View file

@ -0,0 +1,5 @@
Writing output files
--------------------
.. autocmdgroup:: backends
:members:

View file

@ -0,0 +1,5 @@
Formal verification
-------------------
.. autocmdgroup:: formal
:members:

View file

@ -0,0 +1,5 @@
Reading input files
-------------------
.. autocmdgroup:: frontends
:members:

View file

@ -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:: <group>``
+ 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-cmds-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:: <cmd>`` 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

View file

@ -0,0 +1,5 @@
Yosys kernel commands
---------------------
.. autocmdgroup:: kernel
:members:

View file

@ -0,0 +1,9 @@
:orphan:
Other commands
==============
Unknown source location
.. autocmdgroup:: unknown
:members:

View file

@ -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_*

View file

@ -0,0 +1,5 @@
Design modification
-------------------
.. autocmdgroup:: passes/cmds
:members:

View file

@ -0,0 +1,5 @@
Equivalence checking
--------------------
.. autocmdgroup:: passes/equiv
:members:

View file

@ -0,0 +1,5 @@
FSM handling
------------
.. autocmdgroup:: passes/fsm
:members:

View file

@ -0,0 +1,5 @@
Working with hierarchy
----------------------
.. autocmdgroup:: passes/hierarchy
:members:

View file

@ -0,0 +1,5 @@
Memory handling
---------------
.. autocmdgroup:: passes/memory
:members:

View file

@ -0,0 +1,5 @@
Optimization passes
-------------------
.. autocmdgroup:: passes/opt
:members:

View file

@ -0,0 +1,5 @@
Converting process blocks
-------------------------
.. autocmdgroup:: passes/proc
:members:

View file

@ -0,0 +1,5 @@
Simulating circuits
-------------------
.. autocmdgroup:: passes/sat
:members:

View file

@ -0,0 +1,5 @@
Design status
-------------
.. autocmdgroup:: passes/status
:members:

View file

@ -0,0 +1,7 @@
Technology mapping
------------------
.. seealso:: :doc:`/cmd/index_techlibs`
.. autocmdgroup:: passes/techmap
:members:

View file

@ -0,0 +1,11 @@
Technology libraries
====================
Listed in alphabetical order.
.. toctree::
:maxdepth: 2
:glob:
/cmd/index_techlibs_common
/cmd/index_techlibs_*

View file

@ -0,0 +1,5 @@
Achronix
------------------
.. autocmdgroup:: techlibs/achronix
:members:

View file

@ -0,0 +1,5 @@
Anlogic
------------------
.. autocmdgroup:: techlibs/anlogic
:members:

View file

@ -0,0 +1,5 @@
Generic
------------------
.. autocmdgroup:: techlibs/common
:members:

View file

@ -0,0 +1,5 @@
CoolRunner-II
------------------
.. autocmdgroup:: techlibs/coolrunner2
:members:

View file

@ -0,0 +1,5 @@
eASIC
------------------
.. autocmdgroup:: techlibs/easic
:members:

View file

@ -0,0 +1,5 @@
FABulous
------------------
.. autocmdgroup:: techlibs/fabulous
:members:

View file

@ -0,0 +1,5 @@
Gatemate
------------------
.. autocmdgroup:: techlibs/gatemate
:members:

View file

@ -0,0 +1,5 @@
Gowin
------------------
.. autocmdgroup:: techlibs/gowin
:members:

View file

@ -0,0 +1,5 @@
GreenPAK4
------------------
.. autocmdgroup:: techlibs/greenpak4
:members:

View file

@ -0,0 +1,5 @@
iCE40
------------------
.. autocmdgroup:: techlibs/ice40
:members:

View file

@ -0,0 +1,5 @@
Intel (MAX10, Cyclone IV)
-------------------------
.. autocmdgroup:: techlibs/intel
:members:

View file

@ -0,0 +1,5 @@
Intel ALM (Cyclone V, Arria V, Cyclone 10 GX)
---------------------------------------------
.. autocmdgroup:: techlibs/intel_alm
:members:

View file

@ -0,0 +1,5 @@
Lattice
------------------
.. autocmdgroup:: techlibs/lattice
:members:

View file

@ -0,0 +1,5 @@
Microchip
------------------
.. autocmdgroup:: techlibs/microchip
:members:

View file

@ -0,0 +1,5 @@
Microchip - SmartFusion2/IGLOO2
-----------------------------------
.. autocmdgroup:: techlibs/sf2
:members:

View file

@ -0,0 +1,5 @@
NanoXplore
------------------
.. autocmdgroup:: techlibs/nanoxplore
:members:

View file

@ -0,0 +1,5 @@
QuickLogic
------------------
.. autocmdgroup:: techlibs/quicklogic
:members:

View file

@ -0,0 +1,5 @@
Xilinx
------------------
.. autocmdgroup:: techlibs/xilinx
:members:

View file

@ -1,5 +1,3 @@
.. _cmd_ref:
================================================================================
Command line reference
================================================================================
@ -7,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<cmd-cmd>`
.. 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

View file

@ -10,7 +10,7 @@ struct MyPass : public Pass {
{
log("Arguments to my_cmd:\n");
for (auto &arg : args)
log(" %s\n", arg.c_str());
log(" %s\n", arg);
log("Modules in current design:\n");
for (auto mod : design->modules())

View file

@ -16,7 +16,7 @@ struct FunctionalDummyBackend : public Backend {
for (auto module : design->selected_modules())
{
log("Processing module `%s`.\n", module->name.c_str());
log("Processing module `%s`.\n", module->name);
// convert module to FunctionalIR
auto ir = Functional::IR::from_module(module);

View file

@ -9,6 +9,7 @@ do
opt_merge
opt_share (-full only)
opt_dff (except when called with -noff)
opt_hier (-hier only)
opt_clean
opt_expr
while <changed design>

View file

@ -0,0 +1,23 @@
#start:The following commands are executed by this synthesis command:
#end:$
begin:
hierarchy -check [-top <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

View file

@ -0,0 +1,37 @@
from pyosys import libyosys as ys
class AllEnablePass(ys.Pass):
def __init__(self):
super().__init__(
"all_enable",
"makes all _DFF_P_ registers require an enable signal"
)
def execute(self, args, design):
ys.log_header(design, "Adding enable signals\n")
ys.log_push()
top_module = design.top_module()
if "\\enable" not in top_module.wires_:
enable_line = top_module.addWire("\\enable")
enable_line.port_input = True
top_module.fixup_ports()
for cell in top_module.cells_.values():
if cell.type != "$_DFF_P_":
continue
cell.type = "$_DFFE_PP_"
cell.setPort("\\E", ys.SigSpec(enable_line))
ys.log_pop()
p = AllEnablePass() # register the pass
# using the pass
design = ys.Design()
ys.run_pass("read_verilog tests/simple/fiedler-cooley.v", design)
ys.run_pass("hierarchy -check -auto-top", design)
ys.run_pass("synth", design)
ys.run_pass("all_enable", design)
ys.run_pass("write_verilog out.v", design)
ys.run_pass("synth_ice40 -json out.json", design)

View file

@ -0,0 +1,51 @@
from pyosys import libyosys as ys
# loading design
design = ys.Design()
ys.run_pass("read_verilog tests/simple/fiedler-cooley.v", design)
ys.run_pass("hierarchy -check -auto-top", design)
# top module inspection
top_module = design.top_module()
for id, wire in top_module.wires_.items():
if not wire.port_input and not wire.port_output:
continue
description = "input" if wire.port_input else "output"
description += " " + wire.name.str()
if wire.width != 1:
frm = wire.start_offset
to = wire.start_offset + wire.width
if wire.upto:
to, frm = frm, to
description += f" [{to}:{frm}]"
print(description)
# synth
ys.run_pass("synth", design)
# adding the enable line
enable_line = top_module.addWire("\\enable")
enable_line.port_input = True
top_module.fixup_ports()
# hooking the enable line to the internal dff cells
for cell in top_module.cells_.values():
if cell.type != "$_DFF_P_":
continue
cell.type = "$_DFFE_PP_"
cell.setPort("\\E", ys.SigSpec(enable_line))
# run check
top_module.check()
ys.run_pass("stat", design)
# write outputs
ys.run_pass("write_verilog out.v", design)
ys.run_pass("synth_ice40 -json out.json", design)

View file

@ -6,7 +6,7 @@ import os
project = 'YosysHQ Yosys'
author = 'YosysHQ GmbH'
copyright ='2025 YosysHQ GmbH'
yosys_ver = "0.53"
yosys_ver = "0.59"
# select HTML theme
html_theme = 'furo-ys'
@ -43,10 +43,14 @@ 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']
extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex', 'sphinx_inline_tabs']
if os.getenv("READTHEDOCS"):
# Use rtds_action if we are building on read the docs and have a github token env var
@ -64,7 +68,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')
@ -106,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:

View file

@ -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 <adv_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`

View file

@ -88,64 +88,71 @@ Build prerequisites
^^^^^^^^^^^^^^^^^^^
A C++ compiler with C++17 support is required as well as some standard tools
such as GNU Flex, GNU Bison, Make and Python. Some additional tools: readline,
libffi, Tcl and zlib; are optional but enabled by default (see
such as GNU Flex, GNU Bison (>=3.8), Make, and Python (>=3.11). Some additional
tools: readline, libffi, Tcl and zlib; are optional but enabled by default (see
:makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the
`show` command to display schematics.
Installing all prerequisites for Ubuntu 20.04:
Installing all prerequisites:
.. code:: console
sudo apt-get install gperf build-essential bison flex \
libreadline-dev gawk tcl-dev libffi-dev git graphviz \
xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev
Installing all prerequisites for macOS 13 (with Homebrew):
.. code:: console
brew tap Homebrew/bundle && brew bundle
or MacPorts:
.. code:: console
sudo port install bison flex readline gawk libffi graphviz \
pkgconfig python311 boost zlib tcl
On FreeBSD use the following command to install all prerequisites:
.. code:: console
pkg install bison flex readline gawk libffi graphviz \
pkgconf python311 tcl-wrapper boost-libs
.. note:: On FreeBSD system use gmake instead of make. To run tests use:
``MAKE=gmake CXX=cxx CC=cc gmake test``
For Cygwin use the following command to install all prerequisites, or select these additional packages:
.. code:: console
setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel
.. warning::
As of this writing, Cygwin only supports up to Python 3.9.16 while the
minimum required version of Python is 3.11. This means that Cygwin is not
compatible with many of the Python-based frontends. While this does not
currently prevent Yosys itself from working, no guarantees are made for
continued support. It is instead recommended to use Windows Subsystem for
Linux (WSL) and follow the instructions for Ubuntu.
..
For MSYS2 (MINGW64):
.. tab:: Ubuntu 22.04
.. code:: console
pacman -S bison flex mingw-w64-x86_64-gcc git libffi-devel libreadline-devel make pkg-config python3 tcl-devel mingw-w64-x86_64-boost zlib-devel
sudo apt-get install gawk git make python3 lld bison clang flex \
libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev \
graphviz xdot
curl -LsSf https://astral.sh/uv/install.sh | sh
.. tab:: macOS 13 (with Homebrew)
.. code:: console
brew tap Homebrew/bundle && brew bundle
.. tab:: MacPorts
.. code:: console
sudo port install bison flex readline gawk libffi graphviz \
pkgconfig python311 zlib tcl
.. tab:: FreeBSD
.. code:: console
pkg install bison flex readline gawk libffi graphviz \
pkgconf python311 tcl-wrapper
.. note:: On FreeBSD system use gmake instead of make. To run tests use:
``MAKE=gmake CXX=cxx CC=cc gmake test``
.. tab:: Cygwin
Use the following command to install all prerequisites, or select these
additional packages:
.. code:: console
setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,zlib-devel
.. warning::
As of this writing, Cygwin only supports up to Python 3.9.16 while the
minimum required version of Python is 3.11. This means that Cygwin is not
compatible with many of the Python-based frontends. While this does not
currently prevent Yosys itself from working, no guarantees are made for
continued support. You may also need to specify ``CXXSTD=gnu++17`` to
resolve missing ``strdup`` function when using gcc. It is instead
recommended to use Windows Subsystem for Linux (WSL) and follow the
instructions for Ubuntu.
..
tab:: MSYS2 (MINGW64)
.. code:: console
pacman -S bison flex mingw-w64-x86_64-gcc git libffi-devel libreadline-devel make pkg-config python3 tcl-devel zlib-devel
Not that I can get this to work; it's failing during ld with what looks like
math library issues: ``multiple definition of `tanh'`` and
@ -214,7 +221,7 @@ Running the build system
From the root ``yosys`` directory, call the following commands:
.. code:: console
make
sudo make install
@ -227,7 +234,7 @@ To use a separate (out-of-tree) build directory, provide a path to the Makefile.
Out-of-tree builds require a clean source tree.
.. seealso::
.. seealso::
Refer to :doc:`/yosys_internals/extending_yosys/test_suites` for details on
testing Yosys once compiled.

View file

@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -122,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:
@ -219,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.

View file

@ -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

View file

@ -1,3 +1,4 @@
furo-ys @ git+https://github.com/YosysHQ/furo-ys
sphinxcontrib-bibtex
rtds-action
sphinx-inline-tabs

View file

@ -0,0 +1,446 @@
Minimizing failing (or bugged) designs
======================================
.. TODO:: pending merge of https://github.com/YosysHQ/yosys/pull/5068
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.
.. _How to create a Minimal, Reproducible Example: https://stackoverflow.com/help/minimal-reproducible-example
.. note::
This guide assumes a moderate degree of familiarity with Yosys and requires
some amount of problem solving ability.
Before you start
----------------
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/
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
--------------------------------------
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.
.. 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?
~~~~~~~~~~~~~~~~~~~
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 -h bugpoint``. If
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 <load.ys> -s
<failure.ys>``. 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.
.. note::
You should also be able to run the two scripts separately, calling first
``yosys -s <load.ys> -p 'write_rtlil design.il'`` and then ``yosys -s
<failure.ys> 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 ``<failure.ys>`` 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 ``<failure.ys>``. 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:
.. code-block:: yoscrypt
exec -expect-return 1 --bash <script.sh>
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 ``<wrapper> yosys -s <failure.ys> design.il``. Here, Yosys is
run under a wrapper process which checks for some failure state, like a memory
leak or excessive runtime.
How do I use bugpoint?
~~~~~~~~~~~~~~~~~~~~~~
At this point you should have:
1. either an RTLIL file containing the design to minimize (referred to here as
``design.il``), or a Yosys script, ``<load.ys>``, which loads it; and
2. a Yosys script, ``<failure.ys>``, which produces the failure and returns a
non-zero return status.
Now call ``yosys -qq -s <failure.ys> design.il`` and take note of the error(s)
that get printed. A template script, ``<bugpoint.ys>``, 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 "<wrapper>"`` option to the `bugpoint` call.
.. code-block:: yoscrypt
:caption: ``<bugpoint.ys>`` template script
# Load design
read_rtlil design.il
## OR
script <load.ys>
# Call bugpoint with failure
bugpoint -script <failure.ys> -grep "<string>"
# 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::
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 ``<failure.ys>`` 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
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 :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
``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::
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</appendix/env_vars>`
``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 <bugpoint.ys>``.
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, *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,
``!<wrapper> yosys -s <failure.ys> test.il`` to check it works as expected and
returns a non-zero status.
.. 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 ``<failure.ys>``,
`bugpoint` may take some time; remember, it will run ``yosys -s <failure.ys>``
on each iteration of the design. The bigger the design, the more iterations.
The longer the ``<failure.ys>``, 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?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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 <failure.ys>
min.v`` should still fail in the same way.
.. code-block:: yoscrypt
:caption: example `bugpoint` minimizer
:name: bugpoint_script
read_verilog design.v
bugpoint -script <failure.ys>
write_verilog min.v
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
<failure.ys> 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 <failure.ys>``.
Once you've verified the failure still happens, check out
:ref:`using_yosys/bugpoint:identifying issues` for more on what to do next.
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`_.
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.
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`_.
.. _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 "<string>" 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 for C-Reduce
: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
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
~~~~~~~~~~~~~~~~~
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
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.
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.
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.
.. note::
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
------------------
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?
.. note::
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.
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::
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.

View file

@ -15,3 +15,6 @@ ways Yosys can interact with designs for a deeper investigation.
synthesis/index
more_scripting/index
bugpoint
verilog
pyosys

View file

@ -73,7 +73,7 @@ contain bits that are not 0 or 1 (i.e. ``x`` or ``z``). Ordinary 32-bit
constants are written using decimal numbers.
Single-bit signals are shown as thin arrows pointing from the driver to the
load. Signals that are multiple bits wide are shown as think arrows.
load. Signals that are multiple bits wide are shown as thick arrows.
Finally *processes* are shown in boxes with round corners. Processes are Yosys'
internal representation of the decision-trees and synchronization events
@ -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).
@ -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

View file

@ -1,11 +1,107 @@
Loading a design
~~~~~~~~~~~~~~~~
----------------
keyword: Frontends
.. _input files:
- :doc:`/cmd/read_verilog`
Input files on the command line
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. todo:: include ``read_verilog <<EOF``, also other methods of loading designs
- 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
+ elaborate designs with ``verific -import [options] <top>`` (or use
`hierarchy`)
- 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::
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
~~~~~~~~~~~~~~~
- :doc:`/cmd/index_frontends`
- typically start with ``read_``
- built-in support for heredocs
+ in-line code with ``<<EOT``
+ can use any eot marker, but EOT (End-of-Transmission) and EOF
(End-of-File) are most common
- built-in support for reading multiple files in the same command
+ 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
.. note::
'Frontend' here means that the command is implemented as a sub-class of
``RTLIL::Frontend``, as opposed to the usual ``RTLIL::Pass``.
.. todo:: link note to as-yet non-existent section on ``RTLIL::Pass`` under
:doc:`/yosys_internals/extending_yosys/index`
The `read_verilog` command
""""""""""""""""""""""""""
- :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
- please do not rely on `read_verilog` for syntax checking
+ recommend using a simulator (for example Icarus Verilog) or linting with
another tool (such as verilator) first
.. todo:: figure out this example code block
.. code-block:: yoscrypt
@ -24,25 +120,38 @@ keyword: Frontends
read_verilog file6.v
verilog_defaults -pop
.. todo:: more info on other ``read_*`` commands, also is this the first time we
mention verific?
Other built-in ``read_*`` commands
""""""""""""""""""""""""""""""""""
.. note::
- :cmd:title:`read_rtlil`
- :cmd:title:`read_aiger`
- :cmd:title:`read_blif`
- :cmd:title:`read_json`
- :cmd:title:`read_liberty`
- :cmd:title:`read_xaiger2`
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.
.. TODO:: does `write_file` count?
Others:
Externally maintained plugins
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- :doc:`/cmd/read`
- `GHDL plugin`_ for VHDL
- :doc:`/cmd/read_rtlil` (direct textual representation of Yosys internal state)
- :doc:`/cmd/read_aiger`
- :doc:`/cmd/read_blif`
- :doc:`/cmd/read_json`
- :doc:`/cmd/read_liberty`
- `GHDL plugin`_ for VHDL (check ``help ghdl``)
- `yosys-slang plugin`_ for more comprehensive SystemVerilog support (check
``help read_slang``)
+ yosys-slang is implemented as a '`Frontend`_,' with all the built-in support
that entails
.. _GHDL plugin: https://github.com/ghdl/ghdl-yosys-plugin
.. _yosys-slang plugin: https://github.com/povik/yosys-slang
- 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

View file

@ -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
^^^^^^^^^^^^^^^^^^^^^

View file

@ -0,0 +1,216 @@
Scripting with Pyosys
=====================
Pyosys is a limited subset of the Yosys C++ API (aka "libyosys") made available
using the Python programming language.
Like ``.ys`` and ``.tcl`` scripts, Pyosys provides an interface to write Yosys
scripts in the Python programming language, giving you the benefits of
a type system, control flow, object-oriented programming, and more; especially
that the other options lack a type system and control flow/OOP in Tcl is
limited.
Though unlike these two, Pyosys goes a bit further, allowing you to use the
Yosys API to implement advanced functionality that would otherwise require
custom passes written in C++.
Getting Pyosys
--------------
Pyosys supports CPython 3.8 or higher. You can access Pyosys using one of two
methods:
1. Compiling Yosys with the Makefile flag ``ENABLE_PYOSYS=1``
This adds the flag ``-y`` to the Yosys binary, which allows you to execute
Python scripts using an interpreter embedded in Yosys itself:
``yosys -y ./my_pyosys_script.py``
Do note this requires some build-time dependencies to be available to Python,
namely, ``pybind11`` and ``cxxheaderparser``. By default, the required
``uv`` package will be used to create an ephemeral environment with the
correct versions of the tools installed.
You can force use of your current Python environment by passing the Makefile
flag ``PYOSYS_USE_UV=0``.
2. Installing the Pyosys wheels
On macOS and GNU/Linux you can install pre-built wheels of Yosys using
``pip``:
``python3 -m pip install pyosys``
Which then allows you to run your scripts as follows:
``python3 ./my_pyosys_script.py``
Scripting and Database Inspection
---------------------------------
To start with, you have to import libyosys as follows:
.. code-block:: python
from pyosys import libyosys
As a reminder, Python allows you to alias imported modules and objects, so
this import may be preferable for terseness:
.. code-block:: python
from pyosys import libyosys as ys
Now, scripting is actually quite similar to ``.ys`` and ``.tcl`` script in that
you can provide mostly text commands. Albeit, you can construct your scripts
to use Python's amenities like conditional execution, loops, and functions:
.. code-block:: python
do_flatten = True
ys.run_pass("read_verilog tests/simple/fiedler-cooley.v")
ys.run_pass("hierarchy -check -auto-top")
if do_flatten:
ys.run_pass("flatten")
…but this does not strictly provide anything that Tcl scripts do not provide you
with. The real power of using Pyosys comes from the fact you can manually
instantiate, manage, and interact with the design database.
As an example, here is the same script with a manually instantiated design.
.. literalinclude:: /code_examples/pyosys/simple_database.py
:start-after: loading design
:end-before: top module inspection
:language: python
What's new here is that you can manually inspect the design's database. This
gives you access to a huge chunk of the design database API as declared in
the ``kernel/rtlil.h`` header.
For example, here's how to list the input and output ports of the top module
of your design:
.. literalinclude:: /code_examples/pyosys/simple_database.py
:start-after: top module inspection
:end-before: # synth
:language: python
.. tip::
C++ data structures in Yosys are bridged to Python such that they have a
pretty similar API to Python objects, for example:
- ``std::vector`` supports the same methods as
`iterables <https://docs.python.org/3/glossary.html#term-iterable>`_ in
Python.
- ``std::set`` and hashlib ``pool`` support the same methods as ``set``\s in
Python. While ``set`` is ordered, ``pool`` is not and modifications may
cause a complete reordering of the set.
- ``dict`` supports the same methods as ``dict``\s in Python, albeit it is
unordered, and modifications may cause a complete reordering of the
dictionary.
- ``idict`` uses a custom set of methods because it doesn't map very cleanly
to an existing Python data structure. See ``pyosys/hashlib.h`` for more
info.
For most operations, the Python equivalents are also supported as arguments
where they will automatically be cast to the right type, so you do not have
to manually instantiate the right underlying C++ object(s) yourself.
Modifying the Database
----------------------
.. warning::
Any modifications to the database may invalidate previous references held
by Python, just as if you were writing C++. Pyosys does not currently attempt
to keep deleted objects alive if a reference is held by Python.
You are not restricted to inspecting the database either: you have the ability
to modify it, and introduce new elements and/or changes to your design.
As a demonstrative example, let's assume we want to add an enable line to all
flip-flops in our fiedler-cooley design.
First of all, we will run :yoscrypt:`synth` to convert all of the logic to
Yosys's internal cell structure (see :ref:`sec:celllib_gates`):
.. literalinclude:: /code_examples/pyosys/simple_database.py
:start-after: # synth
:end-before: adding the enable line
:language: python
Next, we need to add the new port. The method for this is ``Module::addWire``\.
.. tip::
IdString is Yosys's internal representation of strings used as identifiers
within Verilog designs. They are efficient as only integers are stored and
passed around, but they can be translated to and from normal strings at will.
Pyosys will automatically cast Python strings to IdStrings for you, but the
rules around IdStrings apply, namely that *broadly*:
- Identifiers for internal cells must start with ``$``\.
- All other identifiers must start with ``\``\.
.. literalinclude:: /code_examples/pyosys/simple_database.py
:start-after: adding the enable line
:end-before: hooking the enable line
:language: python
Notice how we modified the wire then called a method to make Yosys re-process
the ports.
Next, we can iterate over all constituent cells, and if they are of the type
``$_DFF_P_``, we do two things:
1. Change their type to ``$_DFFE_PP_`` to enable hooking up an enable signal.
2. Hooking up the enable signal.
.. literalinclude:: /code_examples/pyosys/simple_database.py
:start-after: hooking the enable line
:end-before: run check
:language: python
To verify that you did everything correctly, it is prudent to call ``.check()``
on the module you're manipulating as follows after you're done with a set of
changes:
.. literalinclude:: /code_examples/pyosys/simple_database.py
:start-after: run check
:end-before: write output
:language: python
And then finally, write your outputs. Here, I choose an intermediate Verilog
file and :yoscrypt:`synth_ice40` to map it to the iCE40 architecture.
.. literalinclude:: /code_examples/pyosys/simple_database.py
:start-after: write output
:language: python
And voilà, you will note that in the intermediate output, all ``always @``
statements should have an ``if (enable)``\.
Encapsulating as Passes
-----------------------
Just like when writing C++, you can encapsulate routines in terms of "passes",
which adds your Pass to a global registry of commands accessible using
``run_pass``\.
.. literalinclude:: /code_examples/pyosys/pass.py
:language: python
In general, abstract classes and virtual methods are not really supported by
Pyosys due to their complexity, but there are two exceptions which are:
- ``Pass`` in ``kernel/register.h``
- ``Monitor`` in ``kernel/rtlil.h``

View file

@ -176,5 +176,6 @@ implemented as whiteboxes too.
Boxes are arguably the biggest advantage that ABC9 has over ABC: by being aware
of carry chains and DSPs, it avoids optimising for a path that isn't the actual
critical path, while the generally-longer paths result in ABC9 being able to
reduce design area by mapping other logic to larger-but-slower cells.
reduce design area by mapping other logic to slower cells with greater logic
density.

View file

@ -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`.

View file

@ -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
-------

View file

@ -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
@ -192,6 +192,13 @@ control inputs.
Called with ``-nodffe`` and ``-nosdff``, this pass is used to prepare a design
for :doc:`/using_yosys/synthesis/fsm`.
Hierarchical optimization - `opt_hier` pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This pass considers the design hierarchy and propagates unused signals, constant
signals, and tied-together signals across module boundaries to facilitate
optimization by other passes.
Removing unused cells and wires - `opt_clean` pass
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -226,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`.

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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
---------------------------------
@ -11,7 +9,7 @@ Yosys and there are currently no plans to add support
for them:
- Non-synthesizable language features as defined in
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
- The ``tri``, ``triand`` and ``trior`` net types
@ -96,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.
@ -358,20 +356,37 @@ from SystemVerilog:
files being read into the same design afterwards.
- typedefs are supported (including inside packages)
- type casts are currently not supported
- type casts are currently not supported
- enums are supported (including inside packages)
- but are currently not strongly typed
- but are currently not strongly typed
- packed structs and unions are supported
- arrays of packed structs/unions are currently not supported
- structure literals are currently not supported
- arrays of packed structs/unions are currently not supported
- structure literals are currently not supported
- multidimensional arrays are supported
- array assignment of unpacked arrays is currently not supported
- array literals are currently not supported
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
ports are inputs or outputs are supported.
- array assignment of unpacked arrays is currently not supported
- array literals are currently not supported
- SystemVerilog interfaces (SVIs), including modports for specifying whether
ports are inputs or outputs, are partially supported.
- interfaces must be provided as *named* arguments, not positional arguments.
i.e. ``foo bar(.intf(intf0), .x(x));`` is supported but ``foo bar(intf0,
x);`` is not.
- Assignments within expressions are supported.
- The ``unique``, ``unique0``, and ``priority`` SystemVerilog keywords are
supported on ``if`` and ``case`` conditionals. (The Verilog frontend
will process conditionals using these keywords by annotating their
representation with the appropriate ``full_case`` and/or ``parallel_case``
attributes, which are described above.)
- SystemVerilog string literals are supported (triple-quoted strings and
escape sequences such as line continuations and hex escapes).

View file

@ -0,0 +1,271 @@
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 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.
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.
Minimizing scripts
------------------
.. 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
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. 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 <top> -lut`` with the :ref:`replace_synth`. The options ``-top
<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 <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 <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.il>; design -reset; read_rtlil <design.il>;
In most cases, this can be inserted immediately before the failing command while
still producing the error, allowing you to :ref:`minimize your
RTLIL<using_yosys/bugpoint:minimizing rtlil designs with bugpoint>` with the
``<design.il>`` 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 <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
<design.il>``.
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
-------------------
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.
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
~~~~~~~~~~~~~~~~
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.
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. 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`.
.. seealso::
This example is taken from `YosysHQ/yosys#4590
<https://github.com/YosysHQ/yosys/issues/4590>`_ and can be reproduced with a
version of Yosys between 0.45 and 0.51.

View file

@ -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 <<EOF
# minimized RTLIL design
EOF
# minimum sequence of commands
```
- 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/<commit_hash>/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 <failure.ys> -grep "<string>"
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/

View file

@ -9,7 +9,7 @@ Writing extensions
.. 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 Slack.
yosys extensions. Don't be afraid to ask questions on the YosysHQ Discourse.
.. todo:: mention coding guide

View file

@ -11,6 +11,7 @@ of interest for developers looking to customise Yosys builds.
extensions
build_verific
functional_ir
advanced_bugpoint
contributing
test_suites

View file

@ -1,7 +1,72 @@
Testing Yosys
=============
.. TODO:: more about the included test suite and how to add tests
.. todo:: adding tests (makefile-tests vs seed-tests)
Running the included test suite
-------------------------------
The Yosys source comes with a test suite to avoid regressions and keep
everything working as expected. Tests can be run by calling ``make test`` from
the root Yosys directory.
Functional tests
~~~~~~~~~~~~~~~~
Testing functional backends (see
:doc:`/yosys_internals/extending_yosys/functional_ir`) has a few requirements in
addition to those listed in :ref:`getting_started/installation:Build
prerequisites`:
.. tab:: Ubuntu
.. code:: console
sudo apt-get install racket
raco pkg install rosette
pip install pytest-xdist pytest-xdist-gnumake
.. tab:: macOS
.. code:: console
brew install racket
raco pkg install rosette
pip install pytest-xdist pytest-xdist-gnumake
If you don't have one of the :ref:`getting_started/installation:CAD suite(s)`
installed, you should also install Z3 `following their
instructions <https://github.com/Z3Prover/z3>`_.
Then, set the :makevar:`ENABLE_FUNCTIONAL_TESTS` make variable when calling
``make test`` and the functional tests will be run as well.
Unit tests
~~~~~~~~~~
Running the unit tests requires the following additional packages:
.. tab:: Ubuntu
.. code:: console
sudo apt-get install libgtest-dev
.. tab:: macOS
No additional requirements.
Unit tests can be run with ``make unit-test``.
Docs tests
~~~~~~~~~~
There are some additional tests for checking examples included in the
documentation, which can be run by calling ``make test`` from the
:file:`yosys/docs` sub-directory (or ``make -C docs test`` from the root). This
also includes checking some macro commands to ensure that descriptions of them
are kept up to date, and is mostly intended for CI.
Automatic testing
-----------------

View file

@ -47,9 +47,9 @@ be found in :file:`frontends/verilog/verilog_lexer.l` in the Yosys source tree.
The lexer does little more than identifying all keywords and literals recognised
by the Yosys Verilog frontend.
The lexer keeps track of the current location in the Verilog source code using
some global variables. These variables are used by the constructor of AST nodes
to annotate each node with the source code location it originated from.
The lexer keeps track of the current location in the Verilog source code with
a ``VerilogLexer::out_loc`` and uses it to construct parser-defined
symbol objects.
Finally the lexer identifies and handles special comments such as "``// synopsys
translate_off``" and "``// synopsys full_case``". (It is recommended to use
@ -178,21 +178,22 @@ properties:
- | Source code location
| Each ``AST::AstNode`` is automatically annotated with the current source
code location by the ``AST::AstNode`` constructor. It is stored in the
``std::string filename`` and ``int linenum`` member variables.
code location by the ``AST::AstNode`` constructor. The ``location`` type
is a manual reimplementation of the bison-provided location type. This
type is defined at ``frontends/verilog/verilog_location.h``.
The ``AST::AstNode`` constructor can be called with up to two child nodes that
are automatically added to the list of child nodes for the new object. This
The ``AST::AstNode`` constructor can be called with up to 4 child nodes. This
simplifies the creation of AST nodes for simple expressions a bit. For example
the bison code for parsing multiplications:
.. code:: none
:number-lines:
:number-lines:
basic_expr '*' attr basic_expr {
$$ = new AstNode(AST_MUL, $1, $4);
append_attr($$, $3);
} |
basic_expr TOK_ASTER attr basic_expr {
$$ = std::make_unique<AstNode>(AST_MUL, std::move($1), std::move($4));
SET_AST_NODE_LOC($$.get(), @1, @4);
append_attr($$.get(), $3);
} |
The generated AST data structure is then passed directly to the AST frontend
that performs the actual conversion to RTLIL.
@ -204,7 +205,7 @@ tree respectively.
Transforming AST to RTLIL
-------------------------
The AST Frontend converts a set of modules in AST representation to modules in
The AST frontend converts a set of modules in AST representation to modules in
RTLIL representation and adds them to the current design. This is done in two
steps: simplification and RTLIL generation.
@ -626,7 +627,7 @@ pass and the passes it launches:
| This pass replaces the ``RTLIL::SyncRule``\ s to d-type flip-flops (with
asynchronous resets if necessary).
- | `proc_dff`
- | `proc_memwr`
| This pass replaces the ``RTLIL::MemWriteAction``\ s with `$memwr` cells.
- | `proc_clean`

View file

@ -194,17 +194,18 @@ RTLIL::SigSpec
A "signal" is everything that can be applied to a cell port. I.e.
- | Any constant value of arbitrary bit-width
- | A bit from a wire (``RTLIL::SigBit``)
| 1em For example: ``mywire[24]``
- | A range of bits from a wire (wire variant of ``RTLIL::SigChunk``)
| 1em For example: ``mywire, mywire[15:8]``
- | Any constant value of arbitrary bit-width (``std::vector<RTLIL::State>>`` variant of ``RTLIL::SigChunk``)
| 1em For example: ``1337, 16'b0000010100111001, 1'b1, 1'bx``
- | All bits of a wire or a selection of bits from a wire
| 1em For example: ``mywire, mywire[24], mywire[15:8]``
- | Concatenations of the above
| 1em For example: ``{16'd1337, mywire[15:8]}``
The ``RTLIL::SigSpec`` data type is used to represent signals. The
``RTLIL::Cell`` object contains one ``RTLIL::SigSpec`` for each cell port.
The ``RTLIL::SigSpec`` data type is used to represent signals.
It contains a single ``RTLIL::SigChunk`` or a vector of ``RTLIL::SigBit``.
The ``RTLIL::Cell`` object contains one ``RTLIL::SigSpec`` for each cell port.
In addition, connections between wires are represented using a pair of
``RTLIL::SigSpec`` objects. Such pairs are needed in different locations.

View file

@ -36,7 +36,7 @@ The main characteristics are:
all compilers, standard libraries and architectures.
In addition to ``dict<K, T>`` and ``pool<T>`` there is also an ``idict<K>`` that
creates a bijective map from ``K`` to the integers. For example:
creates a bijective map from ``K`` to incrementing integers. For example:
::
@ -45,9 +45,9 @@ creates a bijective map from ``K`` to the integers. For example:
log("%d\n", si("world")); // will print 43
log("%d\n", si.at("world")); // will print 43
log("%d\n", si.at("dummy")); // will throw exception
log("%s\n", si[42].c_str())); // will print hello
log("%s\n", si[43].c_str())); // will print world
log("%s\n", si[44].c_str())); // will throw exception
log("%s\n", si[42])); // will print hello
log("%s\n", si[43])); // will print world
log("%s\n", si[44])); // will throw exception
It is not possible to remove elements from an idict.
@ -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

View file

@ -38,5 +38,4 @@ as reference to implement a similar system in any language.
formats/index
extending_yosys/index
techmap
verilog
hashing

443
docs/util/cmd_documenter.py Normal file
View file

@ -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,
}

View file

@ -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,
}