3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-18 22:59:03 +00:00
This commit is contained in:
KrystalDelusion 2025-03-21 10:41:40 +13:00 committed by GitHub
commit 5701b7c282
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
124 changed files with 2037 additions and 472 deletions

View file

@ -59,7 +59,6 @@ jobs:
with:
name: cmd-ref-${{ github.sha }}
path: |
docs/source/cmd
docs/source/generated
docs/source/_images
docs/source/code_examples

View file

@ -519,7 +519,6 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE
endif
endif
ifeq ($(ENABLE_COVER),1)
CXXFLAGS += -DYOSYS_ENABLE_COVER
endif
@ -620,6 +619,7 @@ $(eval $(call add_include_file,frontends/blif/blifparse.h))
$(eval $(call add_include_file,backends/rtlil/rtlil_backend.h))
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/io.o kernel/gzip.o
OBJS += kernel/log_help.o
OBJS += kernel/binding.o kernel/tclapi.o
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o
OBJS += kernel/drivertools.o kernel/functional.o
@ -1002,19 +1002,8 @@ ifeq ($(ENABLE_PYOSYS),1)
endif
endif
# also others, but so long as it doesn't fail this is enough to know we tried
docs/source/cmd/abc.rst: $(TARGETS) $(EXTRA_TARGETS)
$(Q) mkdir -p docs/source/cmd
$(Q) mkdir -p temp/docs/source/cmd
$(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-command-reference-manual'
$(Q) rsync -rc temp/docs/source/cmd docs/source
$(Q) rm -rf temp
docs/source/cell/word_add.rst: $(TARGETS) $(EXTRA_TARGETS)
$(Q) mkdir -p docs/source/cell
$(Q) mkdir -p temp/docs/source/cell
$(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-cells-manual'
$(Q) rsync -rc temp/docs/source/cell docs/source
$(Q) rm -rf temp
docs/source/generated/cmds.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
$(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cmds-json $@'
docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
$(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@'
@ -1031,6 +1020,15 @@ docs/source/generated/functional/rosette.diff: backends/functional/smtlib.cc bac
PHONY: docs/gen/functional_ir
docs/gen/functional_ir: docs/source/generated/functional/smtlib.cc docs/source/generated/functional/rosette.diff
docs/source/generated/%.log: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
$(Q) ./$(PROGRAM_PREFIX)yosys -qQT -h '$*' -l $@
docs/source/generated/chformal.cc: passes/cmds/chformal.cc docs/source/generated
$(Q) cp $< $@
PHONY: docs/gen/chformal
docs/gen/chformal: docs/source/generated/chformal.log docs/source/generated/chformal.cc
PHONY: docs/gen docs/usage docs/reqs
docs/gen: $(TARGETS)
$(Q) $(MAKE) -C docs gen
@ -1066,7 +1064,7 @@ docs/reqs:
$(Q) $(MAKE) -C docs reqs
.PHONY: docs/prep
docs/prep: docs/source/cmd/abc.rst docs/source/generated/cells.json docs/gen docs/usage docs/gen/functional_ir
docs/prep: docs/source/generated/cells.json docs/source/generated/cmds.json docs/gen docs/usage docs/gen/functional_ir docs/gen/chformal
DOC_TARGET ?= html
docs: docs/prep
@ -1089,7 +1087,7 @@ clean:
rm -f tests/tools/cmp_tbdata
rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS))
-$(MAKE) -C docs clean
rm -rf docs/source/cmd docs/util/__pycache__
rm -rf docs/util/__pycache__
clean-abc:
$(MAKE) -C abc DEP= clean

View file

@ -116,7 +116,9 @@ struct MemContentsTest {
struct FunctionalTestGeneric : public Pass
{
FunctionalTestGeneric() : Pass("test_generic", "test the generic compute graph") {}
FunctionalTestGeneric() : Pass("test_generic", "test the generic compute graph") {
internal();
}
void help() override
{

1
docs/.gitignore vendored
View file

@ -1,5 +1,4 @@
/build/
/source/cmd
/source/generated
/source/_images/**/*.log
/source/_images/**/*.aux

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

@ -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-cells-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 @@
ECP5
------------------
.. autocmdgroup:: techlibs/ecp5
: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 @@
Lattice Nexus
------------------
.. autocmdgroup:: techlibs/nexus
: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,29 @@ 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?
.. 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

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

@ -18,13 +18,14 @@ html_theme_options: dict[str] = {
}
# try to fix the readthedocs detection
html_context: dict[str] = {
"READTHEDOCS": True,
"display_github": True,
"github_user": "YosysHQ",
"github_repo": "yosys",
"slug": "yosys",
}
if os.getenv("READTHEDOCS"):
html_context: dict[str] = {
"READTHEDOCS": True,
"display_github": True,
"github_user": "YosysHQ",
"github_repo": "yosys",
"slug": "yosys",
}
# override source_branch if not main
git_slug = os.getenv("READTHEDOCS_VERSION_NAME")
@ -41,8 +42,12 @@ 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']
@ -104,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

@ -122,7 +122,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 +219,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

@ -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,9 +1,11 @@
Loading a design
~~~~~~~~~~~~~~~~
.. TODO:: fill out this page better
keyword: Frontends
- :doc:`/cmd/read_verilog`
- :doc:`/cmd/index_frontends`
.. todo:: include ``read_verilog <<EOF``, also other methods of loading designs
@ -29,20 +31,14 @@ keyword: Frontends
.. 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
The Verific frontend for Yosys, which provides the `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.
Others:
- :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: https://github.com/ghdl/ghdl-yosys-plugin

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

@ -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
@ -226,7 +226,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

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

@ -96,7 +96,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.

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'
@ -507,16 +588,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 +634,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 +644,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 +692,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 +730,7 @@ def setup(app: Sphinx):
app.add_role('autoref', autoref)
return {'version': '0.2'}
return {
'version': '0.3',
'parallel_read_safe': False,
}

View file

@ -90,10 +90,10 @@ public:
template<typename T>
void array(const T &&values)
{
begin_object();
begin_array();
for (auto &item : values)
value(item);
end_object();
end_array();
}
};

151
kernel/log_help.cc Normal file
View file

@ -0,0 +1,151 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2025 Krystine Dawn <krystinedawn@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
Json ContentListing::to_json() {
Json::object object;
object["type"] = type;
if (body.length()) object["body"] = body;
if (strcmp(source_file, "unknown") != 0) object["source_file"] = source_file;
if (source_line != 0) object["source_line"] = source_line;
object["options"] = Json(options);
Json::array content_array;
for (auto child : _content) content_array.push_back(child->to_json());
object["content"] = content_array;
return object;
}
void ContentListing::usage(const string &text,
const source_location location)
{
log_assert(type.compare("root") == 0);
add_content("usage", text, location);
}
void ContentListing::option(const string &text, const string &description,
const source_location location)
{
auto option = open_option(text);
if (description.length())
option->add_content("text", description, location);
}
void ContentListing::codeblock(const string &code, const string &language,
const source_location location)
{
add_content("code", code, location);
back()->set_option("language", language);
}
void ContentListing::paragraph(const string &text,
const source_location location)
{
add_content("text", text, location);
}
ContentListing* ContentListing::open_usage(const string &text,
const source_location location)
{
usage(text, location);
return back();
}
ContentListing* ContentListing::open_option(const string &text,
const source_location location)
{
log_assert(type.compare("root") == 0 || type.compare("usage") == 0);
auto option = new ContentListing("option", text, location);
add_content(option);
return option;
}
#define MAX_LINE_LEN 80
void log_pass_str(const std::string &pass_str, std::string indent_str, bool leading_newline=false) {
if (pass_str.empty())
return;
std::istringstream iss(pass_str);
if (leading_newline)
log("\n");
for (std::string line; std::getline(iss, line);) {
log("%s", indent_str.c_str());
auto curr_len = indent_str.length();
std::istringstream lss(line);
for (std::string word; std::getline(lss, word, ' ');) {
while (word[0] == '`' && word.back() == '`')
word = word.substr(1, word.length()-2);
if (curr_len + word.length() >= MAX_LINE_LEN-1) {
curr_len = 0;
log("\n%s", indent_str.c_str());
}
if (word.length()) {
log("%s ", word.c_str());
curr_len += word.length() + 1;
}
}
log("\n");
}
}
void log_pass_str(const std::string &pass_str, int indent=0, bool leading_newline=false) {
std::string indent_str(indent*4, ' ');
log_pass_str(pass_str, indent_str, leading_newline);
}
PrettyHelp *current_help = nullptr;
PrettyHelp::PrettyHelp()
{
_prior = current_help;
_root_listing = ContentListing("root", "");
current_help = this;
}
PrettyHelp::~PrettyHelp()
{
current_help = _prior;
}
PrettyHelp *PrettyHelp::get_current()
{
if (current_help == nullptr)
new PrettyHelp();
return current_help;
}
void PrettyHelp::log_help()
{
for (auto content : _root_listing.get_content()) {
if (content->type.compare("usage") == 0) {
log_pass_str(content->body, 1, true);
log("\n");
} else if (content->type.compare("option") == 0) {
log_pass_str(content->body, 1);
for (auto text : content->get_content()) {
log_pass_str(text->body, 2);
log("\n");
}
} else {
log_pass_str(content->body, 0);
log("\n");
}
}
}

132
kernel/log_help.h Normal file
View file

@ -0,0 +1,132 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2025 Krystine Dawn <krystinedawn@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef LOG_HELP_H
#define LOG_HELP_H
#include "kernel/yosys_common.h"
#include "kernel/json.h"
YOSYS_NAMESPACE_BEGIN
class ContentListing {
vector<ContentListing *> _content;
public:
string type;
string body;
const char* source_file;
int source_line;
std::map<string, string> options;
ContentListing(
string type = "root", string body = "",
const char* source_file = "unknown", int source_line = 0
) : type(type), body(body), source_file(source_file), source_line(source_line) {
_content = {};
options = {};
}
ContentListing(string type, string body, source_location location) :
ContentListing(type, body, location.file_name(), location.line()) { }
void add_content(ContentListing *new_content) {
_content.push_back(new_content);
}
void add_content(string type, string body, source_location location) {
auto new_content = new ContentListing(type, body, location);
add_content(new_content);
}
bool has_content() { return _content.size() != 0; }
const vector<ContentListing *> get_content() {
const vector<ContentListing *> content = _content;
return content;
}
ContentListing* back() {
return _content.back();
}
void set_option(string key, string val = "") {
options[key] = val;
}
void usage(
const string &text,
const source_location location = source_location::current()
);
void option(
const string &text,
const string &description = "",
const source_location location = source_location::current()
);
void codeblock(
const string &code,
const string &language = "none",
const source_location location = source_location::current()
);
void paragraph(
const string &text,
const source_location location = source_location::current()
);
ContentListing* open_usage(
const string &text,
const source_location location = source_location::current()
);
ContentListing* open_option(
const string &text,
const source_location location = source_location::current()
);
Json to_json();
};
class PrettyHelp
{
public:
string group = "unknown";
private:
PrettyHelp *_prior;
ContentListing _root_listing;
public:
PrettyHelp();
~PrettyHelp();
static PrettyHelp *get_current();
bool has_content() { return _root_listing.has_content(); }
const vector<ContentListing *> get_content() {
return _root_listing.get_content();
}
ContentListing* get_root() {
return &_root_listing;
}
void set_group(const string g) { group = g; }
bool has_group() { return group.compare("unknown") != 0; }
void log_help();
};
YOSYS_NAMESPACE_END
#endif

View file

@ -21,6 +21,7 @@
#include "kernel/satgen.h"
#include "kernel/json.h"
#include "kernel/gzip.h"
#include "kernel/log_help.h"
#include <string.h>
#include <stdlib.h>
@ -41,7 +42,8 @@ std::map<std::string, Backend*> backend_register;
std::vector<std::string> Frontend::next_args;
Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help)
Pass::Pass(std::string name, std::string short_help, source_location location) :
pass_name(name), short_help(short_help), location(location)
{
next_queued_pass = first_queued_pass;
first_queued_pass = this;
@ -116,9 +118,19 @@ void Pass::post_execute(Pass::pre_post_exec_state_t state)
void Pass::help()
{
log("\n");
log("No help message for command `%s'.\n", pass_name.c_str());
log("\n");
auto prettyHelp = PrettyHelp();
if (formatted_help()) {
prettyHelp.log_help();
} else {
log("\n");
log("No help message for command `%s'.\n", pass_name.c_str());
log("\n");
}
}
bool Pass::formatted_help()
{
return false;
}
void Pass::clear_flags()
@ -381,8 +393,8 @@ void ScriptPass::help_script()
script();
}
Frontend::Frontend(std::string name, std::string short_help) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help),
Frontend::Frontend(std::string name, std::string short_help, source_location location) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help, location),
frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
{
}
@ -529,8 +541,8 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string
}
}
Backend::Backend(std::string name, std::string short_help) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help),
Backend::Backend(std::string name, std::string short_help, source_location location) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help, location),
backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
{
}
@ -683,6 +695,23 @@ static string get_cell_name(string name) {
return is_code_getter(name) ? name.substr(0, name.length()-1) : name;
}
static void log_warning_flags(Pass *pass) {
bool has_warnings = false;
const string name = pass->pass_name;
if (pass->experimental_flag) {
if (!has_warnings) log("\n");
has_warnings = true;
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", name.c_str());
}
if (pass->internal_flag) {
if (!has_warnings) log("\n");
has_warnings = true;
log("WARNING: THE '%s' COMMAND IS INTENDED FOR INTERNAL DEVELOPER USE ONLY.\n", name.c_str());
}
if (has_warnings)
log("\n");
}
static struct CellHelpMessages {
dict<string, SimHelper> cell_help;
CellHelpMessages() {
@ -708,155 +737,211 @@ struct HelpPass : public Pass {
log(" help <celltype>+ .... print verilog code for given cell type\n");
log("\n");
}
void write_cmd_rst(std::string cmd, std::string title, std::string text)
{
FILE *f = fopen(stringf("docs/source/cmd/%s.rst", cmd.c_str()).c_str(), "wt");
// make header
size_t char_len = cmd.length() + 3 + title.length();
std::string title_line = "\n";
title_line.insert(0, char_len, '=');
fprintf(f, "%s", title_line.c_str());
fprintf(f, "%s - %s\n", cmd.c_str(), title.c_str());
fprintf(f, "%s\n", title_line.c_str());
bool dump_cmds_json(PrettyJson &json) {
// init json
json.begin_object();
json.entry("version", "Yosys command reference");
json.entry("generator", yosys_version_str);
// render html
fprintf(f, ".. cmd:def:: %s\n", cmd.c_str());
fprintf(f, " :title: %s\n\n", title.c_str());
fprintf(f, " .. only:: html\n\n");
std::stringstream ss;
std::string textcp = text;
ss << text;
bool IsUsage = true;
int blank_count = 0;
size_t def_strip_count = 0;
bool WasDefinition = false;
for (std::string line; std::getline(ss, line, '\n');) {
// find position of first non space character
std::size_t first_pos = line.find_first_not_of(" \t");
std::size_t last_pos = line.find_last_not_of(" \t");
if (first_pos == std::string::npos) {
// skip formatting empty lines
if (!WasDefinition)
fputc('\n', f);
blank_count += 1;
continue;
bool raise_error = false;
std::map<string, vector<string>> groups;
json.name("cmds"); json.begin_object();
// iterate over commands
for (auto &it : pass_register) {
auto name = it.first;
auto pass = it.second;
auto title = pass->short_help;
auto cmd_help = PrettyHelp();
auto has_pretty_help = pass->formatted_help();
if (!has_pretty_help) {
enum PassUsageState {
PUState_none,
PUState_signature,
PUState_options,
PUState_optionbody,
};
source_location null_source;
string current_buffer = "";
auto root_listing = cmd_help.get_root();
auto current_listing = root_listing;
// dump command help
std::ostringstream buf;
log_streams.push_back(&buf);
pass->help();
log_streams.pop_back();
std::stringstream ss;
ss << buf.str();
// parse command help
size_t def_strip_count = 0;
auto current_state = PUState_none;
auto catch_verific = false;
auto blank_lines = 2;
for (string line; std::getline(ss, line, '\n');) {
// find position of first non space character
std::size_t first_pos = line.find_first_not_of(" \t");
std::size_t last_pos = line.find_last_not_of(" \t");
if (first_pos == std::string::npos) {
switch (current_state)
{
case PUState_signature:
root_listing->usage(current_buffer, null_source);
current_listing = root_listing;
current_state = PUState_none;
current_buffer = "";
break;
case PUState_none:
case PUState_optionbody:
blank_lines += 1;
break;
default:
break;
}
// skip empty lines
continue;
}
// strip leading and trailing whitespace
std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1);
bool IsDefinition = stripped_line[0] == '-';
IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>';
bool IsDedent = def_strip_count && first_pos < def_strip_count;
bool IsIndent = def_strip_count < first_pos;
// line looks like a signature
bool IsSignature = stripped_line.find(name) == 0 && (stripped_line.length() == name.length() || stripped_line.at(name.size()) == ' ');
if (IsSignature && first_pos <= 4 && (blank_lines >= 2 || current_state == PUState_signature)) {
if (current_state == PUState_options || current_state == PUState_optionbody) {
current_listing->codeblock(current_buffer, "none", null_source);
current_buffer = "";
} else if (current_state == PUState_signature) {
root_listing->usage(current_buffer, null_source);
current_buffer = "";
} else if (current_state == PUState_none && !current_buffer.empty()) {
current_listing->codeblock(current_buffer, "none", null_source);
current_buffer = "";
}
current_listing = root_listing;
current_state = PUState_signature;
def_strip_count = first_pos;
catch_verific = false;
} else if (IsDedent) {
def_strip_count = first_pos;
if (current_state == PUState_optionbody) {
if (!current_buffer.empty()) {
current_listing->codeblock(current_buffer, "none", null_source);
current_buffer = "";
}
if (IsIndent) {
current_state = PUState_options;
current_listing = root_listing->back();
} else {
current_state = PUState_none;
current_listing = root_listing;
}
} else {
current_state = PUState_none;
}
}
if (IsDefinition && !catch_verific && current_state != PUState_signature) {
if (!current_buffer.empty()) {
current_listing->codeblock(current_buffer, "none", null_source);
current_buffer = "";
}
current_state = PUState_options;
current_listing = root_listing->open_option(stripped_line, null_source);
def_strip_count = first_pos;
} else {
if (current_state == PUState_options) {
current_state = PUState_optionbody;
}
if (current_buffer.empty())
current_buffer = stripped_line;
else if (current_state == PUState_signature && IsIndent)
current_buffer += stripped_line;
else if (current_state == PUState_none) {
current_buffer += (blank_lines > 0 ? "\n\n" : "\n") + line;
} else
current_buffer += (blank_lines > 0 ? "\n\n" : "\n") + stripped_line;
if (stripped_line.compare("Command file parser supports following commands in file:") == 0)
catch_verific = true;
}
blank_lines = 0;
}
if (!current_buffer.empty()) {
if (current_buffer.size() > 64 && current_buffer.substr(0, 64).compare("The following commands are executed by this synthesis command:\n\n") == 0) {
current_listing->paragraph(current_buffer.substr(0, 62), null_source);
current_listing->codeblock(current_buffer.substr(64), "yoscrypt", null_source);
} else
current_listing->codeblock(current_buffer, "none", null_source);
current_buffer = "";
}
}
// strip leading and trailing whitespace
std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1);
bool IsDefinition = stripped_line[0] == '-';
IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>';
bool IsDedent = def_strip_count && first_pos <= def_strip_count;
bool IsIndent = first_pos == 2 || first_pos == 4;
if (cmd.compare(0, 7, "verific") == 0)
// verific.cc has strange and different formatting from the rest
IsIndent = false;
// another usage block
bool NewUsage = stripped_line.find(cmd) == 0;
if (IsUsage) {
if (stripped_line.compare(0, 4, "See ") == 0) {
// description refers to another function
fprintf(f, "\n %s\n", stripped_line.c_str());
} else {
// usage should be the first line of help output
fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
WasDefinition = true;
// attempt auto group
if (!cmd_help.has_group()) {
string source_file = pass->location.file_name();
bool has_source = source_file.compare("unknown") != 0;
if (pass->internal_flag)
cmd_help.group = "internal";
else if (source_file.find("backends/") == 0 || (!has_source && name.find("read_") == 0))
cmd_help.group = "backends";
else if (source_file.find("frontends/") == 0 || (!has_source && name.find("write_") == 0))
cmd_help.group = "frontends";
else if (has_source) {
auto last_slash = source_file.find_last_of('/');
if (last_slash != string::npos) {
auto parent_path = source_file.substr(0, last_slash);
cmd_help.group = parent_path;
}
}
IsUsage = false;
} else if (IsIndent && NewUsage && (blank_count >= 2 || WasDefinition)) {
// another usage block
fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
WasDefinition = true;
def_strip_count = 0;
} else if (IsIndent && IsDefinition && (blank_count || WasDefinition)) {
// format definition term
fprintf(f, "\n\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
WasDefinition = true;
def_strip_count = first_pos;
} else {
if (IsDedent) {
fprintf(f, "\n\n ::\n");
def_strip_count = first_pos;
} else if (WasDefinition) {
fprintf(f, "::\n");
WasDefinition = false;
}
fprintf(f, "\n %s", line.substr(def_strip_count, std::string::npos).c_str());
// implicit !has_source
else if (name.find("equiv") == 0)
cmd_help.group = "passes/equiv";
else if (name.find("fsm") == 0)
cmd_help.group = "passes/fsm";
else if (name.find("memory") == 0)
cmd_help.group = "passes/memory";
else if (name.find("opt") == 0)
cmd_help.group = "passes/opt";
else if (name.find("proc") == 0)
cmd_help.group = "passes/proc";
}
blank_count = 0;
if (groups.count(cmd_help.group) == 0) {
groups[cmd_help.group] = vector<string>();
}
groups[cmd_help.group].push_back(name);
// write to json
json.name(name.c_str()); json.begin_object();
json.entry("title", title);
json.name("content"); json.begin_array();
for (auto content : cmd_help.get_content())
json.value(content->to_json());
json.end_array();
json.entry("group", cmd_help.group);
json.entry("source_file", pass->location.file_name());
json.entry("source_line", pass->location.line());
json.entry("source_func", pass->location.function_name());
json.entry("experimental_flag", pass->experimental_flag);
json.entry("internal_flag", pass->internal_flag);
json.end_object();
}
fputc('\n', f);
json.end_object();
// render latex
fprintf(f, ".. only:: latex\n\n");
fprintf(f, " ::\n\n");
std::stringstream ss2;
ss2 << textcp;
for (std::string line; std::getline(ss2, line, '\n');) {
fprintf(f, " %s\n", line.c_str());
}
fclose(f);
}
void write_cell_rst(Yosys::SimHelper cell, Yosys::CellType ct)
{
// open
FILE *f = fopen(stringf("docs/source/cell/%s.rst", cell.filesafe_name().c_str()).c_str(), "wt");
json.entry("groups", groups);
// make header
string title_line;
if (cell.title.length())
title_line = stringf("%s - %s", cell.name.c_str(), cell.title.c_str());
else title_line = cell.name;
string underline = "\n";
underline.insert(0, title_line.length(), '=');
fprintf(f, "%s\n", title_line.c_str());
fprintf(f, "%s\n", underline.c_str());
// help text, with cell def for links
fprintf(f, ".. cell:def:: %s\n", cell.name.c_str());
if (cell.title.length())
fprintf(f, " :title: %s\n\n", cell.title.c_str());
else
fprintf(f, " :title: %s\n\n", cell.name.c_str());
std::stringstream ss;
ss << cell.desc;
for (std::string line; std::getline(ss, line, '\n');) {
fprintf(f, " %s\n", line.c_str());
}
// properties
fprintf(f, "\nProperties");
fprintf(f, "\n----------\n\n");
dict<string, bool> prop_dict = {
{"is_evaluable", ct.is_evaluable},
{"is_combinatorial", ct.is_combinatorial},
{"is_synthesizable", ct.is_synthesizable},
};
for (auto &it : prop_dict) {
fprintf(f, "- %s: %s\n", it.first.c_str(), it.second ? "true" : "false");
}
// source code
fprintf(f, "\nSimulation model (Verilog)");
fprintf(f, "\n--------------------------\n\n");
fprintf(f, ".. code-block:: verilog\n");
fprintf(f, " :caption: %s\n\n", cell.source.c_str());
std::stringstream ss2;
ss2 << cell.code;
for (std::string line; std::getline(ss2, line, '\n');) {
fprintf(f, " %s\n", line.c_str());
}
// footer
fprintf(f, "\n.. note::\n\n");
fprintf(f, " This page was auto-generated from the output of\n");
fprintf(f, " ``help %s``.\n", cell.name.c_str());
// close
fclose(f);
json.end_object();
return raise_error;
}
bool dump_cells_json(PrettyJson &json) {
// init json
@ -962,11 +1047,7 @@ struct HelpPass : public Pass {
log("=");
log("\n");
it.second->help();
if (it.second->experimental_flag) {
log("\n");
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
log("\n");
}
log_warning_flags(it.second);
}
}
else if (args[1] == "-cells") {
@ -980,44 +1061,9 @@ struct HelpPass : public Pass {
log("\n");
return;
}
// this option is undocumented as it is for internal use only
else if (args[1] == "-write-rst-command-reference-manual") {
for (auto &it : pass_register) {
std::ostringstream buf;
log_streams.push_back(&buf);
it.second->help();
if (it.second->experimental_flag) {
log("\n");
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
log("\n");
}
log_streams.pop_back();
write_cmd_rst(it.first, it.second->short_help, buf.str());
}
}
// this option is also undocumented as it is for internal use only
else if (args[1] == "-write-rst-cells-manual") {
bool raise_error = false;
for (auto &it : yosys_celltypes.cell_types) {
auto name = it.first.str();
if (cell_help_messages.contains(name)) {
write_cell_rst(cell_help_messages.get(name), it.second);
} else {
log("ERROR: Missing cell help for cell '%s'.\n", name.c_str());
raise_error |= true;
}
}
if (raise_error) {
log_error("One or more cells defined in celltypes.h are missing help documentation.\n");
}
}
else if (pass_register.count(args[1])) {
pass_register.at(args[1])->help();
if (pass_register.at(args[1])->experimental_flag) {
log("\n");
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", args[1].c_str());
log("\n");
}
log_warning_flags(pass_register.at(args[1]));
}
else if (cell_help_messages.contains(args[1])) {
auto help_cell = cell_help_messages.get(args[1]);
@ -1046,7 +1092,17 @@ struct HelpPass : public Pass {
log("No such command or cell type: %s\n", args[1].c_str());
return;
} else if (args.size() == 3) {
if (args[1] == "-dump-cells-json") {
// this option is undocumented as it is for internal use only
if (args[1] == "-dump-cmds-json") {
PrettyJson json;
if (!json.write_to_file(args[2]))
log_error("Can't open file `%s' for writing: %s\n", args[2].c_str(), strerror(errno));
if (dump_cmds_json(json)) {
log_abort();
}
}
// this option is undocumented as it is for internal use only
else if (args[1] == "-dump-cells-json") {
PrettyJson json;
if (!json.write_to_file(args[2]))
log_error("Can't open file `%s' for writing: %s\n", args[2].c_str(), strerror(errno));
@ -1054,6 +1110,8 @@ struct HelpPass : public Pass {
log_error("One or more cells defined in celltypes.h are missing help documentation.\n");
}
}
else
log("Unknown help command: `%s %s'\n", args[1].c_str(), args[2].c_str());
return;
}

View file

@ -23,26 +23,61 @@
#include "kernel/yosys_common.h"
#include "kernel/yosys.h"
#include <version>
#if __cpp_lib_source_location == 201907L
#include <source_location>
using std::source_location;
#elif defined(__has_include)
# if __has_include(<experimental/source_location>)
#include <experimental/source_location>
using std::experimental::source_location;
# else
#define SOURCE_FALLBACK
# endif
#else
#define SOURCE_FALLBACK
#endif
#ifdef SOURCE_FALLBACK
struct source_location { // dummy placeholder
int line() const { return 0; }
int column() const { return 0; }
const char* file_name() const { return "unknown"; }
const char* function_name() const { return "unknown"; }
static const source_location current(...) { return source_location(); }
};
#endif
YOSYS_NAMESPACE_BEGIN
struct Pass
{
std::string pass_name, short_help;
Pass(std::string name, std::string short_help = "** document me **");
source_location location;
Pass(std::string name, std::string short_help = "** document me **",
source_location location = source_location::current());
virtual ~Pass();
// Makes calls to log() to generate help message
virtual void help();
// Uses PrettyHelp::get_current() to produce a more portable formatted help message
virtual bool formatted_help();
virtual void clear_flags();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
int call_counter;
int64_t runtime_ns;
bool experimental_flag = false;
bool internal_flag = false;
void experimental() {
experimental_flag = true;
}
void internal() {
internal_flag = true;
}
struct pre_post_exec_state_t {
Pass *parent_pass;
int64_t begin_ns;
@ -80,7 +115,8 @@ struct ScriptPass : Pass
RTLIL::Design *active_design;
std::string active_run_from, active_run_to;
ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { }
ScriptPass(std::string name, std::string short_help = "** document me **", source_location location = source_location::current()) :
Pass(name, short_help, location) { }
virtual void script() = 0;
@ -98,7 +134,8 @@ struct Frontend : Pass
static std::string last_here_document;
std::string frontend_name;
Frontend(std::string name, std::string short_help = "** document me **");
Frontend(std::string name, std::string short_help = "** document me **",
source_location location = source_location::current());
void run_register() override;
~Frontend() override;
void execute(std::vector<std::string> args, RTLIL::Design *design) override final;
@ -114,7 +151,8 @@ struct Frontend : Pass
struct Backend : Pass
{
std::string backend_name;
Backend(std::string name, std::string short_help = "** document me **");
Backend(std::string name, std::string short_help = "** document me **",
source_location location = source_location::current());
void run_register() override;
~Backend() override;
void execute(std::vector<std::string> args, RTLIL::Design *design) override final;

View file

@ -22,12 +22,18 @@
#include "kernel/celledges.h"
#include "kernel/celltypes.h"
#include "kernel/utils.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct CheckPass : public Pass {
CheckPass() : Pass("check", "check for obvious problems in the design") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -70,61 +71,61 @@ static bool is_triggered_check_cell(RTLIL::Cell * cell)
}
struct ChformalPass : public Pass {
ChformalPass() : Pass("chformal", "change formal constraints of the design") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" chformal [types] [mode] [options] [selection]\n");
log("\n");
log("Make changes to the formal constraints of the design. The [types] options\n");
log("the type of constraint to operate on. If none of the following options are\n");
log("given, the command will operate on all constraint types:\n");
log("\n");
log(" -assert $assert cells, representing assert(...) constraints\n");
log(" -assume $assume cells, representing assume(...) constraints\n");
log(" -live $live cells, representing assert(s_eventually ...)\n");
log(" -fair $fair cells, representing assume(s_eventually ...)\n");
log(" -cover $cover cells, representing cover() statements\n");
log("\n");
log(" Additionally chformal will operate on $check cells corresponding to the\n");
log(" selected constraint types.\n");
log("\n");
log("Exactly one of the following modes must be specified:\n");
log("\n");
log(" -remove\n");
log(" remove the cells and thus constraints from the design\n");
log("\n");
log(" -early\n");
log(" bypass FFs that only delay the activation of a constraint. When inputs\n");
log(" of the bypassed FFs do not remain stable between clock edges, this may\n");
log(" result in unexpected behavior.\n");
log("\n");
log(" -delay <N>\n");
log(" delay activation of the constraint by <N> clock cycles\n");
log("\n");
log(" -skip <N>\n");
log(" ignore activation of the constraint in the first <N> clock cycles\n");
log("\n");
log(" -coverenable\n");
log(" add cover statements for the enable signals of the constraints\n");
log("\n");
ChformalPass() : Pass("chformal", "change formal constraints of the design") {}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("formal");
auto content_root = help->get_root();
content_root->usage("chformal [types] [mode] [options] [selection]");
content_root->paragraph(
"Make changes to the formal constraints of the design. The [types] options "
"the type of constraint to operate on. If none of the following options are "
"given, the command will operate on all constraint types:"
);
content_root->option("-assert", "`$assert` cells, representing ``assert(...)`` constraints");
content_root->option("-assume", "`$assume` cells, representing ``assume(...)`` constraints");
content_root->option("-live", "`$live` cells, representing ``assert(s_eventually ...)``");
content_root->option("-fair", "`$fair` cells, representing ``assume(s_eventually ...)``");
content_root->option("-cover", "`$cover` cells, representing ``cover()`` statements");
content_root->paragraph(
"Additionally chformal will operate on `$check` cells corresponding to the "
"selected constraint types."
);
content_root->paragraph("Exactly one of the following modes must be specified:");
content_root->option("-remove", "remove the cells and thus constraints from the design");
content_root->option("-early",
"bypass FFs that only delay the activation of a constraint. When inputs "
"of the bypassed FFs do not remain stable between clock edges, this may "
"result in unexpected behavior."
);
content_root->option("-delay <N>", "delay activation of the constraint by <N> clock cycles");
content_root->option("-skip <N>", "ignore activation of the constraint in the first <N> clock cycles");
auto cover_option = content_root->open_option("-coverenable");
cover_option->paragraph(
"add cover statements for the enable signals of the constraints"
);
#ifdef YOSYS_ENABLE_VERIFIC
log(" Note: For the Verific frontend it is currently not guaranteed that a\n");
log(" reachable SVA statement corresponds to an active enable signal.\n");
log("\n");
cover_option->paragraph(
"Note: For the Verific frontend it is currently not guaranteed that a "
"reachable SVA statement corresponds to an active enable signal."
);
#endif
log(" -assert2assume\n");
log(" -assume2assert\n");
log(" -live2fair\n");
log(" -fair2live\n");
log(" change the roles of cells as indicated. these options can be combined\n");
log("\n");
log(" -lower\n");
log(" convert each $check cell into an $assert, $assume, $live, $fair or\n");
log(" $cover cell. If the $check cell contains a message, also produce a\n");
log(" $print cell.\n");
log("\n");
content_root->option("-assert2assume");
content_root->option("-assume2assert");
content_root->option("-live2fair");
content_root->option("-fair2live", "change the roles of cells as indicated. these options can be combined");
content_root->option("-lower",
"convert each $check cell into an $assert, $assume, $live, $fair or "
"$cover cell. If the $check cell contains a message, also produce a "
"$print cell."
);
return true;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{

View file

@ -18,6 +18,7 @@
*/
#include "kernel/yosys.h"
#include "kernel/log_help.h"
#include <sys/types.h>
#ifndef _WIN32
@ -26,15 +27,18 @@
# include <io.h>
#endif
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct CoverPass : public Pass {
CoverPass() : Pass("cover", "print code coverage counters") { }
CoverPass() : Pass("cover", "print code coverage counters") {
internal();
}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -22,6 +22,7 @@
#include "kernel/modtools.h"
#include "kernel/sigtools.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
#include <deque>
USING_YOSYS_NAMESPACE
@ -952,6 +953,11 @@ struct DftTagWorker {
struct DftTagPass : public Pass {
DftTagPass() : Pass("dft_tag", "create tagging logic for data flow tracking") {}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("formal");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -19,12 +19,18 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct EdgetypePass : public Pass {
EdgetypePass() : Pass("edgetypes", "list all types of edges in selection") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -21,15 +21,17 @@ struct ExampleWorker
struct ExampleDtPass : public Pass
{
ExampleDtPass() : Pass("example_dt", "drivertools example") {}
ExampleDtPass() : Pass("example_dt", "drivertools example") {
internal();
}
void help() override
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log("TODO: add help message\n");
log("\n");
}
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override

View file

@ -17,8 +17,8 @@
*
*/
#include "kernel/register.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
#include <cstdio>
#if defined(_WIN32)
@ -38,6 +38,11 @@ PRIVATE_NAMESPACE_BEGIN
struct ExecPass : public Pass {
ExecPass() : Pass("exec", "execute commands in the operating system shell") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -24,6 +24,7 @@
#include "kernel/sigtools.h"
#include "kernel/utils.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
#include <deque>
USING_YOSYS_NAMESPACE
@ -110,6 +111,11 @@ struct FutureWorker {
struct FuturePass : public Pass {
FuturePass() : Pass("future", "resolve future sampled value functions") {}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("formal");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -17,10 +17,9 @@
*
*/
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/utils.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -425,6 +424,12 @@ public:
struct GliftPass : public Pass {
GliftPass() : Pass("glift", "create GLIFT models and optimization problems") {}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("formal");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -18,8 +18,6 @@
*/
#include <iterator>
#include <optional>
#include <stdint.h>
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
@ -71,7 +69,10 @@ std::optional<uint64_t> current_mem_bytes() {
}
struct InternalStatsPass : public Pass {
InternalStatsPass() : Pass("internal_stats", "print internal statistics") { }
InternalStatsPass() : Pass("internal_stats", "print internal statistics") {
experimental();
internal();
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -18,15 +18,19 @@
*
*/
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct LogPass : public Pass {
LogPass() : Pass("log", "print text and log files") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -17,14 +17,19 @@
*
*/
#include "kernel/register.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct LoggerPass : public Pass {
LoggerPass() : Pass("logger", "set logger properties") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -20,6 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -141,6 +142,11 @@ struct LtpWorker
struct LtpPass : public Pass {
LtpPass() : Pass("ltp", "print longest topological path") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -18,6 +18,7 @@
*/
#include "kernel/yosys.h"
#include "kernel/log_help.h"
#ifdef YOSYS_ENABLE_PLUGINS
# include <dlfcn.h>
@ -122,6 +123,11 @@ void load_plugin(std::string, std::vector<std::string>)
struct PluginPass : public Pass {
PluginPass() : Pass("plugin", "load and list loaded plugins") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -22,6 +22,7 @@
#include "kernel/rtlil.h"
#include "kernel/utils.h"
#include "kernel/celltypes.h"
#include "kernel/log_help.h"
PRIVATE_NAMESPACE_BEGIN
USING_YOSYS_NAMESPACE
@ -38,6 +39,11 @@ static RTLIL::SigBit canonical_bit(RTLIL::SigBit bit)
struct PortarcsPass : Pass {
PortarcsPass() : Pass("portarcs", "derive port arcs for propagation delay") {}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{

View file

@ -19,12 +19,18 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct PortlistPass : public Pass {
PortlistPass() : Pass("portlist", "list (top-level) ports") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -18,12 +18,18 @@
*/
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct PrintAttrsPass : public Pass {
PrintAttrsPass() : Pass("printattrs", "print attributes of selected objects") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -21,12 +21,10 @@
// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010
// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
#include "kernel/register.h"
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -252,6 +250,11 @@ struct SccWorker
struct SccPass : public Pass {
SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -18,15 +18,19 @@
*
*/
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct ScratchpadPass : public Pass {
ScratchpadPass() : Pass("scratchpad", "get/set values in the scratchpad") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -20,8 +20,7 @@
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include <string.h>
#include <errno.h>
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -1034,6 +1033,11 @@ PRIVATE_NAMESPACE_BEGIN
struct SelectPass : public Pass {
SelectPass() : Pass("select", "modify and view the list of selected objects") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@ -1631,6 +1635,11 @@ struct SelectPass : public Pass {
struct CdPass : public Pass {
CdPass() : Pass("cd", "a shortcut for 'select -module <name>'") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@ -1739,6 +1748,11 @@ static void log_matches(const char *title, Module *module, const T &list)
struct LsPass : public Pass {
LsPass() : Pass("ls", "list modules or objects in modules") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -17,15 +17,18 @@
*
*/
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include <stdlib.h>
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SetenvPass : public Pass {
SetenvPass() : Pass("setenv", "set an environment variable") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -17,10 +17,9 @@
*
*/
#include "kernel/register.h"
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string.h>
#include "kernel/log_help.h"
#ifndef _WIN32
# include <dirent.h>
@ -658,6 +657,11 @@ struct ShowWorker
struct ShowPass : public Pass {
ShowPass() : Pass("show", "generate schematics using graphviz") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -21,6 +21,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/timinginfo.h"
#include "kernel/log_help.h"
#include <deque>
USING_YOSYS_NAMESPACE
@ -275,6 +276,11 @@ struct StaWorker
struct StaPass : public Pass {
StaPass() : Pass("sta", "perform static timing analysis") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -25,6 +25,7 @@
#include "kernel/cost.h"
#include "kernel/gzip.h"
#include "libs/json11/json11.hpp"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -369,6 +370,11 @@ void read_liberty_cellarea(dict<IdString, cell_area_t> &cell_area, string libert
struct StatPass : public Pass {
StatPass() : Pass("stat", "print some statistics") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -18,15 +18,19 @@
*
*/
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct TeePass : public Pass {
TeePass() : Pass("tee", "redirect command output to file") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -21,12 +21,18 @@
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/utils.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct TorderPass : public Pass {
TorderPass() : Pass("torder", "print cells in topological order") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -19,6 +19,7 @@
*/
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -60,6 +61,11 @@ struct TraceMonitor : public RTLIL::Monitor
struct TracePass : public Pass {
TracePass() : Pass("trace", "redirect command output to file") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@ -96,6 +102,11 @@ struct TracePass : public Pass {
struct DebugPass : public Pass {
DebugPass() : Pass("debug", "run command with debug log messages enabled") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log_help.h"
#ifndef _WIN32
# include <dirent.h>
@ -817,6 +818,11 @@ struct VizWorker
struct VizPass : public Pass {
VizPass() : Pass("viz", "visualize data flow graph") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -19,12 +19,18 @@
*/
#include "kernel/yosys.h"
#include "kernel/log_help.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct WriteFileFrontend : public Frontend {
WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

View file

@ -24,6 +24,7 @@
#include "kernel/sigtools.h"
#include "kernel/utils.h"
#include "kernel/yosys.h"
#include "kernel/log_help.h"
#include <deque>
USING_YOSYS_NAMESPACE
@ -1100,6 +1101,11 @@ struct XpropWorker
struct XpropPass : public Pass {
XpropPass() : Pass("xprop", "formal x propagation") {}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("formal");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|

Some files were not shown because too many files have changed in this diff Show more