mirror of
https://github.com/YosysHQ/yosys
synced 2025-08-17 16:52:16 +00:00
Merge branch 'main' of github.com:zhanghongce/yosys
This commit is contained in:
commit
b635ab72bf
143 changed files with 3222 additions and 563 deletions
2
.github/workflows/prepare-docs.yml
vendored
2
.github/workflows/prepare-docs.yml
vendored
|
@ -47,6 +47,7 @@ jobs:
|
|||
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
|
||||
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf
|
||||
make -j$procs ENABLE_LTO=1
|
||||
|
||||
- name: Prepare docs
|
||||
|
@ -59,7 +60,6 @@ jobs:
|
|||
with:
|
||||
name: cmd-ref-${{ github.sha }}
|
||||
path: |
|
||||
docs/source/cmd
|
||||
docs/source/generated
|
||||
docs/source/_images
|
||||
docs/source/code_examples
|
||||
|
|
1
.github/workflows/test-build.yml
vendored
1
.github/workflows/test-build.yml
vendored
|
@ -225,6 +225,7 @@ jobs:
|
|||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf
|
||||
make -j$procs
|
||||
|
||||
- name: Install doc prereqs
|
||||
|
|
8
.github/workflows/wheels.yml
vendored
8
.github/workflows/wheels.yml
vendored
|
@ -119,6 +119,11 @@ jobs:
|
|||
upload_wheels:
|
||||
name: Upload Wheels
|
||||
runs-on: ubuntu-latest
|
||||
# Specifying a GitHub environment is optional, but strongly encouraged
|
||||
environment: pypi
|
||||
permissions:
|
||||
# IMPORTANT: this permission is mandatory for Trusted Publishing
|
||||
id-token: write
|
||||
needs: build_wheels
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
|
@ -132,6 +137,3 @@ jobs:
|
|||
mv *.whl ./dist
|
||||
- name: Publish
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
password: ${{ secrets.PYPI_TOKEN }}
|
||||
repository-url: ${{ vars.PYPI_INDEX || 'https://upload.pypi.org/legacy/' }}
|
||||
|
|
|
@ -19,14 +19,14 @@ much easier for someone to respond and help.
|
|||
|
||||
### Bug reports
|
||||
|
||||
Before you submit an issue, please have a search of the existing issues in case
|
||||
one already exists. Making sure that you have a minimal, complete and
|
||||
verifiable example (MVCE) is a great way to quickly check an existing issue
|
||||
against a new one. Stack overflow has a guide on [how to create an
|
||||
MVCE](https://stackoverflow.com/help/minimal-reproducible-example). The
|
||||
[`bugpoint`
|
||||
command](https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/bugpoint.html)
|
||||
in Yosys can be helpful for this process.
|
||||
Before you submit an issue, please check out the [how-to guide for
|
||||
`bugpoint`](https://yosys.readthedocs.io/en/latest/using_yosys/bugpoint.html).
|
||||
This guide will take you through the process of using the [`bugpoint`
|
||||
command](https://yosys.readthedocs.io/en/latest/cmd/bugpoint.html) in Yosys to
|
||||
produce a [minimal, complete and verifiable
|
||||
example](https://stackoverflow.com/help/minimal-reproducible-example) (MVCE).
|
||||
Providing an MVCE with your bug report drastically increases the likelihood that
|
||||
someone will be able to help resolve your issue.
|
||||
|
||||
|
||||
# Using pull requests
|
||||
|
|
43
Makefile
43
Makefile
|
@ -24,6 +24,7 @@ ENABLE_VERIFIC_LIBERTY := 0
|
|||
ENABLE_COVER := 1
|
||||
ENABLE_LIBYOSYS := 0
|
||||
ENABLE_ZLIB := 1
|
||||
ENABLE_HELP_SOURCE := 0
|
||||
|
||||
# python wrappers
|
||||
ENABLE_PYOSYS := 0
|
||||
|
@ -109,18 +110,16 @@ PLUGIN_LINKFLAGS += -L"$(LIBDIR)"
|
|||
PLUGIN_LIBS := -lyosys_exe
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_HELP_SOURCE),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_HELP_SOURCE
|
||||
endif
|
||||
|
||||
PKG_CONFIG ?= pkg-config
|
||||
SED ?= sed
|
||||
BISON ?= bison
|
||||
STRIP ?= strip
|
||||
AWK ?= awk
|
||||
|
||||
ifneq ($(shell :; command -v rsync),)
|
||||
RSYNC_CP ?= rsync -rc
|
||||
else
|
||||
RSYNC_CP ?= cp -ru
|
||||
endif
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
PLUGIN_LINKFLAGS += -undefined dynamic_lookup
|
||||
LINKFLAGS += -rdynamic
|
||||
|
@ -160,7 +159,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.55+150
|
||||
YOSYS_VER := 0.55+209
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
|
||||
|
@ -532,7 +531,6 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE
|
|||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(ENABLE_COVER),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_COVER
|
||||
endif
|
||||
|
@ -634,6 +632,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
|
||||
|
@ -1035,19 +1034,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_CP) 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_CP) 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 $@'
|
||||
|
@ -1064,6 +1052,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
|
||||
|
@ -1099,7 +1096,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
|
||||
|
@ -1123,7 +1120,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__
|
||||
rm -f *.whl
|
||||
rm -f libyosys.so
|
||||
|
||||
|
|
|
@ -276,3 +276,11 @@ From the root of the repository, run `make docs`. This will build/rebuild yosys
|
|||
as necessary before generating the website documentation from the yosys help
|
||||
commands. To build for pdf instead of html, call
|
||||
`make docs DOC_TARGET=latexpdf`.
|
||||
|
||||
It is recommended to use the `ENABLE_HELP_SOURCE` make option for Yosys builds
|
||||
that will be used to build the documentation. This option enables source
|
||||
location tracking for passes and improves the command reference through grouping
|
||||
related commands and allowing for the documentation to link to the corresponding
|
||||
source files. Without this, a warning will be raised during the Sphinx build
|
||||
about `Found commands assigned to group unknown` and `make docs` is configured
|
||||
to fail on warnings by default.
|
||||
|
|
2
abc
2
abc
|
@ -1 +1 @@
|
|||
Subproject commit fcd8ac34d6105b48f32dfaf31983b071c46fb7b9
|
||||
Subproject commit fa7fa163dacdf81bdcb72b2d2713fbe9984b62bb
|
|
@ -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
1
docs/.gitignore
vendored
|
@ -1,5 +1,4 @@
|
|||
/build/
|
||||
/source/cmd
|
||||
/source/generated
|
||||
/source/_images/**/*.log
|
||||
/source/_images/**/*.aux
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
5
docs/source/cmd/index_backends.rst
Normal file
5
docs/source/cmd/index_backends.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Writing output files
|
||||
--------------------
|
||||
|
||||
.. autocmdgroup:: backends
|
||||
:members:
|
5
docs/source/cmd/index_formal.rst
Normal file
5
docs/source/cmd/index_formal.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Formal verification
|
||||
-------------------
|
||||
|
||||
.. autocmdgroup:: formal
|
||||
:members:
|
5
docs/source/cmd/index_frontends.rst
Normal file
5
docs/source/cmd/index_frontends.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Reading input files
|
||||
-------------------
|
||||
|
||||
.. autocmdgroup:: frontends
|
||||
:members:
|
152
docs/source/cmd/index_internal.rst
Normal file
152
docs/source/cmd/index_internal.rst
Normal 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
|
5
docs/source/cmd/index_kernel.rst
Normal file
5
docs/source/cmd/index_kernel.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Yosys kernel commands
|
||||
---------------------
|
||||
|
||||
.. autocmdgroup:: kernel
|
||||
:members:
|
9
docs/source/cmd/index_other.rst
Normal file
9
docs/source/cmd/index_other.rst
Normal file
|
@ -0,0 +1,9 @@
|
|||
:orphan:
|
||||
|
||||
Other commands
|
||||
==============
|
||||
|
||||
Unknown source location
|
||||
|
||||
.. autocmdgroup:: unknown
|
||||
:members:
|
14
docs/source/cmd/index_passes.rst
Normal file
14
docs/source/cmd/index_passes.rst
Normal 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_*
|
5
docs/source/cmd/index_passes_cmds.rst
Normal file
5
docs/source/cmd/index_passes_cmds.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Design modification
|
||||
-------------------
|
||||
|
||||
.. autocmdgroup:: passes/cmds
|
||||
:members:
|
5
docs/source/cmd/index_passes_equiv.rst
Normal file
5
docs/source/cmd/index_passes_equiv.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Equivalence checking
|
||||
--------------------
|
||||
|
||||
.. autocmdgroup:: passes/equiv
|
||||
:members:
|
5
docs/source/cmd/index_passes_fsm.rst
Normal file
5
docs/source/cmd/index_passes_fsm.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
FSM handling
|
||||
------------
|
||||
|
||||
.. autocmdgroup:: passes/fsm
|
||||
:members:
|
5
docs/source/cmd/index_passes_hierarchy.rst
Normal file
5
docs/source/cmd/index_passes_hierarchy.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Working with hierarchy
|
||||
----------------------
|
||||
|
||||
.. autocmdgroup:: passes/hierarchy
|
||||
:members:
|
5
docs/source/cmd/index_passes_memory.rst
Normal file
5
docs/source/cmd/index_passes_memory.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Memory handling
|
||||
---------------
|
||||
|
||||
.. autocmdgroup:: passes/memory
|
||||
:members:
|
5
docs/source/cmd/index_passes_opt.rst
Normal file
5
docs/source/cmd/index_passes_opt.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Optimization passes
|
||||
-------------------
|
||||
|
||||
.. autocmdgroup:: passes/opt
|
||||
:members:
|
5
docs/source/cmd/index_passes_proc.rst
Normal file
5
docs/source/cmd/index_passes_proc.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Converting process blocks
|
||||
-------------------------
|
||||
|
||||
.. autocmdgroup:: passes/proc
|
||||
:members:
|
5
docs/source/cmd/index_passes_sat.rst
Normal file
5
docs/source/cmd/index_passes_sat.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Simulating circuits
|
||||
-------------------
|
||||
|
||||
.. autocmdgroup:: passes/sat
|
||||
:members:
|
5
docs/source/cmd/index_passes_status.rst
Normal file
5
docs/source/cmd/index_passes_status.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Design status
|
||||
-------------
|
||||
|
||||
.. autocmdgroup:: passes/status
|
||||
:members:
|
7
docs/source/cmd/index_passes_techmap.rst
Normal file
7
docs/source/cmd/index_passes_techmap.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
Technology mapping
|
||||
------------------
|
||||
|
||||
.. seealso:: :doc:`/cmd/index_techlibs`
|
||||
|
||||
.. autocmdgroup:: passes/techmap
|
||||
:members:
|
11
docs/source/cmd/index_techlibs.rst
Normal file
11
docs/source/cmd/index_techlibs.rst
Normal file
|
@ -0,0 +1,11 @@
|
|||
Technology libraries
|
||||
====================
|
||||
|
||||
Listed in alphabetical order.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
/cmd/index_techlibs_common
|
||||
/cmd/index_techlibs_*
|
5
docs/source/cmd/index_techlibs_achronix.rst
Normal file
5
docs/source/cmd/index_techlibs_achronix.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Achronix
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/achronix
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_anlogic.rst
Normal file
5
docs/source/cmd/index_techlibs_anlogic.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Anlogic
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/anlogic
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_common.rst
Normal file
5
docs/source/cmd/index_techlibs_common.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Generic
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/common
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_coolrunner2.rst
Normal file
5
docs/source/cmd/index_techlibs_coolrunner2.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
CoolRunner-II
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/coolrunner2
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_easic.rst
Normal file
5
docs/source/cmd/index_techlibs_easic.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
eASIC
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/easic
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_ecp5.rst
Normal file
5
docs/source/cmd/index_techlibs_ecp5.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
ECP5
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/ecp5
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_fabulous.rst
Normal file
5
docs/source/cmd/index_techlibs_fabulous.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
FABulous
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/fabulous
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_gatemate.rst
Normal file
5
docs/source/cmd/index_techlibs_gatemate.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Gatemate
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/gatemate
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_gowin.rst
Normal file
5
docs/source/cmd/index_techlibs_gowin.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Gowin
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/gowin
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_greenpak4.rst
Normal file
5
docs/source/cmd/index_techlibs_greenpak4.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
GreenPAK4
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/greenpak4
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_ice40.rst
Normal file
5
docs/source/cmd/index_techlibs_ice40.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
iCE40
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/ice40
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_intel.rst
Normal file
5
docs/source/cmd/index_techlibs_intel.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Intel (MAX10, Cyclone IV)
|
||||
-------------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/intel
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_intel_alm.rst
Normal file
5
docs/source/cmd/index_techlibs_intel_alm.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Intel ALM (Cyclone V, Arria V, Cyclone 10 GX)
|
||||
---------------------------------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/intel_alm
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_lattice.rst
Normal file
5
docs/source/cmd/index_techlibs_lattice.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Lattice
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/lattice
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_lattice_nexus.rst
Normal file
5
docs/source/cmd/index_techlibs_lattice_nexus.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Lattice Nexus
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/nexus
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_microchip.rst
Normal file
5
docs/source/cmd/index_techlibs_microchip.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Microchip
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/microchip
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_microchip_sf2.rst
Normal file
5
docs/source/cmd/index_techlibs_microchip_sf2.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Microchip - SmartFusion2/IGLOO2
|
||||
-----------------------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/sf2
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_nanoxplore.rst
Normal file
5
docs/source/cmd/index_techlibs_nanoxplore.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
NanoXplore
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/nanoxplore
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_quicklogic.rst
Normal file
5
docs/source/cmd/index_techlibs_quicklogic.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
QuickLogic
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/quicklogic
|
||||
:members:
|
5
docs/source/cmd/index_techlibs_xilinx.rst
Normal file
5
docs/source/cmd/index_techlibs_xilinx.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Xilinx
|
||||
------------------
|
||||
|
||||
.. autocmdgroup:: techlibs/xilinx
|
||||
:members:
|
|
@ -1,5 +1,3 @@
|
|||
.. _cmd_ref:
|
||||
|
||||
================================================================================
|
||||
Command line reference
|
||||
================================================================================
|
||||
|
@ -7,10 +5,31 @@ Command line reference
|
|||
.. literalinclude:: /generated/yosys
|
||||
:start-at: Usage
|
||||
|
||||
.. _cmd_ref:
|
||||
|
||||
Command reference
|
||||
-----------------
|
||||
|
||||
.. todo:: Can we warn on command groups that aren't included anywhere?
|
||||
|
||||
:ref:`List of all commands<cmd-cmd>`
|
||||
|
||||
.. toctree::
|
||||
:caption: Command reference
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
:maxdepth: 2
|
||||
|
||||
/appendix/env_vars
|
||||
/cmd/*
|
||||
/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
|
||||
|
|
23
docs/source/code_examples/macro_commands/prep.ys
Normal file
23
docs/source/code_examples/macro_commands/prep.ys
Normal 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
|
|
@ -43,8 +43,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']
|
||||
|
||||
|
@ -64,7 +68,6 @@ if os.getenv("READTHEDOCS"):
|
|||
|
||||
# Ensure that autosectionlabel will produce unique names
|
||||
autosectionlabel_prefix_document = True
|
||||
autosectionlabel_maxdepth = 1
|
||||
|
||||
# include todos for previews
|
||||
extensions.append('sphinx.ext.todo')
|
||||
|
@ -106,12 +109,14 @@ latex_elements = {
|
|||
|
||||
# custom cmd-ref parsing/linking
|
||||
sys.path += [os.path.dirname(__file__) + "/../"]
|
||||
extensions.append('util.cmdref')
|
||||
extensions.append('util.custom_directives')
|
||||
|
||||
# use autodocs
|
||||
extensions.append('sphinx.ext.autodoc')
|
||||
extensions.append('util.cellref')
|
||||
extensions.append('util.cell_documenter')
|
||||
cells_json = Path(__file__).parent / 'generated' / 'cells.json'
|
||||
extensions.append('util.cmd_documenter')
|
||||
cmds_json = Path(__file__).parent / 'generated' / 'cmds.json'
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
def setup(app: Sphinx) -> None:
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -26,7 +26,7 @@ of the comment is a semicolon ``;`` or a new line.
|
|||
.. code-block::
|
||||
:caption: Using the ``-p`` option
|
||||
|
||||
$ yosys -p "read_verilog fifo.v; :this is a comment; prep"
|
||||
$ yosys -p 'read_verilog fifo.v; :this is a comment; prep'
|
||||
|
||||
.. warning::
|
||||
|
||||
|
@ -42,6 +42,13 @@ will be raised by Yosys. `exec` provides a much more flexible way of executing
|
|||
commands, allowing the output to be logged and more control over when to
|
||||
generate errors.
|
||||
|
||||
.. warning::
|
||||
|
||||
Take care when using the ``yosys -p`` option. Some shells such as bash will
|
||||
perform substitution options inside of a double quoted string, such as ``!``
|
||||
for history substitution and ``$`` for variable substitution; single quotes
|
||||
should be used instead to pass the string to Yosys without substitution.
|
||||
|
||||
The synthesis starter script
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -122,7 +129,7 @@ module.
|
|||
|
||||
Detailed documentation of the select framework can be found under
|
||||
:doc:`/using_yosys/more_scripting/selections` or in the command reference at
|
||||
:doc:`/cmd/select`.
|
||||
:cmd:title:`select`.
|
||||
|
||||
.. _show_intro:
|
||||
|
||||
|
@ -219,7 +226,7 @@ those used in options, must be a single expression instead.
|
|||
.. _GraphViz color docs: https://graphviz.org/doc/info/colors
|
||||
|
||||
For all of the options available to `show`, check the command reference at
|
||||
:doc:`/cmd/show`.
|
||||
:cmd:title:`show`.
|
||||
|
||||
.. seealso:: :ref:`interactive_show` on the
|
||||
:doc:`/using_yosys/more_scripting/interactive_investigation` page.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
446
docs/source/using_yosys/bugpoint.rst
Normal file
446
docs/source/using_yosys/bugpoint.rst
Normal file
|
@ -0,0 +1,446 @@
|
|||
Minimizing failing (or bugged) designs
|
||||
======================================
|
||||
|
||||
.. TODO:: pending merge of https://github.com/YosysHQ/yosys/pull/5068
|
||||
|
||||
This document is a how-to guide for reducing problematic designs to the bare
|
||||
minimum needed for reproducing the issue. This is a Yosys specific alternative
|
||||
to the Stack Overflow article: `How to create a Minimal, Reproducible Example`_,
|
||||
and is intended to help when there's something wrong with your design, or with
|
||||
Yosys itself.
|
||||
|
||||
.. _How to create a Minimal, Reproducible Example: https://stackoverflow.com/help/minimal-reproducible-example
|
||||
|
||||
.. note::
|
||||
|
||||
This guide assumes a moderate degree of familiarity with Yosys and requires
|
||||
some amount of problem solving ability.
|
||||
|
||||
|
||||
Before you start
|
||||
----------------
|
||||
|
||||
The first (and often overlooked) step, is to check for and *read* any error
|
||||
messages or warnings. Passing the ``-q`` flag when running Yosys will make it
|
||||
so that only warnings and error messages are written to the console. Don't just
|
||||
read the last message either, there may be warnings that indicate a problem
|
||||
before it happens. While some things may only be regarded as warnings, such as
|
||||
multiple drivers for the same signal or logic loops, these can cause problems in
|
||||
some synthesis flows but not others.
|
||||
|
||||
A Yosys error (one that starts with ``ERROR:``) may give you a line number from
|
||||
your design, or the name of the object causing issues. If so, you may already
|
||||
have enough information to resolve the problem, or at least understand why it's
|
||||
happening.
|
||||
|
||||
.. note::
|
||||
|
||||
If you're not already, try using the latest version from the `Yosys GitHub`_.
|
||||
You may find that your issue has already been fixed! And even if it isn't,
|
||||
testing with two different versions is a good way to ensure reproducibility.
|
||||
|
||||
.. _Yosys GitHub: https://github.com/YosysHQ/yosys
|
||||
|
||||
Another thing to be aware of is that Yosys generally doesn't perform rigorous
|
||||
checking of input designs to ensure they are valid. This is especially true for
|
||||
the `read_verilog` frontend. It is instead recommended that you try load it
|
||||
with `iverilog`_ or `verilator`_ first, as an invalid design can often lead to
|
||||
unexpected issues.
|
||||
|
||||
.. _iverilog: https://steveicarus.github.io/iverilog/
|
||||
.. _verilator: https://www.veripool.org/verilator/
|
||||
|
||||
If you're using a custom synthesis script, try take a bit of time to figure out
|
||||
which command is failing. Calling ``echo on`` at the start of your script will
|
||||
`echo` each command executed; the last echo before the error should then be
|
||||
where the error has come from. Check the help message for the failing command;
|
||||
does it indicate limited support, or mention some other command that needs to be
|
||||
run first? You can also try to call `check` and/or ``hierarchy -check`` before
|
||||
the failure to see if they report and errors or warnings.
|
||||
|
||||
|
||||
Minimizing RTLIL designs with bugpoint
|
||||
--------------------------------------
|
||||
|
||||
Yosys provides the `bugpoint` command for reducing a failing design to the
|
||||
smallest portion of that design which still results in failure. While initially
|
||||
developed for Yosys crashes, `bugpoint` can also be used for designs that lead
|
||||
to non-fatal errors, or even failures in other tools that use the output of a
|
||||
Yosys script.
|
||||
|
||||
.. note::
|
||||
|
||||
Make sure to back up your code (design source and yosys script(s)) before
|
||||
making any modifications. Even if the code itself isn't important, this can
|
||||
help avoid "losing" the error while trying to debug it.
|
||||
|
||||
Can I use bugpoint?
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The first thing to be aware of is that `bugpoint` is not available in every
|
||||
build of Yosys. Because the command works by invoking external processes, it
|
||||
requires that Yosys can spawn executables. Notably this means `bugpoint` is not
|
||||
able to be used in WebAssembly builds such as that available via YoWASP. The
|
||||
easiest way to check your build of Yosys is by running ``yosys -h bugpoint``. If
|
||||
Yosys displays the help text for `bugpoint` then it is available for use.
|
||||
|
||||
.. code-block:: console
|
||||
:caption: `bugpoint` is unavailable
|
||||
|
||||
$ yosys -h bugpoint
|
||||
|
||||
-- Running command `help bugpoint' --
|
||||
No such command or cell type: bugpoint
|
||||
|
||||
Next you need to separate loading the design from the failure point; you should
|
||||
be aiming to reproduce the failure by running ``yosys -s <load.ys> -s
|
||||
<failure.ys>``. If the failure occurs while loading the design, such as during
|
||||
`read_verilog` you will instead have to minimize the input design yourself.
|
||||
Check out the instructions for :ref:`using_yosys/bugpoint:minimizing verilog
|
||||
designs` below.
|
||||
|
||||
.. note::
|
||||
|
||||
You should also be able to run the two scripts separately, calling first
|
||||
``yosys -s <load.ys> -p 'write_rtlil design.il'`` and then ``yosys -s
|
||||
<failure.ys> design.il``. If this doesn't work then it may mean that the
|
||||
failure isn't reproducible from RTLIL and `bugpoint` won't work either.
|
||||
|
||||
When we talk about failure points here, it doesn't just mean crashes or errors
|
||||
in Yosys. The ``<failure.ys>`` script can also be a user-defined failure such
|
||||
as the `select` command with one of the ``-assert-*`` options; an example where
|
||||
this might be useful is when a pass is supposed to remove a certain kind of
|
||||
cell, but there is some edge case where the cell is not removed. Another
|
||||
use-case would be minimizing a design which fails with the `equiv_opt` command,
|
||||
suggesting that the optimization in question alters the circuit in some way.
|
||||
|
||||
It is even possible to use `bugpoint` with failures *external* to Yosys, by
|
||||
making use of the `exec` command in ``<failure.ys>``. This is especially useful
|
||||
when Yosys is outputting an invalid design, or when some other tool is
|
||||
incompatible with the design. Be sure to use the ``exec -expect-*`` options so
|
||||
that the pass/fail can be detected correctly. Multiple calls to `exec` can be
|
||||
made, or even entire shell scripts:
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
|
||||
exec -expect-return 1 --bash <script.sh>
|
||||
|
||||
Our final failure we can use with `bugpoint` is one returned by a wrapper
|
||||
process, such as ``valgrind`` or ``timeout``. In this case you will be calling
|
||||
something like ``<wrapper> yosys -s <failure.ys> design.il``. Here, Yosys is
|
||||
run under a wrapper process which checks for some failure state, like a memory
|
||||
leak or excessive runtime.
|
||||
|
||||
|
||||
How do I use bugpoint?
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
At this point you should have:
|
||||
|
||||
1. either an RTLIL file containing the design to minimize (referred to here as
|
||||
``design.il``), or a Yosys script, ``<load.ys>``, which loads it; and
|
||||
2. a Yosys script, ``<failure.ys>``, which produces the failure and returns a
|
||||
non-zero return status.
|
||||
|
||||
Now call ``yosys -qq -s <failure.ys> design.il`` and take note of the error(s)
|
||||
that get printed. A template script, ``<bugpoint.ys>``, is provided here which
|
||||
you can use. Make sure to configure it with the correct filenames and use only
|
||||
one of the methods to load the design. Fill in the ``-grep`` option with the
|
||||
error message printed just before. If you are using a wrapper process for your
|
||||
failure state, add the ``-runner "<wrapper>"`` option to the `bugpoint` call.
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
:caption: ``<bugpoint.ys>`` template script
|
||||
|
||||
# Load design
|
||||
read_rtlil design.il
|
||||
## OR
|
||||
script <load.ys>
|
||||
|
||||
# Call bugpoint with failure
|
||||
bugpoint -script <failure.ys> -grep "<string>"
|
||||
|
||||
# Save minimized design
|
||||
write_rtlil min.il
|
||||
|
||||
The ``-grep`` option is used to search the log file generated by the Yosys under
|
||||
test. If the error message is generated by something else, such as a wrapper
|
||||
process or compiler sanitizer, then you should instead use ``-err_grep``. For
|
||||
an OS error, like a SEGFAULT, you can also use ``-expect-return`` to check the
|
||||
error code returned.
|
||||
|
||||
.. note::
|
||||
|
||||
Checking the error message or return status is optional, but highly
|
||||
recommended. `bugpoint` can quite easily introduce bugs by creating
|
||||
malformed designs that commands were not intended to handle. By having some
|
||||
way to check the error, `bugpoint` can ensure that it is the *right* error
|
||||
being reproduced. This is even more important when ``<failure.ys>`` contains
|
||||
more than one command.
|
||||
|
||||
By default, `bugpoint` is able to remove any part of the design. In order to
|
||||
keep certain parts, for instance because you already know they are related to
|
||||
the failure, you can use the ``bugpoint_keep`` attribute. This can be done with
|
||||
``(* bugpoint_keep *)`` in Verilog, ``attribute \bugpoint_keep 1`` in RTLIL, or
|
||||
``setattr -set bugpoint_keep 1 [selection]`` from a Yosys script. It is also
|
||||
possible to limit `bugpoint` to only removing certain *kinds* of objects, such
|
||||
as only removing entire modules or cells (instances of modules). For more about
|
||||
the options available, check ``help bugpoint`` or :cmd:title:`bugpoint`.
|
||||
|
||||
In some situations, it may also be helpful to use `setenv` before `bugpoint` to
|
||||
set environment variables for the spawned processes. An example of this is
|
||||
``setenv UBSAN_OPTIONS halt_on_error=1`` for where you are trying to raise an
|
||||
error on undefined behaviour but only want the child process to halt on error.
|
||||
|
||||
.. note::
|
||||
|
||||
Using `setenv` in this way may or may not affect the current process. For
|
||||
instance the ``UBSAN_OPTIONS halt_on_error`` here only affects child
|
||||
processes, as does the :doc:`Yosys environment variable</appendix/env_vars>`
|
||||
``ABC`` because they are only read on start-up. While others, such as
|
||||
``YOSYS_NOVERIFIC`` and ``HOME``, are evaluated each time they are used.
|
||||
|
||||
Once you have finished configuration, you can now run ``yosys <bugpoint.ys>``.
|
||||
The first thing `bugpoint` will do is test the input design fails. If it
|
||||
doesn't, make sure you are using the right ``yosys`` executable; unless the
|
||||
``-yosys`` option is provided, it will use whatever the shell defaults to, *not*
|
||||
the current ``yosys``. If you are using the ``-runner`` option, try replacing
|
||||
the `bugpoint` command with ``write_rtlil test.il`` and then on a new line,
|
||||
``!<wrapper> yosys -s <failure.ys> test.il`` to check it works as expected and
|
||||
returns a non-zero status.
|
||||
|
||||
.. seealso::
|
||||
|
||||
For more on script parsing and the use of ``!``, check out
|
||||
:ref:`getting_started/scripting_intro:script parsing`.
|
||||
|
||||
Depending on the size of your design, and the length of your ``<failure.ys>``,
|
||||
`bugpoint` may take some time; remember, it will run ``yosys -s <failure.ys>``
|
||||
on each iteration of the design. The bigger the design, the more iterations.
|
||||
The longer the ``<failure.ys>``, the longer each iteration will take. As the
|
||||
design shrinks and `bugpoint` converges, each iteration should take less and
|
||||
less time. Once all simplifications are exhausted and there are no more objects
|
||||
that can be removed, the script will continue and the minimized design can be
|
||||
saved.
|
||||
|
||||
|
||||
What do I do with the minimized design?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
First off, check the minimized design still fails. This is especially important
|
||||
if you're not using `write_rtlil` to output the minimized design. For example,
|
||||
if you ran :ref:`bugpoint_script` below, then calling ``yosys -s <failure.ys>
|
||||
min.v`` should still fail in the same way.
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
:caption: example `bugpoint` minimizer
|
||||
:name: bugpoint_script
|
||||
|
||||
read_verilog design.v
|
||||
bugpoint -script <failure.ys>
|
||||
write_verilog min.v
|
||||
|
||||
The `write_rtlil` command is generally more reliable, since `bugpoint` will have
|
||||
run that exact code through the failing script. Other ``write_*`` commands
|
||||
convert from the RTLIL and then back again during the ``read_*`` which can
|
||||
result in differences which mean the design no longer fails.
|
||||
|
||||
.. note::
|
||||
|
||||
Simply calling Yosys with the output of ``write_*``, as in ``yosys -s
|
||||
<failure.ys> min.v``, does not guarantee that the corresponding ``read_*``
|
||||
will be used. For more about this, refer to
|
||||
:doc:`/using_yosys/more_scripting/load_design`, or load the design explicitly
|
||||
with ``yosys -p 'read_verilog min.v' -s <failure.ys>``.
|
||||
|
||||
Once you've verified the failure still happens, check out
|
||||
:ref:`using_yosys/bugpoint:identifying issues` for more on what to do next.
|
||||
|
||||
|
||||
Minimizing Verilog designs
|
||||
--------------------------
|
||||
|
||||
.. seealso::
|
||||
|
||||
This section is not specific to Yosys, so feel free to use another guide such
|
||||
as Stack Overflow's `How to create a Minimal, Reproducible Example`_.
|
||||
|
||||
Be sure to check any errors or warnings for messages that might identify source
|
||||
lines or object names that might be causing the failure, and back up your source
|
||||
code before modifying it. If you have multiple source files, you should start
|
||||
by reducing them down to a single file. If a specific file is failing to read,
|
||||
try removing everything else and just focus on that one. If your source uses
|
||||
the ``include`` directive, replace it with the contents of the file referenced.
|
||||
|
||||
Unlike RTLIL designs where we can use `bugpoint`, Yosys does not provide any
|
||||
tools for minimizing Verilog designs. Instead, you should use an external tool
|
||||
like `C-Reduce`_ (with the ``--not-c`` flag) or `sv-bugpoint`_.
|
||||
|
||||
.. _C-Reduce: https://github.com/csmith-project/creduce
|
||||
.. _sv-bugpoint: https://github.com/antmicro/sv-bugpoint
|
||||
|
||||
C-Reduce
|
||||
~~~~~~~~
|
||||
|
||||
As a very brief overview for using C-Reduce, you want your failing source design
|
||||
(``test.v``), and some shell script which checks for the error being
|
||||
investigated (``test.sh``). Below is an :ref:`egtest` which uses `logger` and
|
||||
the ``-expect error "<string>" 1`` option to perform a similar role to
|
||||
``bugpoint -grep``, along with ``verilator`` to lint the code and make sure it
|
||||
is still valid.
|
||||
|
||||
.. code-block:: bash
|
||||
:caption: Example test.sh for C-Reduce
|
||||
:name: egtest
|
||||
|
||||
#!/bin/bash
|
||||
verilator --lint-only test.v &&/
|
||||
yosys -p 'logger -expect error "unsupported" 1; read_verilog test.v'
|
||||
|
||||
.. code-block:: verilog
|
||||
:caption: input test.v
|
||||
|
||||
module top(input clk, a, b, c, output x, y, z);
|
||||
always @(posedge clk) begin
|
||||
if (a == 1'b1)
|
||||
$stop;
|
||||
end
|
||||
assign x = a;
|
||||
assign y = a ^ b;
|
||||
assign z = c;
|
||||
endmodule
|
||||
|
||||
In this example ``read_verilog test.v`` is giving an error message that contains
|
||||
the string "unsupported" because the ``$stop`` system task is only supported in
|
||||
``initial`` blocks. By calling ``creduce ./test.sh test.v --not-c`` we can
|
||||
minimize the design to just the failing code, while still being valid Verilog.
|
||||
|
||||
.. code-block:: verilog
|
||||
:caption: output test.v
|
||||
|
||||
module a;
|
||||
always begin $stop;
|
||||
end endmodule
|
||||
|
||||
|
||||
sv-bugpoint
|
||||
~~~~~~~~~~~
|
||||
|
||||
sv-bugpoint works quite similarly to C-Reduce, except it requires an output
|
||||
directory to be provided and the check script needs to accept the target file as
|
||||
an input argument: ``sv-bugpoint outDir/ test.sh test.v``
|
||||
|
||||
.. code-block:: bash
|
||||
:caption: Example test.sh for sv-bugpoint
|
||||
|
||||
#!/bin/bash
|
||||
verilator --lint-only $1 &&/
|
||||
yosys -p "logger -expect error \"unsupported\" 1; read_verilog $1"
|
||||
|
||||
Notice that the commands for ``yosys -p`` are now in double quotes (``"``), and
|
||||
the quotes around the error string are escaped (``\"``). This is necessary for
|
||||
the ``$1`` argument subsitution to work correctly.
|
||||
|
||||
|
||||
Doing it manually
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
If for some reason you are unable to use a tool to minimize your code, you can
|
||||
still do it manually. But it can be a time consuming process and requires a lot
|
||||
of iteration. At any point in the process, you can check for anything that is
|
||||
unused or totally disconnected (ports, wires, etc) and remove them. If a
|
||||
specific module is causing the problem, try to set that as the top module
|
||||
instead. Any parameters should have their default values changed to match the
|
||||
failing usage.
|
||||
|
||||
As a rule of thumb, try to split things roughly in half at each step; similar to
|
||||
a "binary search". If you have 10 cells (instances of modules) in your top
|
||||
module, and have no idea what is causing the issue, split them into two groups
|
||||
of 5 cells. For each group of cells, try remove them and see if the failure
|
||||
still happens. If the error still occurs with the first group removed, but
|
||||
disappears when the second group is removed, then the first group can be safely
|
||||
removed. If a module has no more instances, remove it entirely. Repeat this
|
||||
for each remaining group of cells until each group only has 1 cell in it and no
|
||||
more cells can be removed without making the error disappear. You can also
|
||||
repeat this for each module still in your design.
|
||||
|
||||
After minimizing the number of cells, do the same for the process blocks in your
|
||||
top module. And again for any generate blocks and combinational blocks.
|
||||
Remember to check for any ports or signals which are no longer used and remove
|
||||
those too. Any signals which are written but never read can also be removed.
|
||||
|
||||
.. note::
|
||||
|
||||
Depending on where the design is failing, there are some commands which may
|
||||
help in identifying unused objects in the design. `hierarchy` will identify
|
||||
which modules are used and which are not, but check for ``$paramod`` modules
|
||||
before removing unused ones. ``debug clean`` will list all unused wires in
|
||||
each module, as well as unused cells which were automatically generated
|
||||
(giving the line number of the source that generated them). Adding the
|
||||
``-purge`` flag will also include named wires that would normally be ignored
|
||||
by `clean`. Though when there are large numbers of unused wires it is often
|
||||
easier to just delete sections of the code and see what happens.
|
||||
|
||||
Next, try to remove or reduce assignments (``a = b``) and operations (``a +
|
||||
b``). A good place to start is by checking for any wires/registers which are
|
||||
read but never written. Try removing the signal declaration and replacing
|
||||
references to it with ``'0`` or ``'x``. Do this with any constants too. Try to
|
||||
replace strings with numeric values, and wide signals with smaller ones, then
|
||||
see if the error persists.
|
||||
|
||||
Check if there are any operations that you can simplify, like replacing ``a &
|
||||
'0`` with ``'0``. If you have enable or reset logic, try removing it and see if
|
||||
the error still occurs. Try reducing ``if .. else`` and ``case`` blocks to a
|
||||
single case. Even if that doesn't work, you may still be able to remove some
|
||||
paths; start with cases that appear to be unreachable and go from there.
|
||||
|
||||
.. note::
|
||||
|
||||
When sharing code on the `Yosys GitHub`_, please try to keep things in
|
||||
English. Declarations and strings should stick to the letters a-z and
|
||||
numbers 0-9, unless the error is arising because of the names/characters
|
||||
used.
|
||||
|
||||
|
||||
Identifying issues
|
||||
------------------
|
||||
|
||||
When identifying issues, it is quite useful to understand the conditions under
|
||||
which the issue is occurring. While there are occasionally bugs that affect a
|
||||
significant number of designs, Yosys changes are tested on a variety of designs
|
||||
and operating systems which typically catch any such issues before they make it
|
||||
into the main branch. So what is is it about your situation that makes it
|
||||
unusual?
|
||||
|
||||
.. note::
|
||||
|
||||
If you have access to a different platform you could also check if your issue
|
||||
is reproducible there. Some issues may be specific to the platform or build
|
||||
of Yosys.
|
||||
|
||||
Try to match the minimized design back to its original context. Could you
|
||||
achieve the same thing a different way, and if so, does this other method have
|
||||
the same issue? Try to change the design in small ways and see what happens;
|
||||
while `bugpoint` can reduce and simplify a design, it doesn't *change* much.
|
||||
What happens if you change operators, for example a left shift (or `$shl`) to a
|
||||
right shift (or `$shr`)? Try to see if the issue is tied to specific
|
||||
parameters, widths, or values.
|
||||
|
||||
Search `the existing issues`_ and see if someone has already made a bug report.
|
||||
This is where changing the design and finding the limits of what causes the
|
||||
failure really comes in handy. If you're more familiar with how the problem can
|
||||
arise, you may be able to find a related issue more easily. If an issue already
|
||||
exists for one case of the problem but you've found other cases, you can comment
|
||||
on the issue and help get it solved. If there are no existing or related issues
|
||||
already, then check out the steps for
|
||||
:ref:`yosys_internals/extending_yosys/contributing:reporting bugs`.
|
||||
|
||||
.. _the existing issues: https://github.com/YosysHQ/yosys/issues
|
||||
|
||||
.. warning::
|
||||
|
||||
If you are using a fuzzer to find bugs, follow the instructions for
|
||||
:doc:`/yosys_internals/extending_yosys/advanced_bugpoint`. **Do not** open
|
||||
more than one fuzzer generated issue at a time if you can not identify the
|
||||
root cause. If you are found to be doing this, your issues may be closed
|
||||
without further investigation.
|
|
@ -15,3 +15,5 @@ ways Yosys can interact with designs for a deeper investigation.
|
|||
|
||||
synthesis/index
|
||||
more_scripting/index
|
||||
bugpoint
|
||||
verilog
|
||||
|
|
|
@ -311,8 +311,8 @@ cells, as the net-names are usually suppressed in the circuit diagram if they
|
|||
are auto-generated. Note that the output is in the RTLIL representation,
|
||||
described in :doc:`/yosys_internals/formats/rtlil_rep`.
|
||||
|
||||
Interactive Design Investigation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Design Investigation
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yosys can also be used to investigate designs (or netlists created from other
|
||||
tools).
|
||||
|
@ -323,10 +323,10 @@ tools).
|
|||
design into an equivalent design that is easier to analyse.
|
||||
- Commands such as `eval` and `sat` can be used to investigate the behavior of
|
||||
the circuit.
|
||||
- :doc:`/cmd/show`.
|
||||
- :doc:`/cmd/dump`.
|
||||
- :doc:`/cmd/add` and :doc:`/cmd/delete` can be used to modify and reorganize a
|
||||
design dynamically.
|
||||
- :cmd:title:`show`.
|
||||
- :cmd:title:`dump`.
|
||||
- :cmd:title:`add` and :cmd:title:`delete` can be used to modify and reorganize
|
||||
a design dynamically.
|
||||
|
||||
The code used is included in the Yosys code base under
|
||||
|code_examples/scrambler|_.
|
||||
|
@ -358,7 +358,7 @@ reorganizing a module in Yosys and checking the resulting circuit.
|
|||
.. figure:: /_images/code_examples/scrambler/scrambler_p02.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
Analyzing the resulting circuit with :doc:`/cmd/eval`:
|
||||
Analyzing the resulting circuit with :cmd:title:`eval`:
|
||||
|
||||
.. todo:: replace inline code
|
||||
|
||||
|
|
|
@ -1,11 +1,107 @@
|
|||
Loading a design
|
||||
~~~~~~~~~~~~~~~~
|
||||
----------------
|
||||
|
||||
keyword: Frontends
|
||||
.. _input files:
|
||||
|
||||
- :doc:`/cmd/read_verilog`
|
||||
Input files on the command line
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. todo:: include ``read_verilog <<EOF``, also other methods of loading designs
|
||||
- guesses frontend based on file extension
|
||||
|
||||
+ ``.v`` -> ``read -vlog2k``
|
||||
+ ``.sv`` -> ``read -sv``
|
||||
+ ``.vhd`` and ``.vhdl`` -> ``read -vhdl``
|
||||
+ ``.blif`` and ``.eblif`` -> `read_blif`
|
||||
+ ``.json`` -> `read_json`
|
||||
+ ``.il`` -> `read_rtlil` (direct textual representation of Yosys internal
|
||||
state)
|
||||
|
||||
- command line also supports
|
||||
|
||||
+ ``.ys`` -> `script`
|
||||
+ ``.tcl`` -> `tcl`
|
||||
+ ``-`` -> reads stdin and treats it as a script
|
||||
|
||||
The `read` command
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- standard method of loading designs
|
||||
- also for defining macros and include directories
|
||||
- uses `verific` command if available
|
||||
|
||||
+ ``-verific`` and ``-noverific`` options to enforce with/without Verific
|
||||
+ check ``help read`` for more about the options available and the filetypes
|
||||
supported
|
||||
+ elaborate designs with ``verific -import [options] <top>`` (or use
|
||||
`hierarchy`)
|
||||
|
||||
- fallback to `read_verilog` with ``-defer`` option
|
||||
|
||||
+ does not compile design until `hierarchy` command as discussed in
|
||||
:doc:`/getting_started/example_synth`
|
||||
+ more similar to `verific` behaviour
|
||||
|
||||
- ``read -define`` et al mapped to `verific` or `verilog_defines`
|
||||
- similarly, ``read -incdir`` et al mapped to `verific` or `verilog_defaults`
|
||||
|
||||
.. note::
|
||||
|
||||
The Verific frontend for Yosys, which provides the :cmd:ref:`verific`
|
||||
command, requires Yosys to be built with Verific. For full functionality,
|
||||
custom modifications to the Verific source code from YosysHQ are required,
|
||||
but limited useability can be achieved with some stock Verific builds. Check
|
||||
:doc:`/yosys_internals/extending_yosys/build_verific` for more.
|
||||
|
||||
.. _Frontend:
|
||||
|
||||
Yosys frontends
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- :doc:`/cmd/index_frontends`
|
||||
- typically start with ``read_``
|
||||
- built-in support for heredocs
|
||||
|
||||
+ in-line code with ``<<EOT``
|
||||
+ can use any eot marker, but EOT (End-of-Transmission) and EOF
|
||||
(End-of-File) are most common
|
||||
|
||||
- built-in support for reading multiple files in the same command
|
||||
|
||||
+ executed as multiple successive calls to the frontend
|
||||
|
||||
- compatible with ``-f`` command line option, e.g. ``yosys -f verilog
|
||||
design.txt`` will use the `read_verilog` frontend with the input file
|
||||
``design.txt``
|
||||
|
||||
- `verific` and `read` commands are technically not 'Frontends', but their
|
||||
behaviour is kept in sync
|
||||
|
||||
.. note::
|
||||
|
||||
'Frontend' here means that the command is implemented as a sub-class of
|
||||
``RTLIL::Frontend``, as opposed to the usual ``RTLIL::Pass``.
|
||||
|
||||
.. todo:: link note to as-yet non-existent section on ``RTLIL::Pass`` under
|
||||
:doc:`/yosys_internals/extending_yosys/index`
|
||||
|
||||
The `read_verilog` command
|
||||
""""""""""""""""""""""""""
|
||||
|
||||
- :cmd:title:`read_verilog`; also
|
||||
|
||||
+ :cmd:title:`verilog_defaults`,
|
||||
+ :cmd:title:`verilog_defines`, and
|
||||
+ :cmd:title:`read_verilog_file_list`
|
||||
|
||||
- supports most of Verilog-2005
|
||||
- limited support for SystemVerilog
|
||||
- some non-standard features/extensions for enabling formal verification
|
||||
- please do not rely on `read_verilog` for syntax checking
|
||||
|
||||
+ recommend using a simulator (for example Icarus Verilog) or linting with
|
||||
another tool (such as verilator) first
|
||||
|
||||
.. todo:: figure out this example code block
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
|
||||
|
@ -24,25 +120,38 @@ keyword: Frontends
|
|||
read_verilog file6.v
|
||||
verilog_defaults -pop
|
||||
|
||||
.. todo:: more info on other ``read_*`` commands, also is this the first time we
|
||||
mention verific?
|
||||
Other built-in ``read_*`` commands
|
||||
""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. note::
|
||||
- :cmd:title:`read_rtlil`
|
||||
- :cmd:title:`read_aiger`
|
||||
- :cmd:title:`read_blif`
|
||||
- :cmd:title:`read_json`
|
||||
- :cmd:title:`read_liberty`
|
||||
- :cmd:title:`read_xaiger2`
|
||||
|
||||
The Verific frontend for Yosys, which provides the :cmd:ref:`verific`
|
||||
command, requires Yosys to be built with Verific. For full functionality,
|
||||
custom modifications to the Verific source code from YosysHQ are required,
|
||||
but limited useability can be achieved with some stock Verific builds. Check
|
||||
:doc:`/yosys_internals/extending_yosys/build_verific` for more.
|
||||
.. TODO:: does `write_file` count?
|
||||
|
||||
Others:
|
||||
Externally maintained plugins
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- :doc:`/cmd/read`
|
||||
- `GHDL plugin`_ for VHDL
|
||||
- :doc:`/cmd/read_rtlil` (direct textual representation of Yosys internal state)
|
||||
- :doc:`/cmd/read_aiger`
|
||||
- :doc:`/cmd/read_blif`
|
||||
- :doc:`/cmd/read_json`
|
||||
- :doc:`/cmd/read_liberty`
|
||||
- `GHDL plugin`_ for VHDL (check ``help ghdl``)
|
||||
- `yosys-slang plugin`_ for more comprehensive SystemVerilog support (check
|
||||
``help read_slang``)
|
||||
|
||||
+ yosys-slang is implemented as a '`Frontend`_,' with all the built-in support
|
||||
that entails
|
||||
|
||||
.. _GHDL plugin: https://github.com/ghdl/ghdl-yosys-plugin
|
||||
.. _yosys-slang plugin: https://github.com/povik/yosys-slang
|
||||
|
||||
- both plugins above are included in `OSS CAD Suite`_
|
||||
|
||||
.. _OSS CAD Suite: https://github.com/YosysHQ/oss-cad-suite-build
|
||||
|
||||
- `Synlig`_, which uses `Surelog`_ to provide SystemVerilog support
|
||||
|
||||
+ also implemented as a '`Frontend`_'
|
||||
|
||||
.. _Synlig: https://github.com/chipsalliance/synlig
|
||||
.. _Surelog: https://github.com/chipsalliance/Surelog
|
||||
|
|
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
-------
|
||||
|
|
|
@ -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
|
||||
|
@ -233,7 +233,5 @@ Other optimizations
|
|||
|
||||
.. todo:: more on the other optimizations
|
||||
|
||||
- :doc:`/cmd/wreduce`
|
||||
- :doc:`/cmd/peepopt`
|
||||
- :doc:`/cmd/share`
|
||||
- Check :doc:`/cmd/index_passes_opt` for more.
|
||||
- `abc` and `abc9`, see also: :doc:`abc`.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
Notes on Verilog support in Yosys
|
||||
=================================
|
||||
|
||||
.. TODO:: how much of this is specific to the read_verilog and should be in :doc:`/yosys_internals/flow/verilog_frontend`?
|
||||
|
||||
Unsupported Verilog-2005 Features
|
||||
---------------------------------
|
||||
|
||||
|
@ -96,7 +94,7 @@ Verilog Attributes and non-standard features
|
|||
- The ``keep_hierarchy`` attribute on cells and modules keeps the `flatten`
|
||||
command from flattening the indicated cells and modules.
|
||||
|
||||
- The `gate_cost_equivalent` attribute on a module can be used to specify
|
||||
- The ``gate_cost_equivalent`` attribute on a module can be used to specify
|
||||
the estimated cost of the module as a number of basic gate instances. See
|
||||
the help message of command `keep_hierarchy` which interprets this
|
||||
attribute.
|
|
@ -0,0 +1,271 @@
|
|||
Identifying the root cause of bugs
|
||||
==================================
|
||||
|
||||
This document references Yosys internals and is intended for people interested
|
||||
in solving or investigating Yosys bugs. This also applies if you are using a
|
||||
fuzzing tool; fuzzers have a tendency to find many variations of the same bug,
|
||||
so identifying the root cause is important for avoiding issue spam.
|
||||
|
||||
If you're familiar with C/C++, you might try to have a look at the source code
|
||||
of the command that's failing. Even if you can't fix the problem yourself, it
|
||||
can be very helpful for anyone else investigating if you're able to identify
|
||||
where the issue is arising.
|
||||
|
||||
|
||||
Finding the failing command
|
||||
---------------------------
|
||||
|
||||
Using the ``-L`` flag can help here, allowing you to specify a file to log to,
|
||||
such as ``yosys -L out.log -s script.ys``. Most commands will print a header
|
||||
message when they begin; something like ``2.48. Executing HIERARCHY pass
|
||||
(managing design hierarchy).`` The last header message will usually be the
|
||||
failing command. There are some commands which don't print a header message, so
|
||||
you may want to add ``echo on`` to the start of your script. The `echo` command
|
||||
echoes each command executed, along with any arguments given to it. For the
|
||||
`hierarchy` example above this might be ``yosys> hierarchy -check``.
|
||||
|
||||
.. note::
|
||||
|
||||
It may also be helpful to use the `log` command to add messages which you can
|
||||
then search for either in the terminal or the logfile. This can be quite
|
||||
useful if your script contains script-passes, like the
|
||||
:doc:`/using_yosys/synthesis/synth`, which call many sub-commands and you're
|
||||
not sure exactly which script-pass is calling the failing command.
|
||||
|
||||
|
||||
Minimizing scripts
|
||||
------------------
|
||||
|
||||
.. warning::
|
||||
|
||||
This section is intended as **advanced usage**, and generally not necessary
|
||||
for normal bug reports.
|
||||
|
||||
If you're using a command line prompt, such as ``yosys -p 'synth_xilinx' -o
|
||||
design.json design.v``, consider converting it to a script. It's generally much
|
||||
easier to iterate over changes to a script in a file rather than one on the
|
||||
command line, as well as being better for sharing with others.
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
:caption: example script, ``script.ys``, for prompt ``yosys -p 'synth_xilinx' -o design.json design.v``
|
||||
|
||||
read_verilog design.v
|
||||
synth_xilinx
|
||||
write_json design.json
|
||||
|
||||
Next up you want to remove everything *after* the error occurs. If your final
|
||||
command calls sub-commands, replace it with its contents first. In the case of
|
||||
the :doc:`/using_yosys/synthesis/synth`, as well as certain other script-passes,
|
||||
you can use the ``-run`` option to simplify this. For example we can replace
|
||||
``synth -top <top> -lut`` with the :ref:`replace_synth`. The options ``-top
|
||||
<top> -lut`` can be provided to each `synth` step, or to just the step(s) where
|
||||
it is relevant, as done here.
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
:caption: example replacement script for `synth` command
|
||||
:name: replace_synth
|
||||
|
||||
synth -top <top> -run :coarse
|
||||
synth -lut -run coarse:fine
|
||||
synth -lut -run fine:check
|
||||
synth -run check:
|
||||
|
||||
Say we ran :ref:`replace_synth` and were able to remove the ``synth -run
|
||||
check:`` and still got our error, then we check the log and we see the last
|
||||
thing before the error was ``7.2. Executing MEMORY_MAP pass (converting memories
|
||||
to logic and flip-flops)``. By checking the output of ``yosys -h synth`` (or the
|
||||
`synth` help page) we can see that the `memory_map` pass is called in the
|
||||
``fine`` step. We can then update our script to the following:
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
:caption: example replacement script for `synth` when `memory_map` is failing
|
||||
|
||||
synth -top <top> -run :fine
|
||||
opt -fast -full
|
||||
memory_map
|
||||
|
||||
By giving `synth` the option ``-run :fine``, we are telling it to run from the
|
||||
beginning of the script until the ``fine`` step, where we then give it the exact
|
||||
commands to run. There are some cases where the commands given in the help
|
||||
output are not an exact match for what is being run, but are instead a
|
||||
simplification. If you find that replacing the script-pass with its contents
|
||||
causes the error to disappear, or change, try calling the script-pass with
|
||||
``echo on`` to see exactly what commands are being called and what options are
|
||||
used.
|
||||
|
||||
.. warning::
|
||||
|
||||
Before continuing further, *back up your code*. The following steps can
|
||||
remove context and lead to over-minimizing scripts, hiding underlying issues.
|
||||
Check out :ref:`yosys_internals/extending_yosys/advanced_bugpoint:Why
|
||||
context matters` to learn more.
|
||||
|
||||
When a problem is occurring many steps into a script, minimizing the design at
|
||||
the start of the script isn't always enough to identify the cause of the issue.
|
||||
Each extra step of the script can lead to larger sections of the input design
|
||||
being needed for the specific problem to be preserved until it causes a crash.
|
||||
So to find the smallest possible reproducer it can sometimes be helpful to
|
||||
remove commands prior to the failure point.
|
||||
|
||||
The simplest way to do this is by writing out the design, resetting the current
|
||||
state, and reading back the design:
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
|
||||
write_rtlil <design.il>; design -reset; read_rtlil <design.il>;
|
||||
|
||||
In most cases, this can be inserted immediately before the failing command while
|
||||
still producing the error, allowing you to :ref:`minimize your
|
||||
RTLIL<using_yosys/bugpoint:minimizing rtlil designs with bugpoint>` with the
|
||||
``<design.il>`` output. For our previous example with `memory_map`, if
|
||||
:ref:`map_reset` still gives the same error, then we should now be able to call
|
||||
``yosys design.il -p 'memory_map'`` to reproduce it.
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
:caption: resetting the design immediately before failure
|
||||
:name: map_reset
|
||||
|
||||
synth -top <top> -run :fine
|
||||
opt -fast -full
|
||||
write_rtlil design.il; design -reset; read_rtlil design.il;
|
||||
memory_map
|
||||
|
||||
If that doesn't give the error (or doesn't give the same error), then you should
|
||||
try to move the write/reset/read earlier in the script until it does. If you
|
||||
have no idea where exactly you should put the reset, the best way is to use a
|
||||
"binary search" type approach, reducing the possible options by half after each
|
||||
attempt.
|
||||
|
||||
.. note::
|
||||
|
||||
By default, `write_rtlil` doesn't include platform specific IP blocks and
|
||||
other primitive cell models which are typically loaded with a ``read_verilog
|
||||
-lib`` command at the start of the synthesis script. You may have to
|
||||
duplicate these commands *after* the call to ``design -reset``. It is also
|
||||
possible to write out *everything* with ``select =*; write_rtlil -selected
|
||||
<design.il>``.
|
||||
|
||||
As an example, your script has 16 commands in it before failing on the 17th. If
|
||||
resetting immediately before the 17th doesn't reproduce the error, try between
|
||||
the 8th and 9th (8 is half of the total 16). If that produces the error then
|
||||
you can remove everything before the `read_rtlil` and try reset again in the
|
||||
middle of what's left, making sure to use a different name for the output file
|
||||
so that you don't overwrite what you've already got. If the error isn't
|
||||
produced then you need to go earlier still, so in this case you would do between
|
||||
the 4th and 5th (4 is half of the previous 8). Repeat this until you can't
|
||||
reduce the remaining commands any further.
|
||||
|
||||
A more conservative, but more involved, method is to remove or comment out
|
||||
commands prior to the failing command. Each command, or group of commands, can
|
||||
be disabled one at a time while checking if the error still occurs, eventually
|
||||
giving the smallest subset of commands needed to take the original input through
|
||||
to the error. The difficulty with this method is that depending on your design,
|
||||
some commands may be necessary even if they aren't needed to reproduce the
|
||||
error. For example, if your design includes ``process`` blocks, many commands
|
||||
will fail unless you run the `proc` command. While this approach can do a
|
||||
better job of maintaining context, it is often easier to *recover* the context
|
||||
after the design has been minimized for producing the error. For more on
|
||||
recovering context, checkout
|
||||
:ref:`yosys_internals/extending_yosys/advanced_bugpoint:Why context matters`.
|
||||
|
||||
|
||||
Why context matters
|
||||
-------------------
|
||||
|
||||
Sometimes when a command is raising an error, you're seeing a symptom rather
|
||||
than the underlying issue. It's possible that an earlier command may be putting
|
||||
the design in an invalid state, which isn't picked up until the error is raised.
|
||||
This is particularly true for the pre-packaged
|
||||
:doc:`/using_yosys/synthesis/synth`, which rely on a combination of generic and
|
||||
architecture specific passes. As new features are added to Yosys and more
|
||||
designs are supported, the types of cells output by a pass can grow and change;
|
||||
and sometimes this leads to a mismatch in what a pass is intended to handle.
|
||||
|
||||
If you minimized your script, and removed commands prior to the failure to get a
|
||||
smaller reproducer, try to work backwards and find which commands may have
|
||||
contributed to the design failing. From the minimized design you should have
|
||||
some understanding of the cell or cells which are producing the error; but where
|
||||
did those cells come from? The name and/or type of the cell can often point you
|
||||
in the right direction:
|
||||
|
||||
.. code-block::
|
||||
|
||||
# internal cell types start with a $
|
||||
# lowercase for word-level, uppercase for bit-level
|
||||
$and
|
||||
$_AND_
|
||||
|
||||
# cell types with $__ are typically intermediate cells used in techmapping
|
||||
$__MUL16X16
|
||||
|
||||
# cell types without a $ are either user-defined or architecture specific
|
||||
my_module
|
||||
SB_MAC16
|
||||
|
||||
# object names might give you the name of the pass that created them
|
||||
$procdff$1204
|
||||
$memory\rom$rdmux[0][0][0]$a$1550
|
||||
|
||||
# or even the line number in the Yosys source
|
||||
$auto$muxcover.cc:557:implement_best_cover$2152
|
||||
$auto$alumacc.cc:495:replace_alu$1209
|
||||
|
||||
Try running the unminimized script and search the log for the names of the
|
||||
objects in your minimized design. In the case of cells you can also search for
|
||||
the type of the cell. Remember that calling `stat` will list all the types of
|
||||
cells currently used in the design, and ``select -list =*`` will list the names
|
||||
of of all the current objects. You can add these commands to your script, or
|
||||
use an interactive terminal to run each command individually. Adding them to
|
||||
the script can be more repeatable, but if it takes a long time to run to the
|
||||
point you're interested in then an interactive shell session can give you more
|
||||
flexibility once you reach that point. You can also add a call to the `shell`
|
||||
command at any point in a script to start an interactive session at a given
|
||||
point; allowing you to script any preparation steps, then come back once it's
|
||||
done.
|
||||
|
||||
The ``--dump-design`` option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yosys provides the ``--dump-design`` option (or ``-P`` for short) for dumping
|
||||
the design at specific steps of the script based on the log header. If the last
|
||||
step before an error is ``7.2. Executing MEMORY_MAP pass (converting memories to
|
||||
logic and flip-flops)``, then calling Yosys with ``--dump-design 7.2:bad.il``
|
||||
will save the design *before* this command runs, in the file ``bad.il``.
|
||||
|
||||
It is also possible to use this option multiple times, e.g. ``-P2:hierarchy.il
|
||||
-P7 -P7.2:bad.il``, to get multiple dumps in the same run. This can make it
|
||||
easier to follow the design through each step to find where certain cells or
|
||||
connections are coming from. ``--dump-design ALL`` is also allowed, writing out
|
||||
the design at each log header.
|
||||
|
||||
A worked example
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Say you did all the minimization and found that an error in `synth_xilinx`
|
||||
occurs when a call to ``techmap -map +/xilinx/cells_map.v`` with
|
||||
``MIN_MUX_INPUTS`` defined parses a `$_MUX16_` with all inputs set to ``1'x``.
|
||||
You could fix the bug in ``+/xilinx/cells_map.v``, but that might only solve
|
||||
this one case while leaving other problems that haven't been found yet. So you
|
||||
step through the original script, calling `stat` after each step to find when
|
||||
the `$_MUX16_` is added.
|
||||
|
||||
You find that the `$_MUX16_` is introduced by a call to `muxcover`, but all the
|
||||
inputs are defined, so calling `techmap` now works as expected. From running
|
||||
`bugpoint` with the failing techmap you know that the cell with index ``2297``
|
||||
will fail, so you call ``select top/*$2297`` to limit to just that cell. This
|
||||
can then be saved with ``design -save pre_bug`` or ``write_rtlil -selected
|
||||
pre_bug.il``, so that you don't have to re-run all the earlier steps to get back
|
||||
here.
|
||||
|
||||
Next you step through the remaining commands and call `dump` after each to find
|
||||
when the inputs are disconnected. You find that ``opt -full`` has optimized
|
||||
away portions of the circuit, leading to `opt_expr` setting the undriven mux
|
||||
inputs to ``x``, but failing to remove the now unnecessary `$_MUX16_`. Now
|
||||
you've identified a problem in `opt_expr` that affects all of the wide muxes,
|
||||
and could happen in any synthesis flow, not just `synth_xilinx`.
|
||||
|
||||
.. seealso::
|
||||
|
||||
This example is taken from `YosysHQ/yosys#4590
|
||||
<https://github.com/YosysHQ/yosys/issues/4590>`_ and can be reproduced with a
|
||||
version of Yosys between 0.45 and 0.51.
|
|
@ -7,7 +7,7 @@ Contributing to Yosys
|
|||
|CONTRIBUTING|_ file.
|
||||
|
||||
.. |CONTRIBUTING| replace:: :file:`CONTRIBUTING.md`
|
||||
.. _CONTRIBUTING: https://github.com/YosysHQ/yosys/CONTRIBUTING.md
|
||||
.. _CONTRIBUTING: https://github.com/YosysHQ/yosys/blob/main/CONTRIBUTING.md
|
||||
|
||||
Coding Style
|
||||
------------
|
||||
|
@ -42,3 +42,137 @@ for implicit type casts, always use ``GetSize(foobar)`` instead of
|
|||
``foobar.size()``. (``GetSize()`` is defined in :file:`kernel/yosys.h`)
|
||||
|
||||
Use range-based for loops whenever applicable.
|
||||
|
||||
|
||||
Reporting bugs
|
||||
--------------
|
||||
|
||||
- use the `bug report template`_
|
||||
|
||||
.. _bug report template: https://github.com/YosysHQ/yosys/issues/new?template=bug_report.yml
|
||||
|
||||
- short title briefly describing the issue, e.g.
|
||||
|
||||
techmap of wide mux with undefined inputs raises error during synth_xilinx
|
||||
|
||||
+ tells us what's happening ("raises error")
|
||||
+ gives the command affected (`techmap`)
|
||||
+ an overview of the input design ("wide mux with undefined inputs")
|
||||
+ and some context where it was found ("during `synth_xilinx`")
|
||||
|
||||
|
||||
Reproduction Steps
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- ideally a code-block (starting and ending with triple backquotes) containing
|
||||
the minimized design (Verilog or RTLIL), followed by a code-block containing
|
||||
the minimized yosys script OR a command line call to yosys with
|
||||
code-formatting (starting and ending with single backquotes)
|
||||
|
||||
.. code-block:: markdown
|
||||
|
||||
min.v
|
||||
```verilog
|
||||
// minimized Verilog design
|
||||
```
|
||||
|
||||
min.ys
|
||||
```
|
||||
read_verilog min.v
|
||||
# minimum sequence of commands to reproduce error
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
`yosys -p ': minimum sequence of commands;' min.v`
|
||||
|
||||
- alternatively can provide a single code-block which includes the minimized
|
||||
design as a "here document" followed by the sequence of commands which
|
||||
reproduce the error
|
||||
|
||||
+ see :doc:`/using_yosys/more_scripting/load_design` for more on heredocs.
|
||||
|
||||
.. code-block:: markdown
|
||||
|
||||
```
|
||||
read_rtlil <<EOF
|
||||
# minimized RTLIL design
|
||||
EOF
|
||||
# minimum sequence of commands
|
||||
```
|
||||
|
||||
- any environment variables or command line options should also be mentioned
|
||||
- if the problem occurs for a range of values/designs, what is that range
|
||||
- if you're using an external tool, such as ``valgrind``, to detect the issue,
|
||||
what version of that tool are you using and what options are you giving it
|
||||
|
||||
.. warning::
|
||||
|
||||
Please try to avoid the use of any external plugins/tools in the reproduction
|
||||
steps if they are not directly related to the issue being raised. This
|
||||
includes frontend plugins such as GHDL or slang; use `write_rtlil` on the
|
||||
minimized design instead. This also includes tools which provide a wrapper
|
||||
around Yosys such as OpenLane; you should instead minimize your input and
|
||||
reproduction steps to just the Yosys part.
|
||||
|
||||
"Expected Behaviour"
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- if you have a similar design/script that doesn't give the error, include it
|
||||
here as a reference
|
||||
- if the bug is that an error *should* be raised but isn't, are there any other
|
||||
commands with similar error messages
|
||||
|
||||
|
||||
"Actual Behaviour"
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- any error messages go here
|
||||
- any details relevant to the crash that were found with ``--trace`` or
|
||||
``--debug`` flags
|
||||
- if you identified the point of failure in the source code, you could mention
|
||||
it here, or as a comment below
|
||||
|
||||
+ if possible, use a permalink to the source on GitHub
|
||||
+ you can browse the source repository for a certain commit with the failure
|
||||
and open the source file, select the relevant lines (click on the line
|
||||
number for the first relevant line, then while holding shift click on the
|
||||
line number for the last relevant line), click on the ``...`` that appears
|
||||
and select "Copy permalink"
|
||||
+ should look something like
|
||||
``https://github.com/YosysHQ/yosys/blob/<commit_hash>/path/to/file#L139-L147``
|
||||
+ clicking on "Preview" should reveal a code block containing the lines of
|
||||
source specified, with a link to the source file at the given commit
|
||||
|
||||
|
||||
Additional details
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- once you have created the issue, any additional details can be added as a
|
||||
comment on that issue
|
||||
- could include any additional context as to what you were doing when you first
|
||||
encountered the bug
|
||||
- was this issue discovered through the use of a fuzzer
|
||||
- if you've minimized the script, consider including the `bugpoint` script you
|
||||
used, or the original script, e.g.
|
||||
|
||||
.. code-block:: markdown
|
||||
|
||||
Minimized with
|
||||
```
|
||||
read_verilog design.v
|
||||
# original sequence of commands prior to error
|
||||
bugpoint -script <failure.ys> -grep "<string>"
|
||||
write_rtlil min.il
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
Minimized from
|
||||
`yosys -p ': original sequence of commands to produce error;' design.v`
|
||||
|
||||
- if you're able to, it may also help to share the original un-minimized design
|
||||
|
||||
+ if the design is too big for a comment, consider turning it into a `Gist`_
|
||||
|
||||
.. _Gist: https://gist.github.com/
|
||||
|
|
|
@ -11,6 +11,7 @@ of interest for developers looking to customise Yosys builds.
|
|||
extensions
|
||||
build_verific
|
||||
functional_ir
|
||||
advanced_bugpoint
|
||||
contributing
|
||||
test_suites
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -38,5 +38,4 @@ as reference to implement a similar system in any language.
|
|||
formats/index
|
||||
extending_yosys/index
|
||||
techmap
|
||||
verilog
|
||||
hashing
|
||||
|
|
443
docs/util/cmd_documenter.py
Normal file
443
docs/util/cmd_documenter.py
Normal 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,
|
||||
}
|
|
@ -4,20 +4,21 @@ from __future__ import annotations
|
|||
|
||||
import re
|
||||
from typing import cast
|
||||
import warnings
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node, Element, system_message
|
||||
from docutils.nodes import Node, Element, Text
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst.states import Inliner
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.domains import Domain, Index
|
||||
from sphinx.domains.std import StandardDomain
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.roles import XRefRole, SphinxRole
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.directives.code import container_wrapper
|
||||
from sphinx.util.nodes import make_refnode
|
||||
from sphinx.util.docfields import Field
|
||||
from sphinx.util.docfields import Field, GroupedField
|
||||
from sphinx import addnodes
|
||||
|
||||
class TocNode(ObjectDescription):
|
||||
|
@ -31,7 +32,7 @@ class TocNode(ObjectDescription):
|
|||
signode['ids'].append(idx)
|
||||
|
||||
def _object_hierarchy_parts(self, sig_node: addnodes.desc_signature) -> tuple[str, ...]:
|
||||
if 'fullname' not in sig_node:
|
||||
if 'tocname' not in sig_node:
|
||||
return ()
|
||||
|
||||
modname = sig_node.get('module')
|
||||
|
@ -57,16 +58,56 @@ class TocNode(ObjectDescription):
|
|||
return '.'.join(parents + [name])
|
||||
return ''
|
||||
|
||||
class CommandNode(TocNode):
|
||||
class NodeWithOptions(TocNode):
|
||||
"""A custom node with options."""
|
||||
|
||||
doc_field_types = [
|
||||
GroupedField('opts', label='Options', names=('option', 'options', 'opt', 'opts')),
|
||||
]
|
||||
|
||||
def transform_content(self, contentnode: addnodes.desc_content) -> None:
|
||||
"""hack `:option -thing: desc` into a proper option list with yoscrypt highlighting"""
|
||||
newchildren = []
|
||||
for node in contentnode:
|
||||
newnode = node
|
||||
if isinstance(node, nodes.field_list):
|
||||
newnode = nodes.option_list()
|
||||
for field in node:
|
||||
is_option = False
|
||||
option_list_item = nodes.option_list_item()
|
||||
for child in field:
|
||||
if isinstance(child, nodes.field_name):
|
||||
option_group = nodes.option_group()
|
||||
option_list_item += option_group
|
||||
option = nodes.option()
|
||||
option_group += option
|
||||
name, text = child.rawsource.split(' ', 1)
|
||||
is_option = name == 'option'
|
||||
literal = nodes.literal(text=text)
|
||||
literal['classes'] += ['code', 'highlight', 'yoscrypt']
|
||||
literal['language'] = 'yoscrypt'
|
||||
option += literal
|
||||
if not is_option: warnings.warn(f'unexpected option \'{name}\' in {field.source}')
|
||||
elif isinstance(child, nodes.field_body):
|
||||
description = nodes.description()
|
||||
description += child.children
|
||||
option_list_item += description
|
||||
if is_option:
|
||||
newnode += option_list_item
|
||||
newchildren.append(newnode)
|
||||
contentnode.children = newchildren
|
||||
|
||||
class CommandNode(NodeWithOptions):
|
||||
"""A custom node that describes a command."""
|
||||
|
||||
name = 'cmd'
|
||||
required_arguments = 1
|
||||
|
||||
option_spec = {
|
||||
option_spec = NodeWithOptions.option_spec.copy()
|
||||
option_spec.update({
|
||||
'title': directives.unchanged,
|
||||
'tags': directives.unchanged
|
||||
}
|
||||
})
|
||||
|
||||
def handle_signature(self, sig, signode: addnodes.desc_signature):
|
||||
signode['fullname'] = sig
|
||||
|
@ -93,6 +134,46 @@ class CommandNode(TocNode):
|
|||
idx,
|
||||
0))
|
||||
|
||||
class CommandUsageNode(NodeWithOptions):
|
||||
"""A custom node that describes command usages"""
|
||||
|
||||
name = 'cmdusage'
|
||||
|
||||
option_spec = NodeWithOptions.option_spec
|
||||
option_spec.update({
|
||||
'usage': directives.unchanged,
|
||||
})
|
||||
|
||||
def handle_signature(self, sig: str, signode: addnodes.desc_signature):
|
||||
parts = sig.split('::')
|
||||
if len(parts) > 2: parts.pop(0)
|
||||
use = parts[-1]
|
||||
signode['fullname'] = '::'.join(parts)
|
||||
usage = self.options.get('usage', use)
|
||||
if usage:
|
||||
signode['tocname'] = usage
|
||||
signode += addnodes.desc_name(text=usage)
|
||||
return signode['fullname']
|
||||
|
||||
def add_target_and_index(
|
||||
self,
|
||||
name: str,
|
||||
sig: str,
|
||||
signode: addnodes.desc_signature
|
||||
) -> None:
|
||||
idx = ".".join(name.split("::"))
|
||||
signode['ids'].append(idx)
|
||||
if 'noindex' not in self.options:
|
||||
tocname: str = signode.get('tocname', name)
|
||||
objs = self.env.domaindata[self.domain]['objects']
|
||||
# (name, sig, typ, docname, anchor, prio)
|
||||
objs.append((name,
|
||||
tocname,
|
||||
type(self).name,
|
||||
self.env.docname,
|
||||
idx,
|
||||
1))
|
||||
|
||||
class PropNode(TocNode):
|
||||
name = 'prop'
|
||||
fieldname = 'props'
|
||||
|
@ -393,7 +474,7 @@ class TagIndex(Index):
|
|||
lis.append((
|
||||
dispname, 0, docname,
|
||||
anchor,
|
||||
docname, '', typ
|
||||
'', '', ''
|
||||
))
|
||||
ret = [(k, v) for k, v in sorted(content.items())]
|
||||
|
||||
|
@ -432,18 +513,19 @@ class CommandIndex(Index):
|
|||
Qualifier and description are not rendered e.g. in LaTeX output.
|
||||
"""
|
||||
|
||||
content = {}
|
||||
content: dict[str, list[tuple]] = {}
|
||||
items = ((name, dispname, typ, docname, anchor)
|
||||
for name, dispname, typ, docname, anchor, prio
|
||||
in self.domain.get_objects()
|
||||
if typ == self.name)
|
||||
items = sorted(items, key=lambda item: item[0])
|
||||
for name, dispname, typ, docname, anchor in items:
|
||||
title = self.domain.data['obj2title'].get(name)
|
||||
lis = content.setdefault(self.shortname, [])
|
||||
lis.append((
|
||||
dispname, 0, docname,
|
||||
anchor,
|
||||
'', '', typ
|
||||
'', '', title
|
||||
))
|
||||
ret = [(k, v) for k, v in sorted(content.items())]
|
||||
|
||||
|
@ -507,16 +589,27 @@ class PropIndex(TagIndex):
|
|||
|
||||
return (ret, True)
|
||||
|
||||
class TitleRefRole(XRefRole):
|
||||
"""XRefRole used which has the cmd title as the displayed text."""
|
||||
pass
|
||||
|
||||
class OptionRole(SphinxRole):
|
||||
def run(self) -> tuple[list[Node], list]:
|
||||
return self.inliner.interpreted(self.rawtext, self.text, 'yoscrypt', self.lineno)
|
||||
|
||||
class CommandDomain(Domain):
|
||||
name = 'cmd'
|
||||
label = 'Yosys commands'
|
||||
|
||||
roles = {
|
||||
'ref': XRefRole()
|
||||
'ref': XRefRole(),
|
||||
'title': TitleRefRole(),
|
||||
'option': OptionRole(),
|
||||
}
|
||||
|
||||
directives = {
|
||||
'def': CommandNode,
|
||||
'usage': CommandUsageNode,
|
||||
}
|
||||
|
||||
indices = {
|
||||
|
@ -553,7 +646,15 @@ class CommandDomain(Domain):
|
|||
qual_name = match[0][2]
|
||||
title = self.data['obj2title'].get(qual_name, targ)
|
||||
|
||||
return make_refnode(builder,fromdocname,todocname,
|
||||
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} ")
|
||||
|
@ -592,10 +693,18 @@ class CellDomain(CommandDomain):
|
|||
|
||||
def autoref(name, rawtext: str, text: str, lineno, inliner: Inliner,
|
||||
options=None, content=None):
|
||||
role = 'cell:ref' if text[0] == '$' else 'cmd:ref'
|
||||
if text.startswith("help ") and text.count(' ') == 1:
|
||||
_, cmd = text.split(' ', 1)
|
||||
text = f'{text} <{cmd}>'
|
||||
words = text.split(' ')
|
||||
if len(words) == 2 and words[0] == "help":
|
||||
IsLinkable = True
|
||||
thing = words[1]
|
||||
else:
|
||||
IsLinkable = len(words) == 1 and words[0][0] != '-'
|
||||
thing = words[0]
|
||||
if IsLinkable:
|
||||
role = 'cell:ref' if thing[0] == '$' else 'cmd:ref'
|
||||
text = f'{text} <{thing}>'
|
||||
else:
|
||||
role = 'yoscrypt'
|
||||
return inliner.interpreted(rawtext, text, role, lineno)
|
||||
|
||||
def setup(app: Sphinx):
|
||||
|
@ -622,4 +731,7 @@ def setup(app: Sphinx):
|
|||
|
||||
app.add_role('autoref', autoref)
|
||||
|
||||
return {'version': '0.2'}
|
||||
return {
|
||||
'version': '0.3',
|
||||
'parallel_read_safe': False,
|
||||
}
|
|
@ -1616,7 +1616,7 @@ struct VerificSvaImporter
|
|||
inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION ||
|
||||
(mode_cover && (
|
||||
inst->Type() == PRIM_SVA_OVERLAPPED_FOLLOWED_BY ||
|
||||
inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION)))
|
||||
inst->Type() == PRIM_SVA_NON_OVERLAPPED_FOLLOWED_BY)))
|
||||
{
|
||||
Net *antecedent_net = inst->GetInput1();
|
||||
Net *consequent_net = inst->GetInput2();
|
||||
|
|
|
@ -518,10 +518,13 @@ public:
|
|||
if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($check)))
|
||||
queue.emplace_back(cell);
|
||||
}
|
||||
for (auto wire : module->wires()) {
|
||||
if (wire->port_input)
|
||||
// we are relying here on unsorted pools iterating last-in-first-out
|
||||
for (auto riter = module->ports.rbegin(); riter != module->ports.rend(); ++riter) {
|
||||
auto *wire = module->wire(*riter);
|
||||
if (wire && wire->port_input) {
|
||||
factory.add_input(wire->name, ID($input), Sort(wire->width));
|
||||
if (wire->port_output) {
|
||||
}
|
||||
if (wire && wire->port_output) {
|
||||
auto &output = factory.add_output(wire->name, ID($output), Sort(wire->width));
|
||||
output.set_value(enqueue(DriveChunk(DriveChunkWire(wire, 0, wire->width))));
|
||||
}
|
||||
|
|
34
kernel/io.cc
34
kernel/io.cc
|
@ -405,37 +405,9 @@ std::string unescape_format_string(std::string_view fmt)
|
|||
|
||||
static std::string string_view_stringf(std::string_view spec, ...)
|
||||
{
|
||||
std::string fmt(spec);
|
||||
char format_specifier = fmt[fmt.size() - 1];
|
||||
switch (format_specifier) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X': {
|
||||
// Strip any length modifier off `fmt`
|
||||
std::string long_fmt;
|
||||
for (size_t i = 0; i + 1 < fmt.size(); ++i) {
|
||||
char ch = fmt[i];
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
|
||||
break;
|
||||
}
|
||||
long_fmt.push_back(ch);
|
||||
}
|
||||
// Add `lld` or whatever
|
||||
long_fmt += "ll";
|
||||
long_fmt.push_back(format_specifier);
|
||||
fmt = long_fmt;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, spec);
|
||||
std::string result = vstringf(fmt.c_str(), ap);
|
||||
std::string result = vstringf(std::string(spec).c_str(), ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
@ -464,7 +436,7 @@ void format_emit_long_long(std::string &result, std::string_view spec, int *dyna
|
|||
{
|
||||
if (spec == "%d") {
|
||||
// Format checking will have guaranteed num_dynamic_ints == 0.
|
||||
result += std::to_string(arg);
|
||||
result += std::to_string(static_cast<int>(arg));
|
||||
return;
|
||||
}
|
||||
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
|
||||
|
@ -475,7 +447,7 @@ void format_emit_unsigned_long_long(std::string &result, std::string_view spec,
|
|||
{
|
||||
if (spec == "%u") {
|
||||
// Format checking will have guaranteed num_dynamic_ints == 0.
|
||||
result += std::to_string(arg);
|
||||
result += std::to_string(static_cast<unsigned int>(arg));
|
||||
return;
|
||||
}
|
||||
if (spec == "%c") {
|
||||
|
|
|
@ -62,7 +62,7 @@ enum ConversionSpecifier : uint8_t
|
|||
CONVSPEC_UNSIGNED_INT,
|
||||
// Consumes a "double"
|
||||
CONVSPEC_DOUBLE,
|
||||
// Consumes a "const char*"
|
||||
// Consumes a "const char*" or other string type
|
||||
CONVSPEC_CHAR_PTR,
|
||||
// Consumes a "void*"
|
||||
CONVSPEC_VOID_PTR,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
150
kernel/log_help.cc
Normal file
150
kernel/log_help.cc
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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() const {
|
||||
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);
|
||||
add_content("option", text, location);
|
||||
return back();
|
||||
}
|
||||
|
||||
#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() const
|
||||
{
|
||||
for (auto &content : _root_listing) {
|
||||
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) {
|
||||
log_pass_str(text.body, 2);
|
||||
log("\n");
|
||||
}
|
||||
} else {
|
||||
log_pass_str(content.body, 0);
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
}
|
128
kernel/log_help.h
Normal file
128
kernel/log_help.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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(string type, string body, source_location location) {
|
||||
_content.push_back({type, body, location});
|
||||
}
|
||||
|
||||
bool has_content() const { return _content.size() != 0; }
|
||||
|
||||
vector<ContentListing>::const_iterator begin() const { return _content.cbegin(); }
|
||||
vector<ContentListing>::const_iterator end() const { return _content.cend(); }
|
||||
|
||||
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() const;
|
||||
};
|
||||
|
||||
class PrettyHelp
|
||||
{
|
||||
public:
|
||||
string group = "unknown";
|
||||
|
||||
private:
|
||||
PrettyHelp *_prior;
|
||||
ContentListing _root_listing;
|
||||
|
||||
public:
|
||||
PrettyHelp();
|
||||
~PrettyHelp();
|
||||
|
||||
static PrettyHelp *get_current();
|
||||
|
||||
bool has_content() const { return _root_listing.has_content(); }
|
||||
|
||||
vector<ContentListing>::const_iterator begin() const { return _root_listing.begin(); }
|
||||
vector<ContentListing>::const_iterator end() const { return _root_listing.end(); }
|
||||
|
||||
ContentListing* get_root() {
|
||||
return &_root_listing;
|
||||
}
|
||||
|
||||
void set_group(const string g) { group = g; }
|
||||
bool has_group() const { return group.compare("unknown") != 0; }
|
||||
|
||||
void log_help() const;
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
@ -527,8 +539,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)
|
||||
{
|
||||
}
|
||||
|
@ -681,6 +693,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() {
|
||||
|
@ -706,37 +735,72 @@ 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");
|
||||
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;
|
||||
std::string textcp = text;
|
||||
ss << text;
|
||||
bool IsUsage = true;
|
||||
int blank_count = 0;
|
||||
ss << buf.str();
|
||||
|
||||
// parse command help
|
||||
size_t def_strip_count = 0;
|
||||
bool WasDefinition = false;
|
||||
for (std::string line; std::getline(ss, line, '\n');) {
|
||||
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) {
|
||||
// skip formatting empty lines
|
||||
if (!WasDefinition)
|
||||
fputc('\n', f);
|
||||
blank_count += 1;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -744,117 +808,138 @@ struct HelpPass : public Pass {
|
|||
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;
|
||||
bool IsDedent = def_strip_count && first_pos < def_strip_count;
|
||||
bool IsIndent = def_strip_count < first_pos;
|
||||
|
||||
// another usage block
|
||||
bool NewUsage = stripped_line.find(cmd) == 0;
|
||||
// line looks like a signature
|
||||
bool IsSignature = stripped_line.find(name) == 0 && (stripped_line.length() == name.length() || stripped_line.at(name.size()) == ' ');
|
||||
|
||||
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;
|
||||
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 = "";
|
||||
}
|
||||
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;
|
||||
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 (IsDedent) {
|
||||
fprintf(f, "\n\n ::\n");
|
||||
def_strip_count = first_pos;
|
||||
} else if (WasDefinition) {
|
||||
fprintf(f, "::\n");
|
||||
WasDefinition = false;
|
||||
if (current_state == PUState_options) {
|
||||
current_state = PUState_optionbody;
|
||||
}
|
||||
fprintf(f, "\n %s", line.substr(def_strip_count, std::string::npos).c_str());
|
||||
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;
|
||||
}
|
||||
|
||||
blank_count = 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 = "";
|
||||
}
|
||||
fputc('\n', f);
|
||||
|
||||
// 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");
|
||||
|
||||
// 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");
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
// 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";
|
||||
}
|
||||
|
||||
// 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());
|
||||
if (groups.count(cmd_help.group) == 0) {
|
||||
groups[cmd_help.group] = vector<string>();
|
||||
}
|
||||
groups[cmd_help.group].push_back(name);
|
||||
|
||||
// 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());
|
||||
// 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)
|
||||
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();
|
||||
}
|
||||
json.end_object();
|
||||
|
||||
// close
|
||||
fclose(f);
|
||||
json.entry("groups", groups);
|
||||
|
||||
json.end_object();
|
||||
return raise_error;
|
||||
}
|
||||
bool dump_cells_json(PrettyJson &json) {
|
||||
// init json
|
||||
|
@ -960,11 +1045,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") {
|
||||
|
@ -978,44 +1059,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]);
|
||||
|
@ -1044,7 +1090,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));
|
||||
|
@ -1052,6 +1108,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,27 +23,62 @@
|
|||
#include "kernel/yosys_common.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#ifdef YOSYS_ENABLE_HELP_SOURCE
|
||||
#include <version>
|
||||
# if __cpp_lib_source_location == 201907L
|
||||
#include <source_location>
|
||||
using std::source_location;
|
||||
#define HAS_SOURCE_LOCATION
|
||||
# elif defined(__has_include)
|
||||
# if __has_include(<experimental/source_location>)
|
||||
#include <experimental/source_location>
|
||||
using std::experimental::source_location;
|
||||
#define HAS_SOURCE_LOCATION
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAS_SOURCE_LOCATION
|
||||
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());
|
||||
// Prefer overriding 'Pass::on_shutdown()' if possible
|
||||
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;
|
||||
|
@ -81,7 +116,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;
|
||||
|
||||
|
@ -99,7 +135,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;
|
||||
|
@ -115,7 +152,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;
|
||||
|
|
|
@ -71,7 +71,7 @@ keyword_aliases = {
|
|||
|
||||
#These can be used without any explicit conversion
|
||||
primitive_types = ["void", "bool", "int", "double", "size_t", "std::string",
|
||||
"string", "State", "char_p"]
|
||||
"string", "State", "char_p", "std::source_location", "source_location"]
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
@ -515,11 +515,11 @@ class TupleTranslator(PythonDictTranslator):
|
|||
if types[0].name.split(" ")[-1] in primitive_types:
|
||||
text += varname + "___tmp_0, "
|
||||
else:
|
||||
text += varname + "___tmp_0.get_cpp_obj(), "
|
||||
text += "*" + varname + "___tmp_0.get_cpp_obj(), "
|
||||
if types[1].name.split(" ")[-1] in primitive_types:
|
||||
text += varname + "___tmp_1);"
|
||||
else:
|
||||
text += varname + "___tmp_1.get_cpp_obj());"
|
||||
text += "*" + varname + "___tmp_1.get_cpp_obj());"
|
||||
return text
|
||||
|
||||
#Generate c++ code to translate to a boost::python::tuple
|
||||
|
@ -1137,10 +1137,18 @@ class WConstructor:
|
|||
str_def = str_def[0:found].strip()
|
||||
if len(str_def) == 0:
|
||||
return con
|
||||
for arg in split_list(str_def, ","):
|
||||
args = split_list(str_def, ",")
|
||||
for i, arg in enumerate(args):
|
||||
parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
|
||||
if parsed == None:
|
||||
return None
|
||||
# Only allow std::source_location as defaulted last argument, and
|
||||
# don't append so it takes default value
|
||||
if parsed.wtype.name in ["std::source_location", "source_location"]:
|
||||
if parsed.default_value is None or i != len(args) - 1:
|
||||
debug("std::source_location not defaulted last arg of " + class_.name + " is unsupported", 2)
|
||||
return None
|
||||
continue
|
||||
con.args.append(parsed)
|
||||
return con
|
||||
|
||||
|
@ -1379,12 +1387,20 @@ class WFunction:
|
|||
str_def = str_def[:found].strip()
|
||||
if(len(str_def) == 0):
|
||||
return func
|
||||
for arg in split_list(str_def, ","):
|
||||
args = split_list(str_def, ",")
|
||||
for i, arg in enumerate(args):
|
||||
if arg.strip() == "...":
|
||||
continue
|
||||
parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
|
||||
if parsed == None:
|
||||
return None
|
||||
# Only allow std::source_location as defaulted last argument, and
|
||||
# don't append so it takes default value
|
||||
if parsed.wtype.name in ["std::source_location", "source_location"]:
|
||||
if parsed.default_value is None or i != len(args) - 1:
|
||||
debug("std::source_location not defaulted last arg of " + func.name + " is unsupported", 2)
|
||||
return None
|
||||
continue
|
||||
func.args.append(parsed)
|
||||
return func
|
||||
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/log_help.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
@ -70,62 +71,62 @@ 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(" -assert2cover\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("-assert2cover");
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -21,7 +21,9 @@ struct ExampleWorker
|
|||
|
||||
struct ExampleDtPass : public Pass
|
||||
{
|
||||
ExampleDtPass() : Pass("example_dt", "drivertools example") {}
|
||||
ExampleDtPass() : Pass("example_dt", "drivertools example") {
|
||||
internal();
|
||||
}
|
||||
|
||||
void help() override
|
||||
{
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
|
@ -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---|
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue