mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-27 19:18:49 +00:00
commit
42ca75b6b5
392 changed files with 27024 additions and 12879 deletions
4
.github/actions/setup-build-env/action.yml
vendored
4
.github/actions/setup-build-env/action.yml
vendored
|
|
@ -8,14 +8,14 @@ runs:
|
|||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
|
||||
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev
|
||||
|
||||
- name: Install macOS Dependencies
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew update
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf llvm lld
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf llvm lld || true
|
||||
|
||||
- name: Linux runtime environment
|
||||
if: runner.os == 'Linux'
|
||||
|
|
|
|||
5
.github/workflows/prepare-docs.yml
vendored
5
.github/workflows/prepare-docs.yml
vendored
|
|
@ -64,6 +64,11 @@ jobs:
|
|||
docs/source/_images
|
||||
docs/source/code_examples
|
||||
|
||||
- name: Install doc prereqs
|
||||
shell: bash
|
||||
run: |
|
||||
make docs/reqs
|
||||
|
||||
- name: Test build docs
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
|
|||
33
.github/workflows/source-vendor.yml
vendored
Normal file
33
.github/workflows/source-vendor.yml
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
name: Create source archive with vendored dependencies
|
||||
|
||||
on: [push, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
vendor-sources:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository with submodules
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Create clean tarball
|
||||
run: |
|
||||
git archive --format=tar HEAD -o yosys-src-vendored.tar
|
||||
git submodule foreach '
|
||||
git archive --format=tar --prefix="${sm_path}/" HEAD --output=${toplevel}/vendor-${name}.tar
|
||||
'
|
||||
|
||||
# 2008 bug https://lists.gnu.org/archive/html/bug-tar/2008-08/msg00002.html
|
||||
for file in vendor-*.tar; do
|
||||
tar --concatenate --file=yosys-src-vendored.tar "$file"
|
||||
done
|
||||
|
||||
gzip yosys-src-vendored.tar
|
||||
|
||||
- name: Store tarball artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vendored-sources
|
||||
path: yosys-src-vendored.tar.gz
|
||||
retention-days: 1
|
||||
44
.github/workflows/test-build.yml
vendored
44
.github/workflows/test-build.yml
vendored
|
|
@ -56,6 +56,7 @@ jobs:
|
|||
mkdir build
|
||||
cd build
|
||||
make -f ../Makefile config-$CC
|
||||
echo 'SANITIZER = undefined' >> Makefile.conf
|
||||
make -f ../Makefile -j$procs ENABLE_LTO=1
|
||||
|
||||
- name: Log yosys-config output
|
||||
|
|
@ -82,6 +83,7 @@ jobs:
|
|||
if: needs.pre_job.outputs.should_skip != 'true'
|
||||
env:
|
||||
CC: clang
|
||||
UBSAN_OPTIONS: halt_on_error=1
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
|
|
@ -189,3 +191,45 @@ jobs:
|
|||
shell: bash
|
||||
run: |
|
||||
make -C docs test -j${{ env.procs }}
|
||||
|
||||
test-docs-build:
|
||||
name: Try build docs
|
||||
runs-on: [self-hosted, linux, x64, fast]
|
||||
needs: [pre_docs_job]
|
||||
if: needs.pre_docs_job.outputs.should_skip != 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
docs-target: [html, latexpdf]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Runtime environment
|
||||
run: |
|
||||
echo "procs=$(nproc)" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Yosys
|
||||
run: |
|
||||
make config-clang
|
||||
echo "ENABLE_CCACHE := 1" >> Makefile.conf
|
||||
make -j${{ env.procs }}
|
||||
|
||||
- name: Install doc prereqs
|
||||
shell: bash
|
||||
run: |
|
||||
make docs/reqs
|
||||
|
||||
- name: Build docs
|
||||
shell: bash
|
||||
run: |
|
||||
make docs DOC_TARGET=${{ matrix.docs-target }} -j${{ env.procs }}
|
||||
|
||||
- name: Store docs build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docs-build-${{ matrix.docs-target }}
|
||||
path: docs/build/
|
||||
retention-days: 7
|
||||
|
|
|
|||
13
.github/workflows/test-compile.yml
vendored
13
.github/workflows/test-compile.yml
vendored
|
|
@ -30,18 +30,15 @@ jobs:
|
|||
- ubuntu-latest
|
||||
compiler:
|
||||
# oldest supported
|
||||
- 'clang-14'
|
||||
- 'clang-10'
|
||||
- 'gcc-10'
|
||||
# newest
|
||||
- 'clang'
|
||||
- 'gcc'
|
||||
# newest, make sure to update maximum standard step to match
|
||||
- 'clang-19'
|
||||
- 'gcc-13'
|
||||
include:
|
||||
# macOS
|
||||
- os: macos-13
|
||||
compiler: 'clang'
|
||||
# oldest clang not available on ubuntu-latest
|
||||
- os: ubuntu-20.04
|
||||
compiler: 'clang-10'
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout Yosys
|
||||
|
|
@ -72,7 +69,7 @@ jobs:
|
|||
|
||||
# maximum standard, only on newest compilers
|
||||
- name: Build C++20
|
||||
if: ${{ matrix.compiler == 'clang' || matrix.compiler == 'gcc'}}
|
||||
if: ${{ matrix.compiler == 'clang-19' || matrix.compiler == 'gcc-13' }}
|
||||
shell: bash
|
||||
run: |
|
||||
make config-$CC_SHORT
|
||||
|
|
|
|||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -1,6 +1,7 @@
|
|||
[submodule "abc"]
|
||||
path = abc
|
||||
url = https://github.com/YosysHQ/abc
|
||||
[submodule "libs/cxxopts"]
|
||||
# Don't use paths as names to avoid git archive problems
|
||||
[submodule "cxxopts"]
|
||||
path = libs/cxxopts
|
||||
url = https://github.com/jarro2783/cxxopts
|
||||
|
|
|
|||
6
.mailmap
6
.mailmap
|
|
@ -1,6 +1,6 @@
|
|||
Marcelina Kościelnicka <mwk@0x04.net>
|
||||
Marcelina Kościelnicka <mwk@0x04.net> <koriakin@0x04.net>
|
||||
Marcelina Kościelnicka <mwk@0x04.net> <marcin@symbioticeda.com>
|
||||
Wanda Phinode <wanda@phinode.net> <mwk@0x04.net>
|
||||
Wanda Phinode <wanda@phinode.net> <koriakin@0x04.net>
|
||||
Wanda Phinode <wanda@phinode.net> <marcin@symbioticeda.com>
|
||||
Claire Xenia Wolf <claire@yosyshq.com> <claire@clairexen.net>
|
||||
Claire Xenia Wolf <claire@yosyshq.com> <claire@symbioticeda.com>
|
||||
Claire Xenia Wolf <claire@yosyshq.com> <clifford@symbioticeda.com>
|
||||
|
|
|
|||
79
CHANGELOG
79
CHANGELOG
|
|
@ -2,9 +2,86 @@
|
|||
List of major changes and improvements between releases
|
||||
=======================================================
|
||||
|
||||
Yosys 0.46 .. Yosys 0.47-dev
|
||||
Yosys 0.51 .. Yosys 0.52-dev
|
||||
--------------------------
|
||||
|
||||
Yosys 0.50 .. Yosys 0.51
|
||||
--------------------------
|
||||
* New commands and options
|
||||
- Added "abstract" pass to allow reducing and never increasing
|
||||
the constraints on a circuit's behavior in a formal verification setting.
|
||||
|
||||
* Various
|
||||
- "splitcells" pass now splits "aldff" cells.
|
||||
- FunctionalIR documentation
|
||||
|
||||
* QuickLogic support
|
||||
- Added IOFF inference for qlf_k6n10f
|
||||
|
||||
* Intel support
|
||||
- Fixed RAM and DSP support.
|
||||
- Overall performance improvement for "synth_intel".
|
||||
|
||||
Yosys 0.49 .. Yosys 0.50
|
||||
--------------------------
|
||||
* Various
|
||||
- "write_verilog" emits "$check" cell names as labels.
|
||||
|
||||
Yosys 0.48 .. Yosys 0.49
|
||||
--------------------------
|
||||
* Various
|
||||
- "$scopeinfo" cells are now part of JSON export by default.
|
||||
- Added option to specify hierarchical separator for "flatten".
|
||||
- Improved "wreduce" to handle more cases of operator size reduction.
|
||||
- Updated hashing interface, see docs/source/yosys_internals/hashing.rst
|
||||
for breaking API changes.
|
||||
|
||||
* New commands and options
|
||||
- Added "-noscopeinfo" option to "json" and "write_json" pass.
|
||||
|
||||
Yosys 0.47 .. Yosys 0.48
|
||||
--------------------------
|
||||
* Various
|
||||
- Removed "read_ilang" deprecated pass.
|
||||
- Enhanced boxing features in the experimental "abc_new" command.
|
||||
- Added new Tcl methods for design inspection.
|
||||
- Added clock enable inference to "dfflibmap".
|
||||
- Added a Han-Carlson and Sklansky option for $lcu mapping.
|
||||
|
||||
* New commands and options
|
||||
- Added "-nopeepopt" option to "clk2fflogic" pass.
|
||||
- Added "-liberty" and "-dont_use" options to "clockgate" pass.
|
||||
- Added "-ignore_buses" option to "read_liberty" pass.
|
||||
- Added "-dont_map" option to "techmap" pass.
|
||||
- Added "-selected" option to "write_json" pass.
|
||||
- Added "wrapcell" command for creating wrapper modules
|
||||
around selected cells.
|
||||
- Added "portarcs" command for deriving propagation timing arcs.
|
||||
- Added "setenv" command for setting environment variables.
|
||||
|
||||
* Gowin support
|
||||
- Added "-family" option to "synth_gowin" pass.
|
||||
- Cell definitions split by family.
|
||||
|
||||
* Verific support
|
||||
- Improved blackbox support.
|
||||
|
||||
Yosys 0.46 .. Yosys 0.47
|
||||
--------------------------
|
||||
* Various
|
||||
- Added cxxopts library for handling command line arguments.
|
||||
- Added docs generation from cells help output.
|
||||
|
||||
* New commands and options
|
||||
- Added "-json" option to "synth_xilinx" pass.
|
||||
- Added "-derive_luts" option to "cellmatch" pass.
|
||||
- Added "t:@<name>" syntax to "select" pass.
|
||||
- Added "-list-mod" option to "select" pass.
|
||||
- Removed deprecated "qwp" pass.
|
||||
|
||||
* Verific support
|
||||
- Initial state handling for VHDL assertions.
|
||||
|
||||
Yosys 0.45 .. Yosys 0.46
|
||||
--------------------------
|
||||
* Various
|
||||
|
|
|
|||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at contact@yosyshq.com and/or
|
||||
claire@clairexen.net.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
73
CONTRIBUTING.md
Normal file
73
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Introduction
|
||||
|
||||
Thanks for thinking about contributing to the Yosys project. If this is your
|
||||
first time contributing to an open source project, please take a look at the
|
||||
following guide:
|
||||
https://opensource.guide/how-to-contribute/#orienting-yourself-to-a-new-project.
|
||||
|
||||
Information about the Yosys coding style is available on our Read the Docs:
|
||||
https://yosys.readthedocs.io/en/latest/yosys_internals/extending_yosys/contributing.html.
|
||||
|
||||
# Using the issue tracker
|
||||
|
||||
The [issue tracker](https://github.com/YosysHQ/yosys/issues) is used for
|
||||
tracking bugs or other problems with Yosys or its documentation. It is also the
|
||||
place to go for requesting new features.
|
||||
When [creating a new issue](https://github.com/YosysHQ/yosys/issues/new/choose),
|
||||
we have a few templates available. Please make use of these! It will make it
|
||||
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.
|
||||
|
||||
|
||||
# Using pull requests
|
||||
|
||||
If you are working on something to add to Yosys, or fix something that isn't
|
||||
working quite right, make a [PR](https://github.com/YosysHQ/yosys/pulls)! An
|
||||
open PR, even as a draft, tells everyone that you're working on it and they
|
||||
don't have to. It can also be a useful way to solicit feedback on in-progress
|
||||
changes. See below to find the best way to [ask us
|
||||
questions](#asking-questions).
|
||||
|
||||
In general, all changes to the code are done as a PR, with [Continuous
|
||||
Integration (CI)](https://github.com/YosysHQ/yosys/actions) tools that
|
||||
automatically run the full suite of tests compiling and running Yosys. Please
|
||||
make use of this! If you're adding a feature: add a test! Not only does it
|
||||
verify that your feature is working as expected, but it can also be a handy way
|
||||
for people to see how the feature is used. If you're fixing a bug: add a test!
|
||||
If you can, do this first; it's okay if the test starts off failing - you
|
||||
already know there is a bug. CI also helps to make sure that your changes still
|
||||
work under a range of compilers, settings, and targets.
|
||||
|
||||
|
||||
### Labels
|
||||
|
||||
We use [labels](https://github.com/YosysHQ/yosys/labels) to help categorise
|
||||
issues and PRs. If a label seems relevant to your work, please do add it; this
|
||||
also includes the labels beggining with 'status-'. The 'merge-' labels are used
|
||||
by maintainers for tracking and communicating which PRs are ready and pending
|
||||
merge; please do not use these labels if you are not a maintainer.
|
||||
|
||||
|
||||
# Asking questions
|
||||
|
||||
If you have a question about how to use Yosys, please ask on our [discussions
|
||||
page](https://github.com/YosysHQ/yosys/discussions) or in our [community
|
||||
slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA).
|
||||
The slack is also a great place to ask questions about developing or
|
||||
contributing to Yosys.
|
||||
|
||||
We have open dev 'jour fixe' (JF) meetings where developers from YosysHQ and the
|
||||
community come together to discuss open issues and PRs. This is also a good
|
||||
place to talk to us about how to implement larger PRs. Please join the
|
||||
community slack if you would like to join the next meeting, the link is
|
||||
available in the description of the #devel-discuss channel.
|
||||
2
COPYING
2
COPYING
|
|
@ -1,6 +1,6 @@
|
|||
ISC License
|
||||
|
||||
Copyright (C) 2012 - 2020 Claire Xenia Wolf <claire@yosyshq.com>
|
||||
Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@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
|
||||
|
|
|
|||
307
Makefile
307
Makefile
|
|
@ -2,9 +2,7 @@
|
|||
CONFIG := none
|
||||
# CONFIG := clang
|
||||
# CONFIG := gcc
|
||||
# CONFIG := afl-gcc
|
||||
# CONFIG := wasi
|
||||
# CONFIG := mxe
|
||||
# CONFIG := msys2-32
|
||||
# CONFIG := msys2-64
|
||||
|
||||
|
|
@ -118,14 +116,15 @@ AWK ?= awk
|
|||
|
||||
ifeq ($(OS), Darwin)
|
||||
PLUGIN_LINKFLAGS += -undefined dynamic_lookup
|
||||
LINKFLAGS += -rdynamic
|
||||
|
||||
# homebrew search paths
|
||||
ifneq ($(shell :; command -v brew),)
|
||||
BREW_PREFIX := $(shell brew --prefix)/opt
|
||||
$(info $$BREW_PREFIX is [${BREW_PREFIX}])
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost
|
||||
LINKFLAGS += -L$(BREW_PREFIX)/boost/lib
|
||||
CXXFLAGS += -I$(BREW_PREFIX)/boost/include
|
||||
LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib
|
||||
endif
|
||||
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
|
||||
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib
|
||||
|
|
@ -154,7 +153,14 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.46+34
|
||||
YOSYS_VER := 0.51+17
|
||||
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)
|
||||
CXXFLAGS += -DYOSYS_VER=\\"$(YOSYS_VER)\\" \
|
||||
-DYOSYS_MAJOR=$(YOSYS_MAJOR) \
|
||||
-DYOSYS_MINOR=$(YOSYS_MINOR) \
|
||||
-DYOSYS_COMMIT=$(YOSYS_COMMIT)
|
||||
|
||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
||||
|
|
@ -170,7 +176,7 @@ endif
|
|||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
bumpversion:
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline e97731b.. | wc -l`/;" Makefile
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline c4b5190.. | wc -l`/;" Makefile
|
||||
|
||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
||||
|
||||
|
|
@ -264,16 +270,6 @@ ifeq ($(DISABLE_ABC_THREADS),1)
|
|||
ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
|
||||
endif
|
||||
|
||||
else ifeq ($(CONFIG),afl-gcc)
|
||||
CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),cygwin)
|
||||
CXX = g++
|
||||
CXXFLAGS += -std=gnu++11 $(OPT_LEVEL)
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),wasi)
|
||||
ifeq ($(WASI_SDK),)
|
||||
CXX = clang++
|
||||
|
|
@ -301,18 +297,6 @@ LINK_ABC := 1
|
|||
DISABLE_ABC_THREADS := 1
|
||||
endif
|
||||
|
||||
else ifeq ($(CONFIG),mxe)
|
||||
PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config
|
||||
CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s
|
||||
LIBS := $(filter-out -lrt,$(LIBS))
|
||||
ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||
# TODO: Try to solve pthread linking issue in more appropriate way
|
||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LINKFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
|
||||
EXE = .exe
|
||||
|
||||
else ifeq ($(CONFIG),msys2-32)
|
||||
CXX = i686-w64-mingw32-g++
|
||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||
|
|
@ -339,7 +323,7 @@ ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
|||
LTOFLAGS =
|
||||
|
||||
else
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, mxe, msys2-32, msys2-64, none)
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, msys2-32, msys2-64, none)
|
||||
endif
|
||||
|
||||
|
||||
|
|
@ -353,8 +337,13 @@ TARGETS += libyosys.so
|
|||
endif
|
||||
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
# python-config --ldflags includes -l and -L, but LINKFLAGS is only -L
|
||||
LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags))
|
||||
LIBS += $(shell $(PYTHON_CONFIG) --libs)
|
||||
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
|
||||
|
||||
# Detect name of boost_python library. Some distros use boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
|
||||
CHECK_BOOST_PYTHON = (echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_CONFIG) --ldflags) -l$(1) - > /dev/null 2>&1 && echo "-l$(1)")
|
||||
CHECK_BOOST_PYTHON = (echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(LINKFLAGS) $(LIBS) -l$(1) - > /dev/null 2>&1 && echo "-l$(1)")
|
||||
BOOST_PYTHON_LIB ?= $(shell \
|
||||
$(call CHECK_BOOST_PYTHON,boost_python-py$(subst .,,$(PYTHON_VERSION))) || \
|
||||
$(call CHECK_BOOST_PYTHON,boost_python-py$(PYTHON_MAJOR_VERSION)) || \
|
||||
|
|
@ -366,11 +355,7 @@ ifeq ($(BOOST_PYTHON_LIB),)
|
|||
$(error BOOST_PYTHON_LIB could not be detected. Please define manually)
|
||||
endif
|
||||
|
||||
LIBS += $(shell $(PYTHON_CONFIG) --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||
# python-config --ldflags includes LIBS for some reason
|
||||
LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags))
|
||||
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
|
||||
|
||||
LIBS += $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
|
||||
PY_WRAPPER_FILE = kernel/python_wrappers
|
||||
OBJS += $(PY_WRAPPER_FILE).o
|
||||
PY_GEN_SCRIPT= py_wrap_generator
|
||||
|
|
@ -391,16 +376,12 @@ ifeq ($(LINK_TERMCAP),1)
|
|||
LIBS += -ltermcap
|
||||
ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap"
|
||||
endif
|
||||
ifeq ($(CONFIG),mxe)
|
||||
LIBS += -ltermcap
|
||||
endif
|
||||
else
|
||||
ifeq ($(ENABLE_EDITLINE),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_EDITLINE
|
||||
LIBS += -ledit -ltinfo -lbsd
|
||||
else
|
||||
ABCMKARGS += "ABC_USE_NO_READLINE=1"
|
||||
LIBS += -ledit
|
||||
endif
|
||||
ABCMKARGS += "ABC_USE_NO_READLINE=1"
|
||||
endif
|
||||
|
||||
ifeq ($(DISABLE_ABC_THREADS),1)
|
||||
|
|
@ -443,12 +424,10 @@ TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
|
|||
TCL_LIBS ?= -l$(TCL_VERSION)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG),mxe)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_TCL
|
||||
LIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv
|
||||
else
|
||||
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
|
||||
LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo $(TCL_LIBS))
|
||||
ifneq (,$(findstring TCL_WITH_EXTERNAL_TOMMATH,$(CXXFLAGS)))
|
||||
LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libtommath || echo)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
@ -639,7 +618,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
|
||||
OBJS += kernel/binding.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
|
||||
ifeq ($(ENABLE_ZLIB),1)
|
||||
|
|
@ -680,6 +659,9 @@ OBJS += libs/fst/fastlz.o
|
|||
OBJS += libs/fst/lz4.o
|
||||
endif
|
||||
|
||||
techlibs/%_pm.h: passes/pmgen/pmgen.py techlibs/%.pmg
|
||||
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p $(notdir $*) $(filter-out $<,$^)
|
||||
|
||||
ifneq ($(SMALL),1)
|
||||
|
||||
OBJS += libs/subcircuit/subcircuit.o
|
||||
|
|
@ -804,6 +786,15 @@ check-git-abc:
|
|||
elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && ! grep -q '\$$Format:%[hH]\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \
|
||||
echo "'abc' comes from a tarball. Continuing."; \
|
||||
exit 0; \
|
||||
elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^+'; then \
|
||||
echo "'abc' submodule does not match expected commit."; \
|
||||
echo "Run 'git submodule update' to check out the correct version."; \
|
||||
echo "Note: If testing a different version of abc, call 'git commit abc' in the Yosys source directory to update the expected commit."; \
|
||||
exit 1; \
|
||||
elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^U'; then \
|
||||
echo "'abc' submodule has merge conflicts."; \
|
||||
echo "Please resolve merge conflicts before continuing."; \
|
||||
exit 1; \
|
||||
elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && grep -q '\$$Format:%[hH]\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \
|
||||
echo "Error: 'abc' is not configured as a git submodule."; \
|
||||
echo "To resolve this:"; \
|
||||
|
|
@ -839,71 +830,101 @@ else
|
|||
ABCOPT=""
|
||||
endif
|
||||
|
||||
# When YOSYS_NOVERIFIC is set as a make variable, also export it to the
|
||||
# enviornment, so that `YOSYS_NOVERIFIC=1 make test` _and_
|
||||
# `make test YOSYS_NOVERIFIC=1` will run with verific disabled.
|
||||
ifeq ($(YOSYS_NOVERIFIC),1)
|
||||
export YOSYS_NOVERIFIC
|
||||
# Tests that generate .mk with tests/gen-tests-makefile.sh
|
||||
MK_TEST_DIRS =
|
||||
MK_TEST_DIRS += tests/arch/anlogic
|
||||
MK_TEST_DIRS += tests/arch/ecp5
|
||||
MK_TEST_DIRS += tests/arch/efinix
|
||||
MK_TEST_DIRS += tests/arch/gatemate
|
||||
MK_TEST_DIRS += tests/arch/gowin
|
||||
MK_TEST_DIRS += tests/arch/ice40
|
||||
MK_TEST_DIRS += tests/arch/intel_alm
|
||||
MK_TEST_DIRS += tests/arch/machxo2
|
||||
MK_TEST_DIRS += tests/arch/microchip
|
||||
MK_TEST_DIRS += tests/arch/nanoxplore
|
||||
MK_TEST_DIRS += tests/arch/nexus
|
||||
MK_TEST_DIRS += tests/arch/quicklogic/pp3
|
||||
MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f
|
||||
MK_TEST_DIRS += tests/arch/xilinx
|
||||
MK_TEST_DIRS += tests/opt
|
||||
MK_TEST_DIRS += tests/sat
|
||||
MK_TEST_DIRS += tests/sim
|
||||
MK_TEST_DIRS += tests/svtypes
|
||||
MK_TEST_DIRS += tests/techmap
|
||||
MK_TEST_DIRS += tests/various
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifneq ($(YOSYS_NOVERIFIC),1)
|
||||
MK_TEST_DIRS += tests/verific
|
||||
endif
|
||||
endif
|
||||
MK_TEST_DIRS += tests/verilog
|
||||
|
||||
# Tests that don't generate .mk
|
||||
SH_TEST_DIRS =
|
||||
SH_TEST_DIRS += tests/simple
|
||||
SH_TEST_DIRS += tests/simple_abc9
|
||||
SH_TEST_DIRS += tests/hana
|
||||
SH_TEST_DIRS += tests/asicworld
|
||||
# SH_TEST_DIRS += tests/realmath
|
||||
SH_TEST_DIRS += tests/share
|
||||
SH_TEST_DIRS += tests/opt_share
|
||||
SH_TEST_DIRS += tests/fsm
|
||||
SH_TEST_DIRS += tests/memlib
|
||||
SH_TEST_DIRS += tests/bram
|
||||
SH_TEST_DIRS += tests/svinterfaces
|
||||
SH_TEST_DIRS += tests/xprop
|
||||
SH_TEST_DIRS += tests/select
|
||||
SH_TEST_DIRS += tests/proc
|
||||
SH_TEST_DIRS += tests/blif
|
||||
SH_TEST_DIRS += tests/arch
|
||||
SH_TEST_DIRS += tests/rpc
|
||||
SH_TEST_DIRS += tests/memfile
|
||||
SH_TEST_DIRS += tests/fmt
|
||||
SH_TEST_DIRS += tests/cxxrtl
|
||||
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
|
||||
SH_TEST_DIRS += tests/functional
|
||||
endif
|
||||
|
||||
test: $(TARGETS) $(EXTRA_TARGETS)
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifeq ($(YOSYS_NOVERIFIC),1)
|
||||
@echo
|
||||
@echo "Running tests without verific support due to YOSYS_NOVERIFIC=1"
|
||||
@echo
|
||||
else
|
||||
+cd tests/verific && bash run-test.sh $(SEEDOPT)
|
||||
endif
|
||||
endif
|
||||
+cd tests/simple && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/hana && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
|
||||
# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/share && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/opt_share && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/techmap && bash run-test.sh
|
||||
+cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
|
||||
+cd tests/memlib && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/bram && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/various && bash run-test.sh
|
||||
+cd tests/select && bash run-test.sh
|
||||
+cd tests/sat && bash run-test.sh
|
||||
+cd tests/sim && bash run-test.sh
|
||||
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/svtypes && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/proc && bash run-test.sh
|
||||
+cd tests/blif && bash run-test.sh
|
||||
+cd tests/opt && bash run-test.sh
|
||||
+cd tests/aiger && bash run-test.sh $(ABCOPT)
|
||||
+cd tests/arch && bash run-test.sh
|
||||
+cd tests/arch/ice40 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/xilinx && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/ecp5 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/machxo2 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/efinix && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/anlogic && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/gowin && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/nanoxplore && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/nexus && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic/pp3 && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/quicklogic/qlf_k6n10f && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/gatemate && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/arch/microchip && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/rpc && bash run-test.sh
|
||||
+cd tests/memfile && bash run-test.sh
|
||||
+cd tests/verilog && bash run-test.sh
|
||||
+cd tests/xprop && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/fmt && bash run-test.sh
|
||||
+cd tests/cxxrtl && bash run-test.sh
|
||||
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
|
||||
+cd tests/functional && bash run-test.sh
|
||||
endif
|
||||
# Tests that don't generate .mk and need special args
|
||||
SH_ABC_TEST_DIRS =
|
||||
SH_ABC_TEST_DIRS += tests/memories
|
||||
SH_ABC_TEST_DIRS += tests/aiger
|
||||
SH_ABC_TEST_DIRS += tests/alumacc
|
||||
|
||||
# seed-tests/ is a dummy string, not a directory
|
||||
.PHONY: seed-tests
|
||||
seed-tests: $(SH_TEST_DIRS:%=seed-tests/%)
|
||||
.PHONY: seed-tests/%
|
||||
seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd $* && bash run-test.sh $(SEEDOPT)
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
# abcopt-tests/ is a dummy string, not a directory
|
||||
.PHONY: abcopt-tests
|
||||
abcopt-tests: $(SH_ABC_TEST_DIRS:%=abcopt-tests/%)
|
||||
abcopt-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
|
||||
+cd $* && bash run-test.sh $(ABCOPT) $(SEEDOPT)
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
# makefile-tests/ is a dummy string, not a directory
|
||||
.PHONY: makefile-tests
|
||||
makefile-tests: $(MK_TEST_DIRS:%=makefile-tests/%)
|
||||
# this target actually emits .mk files
|
||||
%.mk:
|
||||
+cd $(dir $*) && bash run-test.sh
|
||||
# this one spawns submake on each
|
||||
makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS)
|
||||
$(MAKE) -C $* -f run-test.mk
|
||||
+@echo "...passed tests in $*"
|
||||
|
||||
test: makefile-tests abcopt-tests seed-tests
|
||||
@echo ""
|
||||
@echo " Passed \"make test\"."
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
ifeq ($(YOSYS_NOVERIFIC),1)
|
||||
@echo " Ran tests without verific support due to YOSYS_NOVERIFIC=1."
|
||||
endif
|
||||
endif
|
||||
@echo ""
|
||||
|
||||
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
|
||||
|
|
@ -981,21 +1002,39 @@ 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)
|
||||
mkdir -p docs/source/cmd
|
||||
./$(PROGRAM_PREFIX)yosys -p 'help -write-rst-command-reference-manual'
|
||||
$(Q) mkdir -p docs/source/cmd
|
||||
$(Q) mkdir -p temp/docs/source/cmd
|
||||
$(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-command-reference-manual'
|
||||
$(Q) rsync -rc temp/docs/source/cmd docs/source
|
||||
$(Q) rm -rf temp
|
||||
docs/source/cell/word_add.rst: $(TARGETS) $(EXTRA_TARGETS)
|
||||
$(Q) mkdir -p docs/source/cell
|
||||
$(Q) mkdir -p temp/docs/source/cell
|
||||
$(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-cells-manual'
|
||||
$(Q) rsync -rc temp/docs/source/cell docs/source
|
||||
$(Q) rm -rf temp
|
||||
|
||||
PHONY: docs/gen_examples docs/gen_images docs/guidelines docs/usage docs/reqs
|
||||
docs/gen_examples: $(TARGETS)
|
||||
$(Q) $(MAKE) -C docs examples
|
||||
docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
|
||||
$(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@'
|
||||
|
||||
docs/gen_images: $(TARGETS)
|
||||
$(Q) $(MAKE) -C docs images
|
||||
docs/source/generated/%.cc: backends/%.cc
|
||||
$(Q) mkdir -p $(@D)
|
||||
$(Q) cp $< $@
|
||||
|
||||
DOCS_GUIDELINE_FILES := GettingStarted CodingStyle
|
||||
DOCS_GUIDELINE_SOURCE := $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES))
|
||||
docs/guidelines docs/source/generated: $(DOCS_GUIDELINE_SOURCE)
|
||||
# diff returns exit code 1 if the files are different, but it's not an error
|
||||
docs/source/generated/functional/rosette.diff: backends/functional/smtlib.cc backends/functional/smtlib_rosette.cc
|
||||
$(Q) mkdir -p $(@D)
|
||||
$(Q) diff -U 20 $^ > $@ || exit 0
|
||||
|
||||
PHONY: docs/gen/functional_ir
|
||||
docs/gen/functional_ir: docs/source/generated/functional/smtlib.cc docs/source/generated/functional/rosette.diff
|
||||
|
||||
PHONY: docs/gen docs/usage docs/reqs
|
||||
docs/gen: $(TARGETS)
|
||||
$(Q) $(MAKE) -C docs gen
|
||||
|
||||
docs/source/generated:
|
||||
$(Q) mkdir -p docs/source/generated
|
||||
$(Q) cp -f $(DOCS_GUIDELINE_SOURCE) docs/source/generated
|
||||
|
||||
# some commands return an error and print the usage text to stderr
|
||||
define DOC_USAGE_STDERR
|
||||
|
|
@ -1025,7 +1064,7 @@ docs/reqs:
|
|||
$(Q) $(MAKE) -C docs reqs
|
||||
|
||||
.PHONY: docs/prep
|
||||
docs/prep: docs/source/cmd/abc.rst docs/gen_examples docs/gen_images docs/guidelines docs/usage
|
||||
docs/prep: docs/source/cmd/abc.rst docs/source/generated/cells.json docs/gen docs/usage docs/gen/functional_ir
|
||||
|
||||
DOC_TARGET ?= html
|
||||
docs: docs/prep
|
||||
|
|
@ -1046,8 +1085,8 @@ clean:
|
|||
rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
|
||||
rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff
|
||||
rm -f tests/tools/cmp_tbdata
|
||||
rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS))
|
||||
-$(MAKE) -C docs clean
|
||||
-$(MAKE) -C docs/images clean
|
||||
rm -rf docs/source/cmd docs/util/__pycache__
|
||||
|
||||
clean-abc:
|
||||
|
|
@ -1085,25 +1124,13 @@ vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
|
|||
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
|
||||
set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
|
||||
echo "Analyse: $$f" >&2; cpp -std=c++17 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
|
||||
echo "libs/fst/fst_win_unistd.h" >> srcfiles.txt
|
||||
bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
|
||||
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
|
||||
zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
|
||||
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
|
||||
rm -f srcfiles.txt kernel/version.cc
|
||||
|
||||
ifeq ($(CONFIG),mxe)
|
||||
mxebin: $(TARGETS) $(EXTRA_TARGETS)
|
||||
rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip}
|
||||
mkdir -p yosys-win32-mxebin-$(YOSYS_VER)
|
||||
cp -r $(PROGRAM_PREFIX)yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
ifeq ($(ENABLE_ABC),1)
|
||||
cp -r $(PROGRAM_PREFIX)yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
endif
|
||||
echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
|
||||
echo -en 'Documentation at https://yosyshq.net/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
|
||||
zip -r yosys-win32-mxebin-$(YOSYS_VER).zip yosys-win32-mxebin-$(YOSYS_VER)/
|
||||
endif
|
||||
|
||||
config-clean: clean
|
||||
rm -f Makefile.conf
|
||||
|
||||
|
|
@ -1119,9 +1146,6 @@ config-gcc-static: clean
|
|||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||
|
||||
config-afl-gcc: clean
|
||||
echo 'CONFIG := afl-gcc' > Makefile.conf
|
||||
|
||||
config-wasi: clean
|
||||
echo 'CONFIG := wasi' > Makefile.conf
|
||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||
|
|
@ -1130,10 +1154,6 @@ config-wasi: clean
|
|||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||
echo 'ENABLE_ZLIB := 0' >> Makefile.conf
|
||||
|
||||
config-mxe: clean
|
||||
echo 'CONFIG := mxe' > Makefile.conf
|
||||
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
|
||||
|
||||
config-msys2-32: clean
|
||||
echo 'CONFIG := msys2-32' > Makefile.conf
|
||||
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
||||
|
|
@ -1142,9 +1162,6 @@ config-msys2-64: clean
|
|||
echo 'CONFIG := msys2-64' > Makefile.conf
|
||||
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
||||
|
||||
config-cygwin: clean
|
||||
echo 'CONFIG := cygwin' > Makefile.conf
|
||||
|
||||
config-gcov: clean
|
||||
echo 'CONFIG := gcc' > Makefile.conf
|
||||
echo 'ENABLE_GCOV := 1' >> Makefile.conf
|
||||
|
|
@ -1173,5 +1190,5 @@ echo-cxx:
|
|||
-include kernel/*.d
|
||||
-include techlibs/*/*.d
|
||||
|
||||
.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc mxebin
|
||||
.PHONY: config-clean config-clang config-gcc config-gcc-static config-afl-gcc config-gprof config-sudo
|
||||
.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc
|
||||
.PHONY: config-clean config-clang config-gcc config-gcc-static config-gprof config-sudo
|
||||
|
|
|
|||
477
README.md
477
README.md
|
|
@ -1,22 +1,3 @@
|
|||
```
|
||||
yosys -- Yosys Open SYnthesis Suite
|
||||
|
||||
Copyright (C) 2012 - 2024 Claire Xenia Wolf <claire@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.
|
||||
```
|
||||
|
||||
|
||||
yosys – Yosys Open SYnthesis Suite
|
||||
===================================
|
||||
|
||||
|
|
@ -33,6 +14,10 @@ Yosys is free software licensed under the ISC license (a GPL
|
|||
compatible license that is similar in terms to the MIT license
|
||||
or the 2-clause BSD license).
|
||||
|
||||
Third-party software distributed alongside this software
|
||||
is licensed under compatible licenses.
|
||||
Please refer to `abc` and `libs` subdirectories for their license terms.
|
||||
|
||||
|
||||
Web Site and Other Resources
|
||||
============================
|
||||
|
|
@ -40,17 +25,14 @@ Web Site and Other Resources
|
|||
More information and documentation can be found on the Yosys web site:
|
||||
- https://yosyshq.net/yosys/
|
||||
|
||||
The "Documentation" page on the web site contains links to more resources,
|
||||
including a manual that even describes some of the Yosys internals:
|
||||
- https://yosyshq.net/yosys/documentation.html
|
||||
Documentation from this repository is automatically built and available on Read
|
||||
the Docs:
|
||||
- https://yosyshq.readthedocs.io/projects/yosys
|
||||
|
||||
The directory `guidelines` contains additional information
|
||||
for people interested in using the Yosys C++ APIs.
|
||||
|
||||
Users interested in formal verification might want to use the formal verification
|
||||
front-end for Yosys, SymbiYosys:
|
||||
- https://symbiyosys.readthedocs.io/en/latest/
|
||||
- https://github.com/YosysHQ/SymbiYosys
|
||||
Users interested in formal verification might want to use the formal
|
||||
verification front-end for Yosys, SBY:
|
||||
- https://yosyshq.readthedocs.io/projects/sby/
|
||||
- https://github.com/YosysHQ/sby
|
||||
|
||||
|
||||
Installation
|
||||
|
|
@ -68,9 +50,25 @@ For more information about the difference between Tabby CAD Suite and the OSS CA
|
|||
|
||||
Many Linux distributions also provide Yosys binaries, some more up to date than others. Check with your package manager!
|
||||
|
||||
|
||||
Building from Source
|
||||
====================
|
||||
|
||||
For more details, and instructions for other platforms, check [building from
|
||||
source](https://yosyshq.readthedocs.io/projects/yosys/en/latest/getting_started/installation.html#building-from-source)
|
||||
on Read the Docs.
|
||||
|
||||
When cloning Yosys, some required libraries are included as git submodules. Make
|
||||
sure to call e.g.
|
||||
|
||||
$ git clone --recurse-submodules https://github.com/YosysHQ/yosys.git
|
||||
|
||||
or
|
||||
|
||||
$ git clone https://github.com/YosysHQ/yosys.git
|
||||
$ cd yosys
|
||||
$ git submodule update --init --recursive
|
||||
|
||||
You need a C++ compiler with C++17 support (up-to-date CLANG or GCC is
|
||||
recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
|
||||
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
|
||||
|
|
@ -84,52 +82,22 @@ prerequisites for building yosys:
|
|||
graphviz xdot pkg-config python3 libboost-system-dev \
|
||||
libboost-python-dev libboost-filesystem-dev zlib1g-dev
|
||||
|
||||
Similarily, on Mac OS X Homebrew can be used to install dependencies (from within cloned yosys repository):
|
||||
|
||||
$ brew tap Homebrew/bundle && brew bundle
|
||||
|
||||
or MacPorts:
|
||||
|
||||
$ sudo port install bison flex readline gawk libffi \
|
||||
git graphviz pkgconfig python36 boost zlib tcl
|
||||
|
||||
On FreeBSD use the following command to install all prerequisites:
|
||||
|
||||
# pkg install bison flex readline gawk libffi\
|
||||
git graphviz pkgconf python3 python36 tcl-wrapper boost-libs
|
||||
|
||||
On FreeBSD system use gmake instead of make. To run tests use:
|
||||
% MAKE=gmake CC=cc gmake test
|
||||
|
||||
For Cygwin use the following command to install all prerequisites, or select these additional packages:
|
||||
|
||||
setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel
|
||||
|
||||
The environment variable `CXX` can be used to control the C++ compiler used, or
|
||||
run one of the following:
|
||||
run one of the following to override it:
|
||||
|
||||
$ make config-clang
|
||||
$ make config-gcc
|
||||
|
||||
Note that these will result in `make` ignoring the `CXX` environment variable,
|
||||
unless `CXX` is assigned in the call to make, e.g.
|
||||
The Makefile has many variables influencing the build process. These can be
|
||||
adjusted by modifying the Makefile.conf file which is created at the `make
|
||||
config-...` step (see above), or they can be set by passing an option to the
|
||||
make command directly:
|
||||
|
||||
$ make CXX=$CXX
|
||||
|
||||
The Makefile has many variables influencing the build process. These can be
|
||||
adjusted by modifying the Makefile.conf file which is created at the
|
||||
`make config-...` step (see above), or they can be set by passing an option
|
||||
to the make command directly.
|
||||
|
||||
For example, if you have clang, and (a compatible version of) `ld.lld`
|
||||
available in PATH, it's recommended to speed up incremental builds with
|
||||
lld by enabling LTO:
|
||||
|
||||
$ make ENABLE_LTO=1
|
||||
|
||||
For other compilers and build configurations it might be
|
||||
necessary to make some changes to the config section of the
|
||||
Makefile.
|
||||
For other compilers and build configurations it might be necessary to make some
|
||||
changes to the config section of the Makefile. It's also an alternative way to
|
||||
set the make variables mentioned above.
|
||||
|
||||
$ vi Makefile # ..or..
|
||||
$ vi Makefile.conf
|
||||
|
|
@ -139,10 +107,9 @@ To build Yosys simply type 'make' in this directory.
|
|||
$ make
|
||||
$ sudo make install
|
||||
|
||||
Note that this also downloads, builds and installs ABC (using yosys-abc
|
||||
as executable name).
|
||||
|
||||
Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
|
||||
Tests are located in the tests subdirectory and can be executed using the test
|
||||
target. Note that you need gawk as well as a recent version of iverilog (i.e.
|
||||
build from git). Then, execute tests via:
|
||||
|
||||
$ make test
|
||||
|
||||
|
|
@ -153,6 +120,7 @@ To use a separate (out-of-tree) build directory, provide a path to the Makefile.
|
|||
|
||||
Out-of-tree builds require a clean source tree.
|
||||
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
|
|
@ -257,365 +225,14 @@ The command ``prep`` provides a good default word-level synthesis script, as
|
|||
used in SMT-based formal verification.
|
||||
|
||||
|
||||
Unsupported Verilog-2005 Features
|
||||
=================================
|
||||
|
||||
The following Verilog-2005 features are not supported by
|
||||
Yosys and there are currently no plans to add support
|
||||
for them:
|
||||
|
||||
- Non-synthesizable language features as defined in
|
||||
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
|
||||
|
||||
- The ``tri``, ``triand`` and ``trior`` net types
|
||||
|
||||
- The ``config`` and ``disable`` keywords and library map files
|
||||
|
||||
|
||||
Verilog Attributes and non-standard features
|
||||
============================================
|
||||
|
||||
- The ``full_case`` attribute on case statements is supported
|
||||
(also the non-standard ``// synopsys full_case`` directive)
|
||||
|
||||
- The ``parallel_case`` attribute on case statements is supported
|
||||
(also the non-standard ``// synopsys parallel_case`` directive)
|
||||
|
||||
- The ``// synopsys translate_off`` and ``// synopsys translate_on``
|
||||
directives are also supported (but the use of ``` `ifdef .. `endif ```
|
||||
is strongly recommended instead).
|
||||
|
||||
- The ``nomem2reg`` attribute on modules or arrays prohibits the
|
||||
automatic early conversion of arrays to separate registers. This
|
||||
is potentially dangerous. Usually the front-end has good reasons
|
||||
for converting an array to a list of registers. Prohibiting this
|
||||
step will likely result in incorrect synthesis results.
|
||||
|
||||
- The ``mem2reg`` attribute on modules or arrays forces the early
|
||||
conversion of arrays to separate registers.
|
||||
|
||||
- The ``nomeminit`` attribute on modules or arrays prohibits the
|
||||
creation of initialized memories. This effectively puts ``mem2reg``
|
||||
on all memories that are written to in an ``initial`` block and
|
||||
are not ROMs.
|
||||
|
||||
- The ``nolatches`` attribute on modules or always-blocks
|
||||
prohibits the generation of logic-loops for latches. Instead
|
||||
all not explicitly assigned values default to x-bits. This does
|
||||
not affect clocked storage elements such as flip-flops.
|
||||
|
||||
- The ``nosync`` attribute on registers prohibits the generation of a
|
||||
storage element. The register itself will always have all bits set
|
||||
to 'x' (undefined). The variable may only be used as blocking assigned
|
||||
temporary variable within an always block. This is mostly used internally
|
||||
by Yosys to synthesize Verilog functions and access arrays.
|
||||
|
||||
- The ``nowrshmsk`` attribute on a register prohibits the generation of
|
||||
shift-and-mask type circuits for writing to bit slices of that register.
|
||||
|
||||
- The ``onehot`` attribute on wires mark them as one-hot state register. This
|
||||
is used for example for memory port sharing and set by the fsm_map pass.
|
||||
|
||||
- The ``blackbox`` attribute on modules is used to mark empty stub modules
|
||||
that have the same ports as the real thing but do not contain information
|
||||
on the internal configuration. This modules are only used by the synthesis
|
||||
passes to identify input and output ports of cells. The Verilog backend
|
||||
also does not output blackbox modules on default. ``read_verilog``, unless
|
||||
called with ``-noblackbox`` will automatically set the blackbox attribute
|
||||
on any empty module it reads.
|
||||
|
||||
- The ``noblackbox`` attribute set on an empty module prevents ``read_verilog``
|
||||
from automatically setting the blackbox attribute on the module.
|
||||
|
||||
- The ``whitebox`` attribute on modules triggers the same behavior as
|
||||
``blackbox``, but is for whitebox modules, i.e. library modules that
|
||||
contain a behavioral model of the cell type.
|
||||
|
||||
- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog``
|
||||
is run in `-lib` mode. Otherwise it's automatically removed.
|
||||
|
||||
- The ``dynports`` attribute is used by the Verilog front-end to mark modules
|
||||
that have ports with a width that depends on a parameter.
|
||||
|
||||
- The ``hdlname`` attribute is used by some passes to document the original
|
||||
(HDL) name of a module when renaming a module. It should contain a single
|
||||
name, or, when describing a hierarchical name in a flattened design, multiple
|
||||
names separated by a single space character.
|
||||
|
||||
- The ``keep`` attribute on cells and wires is used to mark objects that should
|
||||
never be removed by the optimizer. This is used for example for cells that
|
||||
have hidden connections that are not part of the netlist, such as IO pads.
|
||||
Setting the ``keep`` attribute on a module has the same effect as setting it
|
||||
on all instances of the module.
|
||||
|
||||
- The ``keep_hierarchy`` attribute on cells and modules keeps the ``flatten``
|
||||
command from flattening the indicated cells and modules.
|
||||
|
||||
- The ``init`` attribute on wires is set by the frontend when a register is
|
||||
initialized "FPGA-style" with ``reg foo = val``. It can be used during
|
||||
synthesis to add the necessary reset logic.
|
||||
|
||||
- The ``top`` attribute on a module marks this module as the top of the
|
||||
design hierarchy. The ``hierarchy`` command sets this attribute when called
|
||||
with ``-top``. Other commands, such as ``flatten`` and various backends
|
||||
use this attribute to determine the top module.
|
||||
|
||||
- The ``src`` attribute is set on cells and wires created by to the string
|
||||
``<hdl-file-name>:<line-number>`` by the HDL front-end and is then carried
|
||||
through the synthesis. When entities are combined, a new |-separated
|
||||
string is created that contains all the string from the original entities.
|
||||
|
||||
- The ``defaultvalue`` attribute is used to store default values for
|
||||
module inputs. The attribute is attached to the input wire by the HDL
|
||||
front-end when the input is declared with a default value.
|
||||
|
||||
- The ``parameter`` and ``localparam`` attributes are used to mark wires
|
||||
that represent module parameters or localparams (when the HDL front-end
|
||||
is run in ``-pwires`` mode).
|
||||
|
||||
- Wires marked with the ``hierconn`` attribute are connected to wires with the
|
||||
same name (format ``cell_name.identifier``) when they are imported from
|
||||
sub-modules by ``flatten``.
|
||||
|
||||
- The ``clkbuf_driver`` attribute can be set on an output port of a blackbox
|
||||
module to mark it as a clock buffer output, and thus prevent ``clkbufmap``
|
||||
from inserting another clock buffer on a net driven by such output.
|
||||
|
||||
- The ``clkbuf_sink`` attribute can be set on an input port of a module to
|
||||
request clock buffer insertion by the ``clkbufmap`` pass.
|
||||
|
||||
- The ``clkbuf_inv`` attribute can be set on an output port of a module
|
||||
with the value set to the name of an input port of that module. When
|
||||
the ``clkbufmap`` would otherwise insert a clock buffer on this output,
|
||||
it will instead try inserting the clock buffer on the input port (this
|
||||
is used to implement clock inverter cells that clock buffer insertion
|
||||
will "see through").
|
||||
|
||||
- The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent
|
||||
automatic clock buffer insertion by ``clkbufmap``. This behaviour can be
|
||||
overridden by providing a custom selection to ``clkbufmap``.
|
||||
|
||||
- The ``invertible_pin`` attribute can be set on a port to mark it as
|
||||
invertible via a cell parameter. The name of the inversion parameter
|
||||
is specified as the value of this attribute. The value of the inversion
|
||||
parameter must be of the same width as the port, with 1 indicating
|
||||
an inverted bit and 0 indicating a non-inverted bit.
|
||||
|
||||
- The ``iopad_external_pin`` attribute on a blackbox module's port marks
|
||||
it as the external-facing pin of an I/O pad, and prevents ``iopadmap``
|
||||
from inserting another pad cell on it.
|
||||
|
||||
- The module attribute ``abc9_lut`` is an integer attribute indicating to
|
||||
`abc9` that this module describes a LUT with an area cost of this value, and
|
||||
propagation delays described using `specify` statements.
|
||||
|
||||
- The module attribute ``abc9_box`` is a boolean specifying a black/white-box
|
||||
definition, with propagation delays described using `specify` statements, for
|
||||
use by `abc9`.
|
||||
|
||||
- The port attribute ``abc9_carry`` marks the carry-in (if an input port) and
|
||||
carry-out (if output port) ports of a box. This information is necessary for
|
||||
`abc9` to preserve the integrity of carry-chains. Specifying this attribute
|
||||
onto a bus port will affect only its most significant bit.
|
||||
|
||||
- The module attribute ``abc9_flop`` is a boolean marking the module as a
|
||||
flip-flop. This allows `abc9` to analyse its contents in order to perform
|
||||
sequential synthesis.
|
||||
|
||||
- The frontend sets attributes ``always_comb``, ``always_latch`` and
|
||||
``always_ff`` on processes derived from SystemVerilog style always blocks
|
||||
according to the type of the always. These are checked for correctness in
|
||||
``proc_dlatch``.
|
||||
|
||||
- The cell attribute ``wildcard_port_conns`` represents wildcard port
|
||||
connections (SystemVerilog ``.*``). These are resolved to concrete
|
||||
connections to matching wires in ``hierarchy``.
|
||||
|
||||
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
||||
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
||||
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||
by adding an empty ``{* *}`` statement.)
|
||||
|
||||
- In module parameter and port declarations, and cell port and parameter
|
||||
lists, a trailing comma is ignored. This simplifies writing Verilog code
|
||||
generators a bit in some cases.
|
||||
|
||||
- Modules can be declared with ``module mod_name(...);`` (with three dots
|
||||
instead of a list of module ports). With this syntax it is sufficient
|
||||
to simply declare a module port as 'input' or 'output' in the module
|
||||
body.
|
||||
|
||||
- When defining a macro with `define, all text between triple double quotes
|
||||
is interpreted as macro body, even if it contains unescaped newlines. The
|
||||
triple double quotes are removed from the macro body. For example:
|
||||
|
||||
`define MY_MACRO(a, b) """
|
||||
assign a = 23;
|
||||
assign b = 42;
|
||||
"""
|
||||
|
||||
- The attribute ``via_celltype`` can be used to implement a Verilog task or
|
||||
function by instantiating the specified cell type. The value is the name
|
||||
of the cell type to use. For functions the name of the output port can
|
||||
be specified by appending it to the cell type separated by a whitespace.
|
||||
The body of the task or function is unused in this case and can be used
|
||||
to specify a behavioral model of the cell type for simulation. For example:
|
||||
|
||||
module my_add3(A, B, C, Y);
|
||||
parameter WIDTH = 8;
|
||||
input [WIDTH-1:0] A, B, C;
|
||||
output [WIDTH-1:0] Y;
|
||||
...
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
...
|
||||
(* via_celltype = "my_add3 Y" *)
|
||||
(* via_celltype_defparam_WIDTH = 32 *)
|
||||
function [31:0] add3;
|
||||
input [31:0] A, B, C;
|
||||
begin
|
||||
add3 = A + B + C;
|
||||
end
|
||||
endfunction
|
||||
...
|
||||
endmodule
|
||||
|
||||
- The ``wiretype`` attribute is added by the verilog parser for wires of a
|
||||
typedef'd type to indicate the type identifier.
|
||||
|
||||
- Various ``enum_value_{value}`` attributes are added to wires of an enumerated type
|
||||
to give a map of possible enum items to their values.
|
||||
|
||||
- The ``enum_base_type`` attribute is added to enum items to indicate which
|
||||
enum they belong to (enums -- anonymous and otherwise -- are
|
||||
automatically named with an auto-incrementing counter). Note that enums
|
||||
are currently not strongly typed.
|
||||
|
||||
- A limited subset of DPI-C functions is supported. The plugin mechanism
|
||||
(see ``help plugin``) can be used to load .so files with implementations
|
||||
of DPI-C routines. As a non-standard extension it is possible to specify
|
||||
a plugin alias using the ``<alias>:`` syntax. For example:
|
||||
|
||||
module dpitest;
|
||||
import "DPI-C" function foo:round = real my_round (real);
|
||||
parameter real r = my_round(12.345);
|
||||
endmodule
|
||||
|
||||
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
|
||||
|
||||
- Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant
|
||||
expressions as ``<size>``. If the expression is not a simple identifier, it
|
||||
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
|
||||
|
||||
- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
|
||||
initial blocks in an unconditional context (only if/case statements on
|
||||
expressions over parameters and constant values are allowed). The intended
|
||||
use for this is synthesis-time DRC.
|
||||
|
||||
- There is limited support for converting ``specify`` .. ``endspecify``
|
||||
statements to special ``$specify2``, ``$specify3``, and ``$specrule`` cells,
|
||||
for use in blackboxes and whiteboxes. Use ``read_verilog -specify`` to
|
||||
enable this functionality. (By default these blocks are ignored.)
|
||||
|
||||
- The ``reprocess_after`` internal attribute is used by the Verilog frontend to
|
||||
mark cells with bindings which might depend on the specified instantiated
|
||||
module. Modules with such cells will be reprocessed during the ``hierarchy``
|
||||
pass once the referenced module definition(s) become available.
|
||||
|
||||
- The ``smtlib2_module`` attribute can be set on a blackbox module to specify a
|
||||
formal model directly using SMT-LIB 2. For such a module, the
|
||||
``smtlib2_comb_expr`` attribute can be used on output ports to define their
|
||||
value using an SMT-LIB 2 expression. For example:
|
||||
|
||||
(* blackbox *)
|
||||
(* smtlib2_module *)
|
||||
module submod(a, b);
|
||||
input [7:0] a;
|
||||
(* smtlib2_comb_expr = "(bvnot a)" *)
|
||||
output [7:0] b;
|
||||
endmodule
|
||||
|
||||
Non-standard or SystemVerilog features for formal verification
|
||||
==============================================================
|
||||
|
||||
- Support for ``assert``, ``assume``, ``restrict``, and ``cover`` is enabled
|
||||
when ``read_verilog`` is called with ``-formal``.
|
||||
|
||||
- The system task ``$initstate`` evaluates to 1 in the initial state and
|
||||
to 0 otherwise.
|
||||
|
||||
- The system function ``$anyconst`` evaluates to any constant value. This is
|
||||
equivalent to declaring a reg as ``rand const``, but also works outside
|
||||
of checkers. (Yosys also supports ``rand const`` outside checkers.)
|
||||
|
||||
- The system function ``$anyseq`` evaluates to any value, possibly a different
|
||||
value in each cycle. This is equivalent to declaring a reg as ``rand``,
|
||||
but also works outside of checkers. (Yosys also supports ``rand``
|
||||
variables outside checkers.)
|
||||
|
||||
- The system functions ``$allconst`` and ``$allseq`` can be used to construct
|
||||
formal exist-forall problems. Assumptions only hold if the trace satisfies
|
||||
the assumption for all ``$allconst/$allseq`` values. For assertions and cover
|
||||
statements it is sufficient if just one ``$allconst/$allseq`` value triggers
|
||||
the property (similar to ``$anyconst/$anyseq``).
|
||||
|
||||
- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq`` attribute
|
||||
(for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven
|
||||
by a ``$anyconst/$anyseq/$allconst/$allseq`` function.
|
||||
|
||||
- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
|
||||
supported in any clocked block.
|
||||
|
||||
- The syntax ``@($global_clock)`` can be used to create FFs that have no
|
||||
explicit clock input (``$ff`` cells). The same can be achieved by using
|
||||
``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
|
||||
is marked with the ``(* gclk *)`` Verilog attribute.
|
||||
|
||||
|
||||
Supported features from SystemVerilog
|
||||
=====================================
|
||||
|
||||
When ``read_verilog`` is called with ``-sv``, it accepts some language features
|
||||
from SystemVerilog:
|
||||
|
||||
- The ``assert`` statement from SystemVerilog is supported in its most basic
|
||||
form. In module context: ``assert property (<expression>);`` and within an
|
||||
always block: ``assert(<expression>);``. It is transformed to an ``$assert`` cell.
|
||||
|
||||
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
|
||||
also supported. The same limitations as with the ``assert`` statement apply.
|
||||
|
||||
- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic``
|
||||
and ``bit`` are supported.
|
||||
|
||||
- Declaring free variables with ``rand`` and ``rand const`` is supported.
|
||||
|
||||
- Checkers without a port list that do not need to be instantiated (but instead
|
||||
behave like a named block) are supported.
|
||||
|
||||
- SystemVerilog packages are supported. Once a SystemVerilog file is read
|
||||
into a design with ``read_verilog``, all its packages are available to
|
||||
SystemVerilog files being read into the same design afterwards.
|
||||
|
||||
- typedefs are supported (including inside packages)
|
||||
- type casts are currently not supported
|
||||
|
||||
- enums are supported (including inside packages)
|
||||
- but are currently not strongly typed
|
||||
|
||||
- packed structs and unions are supported
|
||||
- arrays of packed structs/unions are currently not supported
|
||||
- structure literals are currently not supported
|
||||
|
||||
- multidimensional arrays are supported
|
||||
- array assignment of unpacked arrays is currently not supported
|
||||
- array literals are currently not supported
|
||||
|
||||
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
|
||||
ports are inputs or outputs are supported.
|
||||
|
||||
- Assignments within expressions are supported.
|
||||
Additional information
|
||||
======================
|
||||
|
||||
The ``read_verilog`` command, used by default when calling ``read`` with Verilog
|
||||
source input, does not perform syntax checking. You should instead lint your
|
||||
source with another tool such as
|
||||
[Verilator](https://www.veripool.org/verilator/) first, e.g. by calling
|
||||
``verilator --lint-only``.
|
||||
|
||||
|
||||
Building the documentation
|
||||
|
|
|
|||
2
abc
2
abc
|
|
@ -1 +1 @@
|
|||
Subproject commit cac8f99eaa220a5e3db5caeb87cef0a975c953a2
|
||||
Subproject commit f2d68d590fa6f8fc32295a2edd79afc0d14a1414
|
||||
|
|
@ -53,6 +53,8 @@ struct XAigerWriter
|
|||
dict<SigBit, float> arrival_times;
|
||||
|
||||
vector<pair<int, int>> aig_gates;
|
||||
vector<SigBit> bit2aig_stack;
|
||||
int next_loop_check = 1024;
|
||||
vector<int> aig_outputs;
|
||||
int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0;
|
||||
|
||||
|
|
@ -76,6 +78,24 @@ struct XAigerWriter
|
|||
return it->second;
|
||||
}
|
||||
|
||||
if (GetSize(bit2aig_stack)== next_loop_check) {
|
||||
for (int i = 0; i < next_loop_check; ++i)
|
||||
{
|
||||
SigBit report_bit = bit2aig_stack[i];
|
||||
if (report_bit != bit)
|
||||
continue;
|
||||
for (int j = i; j < next_loop_check; ++j) {
|
||||
report_bit = bit2aig_stack[j];
|
||||
if (report_bit.is_wire() && report_bit.wire->name.isPublic())
|
||||
break;
|
||||
}
|
||||
log_error("Found combinatorial logic loop while processing signal %s.\n", log_signal(report_bit));
|
||||
}
|
||||
next_loop_check *= 2;
|
||||
}
|
||||
|
||||
bit2aig_stack.push_back(bit);
|
||||
|
||||
// NB: Cannot use iterator returned from aig_map.insert()
|
||||
// since this function is called recursively
|
||||
|
||||
|
|
@ -93,6 +113,8 @@ struct XAigerWriter
|
|||
a = bit2aig(alias_map.at(bit));
|
||||
}
|
||||
|
||||
bit2aig_stack.pop_back();
|
||||
|
||||
if (bit == State::Sx || bit == State::Sz) {
|
||||
log_debug("Design contains 'x' or 'z' bits. Treating as 1'b0.\n");
|
||||
a = aig_map.at(State::S0);
|
||||
|
|
|
|||
|
|
@ -262,7 +262,8 @@ struct Index {
|
|||
if (cell->type.in(ID($gt), ID($ge)))
|
||||
std::swap(aport, bport);
|
||||
int carry = cell->type.in(ID($le), ID($ge)) ? CFALSE : CTRUE;
|
||||
Lit a, b;
|
||||
Lit a = Writer::EMPTY_LIT;
|
||||
Lit b = Writer::EMPTY_LIT;
|
||||
// TODO: this might not be the most economic structure; revisit at a later date
|
||||
for (int i = 0; i < width; i++) {
|
||||
a = visit(cursor, aport[i]);
|
||||
|
|
@ -387,7 +388,7 @@ struct Index {
|
|||
if (/* 4 input types */ cell->type.in(ID($_AOI4_), ID($_OAI4_)))
|
||||
d = visit(cursor, cell->getPort(ID::D)[obit]);
|
||||
else
|
||||
d = cell->type == ID($_AOI3_) ? 1 : 0;
|
||||
d = cell->type == ID($_AOI3_) ? CTRUE : CFALSE;
|
||||
|
||||
if (/* aoi */ cell->type.in(ID($_AOI3_), ID($_AOI4_)))
|
||||
return NOT(OR(AND(a, b), AND(c, d)));
|
||||
|
|
@ -664,8 +665,6 @@ struct Index {
|
|||
struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
||||
typedef unsigned int Lit;
|
||||
|
||||
const static Lit CONST_FALSE = 0;
|
||||
const static Lit CONST_TRUE = 1;
|
||||
const static constexpr Lit EMPTY_LIT = std::numeric_limits<Lit>::max();
|
||||
|
||||
static Lit negate(Lit lit) {
|
||||
|
|
@ -802,8 +801,6 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
|||
};
|
||||
|
||||
struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
||||
const static int CONST_FALSE = 0;
|
||||
const static int CONST_TRUE = 0;
|
||||
const static constexpr int EMPTY_LIT = -1;
|
||||
|
||||
XAigerAnalysis()
|
||||
|
|
@ -835,12 +832,8 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
|||
return false;
|
||||
|
||||
Cell *driver = bit.wire->driverCell();
|
||||
if (!driver->type.isPublic())
|
||||
return false;
|
||||
|
||||
Module *mod = design->module(driver->type);
|
||||
log_assert(mod);
|
||||
if (!mod->has_attribute(ID::abc9_box_id))
|
||||
if (!mod || !mod->has_attribute(ID::abc9_box_id))
|
||||
return false;
|
||||
|
||||
int max = 1;
|
||||
|
|
@ -873,7 +866,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
|||
HierCursor cursor;
|
||||
for (auto box : top_minfo->found_blackboxes) {
|
||||
Module *def = design->module(box->type);
|
||||
if (!box->type.isPublic() || (def && !def->has_attribute(ID::abc9_box_id)))
|
||||
if (!(def && def->has_attribute(ID::abc9_box_id)))
|
||||
for (auto &conn : box->connections_)
|
||||
if (box->output(conn.first))
|
||||
for (auto bit : conn.second)
|
||||
|
|
@ -888,7 +881,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
|||
|
||||
for (auto box : top_minfo->found_blackboxes) {
|
||||
Module *def = design->module(box->type);
|
||||
if (!box->type.isPublic() || (def && !def->has_attribute(ID::abc9_box_id)))
|
||||
if (!(def && def->has_attribute(ID::abc9_box_id)))
|
||||
for (auto &conn : box->connections_)
|
||||
if (box->input(conn.first))
|
||||
for (auto bit : conn.second)
|
||||
|
|
@ -1109,7 +1102,7 @@ struct XAigerWriter : AigerWriter {
|
|||
holes_module->ports.push_back(w->name);
|
||||
holes_pis.push_back(w);
|
||||
}
|
||||
in_conn.append(holes_pis[i]);
|
||||
in_conn.append(holes_pis[holes_pi_idx]);
|
||||
holes_pi_idx++;
|
||||
}
|
||||
holes_wb->setPort(port_id, in_conn);
|
||||
|
|
|
|||
|
|
@ -832,7 +832,10 @@ struct BtorWorker
|
|||
}
|
||||
}
|
||||
|
||||
if (constword)
|
||||
// If not fully defined, undef bits should be able to take a
|
||||
// different value for each address so we can't initialise from
|
||||
// one value (and btor2parser doesn't like it)
|
||||
if (constword && firstword.is_fully_def())
|
||||
{
|
||||
if (verbose)
|
||||
btorf("; initval = %s\n", log_signal(firstword));
|
||||
|
|
@ -1077,6 +1080,7 @@ struct BtorWorker
|
|||
btorf("%d input %d\n", nid, sid);
|
||||
ywmap_input(s);
|
||||
nid_width[nid] = GetSize(s);
|
||||
add_nid_sig(nid, s);
|
||||
|
||||
for (int j = 0; j < GetSize(s); j++)
|
||||
nidbits.push_back(make_pair(nid, j));
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ cd test_cells.tmp
|
|||
|
||||
for fn in test_*.il; do
|
||||
../../../yosys -p "
|
||||
read_ilang $fn
|
||||
read_rtlil $fn
|
||||
rename gold gate
|
||||
synth
|
||||
|
||||
read_ilang $fn
|
||||
read_rtlil $fn
|
||||
miter -equiv -make_assert -flatten gold gate main
|
||||
hierarchy -top main
|
||||
write_btor ${fn%.il}.btor
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct Scheduler {
|
|||
struct Vertex {
|
||||
T *data;
|
||||
Vertex *prev, *next;
|
||||
pool<Vertex*, hash_ptr_ops> preds, succs;
|
||||
pool<Vertex*> preds, succs;
|
||||
|
||||
Vertex() : data(NULL), prev(this), next(this) {}
|
||||
Vertex(T *data) : data(data), prev(NULL), next(NULL) {}
|
||||
|
|
@ -300,10 +300,10 @@ struct FlowGraph {
|
|||
};
|
||||
|
||||
std::vector<Node*> nodes;
|
||||
dict<const RTLIL::Wire*, pool<Node*, hash_ptr_ops>> wire_comb_defs, wire_sync_defs, wire_uses;
|
||||
dict<Node*, pool<const RTLIL::Wire*>, hash_ptr_ops> node_comb_defs, node_sync_defs, node_uses;
|
||||
dict<const RTLIL::Wire*, pool<Node*>> wire_comb_defs, wire_sync_defs, wire_uses;
|
||||
dict<Node*, pool<const RTLIL::Wire*>> node_comb_defs, node_sync_defs, node_uses;
|
||||
dict<const RTLIL::Wire*, bool> wire_def_inlinable;
|
||||
dict<const RTLIL::Wire*, dict<Node*, bool, hash_ptr_ops>> wire_use_inlinable;
|
||||
dict<const RTLIL::Wire*, dict<Node*, bool>> wire_use_inlinable;
|
||||
dict<RTLIL::SigBit, bool> bit_has_state;
|
||||
|
||||
~FlowGraph()
|
||||
|
|
@ -365,7 +365,7 @@ struct FlowGraph {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool is_inlinable(const RTLIL::Wire *wire, const pool<Node*, hash_ptr_ops> &nodes) const
|
||||
bool is_inlinable(const RTLIL::Wire *wire, const pool<Node*> &nodes) const
|
||||
{
|
||||
// Can the wire be inlined, knowing that the given nodes are reachable?
|
||||
if (nodes.size() != 1)
|
||||
|
|
@ -612,7 +612,7 @@ std::string escape_c_string(const std::string &input)
|
|||
output.push_back('"');
|
||||
for (auto c : input) {
|
||||
if (::isprint(c)) {
|
||||
if (c == '\\')
|
||||
if (c == '\\' || c == '"')
|
||||
output.push_back('\\');
|
||||
output.push_back(c);
|
||||
} else {
|
||||
|
|
@ -2497,7 +2497,7 @@ struct CxxrtlWorker {
|
|||
// Alias of a member wire
|
||||
const RTLIL::Wire *aliasee = debug_wire_type.sig_subst.as_wire();
|
||||
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
|
||||
dump_debug_attrs(aliasee);
|
||||
dump_debug_attrs(wire);
|
||||
f << ", ";
|
||||
// If the aliasee is an outline, then the alias must be an outline, too; otherwise downstream
|
||||
// tooling has no way to find out about the outline.
|
||||
|
|
@ -3080,7 +3080,7 @@ struct CxxrtlWorker {
|
|||
// without feedback arcs can generally be evaluated in a single pass, i.e. it always requires only
|
||||
// a single delta cycle.
|
||||
Scheduler<FlowGraph::Node> scheduler;
|
||||
dict<FlowGraph::Node*, Scheduler<FlowGraph::Node>::Vertex*, hash_ptr_ops> node_vertex_map;
|
||||
dict<FlowGraph::Node*, Scheduler<FlowGraph::Node>::Vertex*> node_vertex_map;
|
||||
for (auto node : flow.nodes)
|
||||
node_vertex_map[node] = scheduler.add(node);
|
||||
for (auto node_comb_def : flow.node_comb_defs) {
|
||||
|
|
@ -3095,7 +3095,7 @@ struct CxxrtlWorker {
|
|||
|
||||
// Find out whether the order includes any feedback arcs.
|
||||
std::vector<FlowGraph::Node*> node_order;
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> evaluated_nodes;
|
||||
pool<FlowGraph::Node*> evaluated_nodes;
|
||||
pool<const RTLIL::Wire*> feedback_wires;
|
||||
for (auto vertex : scheduler.schedule()) {
|
||||
auto node = vertex->data;
|
||||
|
|
@ -3139,7 +3139,7 @@ struct CxxrtlWorker {
|
|||
}
|
||||
|
||||
// Discover nodes reachable from primary outputs (i.e. members) and collect reachable wire users.
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> worklist;
|
||||
pool<FlowGraph::Node*> worklist;
|
||||
for (auto node : flow.nodes) {
|
||||
if (node->type == FlowGraph::Node::Type::CELL_EVAL && !is_internal_cell(node->cell->type))
|
||||
worklist.insert(node); // node evaluates a submodule
|
||||
|
|
@ -3159,8 +3159,8 @@ struct CxxrtlWorker {
|
|||
worklist.insert(node); // node drives public wires
|
||||
}
|
||||
}
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*, hash_ptr_ops>> live_wires;
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> live_nodes;
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*>> live_wires;
|
||||
pool<FlowGraph::Node*> live_nodes;
|
||||
while (!worklist.empty()) {
|
||||
auto node = worklist.pop();
|
||||
live_nodes.insert(node);
|
||||
|
|
@ -3290,15 +3290,15 @@ struct CxxrtlWorker {
|
|||
|
||||
// Discover nodes reachable from primary outputs (i.e. outlines) up until primary inputs (i.e. members)
|
||||
// and collect reachable wire users.
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> worklist;
|
||||
pool<FlowGraph::Node*> worklist;
|
||||
for (auto node : flow.nodes) {
|
||||
if (flow.node_comb_defs.count(node))
|
||||
for (auto wire : flow.node_comb_defs[node])
|
||||
if (debug_wire_types[wire].is_outline())
|
||||
worklist.insert(node); // node drives outline
|
||||
}
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*, hash_ptr_ops>> debug_live_wires;
|
||||
pool<FlowGraph::Node*, hash_ptr_ops> debug_live_nodes;
|
||||
dict<const RTLIL::Wire*, pool<FlowGraph::Node*>> debug_live_wires;
|
||||
pool<FlowGraph::Node*> debug_live_nodes;
|
||||
while (!worklist.empty()) {
|
||||
auto node = worklist.pop();
|
||||
debug_live_nodes.insert(node);
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ struct EdifBackend : public Backend {
|
|||
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
|
||||
else {
|
||||
std::string hex_string = "";
|
||||
for (size_t i = 0; i < val.size(); i += 4) {
|
||||
for (auto i = 0; i < val.size(); i += 4) {
|
||||
int digit_value = 0;
|
||||
if (i+0 < val.size() && val.at(i+0) == RTLIL::State::S1) digit_value |= 1;
|
||||
if (i+1 < val.size() && val.at(i+1) == RTLIL::State::S1) digit_value |= 2;
|
||||
|
|
|
|||
|
|
@ -210,14 +210,8 @@ struct SmtrModule {
|
|||
state_struct.insert(state->name, state->sort);
|
||||
}
|
||||
|
||||
void write(std::ostream &out)
|
||||
{
|
||||
SExprWriter w(out);
|
||||
|
||||
input_struct.write_definition(w);
|
||||
output_struct.write_definition(w);
|
||||
state_struct.write_definition(w);
|
||||
|
||||
void write_eval(SExprWriter &w)
|
||||
{
|
||||
w.push();
|
||||
w.open(list("define", list(name, "inputs", "state")));
|
||||
auto inlined = [&](Functional::Node n) {
|
||||
|
|
@ -240,7 +234,10 @@ struct SmtrModule {
|
|||
output_struct.write_value(w, [&](IdString name) { return node_to_sexpr(ir.output(name).value()); });
|
||||
state_struct.write_value(w, [&](IdString name) { return node_to_sexpr(ir.state(name).next_value()); });
|
||||
w.pop();
|
||||
}
|
||||
|
||||
void write_initial(SExprWriter &w)
|
||||
{
|
||||
w.push();
|
||||
auto initial = name + "_initial";
|
||||
w.open(list("define", initial));
|
||||
|
|
@ -259,6 +256,18 @@ struct SmtrModule {
|
|||
}
|
||||
w.pop();
|
||||
}
|
||||
|
||||
void write(std::ostream &out)
|
||||
{
|
||||
SExprWriter w(out);
|
||||
|
||||
input_struct.write_definition(w);
|
||||
output_struct.write_definition(w);
|
||||
state_struct.write_definition(w);
|
||||
|
||||
write_eval(w);
|
||||
write_initial(w);
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionalSmtrBackend : public Backend {
|
||||
|
|
@ -267,7 +276,7 @@ struct FunctionalSmtrBackend : public Backend {
|
|||
void help() override {
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" write_functional_rosette [options] [selection] [filename]\n");
|
||||
log(" write_functional_rosette [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Functional Rosette Backend.\n");
|
||||
log("\n");
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ struct JsonWriter
|
|||
bool use_selection;
|
||||
bool aig_mode;
|
||||
bool compat_int_mode;
|
||||
bool scopeinfo_mode;
|
||||
|
||||
Design *design;
|
||||
Module *module;
|
||||
|
|
@ -43,9 +44,9 @@ struct JsonWriter
|
|||
dict<SigBit, string> sigids;
|
||||
pool<Aig> aig_models;
|
||||
|
||||
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) :
|
||||
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode, bool scopeinfo_mode) :
|
||||
f(f), use_selection(use_selection), aig_mode(aig_mode),
|
||||
compat_int_mode(compat_int_mode) { }
|
||||
compat_int_mode(compat_int_mode), scopeinfo_mode(scopeinfo_mode) { }
|
||||
|
||||
string get_string(string str)
|
||||
{
|
||||
|
|
@ -192,9 +193,7 @@ struct JsonWriter
|
|||
for (auto c : module->cells()) {
|
||||
if (use_selection && !module->selected(c))
|
||||
continue;
|
||||
// Eventually we will want to emit $scopeinfo, but currently this
|
||||
// will break JSON netlist consumers like nextpnr
|
||||
if (c->type == ID($scopeinfo))
|
||||
if (!scopeinfo_mode && c->type == ID($scopeinfo))
|
||||
continue;
|
||||
f << stringf("%s\n", first ? "" : ",");
|
||||
f << stringf(" %s: {\n", get_name(c->name).c_str());
|
||||
|
|
@ -353,6 +352,12 @@ struct JsonBackend : public Backend {
|
|||
log(" emit 32-bit or smaller fully-defined parameter values directly\n");
|
||||
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||
log("\n");
|
||||
log(" -selected\n");
|
||||
log(" output only select module\n");
|
||||
log("\n");
|
||||
log(" -noscopeinfo\n");
|
||||
log(" don't include $scopeinfo cells in the output\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log("The general syntax of the JSON output created by this command is as follows:\n");
|
||||
log("\n");
|
||||
|
|
@ -403,7 +408,7 @@ struct JsonBackend : public Backend {
|
|||
log("\n");
|
||||
log("The \"offset\" and \"upto\" fields are skipped if their value would be 0.\n");
|
||||
log("They don't affect connection semantics, and are only used to preserve original\n");
|
||||
log("HDL bit indexing.");
|
||||
log("HDL bit indexing.\n");
|
||||
log("And <cell_details> is:\n");
|
||||
log("\n");
|
||||
log(" {\n");
|
||||
|
|
@ -597,6 +602,8 @@ struct JsonBackend : public Backend {
|
|||
{
|
||||
bool aig_mode = false;
|
||||
bool compat_int_mode = false;
|
||||
bool use_selection = false;
|
||||
bool scopeinfo_mode = true;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
|
@ -609,13 +616,21 @@ struct JsonBackend : public Backend {
|
|||
compat_int_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-selected") {
|
||||
use_selection = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noscopeinfo") {
|
||||
scopeinfo_mode = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
log_header(design, "Executing JSON backend.\n");
|
||||
|
||||
JsonWriter json_writer(*f, false, aig_mode, compat_int_mode);
|
||||
JsonWriter json_writer(*f, use_selection, aig_mode, compat_int_mode, scopeinfo_mode);
|
||||
json_writer.write_design(design);
|
||||
}
|
||||
} JsonBackend;
|
||||
|
|
@ -640,6 +655,9 @@ struct JsonPass : public Pass {
|
|||
log(" emit 32-bit or smaller fully-defined parameter values directly\n");
|
||||
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||
log("\n");
|
||||
log(" -noscopeinfo\n");
|
||||
log(" don't include $scopeinfo cells in the output\n");
|
||||
log("\n");
|
||||
log("See 'help write_json' for a description of the JSON format used.\n");
|
||||
log("\n");
|
||||
}
|
||||
|
|
@ -648,6 +666,7 @@ struct JsonPass : public Pass {
|
|||
std::string filename;
|
||||
bool aig_mode = false;
|
||||
bool compat_int_mode = false;
|
||||
bool scopeinfo_mode = true;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
|
@ -664,6 +683,10 @@ struct JsonPass : public Pass {
|
|||
compat_int_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noscopeinfo") {
|
||||
scopeinfo_mode = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -685,7 +708,7 @@ struct JsonPass : public Pass {
|
|||
f = &buf;
|
||||
}
|
||||
|
||||
JsonWriter json_writer(*f, true, aig_mode, compat_int_mode);
|
||||
JsonWriter json_writer(*f, true, aig_mode, compat_int_mode, scopeinfo_mode);
|
||||
json_writer.write_design(design);
|
||||
|
||||
if (!empty) {
|
||||
|
|
|
|||
|
|
@ -464,21 +464,6 @@ struct RTLILBackend : public Backend {
|
|||
}
|
||||
} RTLILBackend;
|
||||
|
||||
struct IlangBackend : public Backend {
|
||||
IlangBackend() : Backend("ilang", "(deprecated) alias of write_rtlil") { }
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log("See `help write_rtlil`.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
RTLILBackend.execute(f, filename, args, design);
|
||||
}
|
||||
} IlangBackend;
|
||||
|
||||
struct DumpPass : public Pass {
|
||||
DumpPass() : Pass("dump", "print parts of the design in RTLIL format") { }
|
||||
void help() override
|
||||
|
|
|
|||
|
|
@ -329,13 +329,14 @@ struct Smt2Worker
|
|||
{
|
||||
sigmap.apply(bit);
|
||||
|
||||
if (bit_driver.count(bit)) {
|
||||
export_cell(bit_driver.at(bit));
|
||||
sigmap.apply(bit);
|
||||
}
|
||||
|
||||
if (bit.wire == nullptr)
|
||||
return bit == RTLIL::State::S1 ? "true" : "false";
|
||||
|
||||
if (bit_driver.count(bit))
|
||||
export_cell(bit_driver.at(bit));
|
||||
sigmap.apply(bit);
|
||||
|
||||
if (fcache.count(bit) == 0) {
|
||||
if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "",
|
||||
log_signal(bit));
|
||||
|
|
|
|||
|
|
@ -1208,7 +1208,7 @@ class SmtOpts:
|
|||
def helpmsg(self):
|
||||
return """
|
||||
-s <solver>
|
||||
set SMT solver: z3, yices, boolector, bitwuzla, cvc4, mathsat, dummy
|
||||
set SMT solver: z3, yices, boolector, bitwuzla, cvc4, cvc5, mathsat, dummy
|
||||
default: yices
|
||||
|
||||
-S <opt>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ EOT
|
|||
for x in $(set +x; ls test_*.il | sort -R); do
|
||||
x=${x%.il}
|
||||
cat > $x.ys <<- EOT
|
||||
read_ilang $x.il
|
||||
read_rtlil $x.il
|
||||
copy gold gate
|
||||
|
||||
cd gate
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ EOT
|
|||
|
||||
for fn in test_*.il; do
|
||||
../../../yosys -p "
|
||||
read_ilang $fn
|
||||
read_rtlil $fn
|
||||
rename gold gate
|
||||
synth
|
||||
|
||||
read_ilang $fn
|
||||
read_rtlil $fn
|
||||
miter -equiv -flatten gold gate main
|
||||
hierarchy -top main
|
||||
write_smv -tpl template.txt ${fn#.il}.smv
|
||||
|
|
|
|||
|
|
@ -1044,16 +1044,23 @@ void dump_cell_expr_print(std::ostream &f, std::string indent, const RTLIL::Cell
|
|||
void dump_cell_expr_check(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
|
||||
{
|
||||
std::string flavor = cell->getParam(ID(FLAVOR)).decode_string();
|
||||
std::string label = "";
|
||||
if (cell->name.isPublic()) {
|
||||
label = stringf("%s: ", id(cell->name).c_str());
|
||||
}
|
||||
|
||||
if (flavor == "assert")
|
||||
f << stringf("%s" "assert (", indent.c_str());
|
||||
f << stringf("%s" "%s" "assert (", indent.c_str(), label.c_str());
|
||||
else if (flavor == "assume")
|
||||
f << stringf("%s" "assume (", indent.c_str());
|
||||
f << stringf("%s" "%s" "assume (", indent.c_str(), label.c_str());
|
||||
else if (flavor == "live")
|
||||
f << stringf("%s" "assert (eventually ", indent.c_str());
|
||||
f << stringf("%s" "%s" "assert (eventually ", indent.c_str(), label.c_str());
|
||||
else if (flavor == "fair")
|
||||
f << stringf("%s" "assume (eventually ", indent.c_str());
|
||||
f << stringf("%s" "%s" "assume (eventually ", indent.c_str(), label.c_str());
|
||||
else if (flavor == "cover")
|
||||
f << stringf("%s" "cover (", indent.c_str());
|
||||
f << stringf("%s" "%s" "cover (", indent.c_str(), label.c_str());
|
||||
else
|
||||
log_abort();
|
||||
dump_sigspec(f, cell->getPort(ID::A));
|
||||
f << stringf(");\n");
|
||||
}
|
||||
|
|
@ -1071,7 +1078,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($_BUF_)) {
|
||||
if (cell->type.in(ID($_BUF_), ID($buf))) {
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort(ID::Y));
|
||||
f << stringf(" = ");
|
||||
|
|
@ -2332,19 +2339,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
|
||||
dump_attributes(f, indent, module->attributes, "\n", /*modattr=*/true);
|
||||
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
|
||||
bool keep_running = true;
|
||||
int cnt = 0;
|
||||
for (int port_id = 1; keep_running; port_id++) {
|
||||
keep_running = false;
|
||||
for (auto wire : module->wires()) {
|
||||
if (wire->port_id == port_id) {
|
||||
if (port_id != 1)
|
||||
f << stringf(", ");
|
||||
f << stringf("%s", id(wire->name).c_str());
|
||||
keep_running = true;
|
||||
if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++;
|
||||
continue;
|
||||
}
|
||||
for (auto port : module->ports) {
|
||||
Wire *wire = module->wire(port);
|
||||
if (wire) {
|
||||
if (port != module->ports[0])
|
||||
f << stringf(", ");
|
||||
f << stringf("%s", id(wire->name).c_str());
|
||||
if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
f << stringf(");\n");
|
||||
|
|
|
|||
|
|
@ -252,6 +252,11 @@ images:
|
|||
$(MAKE) -C source/_images
|
||||
$(MAKE) -C source/_images convert
|
||||
|
||||
.PHONY: gen
|
||||
gen:
|
||||
$(MAKE) examples
|
||||
$(MAKE) images
|
||||
|
||||
.PHONY: reqs
|
||||
reqs:
|
||||
$(PYTHON) -m pip install -r source/requirements.txt
|
||||
|
|
|
|||
|
|
@ -15,23 +15,23 @@
|
|||
\tikzstyle{data} = [draw, fill=blue!10, ellipse, minimum height=3em, minimum width=7em, node distance=15em]
|
||||
\node[process] (vlog) {Verilog Frontend};
|
||||
\node[process, dashed, fill=green!5] (vhdl) [right of=vlog] {VHDL Frontend};
|
||||
\node[process] (ilang) [right of=vhdl] {RTLIL Frontend};
|
||||
\node[process] (rtlilfe) [right of=vhdl] {RTLIL Frontend};
|
||||
\node[data] (ast) [below of=vlog, node distance=5em, xshift=7.5em] {AST};
|
||||
\node[process] (astfe) [below of=ast, node distance=5em] {AST Frontend};
|
||||
\node[data] (rtlil) [below of=astfe, node distance=5em, xshift=7.5em] {RTLIL};
|
||||
\node[process] (pass) [right of=rtlil, node distance=5em, xshift=7.5em] {Passes};
|
||||
\node[process] (vlbe) [below of=rtlil, node distance=7em, xshift=-13em] {Verilog Backend};
|
||||
\node[process] (ilangbe) [below of=rtlil, node distance=7em, xshift=0em] {RTLIL Backend};
|
||||
\node[process] (rtlilbe) [below of=rtlil, node distance=7em, xshift=0em] {RTLIL Backend};
|
||||
\node[process, dashed, fill=green!5] (otherbe) [below of=rtlil, node distance=7em, xshift=+13em] {Other Backends};
|
||||
|
||||
\draw[-latex] (vlog) -- (ast);
|
||||
\draw[-latex] (vhdl) -- (ast);
|
||||
\draw[-latex] (ast) -- (astfe);
|
||||
\draw[-latex] (astfe) -- (rtlil);
|
||||
\draw[-latex] (ilang) -- (rtlil);
|
||||
\draw[-latex] (rtlilfe) -- (rtlil);
|
||||
\draw[latex-latex] (rtlil) -- (pass);
|
||||
\draw[-latex] (rtlil) -- (vlbe);
|
||||
\draw[-latex] (rtlil) -- (ilangbe);
|
||||
\draw[-latex] (rtlil) -- (rtlilbe);
|
||||
\draw[-latex] (rtlil) -- (otherbe);
|
||||
\end{tikzpicture}
|
||||
\end{document}
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 33 KiB |
|
|
@ -1,40 +0,0 @@
|
|||
/* Don't hide the right sidebar as we're placing our fixed links there */
|
||||
aside.no-toc {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* Colorful headings */
|
||||
h1 {
|
||||
color: var(--color-brand-primary);
|
||||
}
|
||||
|
||||
h2, h3, h4, h5, h6 {
|
||||
color: var(--color-brand-content);
|
||||
}
|
||||
|
||||
/* Use a different color for external links */
|
||||
a.external {
|
||||
color: var(--color-brand-primary) !important;
|
||||
}
|
||||
|
||||
.wy-table-responsive table td {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
body[data-theme="dark"] {
|
||||
.invert-helper {
|
||||
filter: url("data:image/svg+xml,<svg xmlns='http%3A//www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='1.47 -1.73 -0.467 0 0.867 -0.733 0.467 -0.467 0 0.867 -0.667 -1.07 1.07 0 0.867 0 0 0 1.0 0'></feColorMatrix></filter></svg>#f");
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body:not([data-theme="light"]) {
|
||||
.invert-helper {
|
||||
filter: url("data:image/svg+xml,<svg xmlns='http%3A//www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='1.47 -1.73 -0.467 0 0.867 -0.733 0.467 -0.467 0 0.867 -0.667 -1.07 1.07 0 0.867 0 0 0 1.0 0'></feColorMatrix></filter></svg>#f");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
{#
|
||||
|
||||
See https://github.com/pradyunsg/furo/blob/main/src/furo/theme/furo/page.html for the original
|
||||
block this is overwriting.
|
||||
|
||||
The part that is customized is between the "begin of custom part" and "end of custom part"
|
||||
comments below. It uses the same styles as the existing right sidebar code.
|
||||
|
||||
#}
|
||||
{% extends "furo/page.html" %}
|
||||
{% block right_sidebar %}
|
||||
<div class="toc-sticky toc-scroll">
|
||||
{# begin of custom part #}
|
||||
<div class="toc-title-container">
|
||||
<span class="toc-title">
|
||||
YosysHQ
|
||||
</span>
|
||||
</div>
|
||||
<div class="toc-tree-container yosyshq-links" style="padding-bottom: 0">
|
||||
<div class="toc-tree">
|
||||
<ul>
|
||||
<li></li>
|
||||
<li><a class="reference external" href="https://yosyshq.readthedocs.io">Docs</a></li>
|
||||
<li><a class="reference external" href="https://blog.yosyshq.com">Blog</a></li>
|
||||
<li><a class="reference external" href="https://www.yosyshq.com">Website</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{# end of custom part #}
|
||||
{% if not furo_hide_toc %}
|
||||
<div class="toc-title-container">
|
||||
<span class="toc-title">
|
||||
{{ _("On this page") }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="toc-tree-container">
|
||||
<div class="toc-tree">
|
||||
{{ toc }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
Appendix
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:includehidden:
|
||||
|
||||
appendix/primer
|
||||
appendix/auxlibs
|
||||
appendix/auxprogs
|
||||
|
||||
bib
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:includehidden:
|
||||
|
||||
cmd_ref
|
||||
|
|
@ -29,7 +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 :cmd:ref:`sat` pass (see
|
||||
library is written by C. Wolf. It is used by the `sat` pass (see
|
||||
:doc:`/cmd/sat`).
|
||||
|
||||
fst
|
||||
|
|
@ -37,22 +37,22 @@ fst
|
|||
|
||||
``libfst`` files from `gtkwave`_ are included in ``libs/fst`` to support
|
||||
reading/writing signal traces from/to the GTKWave developed FST format. This is
|
||||
primarily used in the :cmd:ref:`sim` command.
|
||||
primarily used in the `sim` command.
|
||||
|
||||
.. _gtkwave: https://github.com/gtkwave/gtkwave
|
||||
|
||||
json11
|
||||
------
|
||||
|
||||
For reading/writing designs from/to JSON, :cmd:ref:`read_json` and
|
||||
:cmd:ref:`write_json` should be used. For everything else there is the `json11
|
||||
For reading/writing designs from/to JSON, `read_json` and
|
||||
`write_json` should be used. For everything else there is the `json11
|
||||
library`_:
|
||||
|
||||
json11 is a tiny JSON library for C++11, providing JSON parsing and
|
||||
serialization.
|
||||
|
||||
This library is used for outputting machine-readable statistics (:cmd:ref:`stat`
|
||||
with ``-json`` flag), using the RPC frontend (:cmd:ref:`connect_rpc`), and the
|
||||
This library is used for outputting machine-readable statistics (`stat`
|
||||
with ``-json`` flag), using the RPC frontend (`connect_rpc`), and the
|
||||
yosys-witness ``yw`` format.
|
||||
|
||||
.. _json11 library: https://github.com/dropbox/json11
|
||||
|
|
@ -61,7 +61,7 @@ MiniSAT
|
|||
-------
|
||||
|
||||
The files in ``libs/minisat`` provide a high-performance SAT solver, used by the
|
||||
:cmd:ref:`sat` command.
|
||||
`sat` command.
|
||||
|
||||
SHA1
|
||||
----
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ Yosys environment variables
|
|||
|
||||
``HOME``
|
||||
Yosys command history is stored in :file:`$HOME/.yosys_history`. Graphics
|
||||
(from :cmd:ref:`show` and :cmd:ref:`viz` commands) will output to this
|
||||
(from `show` and `viz` commands) will output to this
|
||||
directory by default. This environment variable is also used in some cases
|
||||
for resolving filenames with :file:`~`.
|
||||
|
||||
|
|
|
|||
|
|
@ -223,8 +223,8 @@ Cells
|
|||
Declares a cell, with zero or more attributes, with the given identifier and
|
||||
type in the enclosing module.
|
||||
|
||||
Cells perform functions on input signals. See
|
||||
:doc:`/yosys_internals/formats/cell_library` for a detailed list of cell types.
|
||||
Cells perform functions on input signals. See :doc:`/cell_index` for a detailed
|
||||
list of cell types.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ Processes
|
|||
|
||||
Declares a process, with zero or more attributes, with the given identifier in
|
||||
the enclosing module. The body of a process consists of zero or more
|
||||
assignments, exactly one switch, and zero or more syncs.
|
||||
assignments followed by zero or more switches and zero or more syncs.
|
||||
|
||||
See :ref:`sec:rtlil_process` for an overview of processes.
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ See :ref:`sec:rtlil_process` for an overview of processes.
|
|||
|
||||
<process> ::= <attr-stmt>* <proc-stmt> <process-body> <proc-end-stmt>
|
||||
<proc-stmt> ::= process <id> <eol>
|
||||
<process-body> ::= <assign-stmt>* <switch>? <assign-stmt>* <sync>*
|
||||
<process-body> ::= <assign-stmt>* <switch>* <sync>*
|
||||
<assign-stmt> ::= assign <dest-sigspec> <src-sigspec> <eol>
|
||||
<dest-sigspec> ::= <sigspec>
|
||||
<src-sigspec> ::= <sigspec>
|
||||
|
|
@ -262,8 +262,8 @@ Switches
|
|||
Switches test a signal for equality against a list of cases. Each case specifies
|
||||
a comma-separated list of signals to check against. If there are no signals in
|
||||
the list, then the case is the default case. The body of a case consists of zero
|
||||
or more switches and assignments. Both switches and cases may have zero or more
|
||||
attributes.
|
||||
or more assignments followed by zero or more switches. Both switches and cases
|
||||
may have zero or more attributes.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
|
|
@ -272,7 +272,7 @@ attributes.
|
|||
<case> ::= <attr-stmt>* <case-stmt> <case-body>
|
||||
<case-stmt> ::= case <compare>? <eol>
|
||||
<compare> ::= <sigspec> (, <sigspec>)*
|
||||
<case-body> ::= (<switch> | <assign-stmt>)*
|
||||
<case-body> ::= <assign-stmt>* <switch>*
|
||||
<switch-end-stmt> ::= end <eol>
|
||||
|
||||
Syncs
|
||||
53
docs/source/cell/gate_comb_combined.rst
Normal file
53
docs/source/cell/gate_comb_combined.rst
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Combinatorial cells (combined)
|
||||
------------------------------
|
||||
|
||||
These cells combine two or more combinatorial cells (simple) into a single cell.
|
||||
|
||||
.. table:: Cell types for gate level combinatorial cells (combined)
|
||||
|
||||
======================================= =============
|
||||
Verilog Cell Type
|
||||
======================================= =============
|
||||
:verilog:`Y = A & ~B` `$_ANDNOT_`
|
||||
:verilog:`Y = A | ~B` `$_ORNOT_`
|
||||
:verilog:`Y = ~((A & B) | C)` `$_AOI3_`
|
||||
:verilog:`Y = ~((A | B) & C)` `$_OAI3_`
|
||||
:verilog:`Y = ~((A & B) | (C & D))` `$_AOI4_`
|
||||
:verilog:`Y = ~((A | B) & (C | D))` `$_OAI4_`
|
||||
:verilog:`Y = ~(S ? B : A)` `$_NMUX_`
|
||||
(see below) `$_MUX4_`
|
||||
(see below) `$_MUX8_`
|
||||
(see below) `$_MUX16_`
|
||||
======================================= =============
|
||||
|
||||
The `$_MUX4_`, `$_MUX8_` and `$_MUX16_` cells are used to model wide muxes, and
|
||||
correspond to the following Verilog code:
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
// $_MUX4_
|
||||
assign Y = T ? (S ? D : C) :
|
||||
(S ? B : A);
|
||||
// $_MUX8_
|
||||
assign Y = U ? T ? (S ? H : G) :
|
||||
(S ? F : E) :
|
||||
T ? (S ? D : C) :
|
||||
(S ? B : A);
|
||||
// $_MUX16_
|
||||
assign Y = V ? U ? T ? (S ? P : O) :
|
||||
(S ? N : M) :
|
||||
T ? (S ? L : K) :
|
||||
(S ? J : I) :
|
||||
U ? T ? (S ? H : G) :
|
||||
(S ? F : E) :
|
||||
T ? (S ? D : C) :
|
||||
(S ? B : A);
|
||||
|
||||
.. autocellgroup:: comb_combined
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
26
docs/source/cell/gate_comb_simple.rst
Normal file
26
docs/source/cell/gate_comb_simple.rst
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Combinatorial cells (simple)
|
||||
----------------------------
|
||||
|
||||
.. table:: Cell types for gate level combinatorial cells (simple)
|
||||
|
||||
======================================= =============
|
||||
Verilog Cell Type
|
||||
======================================= =============
|
||||
:verilog:`Y = A` `$_BUF_`
|
||||
:verilog:`Y = ~A` `$_NOT_`
|
||||
:verilog:`Y = A & B` `$_AND_`
|
||||
:verilog:`Y = ~(A & B)` `$_NAND_`
|
||||
:verilog:`Y = A | B` `$_OR_`
|
||||
:verilog:`Y = ~(A | B)` `$_NOR_`
|
||||
:verilog:`Y = A ^ B` `$_XOR_`
|
||||
:verilog:`Y = ~(A ^ B)` `$_XNOR_`
|
||||
:verilog:`Y = S ? B : A` `$_MUX_`
|
||||
======================================= =============
|
||||
|
||||
.. autocellgroup:: comb_simple
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
8
docs/source/cell/gate_other.rst
Normal file
8
docs/source/cell/gate_other.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Other gate-level cells
|
||||
----------------------
|
||||
|
||||
.. autocellgroup:: gate_other
|
||||
:caption: Other gate-level cells
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
231
docs/source/cell/gate_reg_ff.rst
Normal file
231
docs/source/cell/gate_reg_ff.rst
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Flip-flop cells
|
||||
---------------
|
||||
|
||||
The cell types `$_DFF_N_` and `$_DFF_P_` represent d-type flip-flops.
|
||||
|
||||
.. table:: Cell types for basic flip-flops
|
||||
|
||||
======================================= =============
|
||||
Verilog Cell Type
|
||||
======================================= =============
|
||||
:verilog:`always @(negedge C) Q <= D` `$_DFF_N_`
|
||||
:verilog:`always @(posedge C) Q <= D` `$_DFF_P_`
|
||||
======================================= =============
|
||||
|
||||
The cell types ``$_DFFE_[NP][NP]_`` implement d-type flip-flops with enable. The
|
||||
values in the table for these cell types relate to the following Verilog code
|
||||
template.
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C)
|
||||
if (EN == EN_LVL)
|
||||
Q <= D;
|
||||
|
||||
|
||||
.. table:: Cell types for gate level logic networks (FFs with enable)
|
||||
:name: tab:CellLib_gates_dffe
|
||||
|
||||
================== ============= ============
|
||||
:math:`ClkEdge` :math:`EnLvl` Cell Type
|
||||
================== ============= ============
|
||||
:verilog:`negedge` ``0`` `$_DFFE_NN_`
|
||||
:verilog:`negedge` ``1`` `$_DFFE_NP_`
|
||||
:verilog:`posedge` ``0`` `$_DFFE_PN_`
|
||||
:verilog:`posedge` ``1`` `$_DFFE_PP_`
|
||||
================== ============= ============
|
||||
|
||||
The cell types ``$_DFF_[NP][NP][01]_`` implement d-type flip-flops with
|
||||
asynchronous reset. The values in the table for these cell types relate to the
|
||||
following Verilog code template, where ``RST_EDGE`` is ``posedge`` if
|
||||
``RST_LVL`` if ``1``, and ``negedge`` otherwise.
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C, RST_EDGE R)
|
||||
if (R == RST_LVL)
|
||||
Q <= RST_VAL;
|
||||
else
|
||||
Q <= D;
|
||||
|
||||
The cell types ``$_SDFF_[NP][NP][01]_`` implement d-type flip-flops with
|
||||
synchronous reset. The values in the table for these cell types relate to the
|
||||
following Verilog code template:
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C)
|
||||
if (R == RST_LVL)
|
||||
Q <= RST_VAL;
|
||||
else
|
||||
Q <= D;
|
||||
|
||||
.. table:: Cell types for gate level logic networks (FFs with reset)
|
||||
:name: tab:CellLib_gates_adff
|
||||
|
||||
================== ============== ============== ===========================
|
||||
:math:`ClkEdge` :math:`RstLvl` :math:`RstVal` Cell Type
|
||||
================== ============== ============== ===========================
|
||||
:verilog:`negedge` ``0`` ``0`` `$_DFF_NN0_`, `$_SDFF_NN0_`
|
||||
:verilog:`negedge` ``0`` ``1`` `$_DFF_NN1_`, `$_SDFF_NN1_`
|
||||
:verilog:`negedge` ``1`` ``0`` `$_DFF_NP0_`, `$_SDFF_NP0_`
|
||||
:verilog:`negedge` ``1`` ``1`` `$_DFF_NP1_`, `$_SDFF_NP1_`
|
||||
:verilog:`posedge` ``0`` ``0`` `$_DFF_PN0_`, `$_SDFF_PN0_`
|
||||
:verilog:`posedge` ``0`` ``1`` `$_DFF_PN1_`, `$_SDFF_PN1_`
|
||||
:verilog:`posedge` ``1`` ``0`` `$_DFF_PP0_`, `$_SDFF_PP0_`
|
||||
:verilog:`posedge` ``1`` ``1`` `$_DFF_PP1_`, `$_SDFF_PP1_`
|
||||
================== ============== ============== ===========================
|
||||
|
||||
The cell types ``$_DFFE_[NP][NP][01][NP]_`` implement d-type flip-flops with
|
||||
asynchronous reset and enable. The values in the table for these cell types
|
||||
relate to the following Verilog code template, where ``RST_EDGE`` is ``posedge``
|
||||
if ``RST_LVL`` if ``1``, and ``negedge`` otherwise.
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C, RST_EDGE R)
|
||||
if (R == RST_LVL)
|
||||
Q <= RST_VAL;
|
||||
else if (EN == EN_LVL)
|
||||
Q <= D;
|
||||
|
||||
The cell types ``$_SDFFE_[NP][NP][01][NP]_`` implement d-type flip-flops with
|
||||
synchronous reset and enable, with reset having priority over enable. The values
|
||||
in the table for these cell types relate to the following Verilog code template:
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C)
|
||||
if (R == RST_LVL)
|
||||
Q <= RST_VAL;
|
||||
else if (EN == EN_LVL)
|
||||
Q <= D;
|
||||
|
||||
The cell types ``$_SDFFCE_[NP][NP][01][NP]_`` implement d-type flip-flops with
|
||||
synchronous reset and enable, with enable having priority over reset. The values
|
||||
in the table for these cell types relate to the following Verilog code template:
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C)
|
||||
if (EN == EN_LVL)
|
||||
if (R == RST_LVL)
|
||||
Q <= RST_VAL;
|
||||
else
|
||||
Q <= D;
|
||||
|
||||
|
||||
.. table:: Cell types for gate level logic networks (FFs with reset and enable)
|
||||
:name: tab:CellLib_gates_adffe
|
||||
|
||||
================== ============== ============== ============= =================================================
|
||||
:math:`ClkEdge` :math:`RstLvl` :math:`RstVal` :math:`EnLvl` Cell Type
|
||||
================== ============== ============== ============= =================================================
|
||||
:verilog:`negedge` ``0`` ``0`` ``0`` `$_DFFE_NN0N_`, `$_SDFFE_NN0N_`, `$_SDFFCE_NN0N_`
|
||||
:verilog:`negedge` ``0`` ``0`` ``1`` `$_DFFE_NN0P_`, `$_SDFFE_NN0P_`, `$_SDFFCE_NN0P_`
|
||||
:verilog:`negedge` ``0`` ``1`` ``0`` `$_DFFE_NN1N_`, `$_SDFFE_NN1N_`, `$_SDFFCE_NN1N_`
|
||||
:verilog:`negedge` ``0`` ``1`` ``1`` `$_DFFE_NN1P_`, `$_SDFFE_NN1P_`, `$_SDFFCE_NN1P_`
|
||||
:verilog:`negedge` ``1`` ``0`` ``0`` `$_DFFE_NP0N_`, `$_SDFFE_NP0N_`, `$_SDFFCE_NP0N_`
|
||||
:verilog:`negedge` ``1`` ``0`` ``1`` `$_DFFE_NP0P_`, `$_SDFFE_NP0P_`, `$_SDFFCE_NP0P_`
|
||||
:verilog:`negedge` ``1`` ``1`` ``0`` `$_DFFE_NP1N_`, `$_SDFFE_NP1N_`, `$_SDFFCE_NP1N_`
|
||||
:verilog:`negedge` ``1`` ``1`` ``1`` `$_DFFE_NP1P_`, `$_SDFFE_NP1P_`, `$_SDFFCE_NP1P_`
|
||||
:verilog:`posedge` ``0`` ``0`` ``0`` `$_DFFE_PN0N_`, `$_SDFFE_PN0N_`, `$_SDFFCE_PN0N_`
|
||||
:verilog:`posedge` ``0`` ``0`` ``1`` `$_DFFE_PN0P_`, `$_SDFFE_PN0P_`, `$_SDFFCE_PN0P_`
|
||||
:verilog:`posedge` ``0`` ``1`` ``0`` `$_DFFE_PN1N_`, `$_SDFFE_PN1N_`, `$_SDFFCE_PN1N_`
|
||||
:verilog:`posedge` ``0`` ``1`` ``1`` `$_DFFE_PN1P_`, `$_SDFFE_PN1P_`, `$_SDFFCE_PN1P_`
|
||||
:verilog:`posedge` ``1`` ``0`` ``0`` `$_DFFE_PP0N_`, `$_SDFFE_PP0N_`, `$_SDFFCE_PP0N_`
|
||||
:verilog:`posedge` ``1`` ``0`` ``1`` `$_DFFE_PP0P_`, `$_SDFFE_PP0P_`, `$_SDFFCE_PP0P_`
|
||||
:verilog:`posedge` ``1`` ``1`` ``0`` `$_DFFE_PP1N_`, `$_SDFFE_PP1N_`, `$_SDFFCE_PP1N_`
|
||||
:verilog:`posedge` ``1`` ``1`` ``1`` `$_DFFE_PP1P_`, `$_SDFFE_PP1P_`, `$_SDFFCE_PP1P_`
|
||||
================== ============== ============== ============= =================================================
|
||||
|
||||
The cell types ``$_DFFSR_[NP][NP][NP]_`` implement d-type flip-flops with
|
||||
asynchronous set and reset. The values in the table for these cell types relate
|
||||
to the following Verilog code template, where ``RST_EDGE`` is ``posedge`` if
|
||||
``RST_LVL`` if ``1``, ``negedge`` otherwise, and ``SET_EDGE`` is ``posedge`` if
|
||||
``SET_LVL`` if ``1``, ``negedge`` otherwise.
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C, RST_EDGE R, SET_EDGE S)
|
||||
if (R == RST_LVL)
|
||||
Q <= 0;
|
||||
else if (S == SET_LVL)
|
||||
Q <= 1;
|
||||
else
|
||||
Q <= D;
|
||||
|
||||
.. table:: Cell types for gate level logic networks (FFs with set and reset)
|
||||
:name: tab:CellLib_gates_dffsr
|
||||
|
||||
================== ============== ============== ==============
|
||||
:math:`ClkEdge` :math:`SetLvl` :math:`RstLvl` Cell Type
|
||||
================== ============== ============== ==============
|
||||
:verilog:`negedge` ``0`` ``0`` `$_DFFSR_NNN_`
|
||||
:verilog:`negedge` ``0`` ``1`` `$_DFFSR_NNP_`
|
||||
:verilog:`negedge` ``1`` ``0`` `$_DFFSR_NPN_`
|
||||
:verilog:`negedge` ``1`` ``1`` `$_DFFSR_NPP_`
|
||||
:verilog:`posedge` ``0`` ``0`` `$_DFFSR_PNN_`
|
||||
:verilog:`posedge` ``0`` ``1`` `$_DFFSR_PNP_`
|
||||
:verilog:`posedge` ``1`` ``0`` `$_DFFSR_PPN_`
|
||||
:verilog:`posedge` ``1`` ``1`` `$_DFFSR_PPP_`
|
||||
================== ============== ============== ==============
|
||||
|
||||
The cell types ``$_DFFSRE_[NP][NP][NP][NP]_`` implement d-type flip-flops with
|
||||
asynchronous set and reset and enable. The values in the table for these cell
|
||||
types relate to the following Verilog code template, where ``RST_EDGE`` is
|
||||
``posedge`` if ``RST_LVL`` if ``1``, ``negedge`` otherwise, and ``SET_EDGE`` is
|
||||
``posedge`` if ``SET_LVL`` if ``1``, ``negedge`` otherwise.
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @(CLK_EDGE C, RST_EDGE R, SET_EDGE S)
|
||||
if (R == RST_LVL)
|
||||
Q <= 0;
|
||||
else if (S == SET_LVL)
|
||||
Q <= 1;
|
||||
else if (E == EN_LVL)
|
||||
Q <= D;
|
||||
|
||||
|
||||
.. table:: Cell types for gate level logic networks (FFs with set and reset and enable)
|
||||
:name: tab:CellLib_gates_dffsre
|
||||
|
||||
================== ============== ============== ============= ================
|
||||
:math:`ClkEdge` :math:`SetLvl` :math:`RstLvl` :math:`EnLvl` Cell Type
|
||||
================== ============== ============== ============= ================
|
||||
:verilog:`negedge` ``0`` ``0`` ``0`` `$_DFFSRE_NNNN_`
|
||||
:verilog:`negedge` ``0`` ``0`` ``1`` `$_DFFSRE_NNNP_`
|
||||
:verilog:`negedge` ``0`` ``1`` ``0`` `$_DFFSRE_NNPN_`
|
||||
:verilog:`negedge` ``0`` ``1`` ``1`` `$_DFFSRE_NNPP_`
|
||||
:verilog:`negedge` ``1`` ``0`` ``0`` `$_DFFSRE_NPNN_`
|
||||
:verilog:`negedge` ``1`` ``0`` ``1`` `$_DFFSRE_NPNP_`
|
||||
:verilog:`negedge` ``1`` ``1`` ``0`` `$_DFFSRE_NPPN_`
|
||||
:verilog:`negedge` ``1`` ``1`` ``1`` `$_DFFSRE_NPPP_`
|
||||
:verilog:`posedge` ``0`` ``0`` ``0`` `$_DFFSRE_PNNN_`
|
||||
:verilog:`posedge` ``0`` ``0`` ``1`` `$_DFFSRE_PNNP_`
|
||||
:verilog:`posedge` ``0`` ``1`` ``0`` `$_DFFSRE_PNPN_`
|
||||
:verilog:`posedge` ``0`` ``1`` ``1`` `$_DFFSRE_PNPP_`
|
||||
:verilog:`posedge` ``1`` ``0`` ``0`` `$_DFFSRE_PPNN_`
|
||||
:verilog:`posedge` ``1`` ``0`` ``1`` `$_DFFSRE_PPNP_`
|
||||
:verilog:`posedge` ``1`` ``1`` ``0`` `$_DFFSRE_PPPN_`
|
||||
:verilog:`posedge` ``1`` ``1`` ``1`` `$_DFFSRE_PPPP_`
|
||||
================== ============== ============== ============= ================
|
||||
|
||||
.. todo:: flip-flops with async load, ``$_ALDFFE?_[NP]{2,3}_``
|
||||
|
||||
.. autocellgroup:: reg_ff
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
105
docs/source/cell/gate_reg_latch.rst
Normal file
105
docs/source/cell/gate_reg_latch.rst
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Latch cells
|
||||
-----------
|
||||
|
||||
The cell types `$_DLATCH_N_` and `$_DLATCH_P_` represent d-type latches.
|
||||
|
||||
.. table:: Cell types for basic latches
|
||||
|
||||
======================================= =============
|
||||
Verilog Cell Type
|
||||
======================================= =============
|
||||
:verilog:`always @* if (!E) Q <= D` `$_DLATCH_N_`
|
||||
:verilog:`always @* if (E) Q <= D` `$_DLATCH_P_`
|
||||
======================================= =============
|
||||
|
||||
The cell types ``$_DLATCH_[NP][NP][01]_`` implement d-type latches with reset.
|
||||
The values in the table for these cell types relate to the following Verilog
|
||||
code template:
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @*
|
||||
if (R == RST_LVL)
|
||||
Q <= RST_VAL;
|
||||
else if (E == EN_LVL)
|
||||
Q <= D;
|
||||
|
||||
.. table:: Cell types for gate level logic networks (latches with reset)
|
||||
:name: tab:CellLib_gates_adlatch
|
||||
|
||||
============= ============== ============== ===============
|
||||
:math:`EnLvl` :math:`RstLvl` :math:`RstVal` Cell Type
|
||||
============= ============== ============== ===============
|
||||
``0`` ``0`` ``0`` `$_DLATCH_NN0_`
|
||||
``0`` ``0`` ``1`` `$_DLATCH_NN1_`
|
||||
``0`` ``1`` ``0`` `$_DLATCH_NP0_`
|
||||
``0`` ``1`` ``1`` `$_DLATCH_NP1_`
|
||||
``1`` ``0`` ``0`` `$_DLATCH_PN0_`
|
||||
``1`` ``0`` ``1`` `$_DLATCH_PN1_`
|
||||
``1`` ``1`` ``0`` `$_DLATCH_PP0_`
|
||||
``1`` ``1`` ``1`` `$_DLATCH_PP1_`
|
||||
============= ============== ============== ===============
|
||||
|
||||
The cell types ``$_DLATCHSR_[NP][NP][NP]_`` implement d-type latches with set
|
||||
and reset. The values in the table for these cell types relate to the following
|
||||
Verilog code template:
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @*
|
||||
if (R == RST_LVL)
|
||||
Q <= 0;
|
||||
else if (S == SET_LVL)
|
||||
Q <= 1;
|
||||
else if (E == EN_LVL)
|
||||
Q <= D;
|
||||
|
||||
.. table:: Cell types for gate level logic networks (latches with set and reset)
|
||||
:name: tab:CellLib_gates_dlatchsr
|
||||
|
||||
============= ============== ============== =================
|
||||
:math:`EnLvl` :math:`SetLvl` :math:`RstLvl` Cell Type
|
||||
============= ============== ============== =================
|
||||
``0`` ``0`` ``0`` `$_DLATCHSR_NNN_`
|
||||
``0`` ``0`` ``1`` `$_DLATCHSR_NNP_`
|
||||
``0`` ``1`` ``0`` `$_DLATCHSR_NPN_`
|
||||
``0`` ``1`` ``1`` `$_DLATCHSR_NPP_`
|
||||
``1`` ``0`` ``0`` `$_DLATCHSR_PNN_`
|
||||
``1`` ``0`` ``1`` `$_DLATCHSR_PNP_`
|
||||
``1`` ``1`` ``0`` `$_DLATCHSR_PPN_`
|
||||
``1`` ``1`` ``1`` `$_DLATCHSR_PPP_`
|
||||
============= ============== ============== =================
|
||||
|
||||
The cell types ``$_SR_[NP][NP]_`` implement sr-type latches. The values in the
|
||||
table for these cell types relate to the following Verilog code template:
|
||||
|
||||
.. code-block:: verilog
|
||||
:force:
|
||||
|
||||
always @*
|
||||
if (R == RST_LVL)
|
||||
Q <= 0;
|
||||
else if (S == SET_LVL)
|
||||
Q <= 1;
|
||||
|
||||
.. table:: Cell types for gate level logic networks (SR latches)
|
||||
:name: tab:CellLib_gates_sr
|
||||
|
||||
============== ============== ==========
|
||||
:math:`SetLvl` :math:`RstLvl` Cell Type
|
||||
============== ============== ==========
|
||||
``0`` ``0`` `$_SR_NN_`
|
||||
``0`` ``1`` `$_SR_NP_`
|
||||
``1`` ``0`` `$_SR_PN_`
|
||||
``1`` ``1`` `$_SR_PP_`
|
||||
============== ============== ==========
|
||||
|
||||
.. autocellgroup:: reg_latch
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
25
docs/source/cell/index_gate.rst
Normal file
25
docs/source/cell/index_gate.rst
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
.. _sec:celllib_gates:
|
||||
|
||||
Gate-level cells
|
||||
----------------
|
||||
|
||||
For gate level logic networks, fixed function single bit cells are used that do
|
||||
not provide any parameters.
|
||||
|
||||
Simulation models for these cells can be found in the file
|
||||
:file:`techlibs/common/simcells.v` in the Yosys source tree.
|
||||
|
||||
In most cases gate level logic networks are created from RTL networks using the
|
||||
techmap pass. The flip-flop cells from the gate level logic network can be
|
||||
mapped to physical flip-flop cells from a Liberty file using the dfflibmap pass.
|
||||
The combinatorial logic cells can be mapped to physical cells from a Liberty
|
||||
file via ABC using the abc pass.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
/cell/gate_comb_simple
|
||||
/cell/gate_comb_combined
|
||||
/cell/gate_reg_ff
|
||||
/cell/gate_reg_latch
|
||||
/cell/gate_other
|
||||
30
docs/source/cell/index_word.rst
Normal file
30
docs/source/cell/index_word.rst
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
Word-level cells
|
||||
----------------
|
||||
|
||||
Most of the RTL cells closely resemble the operators available in HDLs such as
|
||||
Verilog or VHDL. Therefore Verilog operators are used in the following sections
|
||||
to define the behaviour of the RTL cells.
|
||||
|
||||
Note that all RTL cells have parameters indicating the size of inputs and
|
||||
outputs. When passes modify RTL cells they must always keep the values of these
|
||||
parameters in sync with the size of the signals connected to the inputs and
|
||||
outputs.
|
||||
|
||||
Simulation models for the RTL cells can be found in the file
|
||||
:file:`techlibs/common/simlib.v` in the Yosys source tree.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
/cell/word_unary
|
||||
/cell/word_binary
|
||||
/cell/word_mux
|
||||
/cell/word_reg
|
||||
/cell/word_mem
|
||||
/cell/word_fsm
|
||||
/cell/word_arith
|
||||
/cell/word_logic
|
||||
/cell/word_spec
|
||||
/cell/word_formal
|
||||
/cell/word_debug
|
||||
/cell/word_wire
|
||||
21
docs/source/cell/properties.rst
Normal file
21
docs/source/cell/properties.rst
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
Cell properties
|
||||
---------------
|
||||
|
||||
.. cell:defprop:: is_evaluable
|
||||
|
||||
These cells are able to be used in conjunction with the `eval` command. Some
|
||||
passes, such as `opt_expr`, may also be able to perform additional
|
||||
optimizations on cells which are evaluable.
|
||||
|
||||
.. cell:defprop:: x-aware
|
||||
|
||||
Some passes will treat these cells as the non 'x' aware cell. For example,
|
||||
during synthesis `$eqx` will typically be treated as `$eq`.
|
||||
|
||||
.. cell:defprop:: x-output
|
||||
|
||||
These cells can produce 'x' output even if all inputs are defined. For
|
||||
example, a `$div` cell with divisor (``B``) equal to zero has undefined
|
||||
output.
|
||||
|
||||
Refer to the :ref:`propindex` for the list of cells with a given property.
|
||||
50
docs/source/cell/word_arith.rst
Normal file
50
docs/source/cell/word_arith.rst
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
Coarse arithmetics
|
||||
------------------
|
||||
|
||||
.. todo:: Add information about `$alu`, `$fa`, `$macc_v2`, and `$lcu` cells.
|
||||
|
||||
The `$macc` cell type represents a generalized multiply and accumulate
|
||||
operation. The cell is purely combinational. It outputs the result of summing up
|
||||
a sequence of products and other injected summands.
|
||||
|
||||
.. code-block::
|
||||
|
||||
Y = 0 +- a0factor1 * a0factor2 +- a1factor1 * a1factor2 +- ...
|
||||
+ B[0] + B[1] + ...
|
||||
|
||||
The A port consists of concatenated pairs of multiplier inputs ("factors"). A
|
||||
zero length factor2 acts as a constant 1, turning factor1 into a simple summand.
|
||||
|
||||
In this pseudocode, ``u(foo)`` means an unsigned int that's foo bits long.
|
||||
|
||||
.. code-block::
|
||||
|
||||
struct A {
|
||||
u(CONFIG.mul_info[0].factor1_len) a0factor1;
|
||||
u(CONFIG.mul_info[0].factor2_len) a0factor2;
|
||||
u(CONFIG.mul_info[1].factor1_len) a1factor1;
|
||||
u(CONFIG.mul_info[1].factor2_len) a1factor2;
|
||||
...
|
||||
};
|
||||
|
||||
The cell's ``CONFIG`` parameter determines the layout of cell port ``A``. The
|
||||
CONFIG parameter carries the following information:
|
||||
|
||||
.. code-block::
|
||||
|
||||
struct CONFIG {
|
||||
u4 num_bits;
|
||||
struct mul_info {
|
||||
bool is_signed;
|
||||
bool is_subtract;
|
||||
u(num_bits) factor1_len;
|
||||
u(num_bits) factor2_len;
|
||||
}[num_ports];
|
||||
};
|
||||
|
||||
B is an array of concatenated 1-bit-wide unsigned integers to also be summed up.
|
||||
|
||||
.. autocellgroup:: arith
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
91
docs/source/cell/word_binary.rst
Normal file
91
docs/source/cell/word_binary.rst
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Binary operators
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
All binary RTL cells have two input ports ``A`` and ``B`` and one output port
|
||||
``Y``. They also have the following parameters:
|
||||
|
||||
``A_SIGNED``
|
||||
Set to a non-zero value if the input ``A`` is signed and therefore should be
|
||||
sign-extended when needed.
|
||||
|
||||
``A_WIDTH``
|
||||
The width of the input port ``A``.
|
||||
|
||||
``B_SIGNED``
|
||||
Set to a non-zero value if the input ``B`` is signed and therefore should be
|
||||
sign-extended when needed.
|
||||
|
||||
``B_WIDTH``
|
||||
The width of the input port ``B``.
|
||||
|
||||
``Y_WIDTH``
|
||||
The width of the output port ``Y``.
|
||||
|
||||
.. table:: Cell types for binary operators with their corresponding Verilog expressions.
|
||||
|
||||
======================= =============== ======================= ===========
|
||||
Verilog Cell Type Verilog Cell Type
|
||||
======================= =============== ======================= ===========
|
||||
:verilog:`Y = A & B` `$and` :verilog:`Y = A ** B` `$pow`
|
||||
:verilog:`Y = A | B` `$or` :verilog:`Y = A < B` `$lt`
|
||||
:verilog:`Y = A ^ B` `$xor` :verilog:`Y = A <= B` `$le`
|
||||
:verilog:`Y = A ~^ B` `$xnor` :verilog:`Y = A == B` `$eq`
|
||||
:verilog:`Y = A << B` `$shl` :verilog:`Y = A != B` `$ne`
|
||||
:verilog:`Y = A >> B` `$shr` :verilog:`Y = A >= B` `$ge`
|
||||
:verilog:`Y = A <<< B` `$sshl` :verilog:`Y = A > B` `$gt`
|
||||
:verilog:`Y = A >>> B` `$sshr` :verilog:`Y = A + B` `$add`
|
||||
:verilog:`Y = A && B` `$logic_and` :verilog:`Y = A - B` `$sub`
|
||||
:verilog:`Y = A || B` `$logic_or` :verilog:`Y = A * B` `$mul`
|
||||
:verilog:`Y = A === B` `$eqx` :verilog:`Y = A / B` `$div`
|
||||
:verilog:`Y = A !== B` `$nex` :verilog:`Y = A % B` `$mod`
|
||||
``N/A`` `$shift` ``N/A`` `$divfloor`
|
||||
``N/A`` `$shiftx` ``N/A`` `$modfloor`
|
||||
======================= =============== ======================= ===========
|
||||
|
||||
The `$shl` and `$shr` cells implement logical shifts, whereas the `$sshl` and
|
||||
`$sshr` cells implement arithmetic shifts. The `$shl` and `$sshl` cells
|
||||
implement the same operation. All four of these cells interpret the second
|
||||
operand as unsigned, and require ``B_SIGNED`` to be zero.
|
||||
|
||||
Two additional shift operator cells are available that do not directly
|
||||
correspond to any operator in Verilog, `$shift` and `$shiftx`. The `$shift` cell
|
||||
performs a right logical shift if the second operand is positive (or unsigned),
|
||||
and a left logical shift if it is negative. The `$shiftx` cell performs the same
|
||||
operation as the `$shift` cell, but the vacated bit positions are filled with
|
||||
undef (x) bits, and corresponds to the Verilog indexed part-select expression.
|
||||
|
||||
For the binary cells that output a logical value (`$logic_and`, `$logic_or`,
|
||||
`$eqx`, `$nex`, `$lt`, `$le`, `$eq`, `$ne`, `$ge`, `$gt`), when the ``Y_WIDTH``
|
||||
parameter is greater than 1, the output is zero-extended, and only the least
|
||||
significant bit varies.
|
||||
|
||||
Division and modulo cells are available in two rounding modes. The original
|
||||
`$div` and `$mod` cells are based on truncating division, and correspond to the
|
||||
semantics of the verilog ``/`` and ``%`` operators. The `$divfloor` and
|
||||
`$modfloor` cells represent flooring division and flooring modulo, the latter of
|
||||
which corresponds to the ``%`` operator in Python. See the following table for a
|
||||
side-by-side comparison between the different semantics.
|
||||
|
||||
.. table:: Comparison between different rounding modes for division and modulo cells.
|
||||
|
||||
+-----------+--------+-----------+-----------+-----------+-----------+
|
||||
| Division | Result | Truncating | Flooring |
|
||||
+-----------+--------+-----------+-----------+-----------+-----------+
|
||||
| | | $div | $mod | $divfloor | $modfloor |
|
||||
+===========+========+===========+===========+===========+===========+
|
||||
| -10 / 3 | -3.3 | -3 | -1 | -4 | 2 |
|
||||
+-----------+--------+-----------+-----------+-----------+-----------+
|
||||
| 10 / -3 | -3.3 | -3 | 1 | -4 | -2 |
|
||||
+-----------+--------+-----------+-----------+-----------+-----------+
|
||||
| -10 / -3 | 3.3 | 3 | -1 | 3 | -1 |
|
||||
+-----------+--------+-----------+-----------+-----------+-----------+
|
||||
| 10 / 3 | 3.3 | 3 | 1 | 3 | 1 |
|
||||
+-----------+--------+-----------+-----------+-----------+-----------+
|
||||
|
||||
.. autocellgroup:: binary
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
138
docs/source/cell/word_debug.rst
Normal file
138
docs/source/cell/word_debug.rst
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Debugging cells
|
||||
---------------
|
||||
|
||||
The `$print` cell is used to log the values of signals, akin to (and
|
||||
translatable to) the ``$display`` and ``$write`` family of tasks in Verilog. It
|
||||
has the following parameters:
|
||||
|
||||
``FORMAT``
|
||||
The internal format string. The syntax is described below.
|
||||
|
||||
``ARGS_WIDTH``
|
||||
The width (in bits) of the signal on the ``ARGS`` port.
|
||||
|
||||
``TRG_ENABLE``
|
||||
True if triggered on specific signals defined in ``TRG``; false if triggered
|
||||
whenever ``ARGS`` or ``EN`` change and ``EN`` is 1.
|
||||
|
||||
If ``TRG_ENABLE`` is true, the following parameters also apply:
|
||||
|
||||
``TRG_WIDTH``
|
||||
The number of bits in the ``TRG`` port.
|
||||
|
||||
``TRG_POLARITY``
|
||||
For each bit in ``TRG``, 1 if that signal is positive-edge triggered, 0 if
|
||||
negative-edge triggered.
|
||||
|
||||
``PRIORITY``
|
||||
When multiple `$print` or `$check` cells fire on the same trigger, they
|
||||
execute in descending priority order.
|
||||
|
||||
Ports:
|
||||
|
||||
``TRG``
|
||||
The signals that control when this `$print` cell is triggered.
|
||||
|
||||
If the width of this port is zero and ``TRG_ENABLE`` is true, the cell is
|
||||
triggered during initial evaluation (time zero) only.
|
||||
|
||||
``EN``
|
||||
Enable signal for the whole cell.
|
||||
|
||||
``ARGS``
|
||||
The values to be displayed, in format string order.
|
||||
|
||||
.. autocellgroup:: debug
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
|
||||
Format string syntax
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The format string syntax resembles Python f-strings. Regular text is passed
|
||||
through unchanged until a format specifier is reached, starting with a ``{``.
|
||||
|
||||
Format specifiers have the following syntax. Unless noted, all items are
|
||||
required:
|
||||
|
||||
``{``
|
||||
Denotes the start of the format specifier.
|
||||
|
||||
size
|
||||
Signal size in bits; this many bits are consumed from the ``ARGS`` port by
|
||||
this specifier.
|
||||
|
||||
``:``
|
||||
Separates the size from the remaining items.
|
||||
|
||||
justify
|
||||
``>`` for right-justified, ``<`` for left-justified.
|
||||
|
||||
padding
|
||||
``0`` for zero-padding, or a space for space-padding.
|
||||
|
||||
width\ *?*
|
||||
(optional) The number of characters wide to pad to.
|
||||
|
||||
base
|
||||
* ``b`` for base-2 integers (binary)
|
||||
* ``o`` for base-8 integers (octal)
|
||||
* ``d`` for base-10 integers (decimal)
|
||||
* ``h`` for base-16 integers (hexadecimal)
|
||||
* ``c`` for ASCII characters/strings
|
||||
* ``t`` and ``r`` for simulation time (corresponding to :verilog:`$time` and
|
||||
:verilog:`$realtime`)
|
||||
|
||||
For integers, this item may follow:
|
||||
|
||||
``+``\ *?*
|
||||
(optional, decimals only) Include a leading plus for non-negative numbers.
|
||||
This can assist with symmetry with negatives in tabulated output.
|
||||
|
||||
signedness
|
||||
``u`` for unsigned, ``s`` for signed. This distinction is only respected
|
||||
when rendering decimals.
|
||||
|
||||
ASCII characters/strings have no special options, but the signal size must be
|
||||
divisible by 8.
|
||||
|
||||
For simulation time, the signal size must be zero.
|
||||
|
||||
Finally:
|
||||
|
||||
``}``
|
||||
Denotes the end of the format specifier.
|
||||
|
||||
Some example format specifiers:
|
||||
|
||||
+ ``{8:>02hu}`` - 8-bit unsigned integer rendered as hexadecimal,
|
||||
right-justified, zero-padded to 2 characters wide.
|
||||
+ ``{32:< 15d+s}`` - 32-bit signed integer rendered as decimal, left-justified,
|
||||
space-padded to 15 characters wide, positive values prefixed with ``+``.
|
||||
+ ``{16:< 10hu}`` - 16-bit unsigned integer rendered as hexadecimal,
|
||||
left-justified, space-padded to 10 characters wide.
|
||||
+ ``{0:>010t}`` - simulation time, right-justified, zero-padded to 10 characters
|
||||
wide.
|
||||
|
||||
To include literal ``{`` and ``}`` characters in your format string, use ``{{``
|
||||
and ``}}`` respectively.
|
||||
|
||||
It is an error for a format string to consume more or less bits from ``ARGS``
|
||||
than the port width.
|
||||
|
||||
Values are never truncated, regardless of the specified width.
|
||||
|
||||
Note that further restrictions on allowable combinations of options may apply
|
||||
depending on the backend used.
|
||||
|
||||
For example, Verilog does not have a format specifier that allows zero-padding a
|
||||
string (i.e. more than 1 ASCII character), though zero-padding a single
|
||||
character is permitted.
|
||||
|
||||
Thus, while the RTLIL format specifier ``{8:>02c}`` translates to ``%02c``,
|
||||
``{16:>02c}`` cannot be represented in Verilog and will fail to emit. In this
|
||||
case, ``{16:> 02c}`` must be used, which translates to ``%2s``.
|
||||
31
docs/source/cell/word_formal.rst
Normal file
31
docs/source/cell/word_formal.rst
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
Formal verification cells
|
||||
-------------------------
|
||||
|
||||
.. role:: yoscrypt(code)
|
||||
:language: yoscrypt
|
||||
|
||||
.. note::
|
||||
|
||||
Some front-ends may not support the generic `$check` cell, in such cases
|
||||
calling :yoscrypt:`chformal -lower` will convert each `$check` cell into it's
|
||||
equivalent. See `chformal` for more.
|
||||
|
||||
.. todo:: Describe formal cells
|
||||
|
||||
`$check`, `$assert`, `$assume`, `$live`, `$fair`, `$cover`, `$equiv`,
|
||||
`$initstate`, `$anyconst`, `$anyseq`, `$anyinit`, `$allconst`, and `$allseq`.
|
||||
|
||||
Also `$ff` and `$_FF_` cells.
|
||||
|
||||
.. autocellgroup:: formal
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
|
||||
Formal support cells
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autocellgroup:: formal_tag
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
9
docs/source/cell/word_fsm.rst
Normal file
9
docs/source/cell/word_fsm.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Finite state machines
|
||||
---------------------
|
||||
|
||||
.. todo:: Describe `$fsm` cell
|
||||
|
||||
.. autocellgroup:: fsm
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
46
docs/source/cell/word_logic.rst
Normal file
46
docs/source/cell/word_logic.rst
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
Arbitrary logic functions
|
||||
-------------------------
|
||||
|
||||
The `$lut` cell type implements a single-output LUT (lookup table). It
|
||||
implements an arbitrary logic function with its ``\LUT`` parameter to map input
|
||||
port ``\A`` to values of ``\Y`` output port values. In psuedocode: ``Y =
|
||||
\LUT[A]``. ``\A`` has width set by parameter ``\WIDTH`` and ``\Y`` has a width
|
||||
of 1. Every logic function with a single bit output has a unique `$lut`
|
||||
representation.
|
||||
|
||||
The `$sop` cell type implements a sum-of-products expression, also known as
|
||||
disjunctive normal form (DNF). It implements an arbitrary logic function. Its
|
||||
structure mimics a programmable logic array (PLA). Output port ``\Y`` is the sum
|
||||
of products of the bits of the input port ``\A`` as defined by parameter
|
||||
``\TABLE``. ``\A`` is ``\WIDTH`` bits wide. The number of products in the sum is
|
||||
set by parameter ``\DEPTH``, and each product has two bits for each input bit -
|
||||
for the presence of the unnegated and negated version of said input bit in the
|
||||
product. Therefore the ``\TABLE`` parameter holds ``2 * \WIDTH * \DEPTH`` bits.
|
||||
|
||||
For example:
|
||||
|
||||
Let ``\WIDTH`` be 3. We would like to represent ``\Y =~\A[0] + \A[1]~\A[2]``.
|
||||
There are 2 products to be summed, so ``\DEPTH`` shall be 2.
|
||||
|
||||
.. code-block::
|
||||
|
||||
~A[2]-----+
|
||||
A[2]----+|
|
||||
~A[1]---+||
|
||||
A[1]--+|||
|
||||
~A[0]-+||||
|
||||
A[0]+|||||
|
||||
|||||| product formula
|
||||
010000 ~\A[0]
|
||||
001001 \A[1]~\A[2]
|
||||
|
||||
So the value of ``\TABLE`` will become ``010000001001``.
|
||||
|
||||
Any logic function with a single bit output can be represented with ``$sop`` but
|
||||
may have variously minimized or ordered summands represented in the ``\TABLE``
|
||||
values.
|
||||
|
||||
.. autocellgroup:: logic
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
281
docs/source/cell/word_mem.rst
Normal file
281
docs/source/cell/word_mem.rst
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
.. _sec:memcells:
|
||||
|
||||
Memories
|
||||
~~~~~~~~
|
||||
|
||||
Memories are either represented using ``RTLIL::Memory`` objects, `$memrd_v2`,
|
||||
`$memwr_v2`, and `$meminit_v2` cells, or by `$mem_v2` cells alone.
|
||||
|
||||
In the first alternative the ``RTLIL::Memory`` objects hold the general metadata
|
||||
for the memory (bit width, size in number of words, etc.) and for each port a
|
||||
`$memrd_v2` (read port) or `$memwr_v2` (write port) cell is created. Having
|
||||
individual cells for read and write ports has the advantage that they can be
|
||||
consolidated using resource sharing passes. In some cases this drastically
|
||||
reduces the number of required ports on the memory cell. In this alternative,
|
||||
memory initialization data is represented by `$meminit_v2` cells, which allow
|
||||
delaying constant folding for initialization addresses and data until after the
|
||||
frontend finishes.
|
||||
|
||||
The `$memrd_v2` cells have a clock input ``CLK``, an enable input ``EN``, an
|
||||
address input ``ADDR``, a data output ``DATA``, an asynchronous reset input
|
||||
``ARST``, and a synchronous reset input ``SRST``. They also have the following
|
||||
parameters:
|
||||
|
||||
``MEMID``
|
||||
The name of the ``RTLIL::Memory`` object that is associated with this read
|
||||
port.
|
||||
|
||||
``ABITS``
|
||||
The number of address bits (width of the ``ADDR`` input port).
|
||||
|
||||
``WIDTH``
|
||||
The number of data bits (width of the ``DATA`` output port). Note that this
|
||||
may be a power-of-two multiple of the underlying memory's width -- such ports
|
||||
are called wide ports and access an aligned group of cells at once. In this
|
||||
case, the corresponding low bits of ``ADDR`` must be tied to 0.
|
||||
|
||||
``CLK_ENABLE``
|
||||
When this parameter is non-zero, the clock is used. Otherwise this read port
|
||||
is asynchronous and the ``CLK`` input is not used.
|
||||
|
||||
``CLK_POLARITY``
|
||||
Clock is active on the positive edge if this parameter has the value ``1'b1``
|
||||
and on the negative edge if this parameter is ``1'b0``.
|
||||
|
||||
``TRANSPARENCY_MASK``
|
||||
This parameter is a bitmask of write ports that this read port is transparent
|
||||
with. The bits of this parameter are indexed by the write port's ``PORTID``
|
||||
parameter. Transparency can only be enabled between synchronous ports sharing
|
||||
a clock domain. When transparency is enabled for a given port pair, a read
|
||||
and write to the same address in the same cycle will return the new value.
|
||||
Otherwise the old value is returned.
|
||||
|
||||
``COLLISION_X_MASK``
|
||||
This parameter is a bitmask of write ports that have undefined collision
|
||||
behavior with this port. The bits of this parameter are indexed by the write
|
||||
port's ``PORTID`` parameter. This behavior can only be enabled between
|
||||
synchronous ports sharing a clock domain. When undefined collision is enabled
|
||||
for a given port pair, a read and write to the same address in the same cycle
|
||||
will return the undefined (all-X) value.This option is exclusive (for a given
|
||||
port pair) with the transparency option.
|
||||
|
||||
``ARST_VALUE``
|
||||
Whenever the ``ARST`` input is asserted, the data output will be reset to
|
||||
this value. Only used for synchronous ports.
|
||||
|
||||
``SRST_VALUE``
|
||||
Whenever the ``SRST`` input is synchronously asserted, the data output will
|
||||
be reset to this value. Only used for synchronous ports.
|
||||
|
||||
``INIT_VALUE``
|
||||
The initial value of the data output, for synchronous ports.
|
||||
|
||||
``CE_OVER_SRST``
|
||||
If this parameter is non-zero, the ``SRST`` input is only recognized when
|
||||
``EN`` is true. Otherwise, ``SRST`` is recognized regardless of ``EN``.
|
||||
|
||||
The `$memwr_v2` cells have a clock input ``CLK``, an enable input ``EN`` (one
|
||||
enable bit for each data bit), an address input ``ADDR`` and a data input
|
||||
``DATA``. They also have the following parameters:
|
||||
|
||||
``MEMID``
|
||||
The name of the ``RTLIL::Memory`` object that is associated with this write
|
||||
port.
|
||||
|
||||
``ABITS``
|
||||
The number of address bits (width of the ``ADDR`` input port).
|
||||
|
||||
``WIDTH``
|
||||
The number of data bits (width of the ``DATA`` output port). Like with
|
||||
`$memrd_v2` cells, the width is allowed to be any power-of-two multiple of
|
||||
memory width, with the corresponding restriction on address.
|
||||
|
||||
``CLK_ENABLE``
|
||||
When this parameter is non-zero, the clock is used. Otherwise this write port
|
||||
is asynchronous and the ``CLK`` input is not used.
|
||||
|
||||
``CLK_POLARITY``
|
||||
Clock is active on positive edge if this parameter has the value ``1'b1`` and
|
||||
on the negative edge if this parameter is ``1'b0``.
|
||||
|
||||
``PORTID``
|
||||
An identifier for this write port, used to index write port bit mask
|
||||
parameters.
|
||||
|
||||
``PRIORITY_MASK``
|
||||
This parameter is a bitmask of write ports that this write port has priority
|
||||
over in case of writing to the same address. The bits of this parameter are
|
||||
indexed by the other write port's ``PORTID`` parameter. Write ports can only
|
||||
have priority over write ports with lower port ID. When two ports write to
|
||||
the same address and neither has priority over the other, the result is
|
||||
undefined. Priority can only be set between two synchronous ports sharing
|
||||
the same clock domain.
|
||||
|
||||
The `$meminit_v2` cells have an address input ``ADDR``, a data input ``DATA``,
|
||||
with the width of the ``DATA`` port equal to ``WIDTH`` parameter times ``WORDS``
|
||||
parameter, and a bit enable mask input ``EN`` with width equal to ``WIDTH``
|
||||
parameter. All three of the inputs must resolve to a constant for synthesis to
|
||||
succeed.
|
||||
|
||||
``MEMID``
|
||||
The name of the ``RTLIL::Memory`` object that is associated with this
|
||||
initialization cell.
|
||||
|
||||
``ABITS``
|
||||
The number of address bits (width of the ``ADDR`` input port).
|
||||
|
||||
``WIDTH``
|
||||
The number of data bits per memory location.
|
||||
|
||||
``WORDS``
|
||||
The number of consecutive memory locations initialized by this cell.
|
||||
|
||||
``PRIORITY``
|
||||
The cell with the higher integer value in this parameter wins an
|
||||
initialization conflict.
|
||||
|
||||
The HDL frontend models a memory using ``RTLIL::Memory`` objects and
|
||||
asynchronous `$memrd_v2` and `$memwr_v2` cells. The `memory` pass (i.e. its
|
||||
various sub-passes) migrates `$dff` cells into the `$memrd_v2` and `$memwr_v2`
|
||||
cells making them synchronous, then converts them to a single `$mem_v2` cell and
|
||||
(optionally) maps this cell type to `$dff` cells for the individual words and
|
||||
multiplexer-based address decoders for the read and write interfaces. When the
|
||||
last step is disabled or not possible, a `$mem_v2` cell is left in the design.
|
||||
|
||||
The `$mem_v2` cell provides the following parameters:
|
||||
|
||||
``MEMID``
|
||||
The name of the original ``RTLIL::Memory`` object that became this `$mem_v2`
|
||||
cell.
|
||||
|
||||
``SIZE``
|
||||
The number of words in the memory.
|
||||
|
||||
``ABITS``
|
||||
The number of address bits.
|
||||
|
||||
``WIDTH``
|
||||
The number of data bits per word.
|
||||
|
||||
``INIT``
|
||||
The initial memory contents.
|
||||
|
||||
``RD_PORTS``
|
||||
The number of read ports on this memory cell.
|
||||
|
||||
``RD_WIDE_CONTINUATION``
|
||||
This parameter is ``RD_PORTS`` bits wide, containing a bitmask of "wide
|
||||
continuation" read ports. Such ports are used to represent the extra data
|
||||
bits of wide ports in the combined cell, and must have all control signals
|
||||
identical with the preceding port, except for address, which must have the
|
||||
proper sub-cell address encoded in the low bits.
|
||||
|
||||
``RD_CLK_ENABLE``
|
||||
This parameter is ``RD_PORTS`` bits wide, containing a clock enable bit for
|
||||
each read port.
|
||||
|
||||
``RD_CLK_POLARITY``
|
||||
This parameter is ``RD_PORTS`` bits wide, containing a clock polarity bit for
|
||||
each read port.
|
||||
|
||||
``RD_TRANSPARENCY_MASK``
|
||||
This parameter is ``RD_PORTS*WR_PORTS`` bits wide, containing a concatenation
|
||||
of all ``TRANSPARENCY_MASK`` values of the original `$memrd_v2` cells.
|
||||
|
||||
``RD_COLLISION_X_MASK``
|
||||
This parameter is ``RD_PORTS*WR_PORTS`` bits wide, containing a concatenation
|
||||
of all ``COLLISION_X_MASK`` values of the original `$memrd_v2` cells.
|
||||
|
||||
``RD_CE_OVER_SRST``
|
||||
This parameter is ``RD_PORTS`` bits wide, determining relative synchronous
|
||||
reset and enable priority for each read port.
|
||||
|
||||
``RD_INIT_VALUE``
|
||||
This parameter is ``RD_PORTS*WIDTH`` bits wide, containing the initial value
|
||||
for each synchronous read port.
|
||||
|
||||
``RD_ARST_VALUE``
|
||||
This parameter is ``RD_PORTS*WIDTH`` bits wide, containing the asynchronous
|
||||
reset value for each synchronous read port.
|
||||
|
||||
``RD_SRST_VALUE``
|
||||
This parameter is ``RD_PORTS*WIDTH`` bits wide, containing the synchronous
|
||||
reset value for each synchronous read port.
|
||||
|
||||
``WR_PORTS``
|
||||
The number of write ports on this memory cell.
|
||||
|
||||
``WR_WIDE_CONTINUATION``
|
||||
This parameter is ``WR_PORTS`` bits wide, containing a bitmask of "wide
|
||||
continuation" write ports.
|
||||
|
||||
``WR_CLK_ENABLE``
|
||||
This parameter is ``WR_PORTS`` bits wide, containing a clock enable bit for
|
||||
each write port.
|
||||
|
||||
``WR_CLK_POLARITY``
|
||||
This parameter is ``WR_PORTS`` bits wide, containing a clock polarity bit for
|
||||
each write port.
|
||||
|
||||
``WR_PRIORITY_MASK``
|
||||
This parameter is ``WR_PORTS*WR_PORTS`` bits wide, containing a concatenation
|
||||
of all ``PRIORITY_MASK`` values of the original `$memwr_v2` cells.
|
||||
|
||||
The `$mem_v2` cell has the following ports:
|
||||
|
||||
``RD_CLK``
|
||||
This input is ``RD_PORTS`` bits wide, containing all clock signals for the
|
||||
read ports.
|
||||
|
||||
``RD_EN``
|
||||
This input is ``RD_PORTS`` bits wide, containing all enable signals for the
|
||||
read ports.
|
||||
|
||||
``RD_ADDR``
|
||||
This input is ``RD_PORTS*ABITS`` bits wide, containing all address signals
|
||||
for the read ports.
|
||||
|
||||
``RD_DATA``
|
||||
This output is ``RD_PORTS*WIDTH`` bits wide, containing all data signals for
|
||||
the read ports.
|
||||
|
||||
``RD_ARST``
|
||||
This input is ``RD_PORTS`` bits wide, containing all asynchronous reset
|
||||
signals for the read ports.
|
||||
|
||||
``RD_SRST``
|
||||
This input is ``RD_PORTS`` bits wide, containing all synchronous reset
|
||||
signals for the read ports.
|
||||
|
||||
``WR_CLK``
|
||||
This input is ``WR_PORTS`` bits wide, containing all clock signals for the
|
||||
write ports.
|
||||
|
||||
``WR_EN``
|
||||
This input is ``WR_PORTS*WIDTH`` bits wide, containing all enable signals for
|
||||
the write ports.
|
||||
|
||||
``WR_ADDR``
|
||||
This input is ``WR_PORTS*ABITS`` bits wide, containing all address signals
|
||||
for the write ports.
|
||||
|
||||
``WR_DATA``
|
||||
This input is ``WR_PORTS*WIDTH`` bits wide, containing all data signals for
|
||||
the write ports.
|
||||
|
||||
The `memory_collect` pass can be used to convert discrete `$memrd_v2`,
|
||||
`$memwr_v2`, and `$meminit_v2` cells belonging to the same memory to a single
|
||||
`$mem_v2` cell, whereas the `memory_unpack` pass performs the inverse operation.
|
||||
The `memory_dff` pass can combine asynchronous memory ports that are fed by or
|
||||
feeding registers into synchronous memory ports. The `memory_bram` pass can be
|
||||
used to recognize `$mem_v2` cells that can be implemented with a block RAM
|
||||
resource on an FPGA. The `memory_map` pass can be used to implement `$mem_v2`
|
||||
cells as basic logic: word-wide DFFs and address decoders.
|
||||
|
||||
.. autocellgroup:: mem
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
47
docs/source/cell/word_mux.rst
Normal file
47
docs/source/cell/word_mux.rst
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Multiplexers
|
||||
------------
|
||||
|
||||
Multiplexers are generated by the Verilog HDL frontend for ``?:``-expressions.
|
||||
Multiplexers are also generated by the proc pass to map the decision trees from
|
||||
RTLIL::Process objects to logic.
|
||||
|
||||
The simplest multiplexer cell type is `$mux`. Cells of this type have a
|
||||
``WITDH`` parameter and data inputs ``A`` and ``B`` and a data output ``Y``, all
|
||||
of the specified width. This cell also has a single bit control input ``S``. If
|
||||
``S`` is 0 the value from the input ``A`` is sent to the output, if it is 1 the
|
||||
value from the ``B`` input is sent to the output. So the `$mux` cell implements
|
||||
the function :verilog:`Y = S ? B : A`.
|
||||
|
||||
The `$pmux` cell is used to multiplex between many inputs using a one-hot select
|
||||
signal. Cells of this type have a ``WIDTH`` and a ``S_WIDTH`` parameter and
|
||||
inputs ``A``, ``B``, and ``S`` and an output ``Y``. The ``S`` input is
|
||||
``S_WIDTH`` bits wide. The ``A`` input and the output are both ``WIDTH`` bits
|
||||
wide and the ``B`` input is ``WIDTH*S_WIDTH`` bits wide. When all bits of ``S``
|
||||
are zero, the value from ``A`` input is sent to the output. If the :math:`n`\
|
||||
'th bit from ``S`` is set, the value :math:`n`\ 'th ``WIDTH`` bits wide slice of
|
||||
the ``B`` input is sent to the output. When more than one bit from ``S`` is set
|
||||
the output is undefined. Cells of this type are used to model "parallel cases"
|
||||
(defined by using the ``parallel_case`` attribute or detected by an
|
||||
optimization).
|
||||
|
||||
The `$tribuf` cell is used to implement tristate logic. Cells of this type have
|
||||
a ``WIDTH`` parameter and inputs ``A`` and ``EN`` and an output ``Y``. The ``A``
|
||||
input and ``Y`` output are ``WIDTH`` bits wide, and the ``EN`` input is one bit
|
||||
wide. When ``EN`` is 0, the output is not driven. When ``EN`` is 1, the value
|
||||
from ``A`` input is sent to the ``Y`` output. Therefore, the `$tribuf` cell
|
||||
implements the function :verilog:`Y = EN ? A : 'bz`.
|
||||
|
||||
Behavioural code with cascaded if-then-else- and case-statements usually results
|
||||
in trees of multiplexer cells. Many passes (from various optimizations to FSM
|
||||
extraction) heavily depend on these multiplexer trees to understand dependencies
|
||||
between signals. Therefore optimizations should not break these multiplexer
|
||||
trees (e.g. by replacing a multiplexer between a calculated signal and a
|
||||
constant zero with an `$and` gate).
|
||||
|
||||
.. autocellgroup:: mux
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
124
docs/source/cell/word_reg.rst
Normal file
124
docs/source/cell/word_reg.rst
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Registers
|
||||
---------
|
||||
|
||||
SR-type latches are represented by `$sr` cells. These cells have input ports
|
||||
``SET`` and ``CLR`` and an output port ``Q``. They have the following
|
||||
parameters:
|
||||
|
||||
``WIDTH``
|
||||
The width of inputs ``SET`` and ``CLR`` and output ``Q``.
|
||||
|
||||
``SET_POLARITY``
|
||||
The set input bits are active-high if this parameter has the value ``1'b1``
|
||||
and active-low if this parameter is ``1'b0``.
|
||||
|
||||
``CLR_POLARITY``
|
||||
The reset input bits are active-high if this parameter has the value ``1'b1``
|
||||
and active-low if this parameter is ``1'b0``.
|
||||
|
||||
Both set and reset inputs have separate bits for every output bit. When both the
|
||||
set and reset inputs of an `$sr` cell are active for a given bit index, the
|
||||
reset input takes precedence.
|
||||
|
||||
D-type flip-flops are represented by `$dff` cells. These cells have a clock port
|
||||
``CLK``, an input port ``D`` and an output port ``Q``. The following parameters
|
||||
are available for `$dff` cells:
|
||||
|
||||
``WIDTH``
|
||||
The width of input ``D`` and output ``Q``.
|
||||
|
||||
``CLK_POLARITY``
|
||||
Clock is active on the positive edge if this parameter has the value ``1'b1``
|
||||
and on the negative edge if this parameter is ``1'b0``.
|
||||
|
||||
D-type flip-flops with asynchronous reset are represented by `$adff` cells. As
|
||||
the `$dff` cells they have ``CLK``, ``D`` and ``Q`` ports. In addition they also
|
||||
have a single-bit ``ARST`` input port for the reset pin and the following
|
||||
additional two parameters:
|
||||
|
||||
``ARST_POLARITY``
|
||||
The asynchronous reset is active-high if this parameter has the value
|
||||
``1'b1`` and active-low if this parameter is ``1'b0``.
|
||||
|
||||
``ARST_VALUE``
|
||||
The state of ``Q`` will be set to this value when the reset is active.
|
||||
|
||||
Usually these cells are generated by the `proc` pass using the information in
|
||||
the designs RTLIL::Process objects.
|
||||
|
||||
D-type flip-flops with synchronous reset are represented by `$sdff` cells. As
|
||||
the `$dff` cells they have ``CLK``, ``D`` and ``Q`` ports. In addition they also
|
||||
have a single-bit ``SRST`` input port for the reset pin and the following
|
||||
additional two parameters:
|
||||
|
||||
``SRST_POLARITY``
|
||||
The synchronous reset is active-high if this parameter has the value ``1'b1``
|
||||
and active-low if this parameter is ``1'b0``.
|
||||
|
||||
``SRST_VALUE``
|
||||
The state of ``Q`` will be set to this value when the reset is active.
|
||||
|
||||
Note that the `$adff` and `$sdff` cells can only be used when the reset value is
|
||||
constant.
|
||||
|
||||
D-type flip-flops with asynchronous load are represented by `$aldff` cells. As
|
||||
the `$dff` cells they have ``CLK``, ``D`` and ``Q`` ports. In addition they also
|
||||
have a single-bit ``ALOAD`` input port for the async load enable pin, a ``AD``
|
||||
input port with the same width as data for the async load data, and the
|
||||
following additional parameter:
|
||||
|
||||
``ALOAD_POLARITY``
|
||||
The asynchronous load is active-high if this parameter has the value ``1'b1``
|
||||
and active-low if this parameter is ``1'b0``.
|
||||
|
||||
D-type flip-flops with asynchronous set and reset are represented by `$dffsr`
|
||||
cells. As the `$dff` cells they have ``CLK``, ``D`` and ``Q`` ports. In addition
|
||||
they also have multi-bit ``SET`` and ``CLR`` input ports and the corresponding
|
||||
polarity parameters, like `$sr` cells.
|
||||
|
||||
D-type flip-flops with enable are represented by `$dffe`, `$adffe`, `$aldffe`,
|
||||
`$dffsre`, `$sdffe`, and `$sdffce` cells, which are enhanced variants of `$dff`,
|
||||
`$adff`, `$aldff`, `$dffsr`, `$sdff` (with reset over enable) and `$sdff` (with
|
||||
enable over reset) cells, respectively. They have the same ports and parameters
|
||||
as their base cell. In addition they also have a single-bit ``EN`` input port
|
||||
for the enable pin and the following parameter:
|
||||
|
||||
``EN_POLARITY``
|
||||
The enable input is active-high if this parameter has the value ``1'b1`` and
|
||||
active-low if this parameter is ``1'b0``.
|
||||
|
||||
D-type latches are represented by `$dlatch` cells. These cells have an enable
|
||||
port ``EN``, an input port ``D``, and an output port ``Q``. The following
|
||||
parameters are available for `$dlatch` cells:
|
||||
|
||||
``WIDTH``
|
||||
The width of input ``D`` and output ``Q``.
|
||||
|
||||
``EN_POLARITY``
|
||||
The enable input is active-high if this parameter has the value ``1'b1`` and
|
||||
active-low if this parameter is ``1'b0``.
|
||||
|
||||
The latch is transparent when the ``EN`` input is active.
|
||||
|
||||
D-type latches with reset are represented by `$adlatch` cells. In addition to
|
||||
`$dlatch` ports and parameters, they also have a single-bit ``ARST`` input port
|
||||
for the reset pin and the following additional parameters:
|
||||
|
||||
``ARST_POLARITY``
|
||||
The asynchronous reset is active-high if this parameter has the value
|
||||
``1'b1`` and active-low if this parameter is ``1'b0``.
|
||||
|
||||
``ARST_VALUE``
|
||||
The state of ``Q`` will be set to this value when the reset is active.
|
||||
|
||||
D-type latches with set and reset are represented by `$dlatchsr` cells. In
|
||||
addition to `$dlatch` ports and parameters, they also have multi-bit ``SET`` and
|
||||
``CLR`` input ports and the corresponding polarity parameters, like `$sr` cells.
|
||||
|
||||
.. autocellgroup:: reg
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
9
docs/source/cell/word_spec.rst
Normal file
9
docs/source/cell/word_spec.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Specify rules
|
||||
-------------
|
||||
|
||||
.. todo:: `$specify2`, `$specify3`, and `$specrule` cells.
|
||||
|
||||
.. autocellgroup:: spec
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
50
docs/source/cell/word_unary.rst
Normal file
50
docs/source/cell/word_unary.rst
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
.. role:: verilog(code)
|
||||
:language: Verilog
|
||||
|
||||
Unary operators
|
||||
---------------
|
||||
|
||||
All unary RTL cells have one input port ``A`` and one output port ``Y``. They
|
||||
also have the following parameters:
|
||||
|
||||
``A_SIGNED``
|
||||
Set to a non-zero value if the input ``A`` is signed and therefore should be
|
||||
sign-extended when needed.
|
||||
|
||||
``A_WIDTH``
|
||||
The width of the input port ``A``.
|
||||
|
||||
``Y_WIDTH``
|
||||
The width of the output port ``Y``.
|
||||
|
||||
.. table:: Cell types for unary operators with their corresponding Verilog expressions.
|
||||
|
||||
================== ==============
|
||||
Verilog Cell Type
|
||||
================== ==============
|
||||
:verilog:`Y = ~A` `$not`
|
||||
:verilog:`Y = +A` `$pos`
|
||||
:verilog:`Y = -A` `$neg`
|
||||
:verilog:`Y = &A` `$reduce_and`
|
||||
:verilog:`Y = |A` `$reduce_or`
|
||||
:verilog:`Y = ^A` `$reduce_xor`
|
||||
:verilog:`Y = ~^A` `$reduce_xnor`
|
||||
:verilog:`Y = |A` `$reduce_bool`
|
||||
:verilog:`Y = !A` `$logic_not`
|
||||
================== ==============
|
||||
|
||||
For the unary cells that output a logical value (`$reduce_and`, `$reduce_or`,
|
||||
`$reduce_xor`, `$reduce_xnor`, `$reduce_bool`, `$logic_not`), when the
|
||||
``Y_WIDTH`` parameter is greater than 1, the output is zero-extended, and only
|
||||
the least significant bit varies.
|
||||
|
||||
Note that `$reduce_or` and `$reduce_bool` generally represent the same logic
|
||||
function. But the `read_verilog` frontend will generate them in different
|
||||
situations. A `$reduce_or` cell is generated when the prefix ``|`` operator is
|
||||
being used. A `$reduce_bool` cell is generated when a bit vector is used as a
|
||||
condition in an ``if``-statement or ``?:``-expression.
|
||||
|
||||
.. autocellgroup:: unary
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
9
docs/source/cell/word_wire.rst
Normal file
9
docs/source/cell/word_wire.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Wire cells
|
||||
-------------------------
|
||||
|
||||
.. todo:: Add information about `$slice` and `$concat` cells.
|
||||
|
||||
.. autocellgroup:: wire
|
||||
:members:
|
||||
:source:
|
||||
:linenos:
|
||||
15
docs/source/cell_index.rst
Normal file
15
docs/source/cell_index.rst
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Internal cell library
|
||||
=====================
|
||||
|
||||
The intermediate language used by Yosys (RTLIL) represents logic and memory with
|
||||
a series of cells. This section provides details for those cells, breaking them
|
||||
down into two major categories: coarse-grain word-level cells; and fine-grain
|
||||
gate-level cells. An additional section contains a list of properties which may
|
||||
be shared across multiple cells.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
/cell/index_word
|
||||
/cell/index_gate
|
||||
/cell/properties
|
||||
|
|
@ -4,8 +4,8 @@ YOSYS ?= ../../../../$(PROGRAM_PREFIX)yosys
|
|||
|
||||
.PHONY: all dots examples
|
||||
all: dots examples
|
||||
dots: test1.dot
|
||||
examples: test0.log test1.log test2.log
|
||||
dots: test1.dot my_cmd.so
|
||||
examples: test0.log test1.log test2.log my_cmd.so
|
||||
|
||||
CXXFLAGS=$(shell $(YOSYS)-config --cxxflags)
|
||||
DATDIR=$(shell $(YOSYS)-config --datdir)
|
||||
|
|
|
|||
2
docs/source/code_examples/fifo/.gitignore
vendored
Normal file
2
docs/source/code_examples/fifo/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.out
|
||||
*.stat
|
||||
|
|
@ -5,7 +5,7 @@ module addr_gen
|
|||
) ( input en, clk, rst,
|
||||
output reg [AWIDTH-1:0] addr
|
||||
);
|
||||
initial addr <= 0;
|
||||
initial addr = 0;
|
||||
|
||||
// async reset
|
||||
// increment address when enabled
|
||||
|
|
@ -13,7 +13,7 @@ module addr_gen
|
|||
if (rst)
|
||||
addr <= 0;
|
||||
else if (en) begin
|
||||
if (addr == MAX_DATA-1)
|
||||
if ({'0, addr} == MAX_DATA-1)
|
||||
addr <= 0;
|
||||
else
|
||||
addr <= addr + 1;
|
||||
|
|
@ -57,7 +57,7 @@ module fifo
|
|||
);
|
||||
|
||||
// status signals
|
||||
initial count <= 0;
|
||||
initial count = 0;
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ show -color maroon3 @new_cells -notitle -format dot -prefix rdata_memrdv2 o:rdat
|
|||
# ========================================================
|
||||
|
||||
alumacc
|
||||
select -set new_cells t:$alu t:$macc
|
||||
select -set new_cells t:$alu t:$macc_v2
|
||||
show -color maroon3 @new_cells -notitle -format dot -prefix rdata_alumacc o:rdata %ci*
|
||||
|
||||
# ========================================================
|
||||
|
|
|
|||
44
docs/source/code_examples/functional/dummy.cc
Normal file
44
docs/source/code_examples/functional/dummy.cc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "kernel/functional.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct FunctionalDummyBackend : public Backend {
|
||||
FunctionalDummyBackend() : Backend("functional_dummy", "dump generated Functional IR") {}
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
// backend pass boiler plate
|
||||
log_header(design, "Executing dummy functional backend.\n");
|
||||
|
||||
size_t argidx = 1;
|
||||
extra_args(f, filename, args, argidx, design);
|
||||
|
||||
for (auto module : design->selected_modules())
|
||||
{
|
||||
log("Processing module `%s`.\n", module->name.c_str());
|
||||
|
||||
// convert module to FunctionalIR
|
||||
auto ir = Functional::IR::from_module(module);
|
||||
*f << "module " << module->name.c_str() << "\n";
|
||||
|
||||
// write node functions
|
||||
for (auto node : ir)
|
||||
*f << " assign " << id2cstr(node.name())
|
||||
<< " = " << node.to_string() << "\n";
|
||||
*f << "\n";
|
||||
|
||||
// write outputs and next state
|
||||
for (auto output : ir.outputs())
|
||||
*f << " " << id2cstr(output->kind)
|
||||
<< " " << id2cstr(output->name)
|
||||
<< " = " << id2cstr(output->value().name()) << "\n";
|
||||
for (auto state : ir.states())
|
||||
*f << " " << id2cstr(state->kind)
|
||||
<< " " << id2cstr(state->name)
|
||||
<< " = " << id2cstr(state->next_value().name()) << "\n";
|
||||
}
|
||||
}
|
||||
} FunctionalDummyBackend;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
@ -1,46 +1,49 @@
|
|||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import os
|
||||
|
||||
project = 'YosysHQ Yosys'
|
||||
author = 'YosysHQ GmbH'
|
||||
copyright ='2024 YosysHQ GmbH'
|
||||
yosys_ver = "0.46"
|
||||
copyright ='2025 YosysHQ GmbH'
|
||||
yosys_ver = "0.51"
|
||||
|
||||
# select HTML theme
|
||||
html_theme = 'furo'
|
||||
templates_path = ["_templates"]
|
||||
html_logo = '_static/logo.png'
|
||||
html_favicon = '_static/favico.png'
|
||||
html_css_files = ['yosyshq.css', 'custom.css']
|
||||
|
||||
html_theme_options = {
|
||||
"sidebar_hide_name": True,
|
||||
|
||||
"light_css_variables": {
|
||||
"color-brand-primary": "#d6368f",
|
||||
"color-brand-content": "#4b72b8",
|
||||
"color-api-name": "#8857a3",
|
||||
"color-api-pre-name": "#4b72b8",
|
||||
"color-link": "#8857a3",
|
||||
},
|
||||
|
||||
"dark_css_variables": {
|
||||
"color-brand-primary": "#e488bb",
|
||||
"color-brand-content": "#98bdff",
|
||||
"color-api-name": "#8857a3",
|
||||
"color-api-pre-name": "#4b72b8",
|
||||
"color-link": "#be95d5",
|
||||
},
|
||||
html_theme = 'furo-ys'
|
||||
html_css_files = ['custom.css']
|
||||
html_theme_options: dict[str] = {
|
||||
"source_repository": "https://github.com/YosysHQ/yosys/",
|
||||
"source_branch": "main",
|
||||
"source_directory": "docs/source/",
|
||||
}
|
||||
|
||||
# try to fix the readthedocs detection
|
||||
html_context: dict[str] = {
|
||||
"READTHEDOCS": True,
|
||||
"display_github": True,
|
||||
"github_user": "YosysHQ",
|
||||
"github_repo": "yosys",
|
||||
"slug": "yosys",
|
||||
}
|
||||
|
||||
# override source_branch if not main
|
||||
git_slug = os.getenv("READTHEDOCS_VERSION_NAME")
|
||||
if git_slug not in [None, "latest", "stable"]:
|
||||
html_theme_options["source_branch"] = git_slug
|
||||
|
||||
# edit only works on branches, not tags
|
||||
if os.getenv("READTHEDOCS_VERSION_TYPE", "branch") != "branch":
|
||||
html_theme_options["top_of_page_buttons"] = ["view"]
|
||||
|
||||
# These folders are copied to the documentation's HTML output
|
||||
html_static_path = ['_static', "_images"]
|
||||
|
||||
# code blocks style
|
||||
pygments_style = 'colorful'
|
||||
# default to no highlight
|
||||
highlight_language = 'none'
|
||||
|
||||
# default single quotes to attempt auto reference, or fallback to code
|
||||
default_role = 'autoref'
|
||||
|
||||
extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex']
|
||||
|
||||
if os.getenv("READTHEDOCS"):
|
||||
|
|
@ -76,6 +79,9 @@ if os.getenv("READTHEDOCS"):
|
|||
else:
|
||||
release = yosys_ver
|
||||
todo_include_todos = False
|
||||
elif os.getenv("YOSYS_DOCS_RELEASE") is not None:
|
||||
release = yosys_ver
|
||||
todo_include_todos = False
|
||||
else:
|
||||
release = yosys_ver
|
||||
todo_include_todos = True
|
||||
|
|
@ -97,9 +103,19 @@ latex_elements = {
|
|||
sys.path += [os.path.dirname(__file__) + "/../"]
|
||||
extensions.append('util.cmdref')
|
||||
|
||||
def setup(sphinx):
|
||||
from util.RtlilLexer import RtlilLexer
|
||||
sphinx.add_lexer("RTLIL", RtlilLexer)
|
||||
# use autodocs
|
||||
extensions.append('sphinx.ext.autodoc')
|
||||
extensions.append('util.cellref')
|
||||
cells_json = Path(__file__).parent / 'generated' / 'cells.json'
|
||||
|
||||
from util.YoscryptLexer import YoscryptLexer
|
||||
sphinx.add_lexer("yoscrypt", YoscryptLexer)
|
||||
from sphinx.application import Sphinx
|
||||
def setup(app: Sphinx) -> None:
|
||||
from util.RtlilLexer import RtlilLexer
|
||||
app.add_lexer("RTLIL", RtlilLexer)
|
||||
|
||||
try:
|
||||
from furo_ys.lexers.YoscryptLexer import YoscryptLexer
|
||||
app.add_lexer("yoscrypt", YoscryptLexer)
|
||||
except ModuleNotFoundError:
|
||||
from pygments.lexers.special import TextLexer
|
||||
app.add_lexer("yoscrypt", TextLexer)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ Synthesis starter
|
|||
-----------------
|
||||
|
||||
This page will be a guided walkthrough of the prepackaged iCE40 FPGA synthesis
|
||||
script - :cmd:ref:`synth_ice40`. We will take a simple design through each
|
||||
step, looking at the commands being called and what they do to the design. While
|
||||
:cmd:ref:`synth_ice40` is specific to the iCE40 platform, most of the operations
|
||||
we will be discussing are common across the majority of FPGA synthesis scripts.
|
||||
Thus, this document will provide a good foundational understanding of how
|
||||
synthesis in Yosys is performed, regardless of the actual architecture being
|
||||
used.
|
||||
script - `synth_ice40`. We will take a simple design through each step, looking
|
||||
at the commands being called and what they do to the design. While `synth_ice40`
|
||||
is specific to the iCE40 platform, most of the operations we will be discussing
|
||||
are common across the majority of FPGA synthesis scripts. Thus, this document
|
||||
will provide a good foundational understanding of how synthesis in Yosys is
|
||||
performed, regardless of the actual architecture being used.
|
||||
|
||||
.. seealso:: Advanced usage docs for
|
||||
:doc:`/using_yosys/synthesis/synth`
|
||||
|
|
@ -31,6 +30,14 @@ First, let's quickly look at the design we'll be synthesizing:
|
|||
|
||||
.. todo:: fifo.v description
|
||||
|
||||
While the open source `read_verilog` frontend generally does a pretty good job
|
||||
at processing valid Verilog input, it does not provide very good error handling
|
||||
or reporting. Using an external tool such as `verilator`_ before running Yosys
|
||||
is highly recommended. We can quickly check the Verilog syntax of our design by
|
||||
calling ``verilator --lint-only fifo.v``.
|
||||
|
||||
.. _verilator: https://www.veripool.org/verilator/
|
||||
|
||||
Loading the design
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
@ -59,8 +66,8 @@ can run each of the commands individually for a better sense of how each part
|
|||
contributes to the flow. We will also start with just a single module;
|
||||
``addr_gen``.
|
||||
|
||||
At the bottom of the :cmd:ref:`help` output for
|
||||
:cmd:ref:`synth_ice40` is the complete list of commands called by this script.
|
||||
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
|
||||
|
|
@ -105,10 +112,10 @@ Since we're just getting started, let's instead begin with :yoscrypt:`hierarchy
|
|||
|
||||
.. note::
|
||||
|
||||
:cmd:ref:`hierarchy` should always be the first command after the design has
|
||||
been read. By specifying the top module, :cmd:ref:`hierarchy` will also set
|
||||
the ``(* top *)`` attribute on it. This is used by other commands that need
|
||||
to know which module is the top.
|
||||
`hierarchy` should always be the first command after the design has been
|
||||
read. By specifying the top module, `hierarchy` will also set the ``(* top
|
||||
*)`` attribute on it. This is used by other commands that need to know which
|
||||
module is the top.
|
||||
|
||||
.. use doscon for a console-like display that supports the `yosys> [command]` format.
|
||||
|
||||
|
|
@ -125,24 +132,24 @@ Our ``addr_gen`` circuit now looks like this:
|
|||
:class: width-helper invert-helper
|
||||
:name: addr_gen_hier
|
||||
|
||||
``addr_gen`` module after :cmd:ref:`hierarchy`
|
||||
``addr_gen`` module after `hierarchy`
|
||||
|
||||
Simple operations like ``addr + 1`` and ``addr == MAX_DATA-1`` can be extracted
|
||||
from our ``always @`` block in :ref:`addr_gen-v`. This gives us the highlighted
|
||||
``$add`` and ``$eq`` cells we see. But control logic (like the ``if .. else``)
|
||||
and memory elements (like the ``addr <= 0``) are not so straightforward. These
|
||||
get put into "processes", shown in the schematic as ``PROC``. Note how the
|
||||
second 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.
|
||||
`$add` and `$eq` cells we see. But control logic (like the ``if .. else``) and
|
||||
memory elements (like the ``addr <= 0``) are not so straightforward. These get
|
||||
put into "processes", shown in the schematic as ``PROC``. Note how the second
|
||||
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`.
|
||||
:cmd:ref:`proc` is a macro command like :cmd:ref:`synth_ice40`. Rather than
|
||||
modifying the design directly, it instead calls a series of other commands. In
|
||||
the case of :cmd:ref:`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 will call :yoscrypt:`proc -noopt` to prevent some
|
||||
automatic optimizations which would normally happen.
|
||||
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
|
||||
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
|
||||
will call :yoscrypt:`proc -noopt` to prevent some automatic optimizations which
|
||||
would normally happen.
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/addr_gen_proc.*
|
||||
:class: width-helper invert-helper
|
||||
|
|
@ -151,19 +158,18 @@ automatic optimizations which would normally happen.
|
|||
``addr_gen`` module after :yoscrypt:`proc -noopt`
|
||||
|
||||
There are now a few new cells from our ``always @``, which have been
|
||||
highlighted. The ``if`` statements are now modeled with ``$mux`` cells, while
|
||||
the register uses an ``$adff`` cell. If we look at the terminal output we can
|
||||
also see all of the different ``proc_*`` commands being called. We will look at
|
||||
each of these in more detail in :doc:`/using_yosys/synthesis/proc`.
|
||||
highlighted. The ``if`` statements are now modeled with `$mux` cells, while the
|
||||
register uses an `$adff` cell. If we look at the terminal output we can also
|
||||
see all of the different ``proc_*`` commands being called. We will look at each
|
||||
of these in more detail in :doc:`/using_yosys/synthesis/proc`.
|
||||
|
||||
Notice how in the top left of :ref:`addr_gen_proc` we have a floating wire,
|
||||
generated from the initial assignment of 0 to the ``addr`` wire. However, this
|
||||
initial assignment is not synthesizable, so this will need to be cleaned up
|
||||
before we can generate the physical hardware. We can do this now by calling
|
||||
:cmd:ref:`clean`. We're also going to call :cmd:ref:`opt_expr` now, which would
|
||||
normally be called at the end of :cmd:ref:`proc`. We can call both commands at
|
||||
the same time by separating them with a colon and space: :yoscrypt:`opt_expr;
|
||||
clean`.
|
||||
`clean`. We're also going to call `opt_expr` now, which would normally be
|
||||
called at the end of `proc`. We can call both commands at the same time by
|
||||
separating them with a colon and space: :yoscrypt:`opt_expr; clean`.
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/addr_gen_clean.*
|
||||
:class: width-helper invert-helper
|
||||
|
|
@ -171,24 +177,24 @@ clean`.
|
|||
|
||||
``addr_gen`` module after :yoscrypt:`opt_expr; clean`
|
||||
|
||||
You may also notice that the highlighted ``$eq`` cell input of ``255`` has
|
||||
changed to ``8'11111111``. Constant values are presented in the format
|
||||
You may also notice that the highlighted `$eq` cell input of ``255`` has changed
|
||||
to ``8'11111111``. Constant values are presented in the format
|
||||
``<bit_width>'<bits>``, with 32-bit values instead using the decimal number.
|
||||
This indicates that the constant input has been reduced from 32-bit wide to
|
||||
8-bit wide. This is a side-effect of running :cmd:ref:`opt_expr`, which
|
||||
performs constant folding and simple expression rewriting. For more on why
|
||||
this happens, refer to :doc:`/using_yosys/synthesis/opt` and the :ref:`section
|
||||
on opt_expr <adv_opt_expr>`.
|
||||
8-bit wide. This is a side-effect of running `opt_expr`, which performs
|
||||
constant folding and simple expression rewriting. For more on why this
|
||||
happens, refer to :doc:`/using_yosys/synthesis/opt` and the :ref:`section on
|
||||
opt_expr <adv_opt_expr>`.
|
||||
|
||||
.. note::
|
||||
|
||||
:doc:`/cmd/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 :cmd:ref:`clean` before inspecting
|
||||
intermediate products to remove disconnected parts of the circuit which have
|
||||
been left over, and in some cases can reduce the processing required in
|
||||
subsequent commands.
|
||||
with ``;;``. It is beneficial to run `clean` before inspecting intermediate
|
||||
products to remove disconnected parts of the circuit which have been left
|
||||
over, and in some cases can reduce the processing required in subsequent
|
||||
commands.
|
||||
|
||||
.. todo:: consider a brief glossary for terms like adff
|
||||
|
||||
|
|
@ -202,8 +208,8 @@ The full example
|
|||
|
||||
Let's now go back and check on our full design by using :yoscrypt:`hierarchy
|
||||
-check -top fifo`. By passing the ``-check`` option there we are also telling
|
||||
the :cmd:ref:`hierarchy` command that if the design includes any non-blackbox
|
||||
modules without an implementation it should return an error.
|
||||
the `hierarchy` command that if the design includes any non-blackbox modules
|
||||
without an implementation it should return an error.
|
||||
|
||||
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
|
||||
|
|
@ -218,18 +224,17 @@ could restart our shell session, but instead let's use two new commands:
|
|||
:end-before: yosys> proc
|
||||
:caption: reloading :file:`fifo.v` and running :yoscrypt:`hierarchy -check -top fifo`
|
||||
|
||||
Notice how this time we didn't see any of those `$abstract` modules? That's
|
||||
Notice how this time we didn't see any of those ``$abstract`` modules? That's
|
||||
because when we ran ``yosys fifo.v``, the first command Yosys called was
|
||||
:yoscrypt:`read_verilog -defer fifo.v`. The ``-defer`` option there tells
|
||||
:cmd:ref:`read_verilog` only read the abstract syntax tree and defer actual
|
||||
compilation to a later :cmd:ref:`hierarchy` command. This is useful in cases
|
||||
where the default parameters of modules yield invalid code which is not
|
||||
synthesizable. This is why Yosys defers compilation automatically and is one of
|
||||
the reasons why hierarchy should always be the first command after loading the
|
||||
design. If we know that our design won't run into this issue, we can skip the
|
||||
``-defer``.
|
||||
`read_verilog` only read the abstract syntax tree and defer actual compilation
|
||||
to a later `hierarchy` command. This is useful in cases where the default
|
||||
parameters of modules yield invalid code which is not synthesizable. This is why
|
||||
Yosys defers compilation automatically and is one of the reasons why hierarchy
|
||||
should always be the first command after loading the design. If we know that
|
||||
our design won't run into this issue, we can skip the ``-defer``.
|
||||
|
||||
.. todo:: :cmd:ref:`hierarchy` failure modes
|
||||
.. todo:: `hierarchy` failure modes
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -243,19 +248,19 @@ design. If we know that our design won't run into this issue, we can skip the
|
|||
interactive terminal. :kbd:`ctrl+c` (i.e. SIGINT) will also end the terminal
|
||||
session but will return an error code rather than exiting gracefully.
|
||||
|
||||
We can also run :cmd:ref:`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 :cmd:ref:`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 :cmd:ref:`show`.
|
||||
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
|
||||
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`.
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/rdata_proc.*
|
||||
:class: width-helper invert-helper
|
||||
:name: rdata_proc
|
||||
|
||||
``rdata`` output after :cmd:ref:`proc`
|
||||
``rdata`` output after `proc`
|
||||
|
||||
The highlighted ``fifo_reader`` block contains an instance of the
|
||||
:ref:`addr_gen_proc` that we looked at earlier. Notice how the type is shown as
|
||||
|
|
@ -263,10 +268,10 @@ The highlighted ``fifo_reader`` block contains an instance of the
|
|||
instance of the ``addr_gen`` module with the ``MAX_DATA`` parameter set to the
|
||||
given value.
|
||||
|
||||
The other highlighted block is a ``$memrd`` cell. At this stage of synthesis we
|
||||
The other highlighted block is a `$memrd` cell. At this stage of synthesis we
|
||||
don't yet know what type of memory is going to be implemented, but we *do* know
|
||||
that ``rdata <= data[raddr];`` could be implemented as a read from memory. Note
|
||||
that the ``$memrd`` cell here is asynchronous, with both the clock and enable
|
||||
that the `$memrd` cell here is asynchronous, with both the clock and enable
|
||||
signal undefined; shown with the ``1'x`` inputs.
|
||||
|
||||
.. seealso:: Advanced usage docs for
|
||||
|
|
@ -276,7 +281,7 @@ Flattening
|
|||
~~~~~~~~~~
|
||||
|
||||
At this stage of a synthesis flow there are a few other commands we could run.
|
||||
In :cmd:ref:`synth_ice40` we get these:
|
||||
In `synth_ice40` we get these:
|
||||
|
||||
.. literalinclude:: /cmd/synth_ice40.rst
|
||||
:language: yoscrypt
|
||||
|
|
@ -286,7 +291,7 @@ In :cmd:ref:`synth_ice40` we get these:
|
|||
:name: synth_flatten
|
||||
:caption: ``flatten`` section
|
||||
|
||||
First off is :cmd:ref:`flatten`. Flattening the design like this can allow for
|
||||
First off is `flatten`. Flattening the design like this can allow for
|
||||
optimizations between modules which would otherwise be missed. Let's run
|
||||
:yoscrypt:`flatten;;` on our design.
|
||||
|
||||
|
|
@ -309,23 +314,22 @@ optimizations between modules which would otherwise be missed. Let's run
|
|||
The pieces have moved around a bit, but we can see :ref:`addr_gen_proc` from
|
||||
earlier has replaced the ``fifo_reader`` block in :ref:`rdata_proc`. We can
|
||||
also see that the ``addr`` output has been renamed to :file:`fifo_reader.addr`
|
||||
and merged with the ``raddr`` wire feeding into the ``$memrd`` cell. This wire
|
||||
merging happened during the call to :cmd:ref:`clean` which we can see in the
|
||||
and merged with the ``raddr`` wire feeding into the `$memrd` cell. This wire
|
||||
merging happened during the call to `clean` which we can see in the
|
||||
:ref:`flat_clean`.
|
||||
|
||||
.. note::
|
||||
|
||||
:cmd:ref:`flatten` and :cmd:ref:`clean` would normally be combined into a
|
||||
`flatten` and `clean` would normally be combined into a
|
||||
single :yoterm:`yosys> flatten;;` output, but they appear separately here as
|
||||
a side effect of using :cmd:ref:`echo` for generating the terminal style
|
||||
a side effect of using `echo` for generating the terminal style
|
||||
output.
|
||||
|
||||
Depending on the target architecture, this stage of synthesis might also see
|
||||
commands such as :cmd:ref:`tribuf` with the ``-logic`` option and
|
||||
:cmd:ref:`deminout`. These remove tristate and inout constructs respectively,
|
||||
replacing them with logic suitable for mapping to an FPGA. Since we do not have
|
||||
any such constructs in our example running these commands does not change our
|
||||
design.
|
||||
commands such as `tribuf` with the ``-logic`` option and `deminout`. These
|
||||
remove tristate and inout constructs respectively, replacing them with logic
|
||||
suitable for mapping to an FPGA. Since we do not have any such constructs in
|
||||
our example running these commands does not change our design.
|
||||
|
||||
The coarse-grain representation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -342,9 +346,9 @@ optimizations and other transformations done previously.
|
|||
|
||||
.. note::
|
||||
|
||||
While the iCE40 flow had a :ref:`synth_flatten` and put :cmd:ref:`proc` in
|
||||
the :ref:`synth_begin`, some synthesis scripts will instead include these in
|
||||
this section.
|
||||
While the iCE40 flow had a :ref:`synth_flatten` and put `proc` in the
|
||||
:ref:`synth_begin`, some synthesis scripts will instead include these in this
|
||||
section.
|
||||
|
||||
Part 1
|
||||
^^^^^^
|
||||
|
|
@ -359,36 +363,35 @@ In the iCE40 flow, we start with the following commands:
|
|||
:caption: ``coarse`` section (part 1)
|
||||
:name: synth_coarse1
|
||||
|
||||
We've already come across :cmd:ref:`opt_expr`, and :cmd:ref:`opt_clean` is the
|
||||
same as :cmd:ref:`clean` but with more verbose output. The :cmd:ref:`check`
|
||||
pass identifies a few obvious problems which will cause errors later. Calling
|
||||
it here lets us fail faster rather than wasting time on something we know is
|
||||
impossible.
|
||||
We've already come across `opt_expr`, and `opt_clean` is the same as `clean` but
|
||||
with more verbose output. The `check` pass identifies a few obvious problems
|
||||
which will cause errors later. Calling it here lets us fail faster rather than
|
||||
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 :cmd:ref:`opt` and :cmd:ref:`fsm` are macro commands
|
||||
which are explored in more detail in :doc:`/using_yosys/synthesis/opt` and
|
||||
:doc:`/cmd/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.
|
||||
|
||||
Up until now, the data path for ``rdata`` has remained the same since
|
||||
:ref:`rdata_flat`. However the next call to :cmd:ref:`opt` does cause a change.
|
||||
Specifically, the call to :cmd:ref:`opt_dff` without the ``-nodffe -nosdff``
|
||||
options is able to fold one of the ``$mux`` cells into the ``$adff`` to form an
|
||||
``$adffe`` cell; highlighted below:
|
||||
:ref:`rdata_flat`. However the next call to `opt` does cause a change.
|
||||
Specifically, the call to `opt_dff` without the ``-nodffe -nosdff`` options is
|
||||
able to fold one of the `$mux` cells into the `$adff` to form an `$adffe` cell;
|
||||
highlighted below:
|
||||
|
||||
.. literalinclude:: /code_examples/fifo/fifo.out
|
||||
:language: doscon
|
||||
:start-at: yosys> opt_dff
|
||||
:end-before: yosys> select
|
||||
:caption: output of :cmd:ref:`opt_dff`
|
||||
:caption: output of `opt_dff`
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/rdata_adffe.*
|
||||
:class: width-helper invert-helper
|
||||
:name: rdata_adffe
|
||||
|
||||
``rdata`` output after :cmd:ref:`opt_dff`
|
||||
``rdata`` output after `opt_dff`
|
||||
|
||||
.. seealso:: Advanced usage docs for
|
||||
|
||||
|
|
@ -414,27 +417,27 @@ First up is :doc:`/cmd/wreduce`. If we run this we get the following:
|
|||
:language: doscon
|
||||
:start-at: yosys> wreduce
|
||||
:end-before: yosys> select
|
||||
:caption: output of :cmd:ref:`wreduce`
|
||||
:caption: output of `wreduce`
|
||||
|
||||
Looking at the data path for ``rdata``, the most relevant of these width
|
||||
reductions are the ones affecting ``fifo.$flatten\fifo_reader.$add$fifo.v``.
|
||||
That is the ``$add`` cell incrementing the fifo_reader address. We can look at
|
||||
That is the `$add` cell incrementing the fifo_reader address. We can look at
|
||||
the schematic and see the output of that cell has now changed.
|
||||
|
||||
.. todo:: pending bugfix in :cmd:ref:`wreduce` and/or :cmd:ref:`opt_clean`
|
||||
.. todo:: pending bugfix in `wreduce` and/or `opt_clean`
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/rdata_wreduce.*
|
||||
:class: width-helper invert-helper
|
||||
:name: rdata_wreduce
|
||||
|
||||
``rdata`` output after :cmd:ref:`wreduce`
|
||||
``rdata`` output after `wreduce`
|
||||
|
||||
The next two (new) commands are :doc:`/cmd/peepopt` and :doc:`/cmd/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
|
||||
converting them to LUTs instead. The usage of :cmd:ref:`techmap` is explored
|
||||
more in :doc:`/using_yosys/synthesis/techmap_synth`.
|
||||
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`.
|
||||
|
|
@ -443,17 +446,17 @@ Our next command to run is
|
|||
:language: doscon
|
||||
:start-at: yosys> memory_dff
|
||||
:end-before: yosys> select
|
||||
:caption: output of :cmd:ref:`memory_dff`
|
||||
:caption: output of `memory_dff`
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/rdata_memrdv2.*
|
||||
:class: width-helper invert-helper
|
||||
:name: rdata_memrdv2
|
||||
|
||||
``rdata`` output after :cmd:ref:`memory_dff`
|
||||
``rdata`` output after `memory_dff`
|
||||
|
||||
As the title suggests, :cmd:ref:`memory_dff` has merged the output ``$dff`` into
|
||||
the ``$memrd`` cell and converted it to a ``$memrd_v2`` (highlighted). This has
|
||||
also connected the ``CLK`` port to the ``clk`` input as it is now a synchronous
|
||||
As the title suggests, `memory_dff` has merged the output `$dff` into the
|
||||
`$memrd` cell and converted it to a `$memrd_v2` (highlighted). This has also
|
||||
connected the ``CLK`` port to the ``clk`` input as it is now a synchronous
|
||||
memory read with appropriate enable (``EN=1'1``) and reset (``ARST=1'0`` and
|
||||
``SRST=1'0``) inputs.
|
||||
|
||||
|
|
@ -466,12 +469,11 @@ memory read with appropriate enable (``EN=1'1``) and reset (``ARST=1'0`` and
|
|||
Part 3
|
||||
^^^^^^
|
||||
|
||||
The third part of the :cmd:ref:`synth_ice40` flow is a series of commands for
|
||||
mapping to DSPs. By default, the iCE40 flow will not map to the hardware DSP
|
||||
blocks and 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.
|
||||
The third part of the `synth_ice40` flow is a series of commands for mapping to
|
||||
DSPs. By default, the iCE40 flow will not map to the hardware DSP blocks and
|
||||
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
|
||||
:language: yoscrypt
|
||||
|
|
@ -482,29 +484,27 @@ what they do.
|
|||
:name: synth_coarse3
|
||||
|
||||
:yoscrypt:`wreduce t:$mul` performs width reduction again, this time targetting
|
||||
only cells of type ``$mul``. :yoscrypt:`techmap -map +/mul2dsp.v -map
|
||||
+/ice40/dsp_map.v ... -D DSP_NAME=$__MUL16X16` uses :cmd:ref:`techmap` to map
|
||||
``$mul`` cells to ``$__MUL16X16`` which are, in turn, mapped to the iCE40
|
||||
``SB_MAC16``. Any multipliers which aren't compatible with conversion to
|
||||
``$__MUL16X16`` are relabelled to ``$__soft_mul`` before :cmd:ref:`chtype`
|
||||
changes them back to ``$mul``.
|
||||
only cells of type `$mul`. :yoscrypt:`techmap -map +/mul2dsp.v -map
|
||||
+/ice40/dsp_map.v ... -D DSP_NAME=$__MUL16X16` uses `techmap` to map `$mul`
|
||||
cells to ``$__MUL16X16`` which are, in turn, mapped to the iCE40 ``SB_MAC16``.
|
||||
Any multipliers which aren't compatible with conversion to ``$__MUL16X16`` are
|
||||
relabelled to ``$__soft_mul`` before `chtype` changes them back to `$mul`.
|
||||
|
||||
During the mul2dsp conversion, some of the intermediate signals are marked with
|
||||
the attribute ``mul2dsp``. By calling :yoscrypt:`select a:mul2dsp` we restrict
|
||||
the following commands to only operate on the cells and wires used for these
|
||||
signals. :cmd:ref:`setattr` removes the now unnecessary ``mul2dsp`` attribute.
|
||||
:cmd:ref:`opt_expr` we've already come across for const folding and simple
|
||||
expression rewriting, the ``-fine`` option just enables more fine-grain
|
||||
optimizations. Then we perform width reduction a final time and clear the
|
||||
selection.
|
||||
signals. `setattr` removes the now unnecessary ``mul2dsp`` attribute.
|
||||
`opt_expr` we've already come across for const folding and simple expression
|
||||
rewriting, the ``-fine`` option just enables more fine-grain optimizations.
|
||||
Then we perform width reduction a final time and clear the selection.
|
||||
|
||||
.. todo:: ``ice40_dsp`` is pmgen
|
||||
|
||||
Finally we have :cmd:ref:`ice40_dsp`: similar to the :cmd:ref:`memory_dff`
|
||||
command we saw in the previous section, this merges any surrounding registers
|
||||
into the ``SB_MAC16`` cell. This includes not just the input/output registers,
|
||||
but also pipeline registers and even a post-adder where applicable: turning a
|
||||
multiply + add into a single multiply-accumulate.
|
||||
Finally we have `ice40_dsp`: similar to the `memory_dff` command we saw in the
|
||||
previous section, this merges any surrounding registers into the ``SB_MAC16``
|
||||
cell. This includes not just the input/output registers, but also pipeline
|
||||
registers and even a post-adder where applicable: turning a multiply + add into
|
||||
a single multiply-accumulate.
|
||||
|
||||
.. seealso:: Advanced usage docs for
|
||||
:doc:`/using_yosys/synthesis/techmap_synth`
|
||||
|
|
@ -522,44 +522,43 @@ That brings us to the fourth and final part for the iCE40 synthesis flow:
|
|||
:caption: ``coarse`` section (part 4)
|
||||
:name: synth_coarse4
|
||||
|
||||
Where before each type of arithmetic operation had its own cell, e.g. ``$add``,
|
||||
we now want to extract these into ``$alu`` and ``$macc`` cells which can help
|
||||
identify opportunities for reusing logic. We do this by running
|
||||
:cmd:ref:`alumacc`, which we can see produce the following changes in our
|
||||
example design:
|
||||
Where before each type of arithmetic operation had its own cell, e.g. `$add`, we
|
||||
now want to extract these into `$alu` and `$macc_v2` cells which can help identify
|
||||
opportunities for reusing logic. We do this by running `alumacc`, which we can
|
||||
see produce the following changes in our example design:
|
||||
|
||||
.. literalinclude:: /code_examples/fifo/fifo.out
|
||||
:language: doscon
|
||||
:start-at: yosys> alumacc
|
||||
:end-before: yosys> select
|
||||
:caption: output of :cmd:ref:`alumacc`
|
||||
:caption: output of `alumacc`
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/rdata_alumacc.*
|
||||
:class: width-helper invert-helper
|
||||
:name: rdata_alumacc
|
||||
|
||||
``rdata`` output after :cmd:ref:`alumacc`
|
||||
``rdata`` output after `alumacc`
|
||||
|
||||
Once these cells have been inserted, the call to :cmd:ref:`opt` can combine
|
||||
cells which are now identical but may have been missed due to e.g. the
|
||||
difference between ``$add`` and ``$sub``.
|
||||
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`. :cmd:ref:`memory` is
|
||||
another macro command which we examine in more detail in
|
||||
The other new command in this part is :doc:`/cmd/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: :cmd:ref:`memory_collect`. Up until this
|
||||
point, our memory reads and our memory writes have been totally disjoint cells;
|
||||
operating on the same memory only in the abstract. :cmd:ref:`memory_collect`
|
||||
combines all of the reads and writes for a memory block into a single cell.
|
||||
the step most relevant to our example: `memory_collect`. Up until this point,
|
||||
our memory reads and our memory writes have been totally disjoint cells;
|
||||
operating on the same memory only in the abstract. `memory_collect` combines all
|
||||
of the reads and writes for a memory block into a single cell.
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/rdata_coarse.*
|
||||
:class: width-helper invert-helper
|
||||
:name: rdata_coarse
|
||||
|
||||
``rdata`` output after :cmd:ref:`memory_collect`
|
||||
``rdata`` output after `memory_collect`
|
||||
|
||||
Looking at the schematic after running :cmd:ref:`memory_collect` we see that our
|
||||
``$memrd_v2`` cell has been replaced with a ``$mem_v2`` cell named ``data``, the
|
||||
Looking at the schematic after running `memory_collect` we see that our
|
||||
`$memrd_v2` cell has been replaced with a `$mem_v2` cell named ``data``, the
|
||||
same name that we used in :ref:`fifo-v`. Where before we had a single set of
|
||||
signals for address and enable, we now have one set for reading (``RD_*``) and
|
||||
one for writing (``WR_*``), as well as both ``WR_DATA`` input and ``RD_DATA``
|
||||
|
|
@ -592,8 +591,8 @@ If you skipped calling :yoscrypt:`read_verilog -D ICE40_HX -lib -specify
|
|||
Memory blocks
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Mapping to hard memory blocks uses a combination of :cmd:ref:`memory_libmap` and
|
||||
:cmd:ref:`techmap`.
|
||||
Mapping to hard memory blocks uses a combination of `memory_libmap` and
|
||||
`techmap`.
|
||||
|
||||
.. literalinclude:: /cmd/synth_ice40.rst
|
||||
:language: yoscrypt
|
||||
|
|
@ -609,28 +608,28 @@ Mapping to hard memory blocks uses a combination of :cmd:ref:`memory_libmap` and
|
|||
|
||||
``rdata`` output after :ref:`map_ram`
|
||||
|
||||
The :ref:`map_ram` converts the generic ``$mem_v2`` into the iCE40
|
||||
``SB_RAM40_4K`` (highlighted). We can also see the memory address has been
|
||||
remapped, and the data bits have been reordered (or swizzled). There is also
|
||||
now a ``$mux`` cell controlling the value of ``rdata``. In :ref:`fifo-v` we
|
||||
wrote our memory as read-before-write, however the ``SB_RAM40_4K`` has undefined
|
||||
behaviour when reading from and writing to the same address in the same cycle.
|
||||
As a result, extra logic is added so that the generated circuit matches the
|
||||
behaviour of the verilog. :ref:`no_rw_check` describes how we could change our
|
||||
verilog to match our hardware instead.
|
||||
The :ref:`map_ram` converts the generic `$mem_v2` into the iCE40 ``SB_RAM40_4K``
|
||||
(highlighted). We can also see the memory address has been remapped, and the
|
||||
data bits have been reordered (or swizzled). There is also now a `$mux` cell
|
||||
controlling the value of ``rdata``. In :ref:`fifo-v` we wrote our memory as
|
||||
read-before-write, however the ``SB_RAM40_4K`` has undefined behaviour when
|
||||
reading from and writing to the same address in the same cycle. As a result,
|
||||
extra logic is added so that the generated circuit matches the behaviour of the
|
||||
verilog. :ref:`no_rw_check` describes how we could change our verilog to match
|
||||
our hardware instead.
|
||||
|
||||
If we run :cmd:ref:`memory_libmap` under the :cmd:ref:`debug` command we can see
|
||||
candidates which were identified for mapping, along with the costs of each and
|
||||
what logic requires emulation.
|
||||
If we run `memory_libmap` under the `debug` command we can see candidates which
|
||||
were identified for mapping, along with the costs of each and what logic
|
||||
requires emulation.
|
||||
|
||||
.. literalinclude:: /code_examples/fifo/fifo.libmap
|
||||
:language: doscon
|
||||
:lines: 2, 6-
|
||||
|
||||
The ``$__ICE40_RAM4K_`` cell is defined in the file |techlibs/ice40/brams.txt|_,
|
||||
with the mapping to ``SB_RAM40_4K`` done by :cmd:ref:`techmap` using
|
||||
with the mapping to ``SB_RAM40_4K`` done by `techmap` using
|
||||
|techlibs/ice40/brams_map.v|_. Any leftover memory cells are then converted
|
||||
into flip flops (the ``logic fallback``) with :cmd:ref:`memory_map`.
|
||||
into flip flops (the ``logic fallback``) with `memory_map`.
|
||||
|
||||
.. |techlibs/ice40/brams.txt| replace:: :file:`techlibs/ice40/brams.txt`
|
||||
.. _techlibs/ice40/brams.txt: https://github.com/YosysHQ/yosys/tree/main/techlibs/ice40/brams.txt
|
||||
|
|
@ -654,8 +653,8 @@ into flip flops (the ``logic fallback``) with :cmd:ref:`memory_map`.
|
|||
.. note::
|
||||
|
||||
The visual clutter on the ``RDATA`` output port (highlighted) is an
|
||||
unfortunate side effect of :cmd:ref:`opt_clean` on the swizzled data bits. In
|
||||
connecting the ``$mux`` input port directly to ``RDATA`` to reduce the number
|
||||
unfortunate side effect of `opt_clean` on the swizzled data bits. In
|
||||
connecting the `$mux` input port directly to ``RDATA`` to reduce the number
|
||||
of wires, the ``$techmap579\data.0.0.RDATA`` wire becomes more visually
|
||||
complex.
|
||||
|
||||
|
|
@ -667,11 +666,10 @@ into flip flops (the ``logic fallback``) with :cmd:ref:`memory_map`.
|
|||
Arithmetic
|
||||
^^^^^^^^^^
|
||||
|
||||
Uses :cmd:ref:`techmap` to map basic arithmetic logic to hardware. This sees
|
||||
somewhat of 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.
|
||||
Uses `techmap` to map basic arithmetic logic to hardware. This sees somewhat of
|
||||
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
|
||||
:language: yoscrypt
|
||||
|
|
@ -693,14 +691,14 @@ replaced with single-bit ``$_MUX_`` and ``$_DFFE_PP0P_`` cells, while the
|
|||
Flip-flops
|
||||
^^^^^^^^^^
|
||||
|
||||
Convert FFs to the types supported in hardware with :cmd:ref:`dfflegalize`, and
|
||||
then use :cmd:ref:`techmap` to map them. In our example, this converts the
|
||||
``$_DFFE_PP0P_`` cells to ``SB_DFFER``.
|
||||
Convert FFs to the types supported in hardware with `dfflegalize`, and then use
|
||||
`techmap` to map them. In our example, this converts the `$_DFFE_PP0P_` cells
|
||||
to ``SB_DFFER``.
|
||||
|
||||
We also run :cmd:ref:`simplemap` here to convert any remaining cells which could
|
||||
not be 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.
|
||||
We also run `simplemap` here to convert any remaining cells which could not be
|
||||
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
|
||||
:language: yoscrypt
|
||||
|
|
@ -722,11 +720,10 @@ instead with an ``$_AND_`` cell.
|
|||
LUTs
|
||||
^^^^
|
||||
|
||||
:cmd:ref:`abc` and :cmd:ref:`techmap` are used to map LUTs; converting primitive
|
||||
cell types to use ``$lut`` and ``SB_CARRY`` cells. Note that the iCE40 flow
|
||||
uses :cmd:ref:`abc9` rather than :cmd:ref:`abc`. For more on what these do, and
|
||||
what the difference between these two commands are, refer to
|
||||
:doc:`/using_yosys/synthesis/abc`.
|
||||
`abc` and `techmap` are used to map LUTs; converting primitive cell types to use
|
||||
`$lut` and ``SB_CARRY`` cells. Note that the iCE40 flow uses `abc9` rather than
|
||||
`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
|
||||
:language: yoscrypt
|
||||
|
|
@ -742,8 +739,8 @@ what the difference between these two commands are, refer to
|
|||
|
||||
``rdata`` output after :ref:`map_luts`
|
||||
|
||||
Finally we use :cmd:ref:`techmap` to map the generic ``$lut`` cells to iCE40
|
||||
``SB_LUT4`` cells.
|
||||
Finally we use `techmap` to map the generic `$lut` cells to iCE40 ``SB_LUT4``
|
||||
cells.
|
||||
|
||||
.. literalinclude:: /cmd/synth_ice40.rst
|
||||
:language: yoscrypt
|
||||
|
|
@ -769,12 +766,12 @@ Other cells
|
|||
|
||||
The following commands may also be used for mapping other cells:
|
||||
|
||||
:cmd:ref:`hilomap`
|
||||
`hilomap`
|
||||
Some architectures require special driver cells for driving a constant hi or
|
||||
lo value. This command replaces simple constants with instances of such
|
||||
driver cells.
|
||||
|
||||
:cmd:ref:`iopadmap`
|
||||
`iopadmap`
|
||||
Top-level input/outputs must usually be implemented using special I/O-pad
|
||||
cells. This command inserts such cells to the design.
|
||||
|
||||
|
|
@ -801,28 +798,27 @@ The new commands here are:
|
|||
- :doc:`/cmd/stat`, and
|
||||
- :doc:`/cmd/blackbox`.
|
||||
|
||||
The output from :cmd:ref:`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 of other resources used such as wires and processes. For this
|
||||
design, the final call to :cmd:ref:`stat` should look something like the
|
||||
following:
|
||||
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
|
||||
of other resources used such as wires and processes. For this design, the final
|
||||
call to `stat` should look something like the following:
|
||||
|
||||
.. literalinclude:: /code_examples/fifo/fifo.stat
|
||||
:language: doscon
|
||||
:start-at: yosys> stat -top fifo
|
||||
|
||||
Note that the :yoscrypt:`-top fifo` here is optional. :cmd:ref:`stat` will
|
||||
automatically use the module with the ``top`` attribute set, which ``fifo`` was
|
||||
when we called :cmd:ref:`hierarchy`. If no module is marked ``top``, then stats
|
||||
will be shown for each module selected.
|
||||
Note that the :yoscrypt:`-top fifo` here is optional. `stat` will automatically
|
||||
use the module with the ``top`` attribute set, which ``fifo`` was when we called
|
||||
`hierarchy`. If no module is marked ``top``, then stats will be shown for each
|
||||
module selected.
|
||||
|
||||
The :cmd:ref:`stat` output is also useful as a kind of sanity-check: Since we
|
||||
have already run :cmd:ref:`proc`, we wouldn't expect there to be any processes.
|
||||
We also expect ``data`` to use hard memory; if instead of an ``SB_RAM40_4K`` saw
|
||||
a high number of flip-flops being used we might suspect something was wrong.
|
||||
The `stat` output is also useful as a kind of sanity-check: Since we have
|
||||
already run `proc`, we wouldn't expect there to be any processes. We also expect
|
||||
``data`` to use hard memory; if instead of an ``SB_RAM40_4K`` saw a high number
|
||||
of flip-flops being used we might suspect something was wrong.
|
||||
|
||||
If we instead called :cmd:ref:`stat` immediately after :yoscrypt:`read_verilog
|
||||
fifo.v` we would see something very different:
|
||||
If we instead called `stat` immediately after :yoscrypt:`read_verilog fifo.v` we
|
||||
would see something very different:
|
||||
|
||||
.. literalinclude:: /code_examples/fifo/fifo.stat
|
||||
:language: doscon
|
||||
|
|
@ -845,10 +841,10 @@ The iCE40 synthesis flow has the following output modes available:
|
|||
|
||||
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
|
||||
then read the design back into Yosys with :cmd:ref:`read_json`, but make sure
|
||||
you use :yoscrypt:`design -reset` or open a new interactive terminal first. The
|
||||
JSON output we get can also be loaded into `nextpnr`_ to do place and route; but
|
||||
that is beyond the scope of this documentation.
|
||||
then read the design back into Yosys with `read_json`, but make sure you use
|
||||
:yoscrypt:`design -reset` or open a new interactive terminal first. The JSON
|
||||
output we get can also be loaded into `nextpnr`_ to do place and route; but that
|
||||
is beyond the scope of this documentation.
|
||||
|
||||
.. _nextpnr: https://github.com/YosysHQ/nextpnr
|
||||
|
||||
|
|
|
|||
|
|
@ -62,9 +62,25 @@ The `OSS CAD Suite`_ releases `nightly builds`_ for the following architectures:
|
|||
Building from source
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Refer to the `readme`_ for the most up-to-date install instructions.
|
||||
The Yosys source files can be obtained from the `YosysHQ/Yosys git repository`_.
|
||||
`ABC`_ and some of the other libraries used are included as git submodules. To
|
||||
clone these submodules at the same time, use e.g.:
|
||||
|
||||
.. _readme: https://github.com/YosysHQ/yosys#building-from-source
|
||||
.. code:: console
|
||||
|
||||
git clone --recurse-submodules https://github.com/YosysHQ/yosys.git # ..or..
|
||||
git clone https://github.com/YosysHQ/yosys.git
|
||||
cd yosys
|
||||
git submodule update --init --recursive
|
||||
|
||||
.. _YosysHQ/Yosys git repository: https://github.com/yosyshq/yosys/
|
||||
.. _ABC: https://github.com/berkeley-abc/abc
|
||||
|
||||
.. note::
|
||||
|
||||
As of Yosys v0.47, releases include a ``yosys.tar.gz`` file which includes
|
||||
all source code and all sub-modules in a single archive. This can be used as
|
||||
an alternative which does not rely on ``git``.
|
||||
|
||||
Supported platforms
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -88,53 +104,141 @@ A C++ compiler with C++17 support is required as well as some standard tools
|
|||
such as GNU Flex, GNU Bison, Make and Python. Some additional tools: readline,
|
||||
libffi, Tcl and zlib; are optional but enabled by default (see
|
||||
:makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the
|
||||
:cmd:ref:`show` command to display schematics.
|
||||
`show` command to display schematics.
|
||||
|
||||
Installing all prerequisites for Ubuntu 20.04:
|
||||
|
||||
.. code:: console
|
||||
|
||||
sudo sudo apt-get install build-essential clang lld bison flex \
|
||||
libreadline-dev gawk tcl-dev libffi-dev git make \
|
||||
graphviz xdot pkg-config python3 libboost-system-dev \
|
||||
sudo apt-get install gperf build-essential bison flex \
|
||||
libreadline-dev gawk tcl-dev libffi-dev git graphviz \
|
||||
xdot pkg-config python3 libboost-system-dev \
|
||||
libboost-python-dev libboost-filesystem-dev zlib1g-dev
|
||||
|
||||
Installing all prerequisites for macOS 11 (with Homebrew):
|
||||
Installing all prerequisites for macOS 13 (with Homebrew):
|
||||
|
||||
.. code:: console
|
||||
|
||||
brew install bison flex gawk libffi git graphviz \
|
||||
pkg-config python3 tcl-tk xdot bash boost-python3
|
||||
brew tap Homebrew/bundle && brew bundle
|
||||
|
||||
or MacPorts:
|
||||
|
||||
.. code:: console
|
||||
|
||||
sudo port install bison flex readline gawk libffi graphviz \
|
||||
pkgconfig python311 boost zlib tcl
|
||||
|
||||
On FreeBSD use the following command to install all prerequisites:
|
||||
|
||||
.. code:: console
|
||||
|
||||
pkg install bison flex readline gawk libffi graphviz \
|
||||
pkgconf python311 tcl-wrapper boost-libs
|
||||
|
||||
.. note:: On FreeBSD system use gmake instead of make. To run tests use:
|
||||
``MAKE=gmake CXX=cxx CC=cc gmake test``
|
||||
|
||||
For Cygwin use the following command to install all prerequisites, or select these additional packages:
|
||||
|
||||
.. code:: console
|
||||
|
||||
setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel
|
||||
|
||||
.. warning::
|
||||
|
||||
As of this writing, Cygwin only supports up to Python 3.9.16 while the
|
||||
minimum required version of Python is 3.11. This means that Cygwin is not
|
||||
compatible with many of the Python-based frontends. While this does not
|
||||
currently prevent Yosys itself from working, no guarantees are made for
|
||||
continued support. It is instead recommended to use Windows Subsystem for
|
||||
Linux (WSL) and follow the instructions for Ubuntu.
|
||||
|
||||
..
|
||||
For MSYS2 (MINGW64):
|
||||
|
||||
.. code:: console
|
||||
|
||||
pacman -S bison flex mingw-w64-x86_64-gcc git libffi-devel libreadline-devel make pkg-config python3 tcl-devel mingw-w64-x86_64-boost zlib-devel
|
||||
|
||||
Not that I can get this to work; it's failing during ld with what looks like
|
||||
math library issues: ``multiple definition of `tanh'`` and
|
||||
``undefined reference to `__imp_acosh'``, as well as issues in `aiger2` with
|
||||
``seekg`` et al not being available.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``config-msys2-64`` target uses the ``mingw-w64-x86_64-`` prefixed
|
||||
compiler in order to allow compiled exe files to be run without an MSYS2
|
||||
shell.
|
||||
|
||||
Build configuration
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The Yosys build is based solely on Makefiles, and uses a number of variables
|
||||
which influence the build process. The recommended method for configuring
|
||||
builds is with a ``Makefile.conf`` file in the root ``yosys`` directory. The
|
||||
following commands will clean the directory and provide an initial configuration
|
||||
file:
|
||||
|
||||
.. code:: console
|
||||
|
||||
make config-clang # ..or..
|
||||
make config-gcc
|
||||
|
||||
Check the root Makefile to see what other configuration targets are available.
|
||||
Other variables can then be added to the ``Makefile.conf`` as needed, for
|
||||
example:
|
||||
|
||||
.. code:: console
|
||||
|
||||
echo "ENABLE_ZLIB := 0" >> Makefile.conf
|
||||
|
||||
Using one of these targets will set the ``CONFIG`` variable to something other
|
||||
than ``none``, and will override the environment variable for ``CXX``. To use a
|
||||
different compiler than the default when building, use:
|
||||
|
||||
.. code:: console
|
||||
|
||||
make CXX=$CXX # ..or..
|
||||
make CXX="g++-11"
|
||||
|
||||
.. note::
|
||||
|
||||
Setting the compiler in this way will prevent some other options such as
|
||||
``ENABLE_CCACHE`` from working as expected.
|
||||
|
||||
If you have clang, and (a compatible version of) ``ld.lld`` available in PATH,
|
||||
it's recommended to speed up incremental builds with lld by enabling LTO with
|
||||
``ENABLE_LTO=1``. On macOS, LTO requires using clang from homebrew rather than
|
||||
clang from xcode. For example:
|
||||
|
||||
.. code:: console
|
||||
|
||||
make ENABLE_LTO=1 CXX=$(brew --prefix)/opt/llvm/bin/clang++
|
||||
|
||||
By default, building (and installing) yosys will build (and install) `ABC`_,
|
||||
using :program:`yosys-abc` as the executable name. To use an existing ABC
|
||||
executable instead, set the ``ABCEXTERNAL`` make variable to point to the
|
||||
desired executable.
|
||||
|
||||
Running the build system
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
From the root `yosys` directory, call the following commands:
|
||||
From the root ``yosys`` directory, call the following commands:
|
||||
|
||||
.. code:: console
|
||||
|
||||
make
|
||||
sudo make install
|
||||
|
||||
This will build and then install Yosys, making it available on the command line
|
||||
as `yosys`. Note that this also downloads, builds, and installs `ABC`_ (using
|
||||
:program:`yosys-abc` as the executable name).
|
||||
|
||||
.. _ABC: https://github.com/berkeley-abc/abc
|
||||
|
||||
The default compiler is ``clang``, to change between ``clang`` and ``gcc``, use
|
||||
one of the following:
|
||||
To use a separate (out-of-tree) build directory, provide a path to the Makefile.
|
||||
|
||||
.. code:: console
|
||||
|
||||
make config-clang
|
||||
make config-gcc
|
||||
mkdir build; cd build
|
||||
make -f ../Makefile
|
||||
|
||||
To use a compiler different than the default, use:
|
||||
|
||||
.. code:: console
|
||||
|
||||
make CXX="g++-11"
|
||||
Out-of-tree builds require a clean source tree.
|
||||
|
||||
.. seealso::
|
||||
|
||||
|
|
@ -161,10 +265,6 @@ directories:
|
|||
``frontends/``
|
||||
This directory contains a subdirectory for each of the frontend modules.
|
||||
|
||||
``guidelines/``
|
||||
Contains developer guidelines, including the code of conduct and coding style
|
||||
guide.
|
||||
|
||||
``kernel/``
|
||||
This directory contains all the core functionality of Yosys. This includes
|
||||
the functions and definitions for working with the RTLIL data structures
|
||||
|
|
@ -184,9 +284,8 @@ directories:
|
|||
|
||||
``passes/``
|
||||
This directory contains a subdirectory for each pass or group of passes. For
|
||||
example as of this writing the directory :file:`passes/hierarchy/` contains the
|
||||
code for three passes: :cmd:ref:`hierarchy`, :cmd:ref:`submod`, and
|
||||
:cmd:ref:`uniquify`.
|
||||
example as of this writing the directory :file:`passes/hierarchy/` contains
|
||||
the code for three passes: `hierarchy`, `submod`, and `uniquify`.
|
||||
|
||||
``techlibs/``
|
||||
This directory contains simulation models and standard implementations for
|
||||
|
|
@ -207,9 +306,6 @@ commands.
|
|||
Good starting points for reading example source code to learn how to write
|
||||
passes are :file:`passes/opt/opt_dff.cc` and :file:`passes/opt/opt_merge.cc`.
|
||||
|
||||
See the top-level README file for a quick Getting Started guide and build
|
||||
instructions. The Yosys build is based solely on Makefiles.
|
||||
|
||||
Users of the Qt Creator IDE can generate a QT Creator project file using make
|
||||
qtcreator. Users of the Eclipse IDE can use the "Makefile Project with Existing
|
||||
Code" project type in the Eclipse "New Project" dialog (only available after the
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ file format and how you can make your own synthesis scripts.
|
|||
|
||||
Yosys script files typically use the :file:`.ys` extension and contain a set of
|
||||
commands for Yosys to run sequentially. These commands are the same ones we
|
||||
were using on the previous page like :cmd:ref:`read_verilog` and
|
||||
:cmd:ref:`hierarchy`.
|
||||
were using on the previous page like `read_verilog` and `hierarchy`.
|
||||
|
||||
Script parsing
|
||||
~~~~~~~~~~~~~~
|
||||
|
|
@ -39,9 +38,9 @@ Another special character that can be used in Yosys scripts is the bang ``!``.
|
|||
Anything after the bang will be executed as a shell command. This can only be
|
||||
terminated with a new line. Any semicolons, hashes, or other special characters
|
||||
will be passed to the shell. If an error code is returned from the shell it
|
||||
will be raised by Yosys. :cmd:ref:`exec` provides a much more flexible way of
|
||||
executing commands, allowing the output to be logged and more control over when
|
||||
to generate errors.
|
||||
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.
|
||||
|
||||
The synthesis starter script
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -62,24 +61,23 @@ already, let's take a look at some of those script files now.
|
|||
:caption: A section of :file:`fifo.ys`, generating the images used for :ref:`addr_gen_example`
|
||||
:name: fifo-ys
|
||||
|
||||
The first command there, :yoscrypt:`echo on`, uses :cmd:ref:`echo` to enable
|
||||
command echoes on. This is how we generated the code listing for
|
||||
The first command there, :yoscrypt:`echo on`, uses `echo` to enable command
|
||||
echoes on. This is how we generated the code listing for
|
||||
:ref:`hierarchy_output`. Turning command echoes on prints the ``yosys>
|
||||
hierarchy -top addr_gen`` line, making the output look the same as if it were an
|
||||
interactive terminal. :yoscrypt:`hierarchy -top addr_gen` is of course the
|
||||
command we were demonstrating, including the output text and an image of the
|
||||
design schematic after running it.
|
||||
|
||||
We briefly touched on :cmd:ref:`select` when it came up in
|
||||
:cmd:ref:`synth_ice40`, but let's look at it more now.
|
||||
We briefly touched on `select` when it came up in `synth_ice40`, but let's look
|
||||
at it more now.
|
||||
|
||||
.. _select_intro:
|
||||
|
||||
Selections intro
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
The :cmd:ref:`select` command is used to modify and view the list of selected
|
||||
objects:
|
||||
The `select` command is used to modify and view the list of selected objects:
|
||||
|
||||
.. literalinclude:: /code_examples/fifo/fifo.out
|
||||
:language: doscon
|
||||
|
|
@ -99,7 +97,7 @@ signifies we are matching on the *cell type*, and the ``*`` means to match
|
|||
anything. For this (very simple) selection, we are trying to find all of the
|
||||
cells, regardless of their type. The active selection is now shown as
|
||||
``[addr_gen]*``, indicating some sub-selection of the ``addr_gen`` module. This
|
||||
gives us the ``$add`` and ``$eq`` cells, which we want to highlight for the
|
||||
gives us the `$add` and `$eq` cells, which we want to highlight for the
|
||||
:ref:`addr_gen_hier` image.
|
||||
|
||||
.. _select_new_cells:
|
||||
|
|
@ -111,15 +109,16 @@ by referring to it as ``@new_cells``, which we will see later. Then we clear
|
|||
the selection so that the following commands can operate on the full design.
|
||||
While we split that out for this document, we could have done the same thing in
|
||||
a single line by calling :yoscrypt:`select -set new_cells addr_gen/t:*`. If we
|
||||
know we only have the one module in our design, we can even skip the `addr_gen/`
|
||||
part. Looking further down :ref:`the fifo.ys code <fifo-ys>` we can see this
|
||||
with :yoscrypt:`select -set new_cells t:$mux t:*dff`. We can also see in that
|
||||
command that selections don't have to be limited to a single statement.
|
||||
know we only have the one module in our design, we can even skip the
|
||||
``addr_gen/`` part. Looking further down :ref:`the fifo.ys code <fifo-ys>` we
|
||||
can see this with :yoscrypt:`select -set new_cells t:$mux t:*dff`. We can also
|
||||
see in that command that selections don't have to be limited to a single
|
||||
statement.
|
||||
|
||||
Many commands also support an optional ``[selection]`` argument which can be
|
||||
used to override the currently selected objects. We could, for example, call
|
||||
:yoscrypt:`clean addr_gen` to have :cmd:ref:`clean` operate on *just* the
|
||||
``addr_gen`` module.
|
||||
:yoscrypt:`clean addr_gen` to have `clean` operate on *just* the ``addr_gen``
|
||||
module.
|
||||
|
||||
Detailed documentation of the select framework can be found under
|
||||
:doc:`/using_yosys/more_scripting/selections` or in the command reference at
|
||||
|
|
@ -130,23 +129,23 @@ Detailed documentation of the select framework can be found under
|
|||
Displaying schematics
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While the :cmd:ref:`select` command is very useful, sometimes nothing beats
|
||||
being able to see a design for yourself. This is where :cmd:ref:`show` comes
|
||||
in. Note that this document is just an introduction to the :cmd:ref:`show`
|
||||
command, only covering the basics. For more information, including a guide on
|
||||
what the different symbols represent, see :ref:`interactive_show` and the
|
||||
While the `select` command is very useful, sometimes nothing beats being able to
|
||||
see a design for yourself. This is where `show` comes in. Note that this
|
||||
document is just an introduction to the `show` command, only covering the
|
||||
basics. For more information, including a guide on what the different symbols
|
||||
represent, see :ref:`interactive_show` and the
|
||||
:doc:`/using_yosys/more_scripting/interactive_investigation` page.
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/addr_gen_show.*
|
||||
:class: width-helper invert-helper
|
||||
:name: addr_gen_show
|
||||
|
||||
Calling :yoscrypt:`show addr_gen` after :cmd:ref:`hierarchy`
|
||||
Calling :yoscrypt:`show addr_gen` after `hierarchy`
|
||||
|
||||
.. note::
|
||||
|
||||
The :cmd:ref:`show` command requires a working installation of `GraphViz`_
|
||||
and `xdot`_ for displaying the actual circuit diagrams.
|
||||
The `show` command requires a working installation of `GraphViz`_ and `xdot`_
|
||||
for displaying the actual circuit diagrams.
|
||||
|
||||
.. _GraphViz: http://www.graphviz.org/
|
||||
.. _xdot: https://github.com/jrfonseca/xdot.py
|
||||
|
|
@ -160,8 +159,8 @@ we see the following:
|
|||
:start-at: -prefix addr_gen_show
|
||||
:end-before: yosys> show
|
||||
|
||||
Calling :cmd:ref:`show` with :yoscrypt:`-format dot` tells it we want to output
|
||||
a :file:`.dot` file rather than opening it for display. The :yoscrypt:`-prefix
|
||||
Calling `show` with :yoscrypt:`-format dot` tells it we want to output a
|
||||
:file:`.dot` file rather than opening it for display. The :yoscrypt:`-prefix
|
||||
addr_gen_show` option indicates we want the file to be called
|
||||
:file:`addr_gen_show.{*}`. Remember, we do this in :file:`fifo.ys` because we
|
||||
need to store the image for displaying in the documentation you're reading. But
|
||||
|
|
@ -184,8 +183,8 @@ like when we called :yoscrypt:`select -module addr_gen` in :ref:`select_intro`.
|
|||
That last parameter doesn't have to be a module name, it can be any valid
|
||||
selection string. Remember when we :ref:`assigned a name to a
|
||||
selection<select_new_cells>` and called it ``new_cells``? We saw in the
|
||||
:yoscrypt:`select -list` output that it contained two cells, an ``$add`` and an
|
||||
``$eq``. We can call :cmd:ref:`show` on that selection just as easily:
|
||||
:yoscrypt:`select -list` output that it contained two cells, an `$add` and an
|
||||
`$eq`. We can call `show` on that selection just as easily:
|
||||
|
||||
.. figure:: /_images/code_examples/fifo/new_cells_show.*
|
||||
:class: width-helper invert-helper
|
||||
|
|
@ -207,21 +206,20 @@ the two ``PROC`` blocks. To achieve this highlight, we make use of the
|
|||
|
||||
Calling :yoscrypt:`show -color maroon3 @new_cells -color cornflowerblue p:* -notitle`
|
||||
|
||||
As described in the the :cmd:ref:`help` output for :cmd:ref:`show` (or by
|
||||
clicking on the :cmd:ref:`show` link), colors are specified as :yoscrypt:`-color
|
||||
<color> <object>`. Color names for the ``<color>`` portion can be found on the
|
||||
`GraphViz color docs`_. Unlike the final :cmd:ref:`show` parameter which can
|
||||
have be any selection string, the ``<object>`` part must be a single selection
|
||||
expression or named selection. That means while we can use ``@new_cells``, we
|
||||
couldn't use ``t:$eq t:$add``. In general, if a command lists ``[selection]``
|
||||
as its final parameter it can be any selection string. Any selections that are
|
||||
not the final parameter, such as those used in options, must be a single
|
||||
expression instead.
|
||||
As described in the the `help` output for `show` (or by clicking on the `show`
|
||||
link), colors are specified as :yoscrypt:`-color <color> <object>`. Color names
|
||||
for the ``<color>`` portion can be found on the `GraphViz color docs`_. Unlike
|
||||
the final `show` parameter which can have be any selection string, the
|
||||
``<object>`` part must be a single selection expression or named selection.
|
||||
That means while we can use ``@new_cells``, we couldn't use ``t:$eq t:$add``.
|
||||
In general, if a command lists ``[selection]`` as its final parameter it can be
|
||||
any selection string. Any selections that are not the final parameter, such as
|
||||
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 :cmd:ref:`show`, check the command reference
|
||||
at :doc:`/cmd/show`.
|
||||
For all of the options available to `show`, check the command reference at
|
||||
:doc:`/cmd/show`.
|
||||
|
||||
.. seealso:: :ref:`interactive_show` on the
|
||||
:doc:`/using_yosys/more_scripting/interactive_investigation` page.
|
||||
|
|
|
|||
|
|
@ -7,38 +7,37 @@ 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`.
|
||||
|
||||
.. note::
|
||||
|
||||
This documentation recently went through a major restructure. If you're
|
||||
looking for something from the previous version and can't find it here,
|
||||
please `let us know`_. Documentation from before the restructure can still
|
||||
be found by switching to `version 0.36`_ or earlier. Note that the previous
|
||||
theme does not include a version switcher.
|
||||
|
||||
.. _let us know: https://github.com/YosysHQ/yosys/issues/new/choose
|
||||
.. _version 0.36: https://yosyshq.readthedocs.io/projects/yosys/en/0.36/
|
||||
|
||||
.. todo:: look into command ref improvements
|
||||
|
||||
- Search bar with live drop down suggestions for matching on title /
|
||||
autocompleting commands
|
||||
- Scroll the left sidebar to the current location on page load
|
||||
- Also the formatting/linking in pdf is broken
|
||||
- Also the formatting in pdf uses link formatting instead of code formatting
|
||||
|
||||
.. todolist::
|
||||
|
||||
.. only:: html
|
||||
|
||||
Table of contents
|
||||
-----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:includehidden:
|
||||
|
||||
Yosys (index) <self>
|
||||
introduction
|
||||
|
||||
getting_started/index
|
||||
using_yosys/index
|
||||
yosys_internals/index
|
||||
|
||||
appendix
|
||||
.. toctree::
|
||||
:caption: Appendix
|
||||
:titlesonly:
|
||||
:includehidden:
|
||||
|
||||
appendix/primer
|
||||
appendix/rtlil_text
|
||||
appendix/auxlibs
|
||||
appendix/auxprogs
|
||||
|
||||
bib
|
||||
|
||||
cell_index
|
||||
cmd_ref
|
||||
|
|
|
|||
|
|
@ -69,9 +69,14 @@ Things you can't do
|
|||
|
||||
- Check out `nextpnr`_ for that
|
||||
|
||||
- Rely on built-in syntax checking
|
||||
|
||||
- Use an external tool like `verilator`_ instead
|
||||
|
||||
.. todo:: nextpnr for FPGAs, consider mentioning openlane, vpr, coriolis
|
||||
|
||||
.. _nextpnr: https://github.com/YosysHQ/nextpnr
|
||||
.. _verilator: https://www.veripool.org/verilator/
|
||||
|
||||
The Yosys family
|
||||
----------------
|
||||
|
|
@ -161,9 +166,9 @@ Benefits of open source HDL synthesis
|
|||
|
||||
- Cost (also applies to ``free as in free beer`` solutions):
|
||||
|
||||
Today the cost for a mask set in 180nm technology is far less than
|
||||
the cost for the design tools needed to design the mask layouts. Open Source
|
||||
ASIC flows are an important enabler for ASIC-level Open Source Hardware.
|
||||
Today the cost for a mask set in 180nm technology is far less than the cost
|
||||
for the design tools needed to design the mask layouts. Open Source ASIC flows
|
||||
are an important enabler for ASIC-level Open Source Hardware.
|
||||
|
||||
- Availability and Reproducibility:
|
||||
|
||||
|
|
@ -171,21 +176,23 @@ Benefits of open source HDL synthesis
|
|||
else can also use. Even if most universities have access to all major
|
||||
commercial tools, you usually do not have easy access to the version that was
|
||||
used in a research project a couple of years ago. With Open Source tools you
|
||||
can even release the source code of the tool you have used alongside your data.
|
||||
can even release the source code of the tool you have used alongside your
|
||||
data.
|
||||
|
||||
- Framework:
|
||||
|
||||
Yosys is not only a tool. It is a framework that can be used as basis for other
|
||||
developments, so researchers and hackers alike do not need to re-invent the
|
||||
basic functionality. Extensibility was one of Yosys' design goals.
|
||||
Yosys is not only a tool. It is a framework that can be used as basis for
|
||||
other developments, so researchers and hackers alike do not need to re-invent
|
||||
the basic functionality. Extensibility was one of Yosys' design goals.
|
||||
|
||||
- All-in-one:
|
||||
|
||||
Because of the framework characteristics of Yosys, an increasing number of features
|
||||
become available in one tool. Yosys not only can be used for circuit synthesis but
|
||||
also for formal equivalence checking, SAT solving, and for circuit analysis, to
|
||||
name just a few other application domains. With proprietary software one needs to
|
||||
learn a new tool for each of these applications.
|
||||
Because of the framework characteristics of Yosys, an increasing number of
|
||||
features become available in one tool. Yosys not only can be used for circuit
|
||||
synthesis but also for formal equivalence checking, SAT solving, and for
|
||||
circuit analysis, to name just a few other application domains. With
|
||||
proprietary software one needs to learn a new tool for each of these
|
||||
applications.
|
||||
|
||||
- Educational Tool:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
furo
|
||||
furo-ys @ git+https://github.com/YosysHQ/furo-ys
|
||||
sphinxcontrib-bibtex
|
||||
rtds-action
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ A look at the show command
|
|||
|
||||
.. TODO:: merge into :doc:`/getting_started/scripting_intro` show section
|
||||
|
||||
This section explores the :cmd:ref:`show` command and explains the symbols used
|
||||
in the circuit diagrams generated by it. The code used is included in the Yosys
|
||||
code base under |code_examples/show|_.
|
||||
This section explores the `show` command and explains the symbols used in the
|
||||
circuit diagrams generated by it. The code used is included in the Yosys code
|
||||
base under |code_examples/show|_.
|
||||
|
||||
.. |code_examples/show| replace:: :file:`docs/source/code_examples/show`
|
||||
.. _code_examples/show: https://github.com/YosysHQ/yosys/tree/main/docs/source/code_examples/show
|
||||
|
|
@ -24,7 +24,7 @@ A simple circuit
|
|||
^^^^^^^^^^^^^^^^
|
||||
|
||||
:ref:`example_v` below provides the Verilog code for a simple circuit which we
|
||||
will use to demonstrate the usage of :cmd:ref:`show` in a simple setting.
|
||||
will use to demonstrate the usage of `show` in a simple setting.
|
||||
|
||||
.. literalinclude:: /code_examples/show/example.v
|
||||
:language: Verilog
|
||||
|
|
@ -32,11 +32,10 @@ will use to demonstrate the usage of :cmd:ref:`show` in a simple setting.
|
|||
:name: example_v
|
||||
|
||||
The Yosys synthesis script we will be running is included as
|
||||
:numref:`example_ys`. Note that :cmd:ref:`show` is called with the ``-pause``
|
||||
option, that halts execution of the Yosys script until the user presses the
|
||||
Enter key. Using :yoscrypt:`show -pause` also allows the user to enter an
|
||||
interactive shell to further investigate the circuit before continuing
|
||||
synthesis.
|
||||
:numref:`example_ys`. Note that `show` is called with the ``-pause`` option,
|
||||
that halts execution of the Yosys script until the user presses the Enter key.
|
||||
Using :yoscrypt:`show -pause` also allows the user to enter an interactive shell
|
||||
to further investigate the circuit before continuing synthesis.
|
||||
|
||||
.. literalinclude:: /code_examples/show/example_show.ys
|
||||
:language: yoscrypt
|
||||
|
|
@ -58,7 +57,7 @@ is shown.
|
|||
.. figure:: /_images/code_examples/show/example_first.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
Output of the first :cmd:ref:`show` command in :numref:`example_ys`
|
||||
Output of the first `show` command in :numref:`example_ys`
|
||||
|
||||
The first output shows the design directly after being read by the Verilog
|
||||
front-end. Input and output ports are displayed as octagonal shapes. Cells are
|
||||
|
|
@ -66,7 +65,7 @@ displayed as rectangles with inputs on the left and outputs on the right side.
|
|||
The cell labels are two lines long: The first line contains a unique identifier
|
||||
for the cell and the second line contains the cell type. Internal cell types are
|
||||
prefixed with a dollar sign. For more details on the internal cell library, see
|
||||
:doc:`/yosys_internals/formats/cell_library`.
|
||||
:doc:`/cell_index`.
|
||||
|
||||
Constants are shown as ellipses with the constant value as label. The syntax
|
||||
``<bit_width>'<bits>`` is used for constants that are not 32-bit wide and/or
|
||||
|
|
@ -81,43 +80,43 @@ internal representation of the decision-trees and synchronization events
|
|||
modelled in a Verilog ``always``-block. The label reads ``PROC`` followed by a
|
||||
unique identifier in the first line and contains the source code location of the
|
||||
original ``always``-block in the second line. Note how the multiplexer from the
|
||||
``?:``-expression is represented as a ``$mux`` cell but the multiplexer from the
|
||||
``?:``-expression is represented as a `$mux` cell but the multiplexer from the
|
||||
``if``-statement is yet still hidden within the process.
|
||||
|
||||
The :cmd:ref:`proc` command transforms the process from the first diagram into a
|
||||
The `proc` command transforms the process from the first diagram into a
|
||||
multiplexer and a d-type flip-flop, which brings us to the second diagram:
|
||||
|
||||
.. figure:: /_images/code_examples/show/example_second.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
Output of the second :cmd:ref:`show` command in :numref:`example_ys`
|
||||
Output of the second `show` command in :numref:`example_ys`
|
||||
|
||||
The Rhombus shape to the right is a dangling wire. (Wire nodes are only shown if
|
||||
they are dangling or have "public" names, for example names assigned from the
|
||||
Verilog input.) Also note that the design now contains two instances of a
|
||||
``BUF``-node. These are artefacts left behind by the :cmd:ref:`proc` command. It
|
||||
is quite usual to see such artefacts after calling commands that perform changes
|
||||
in the design, as most commands only care about doing the transformation in the
|
||||
least complicated way, not about cleaning up after them. The next call to
|
||||
:cmd:ref:`clean` (or :cmd:ref:`opt`, which includes :cmd:ref:`clean` as one of
|
||||
its operations) will clean up these artefacts. This operation is so common in
|
||||
Yosys scripts that it can simply be abbreviated with the ``;;`` token, which
|
||||
doubles as separator for commands. Unless one wants to specifically analyze this
|
||||
artefacts left behind some operations, it is therefore recommended to always
|
||||
call :cmd:ref:`clean` before calling :cmd:ref:`show`.
|
||||
``BUF``-node. These are artefacts left behind by the `proc` command. It is quite
|
||||
usual to see such artefacts after calling commands that perform changes in the
|
||||
design, as most commands only care about doing the transformation in the least
|
||||
complicated way, not about cleaning up after them. The next call to `clean` (or
|
||||
`opt`, which includes `clean` as one of its operations) will clean up these
|
||||
artefacts. This operation is so common in Yosys scripts that it can simply be
|
||||
abbreviated with the ``;;`` token, which doubles as separator for commands.
|
||||
Unless one wants to specifically analyze this artefacts left behind some
|
||||
operations, it is therefore recommended to always call `clean` before calling
|
||||
`show`.
|
||||
|
||||
In this script we directly call :cmd:ref:`opt` as the next step, which finally
|
||||
leads us to the third diagram:
|
||||
In this script we directly call `opt` as the next step, which finally leads us
|
||||
to the third diagram:
|
||||
|
||||
.. figure:: /_images/code_examples/show/example_third.*
|
||||
:class: width-helper invert-helper
|
||||
:name: example_out
|
||||
|
||||
Output of the third :cmd:ref:`show` command in :ref:`example_ys`
|
||||
Output of the third `show` command in :ref:`example_ys`
|
||||
|
||||
Here we see that the :cmd:ref:`opt` command not only has removed the artifacts
|
||||
left behind by :cmd:ref:`proc`, but also determined correctly that it can remove
|
||||
the first ``$mux`` cell without changing the behavior of the circuit.
|
||||
Here we see that the `opt` command not only has removed the artifacts left
|
||||
behind by `proc`, but also determined correctly that it can remove the first
|
||||
`$mux` cell without changing the behavior of the circuit.
|
||||
|
||||
Break-out boxes for signal vectors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -129,7 +128,7 @@ accesses.
|
|||
:caption: :file:`splice.v`
|
||||
:name: splice_src
|
||||
|
||||
Notice how the output for this circuit from the :cmd:ref:`show` command
|
||||
Notice how the output for this circuit from the `show` command
|
||||
(:numref:`splice_dia`) appears quite complex. This is an unfortunate side effect
|
||||
of the way Yosys handles signal vectors (aka. multi-bit wires or buses) as
|
||||
native objects. While this provides great advantages when analyzing circuits
|
||||
|
|
@ -169,7 +168,7 @@ mapped to a cell library:
|
|||
:name: first_pitfall
|
||||
|
||||
A half-adder built from simple CMOS gates, demonstrating common pitfalls when
|
||||
using :cmd:ref:`show`
|
||||
using `show`
|
||||
|
||||
.. literalinclude:: /code_examples/show/cmos.ys
|
||||
:language: yoscrypt
|
||||
|
|
@ -188,8 +187,8 @@ individual bits, resulting in an unnecessary complex diagram.
|
|||
:class: width-helper invert-helper
|
||||
:name: second_pitfall
|
||||
|
||||
Effects of :cmd:ref:`splitnets` command and of providing a cell library on
|
||||
design in :numref:`first_pitfall`
|
||||
Effects of `splitnets` command and of providing a cell library on design in
|
||||
:numref:`first_pitfall`
|
||||
|
||||
.. literalinclude:: /code_examples/show/cmos.ys
|
||||
:language: yoscrypt
|
||||
|
|
@ -201,11 +200,11 @@ individual bits, resulting in an unnecessary complex diagram.
|
|||
For :numref:`second_pitfall`, Yosys has been given a description of the cell
|
||||
library as Verilog file containing blackbox modules. There are two ways to load
|
||||
cell descriptions into Yosys: First the Verilog file for the cell library can be
|
||||
passed directly to the :cmd:ref:`show` command using the ``-lib <filename>``
|
||||
option. Secondly it is possible to load cell libraries into the design with the
|
||||
passed directly to the `show` command using the ``-lib <filename>`` option.
|
||||
Secondly it is possible to load cell libraries into the design with the
|
||||
:yoscrypt:`read_verilog -lib <filename>` command. The second method has the
|
||||
great advantage that the library only needs to be loaded once and can then be
|
||||
used in all subsequent calls to the :cmd:ref:`show` command.
|
||||
used in all subsequent calls to the `show` command.
|
||||
|
||||
In addition to that, :numref:`second_pitfall` was generated after
|
||||
:yoscrypt:`splitnet -ports` was run on the design. This command splits all
|
||||
|
|
@ -216,22 +215,22 @@ module ports. Per default the command only operates on interior signals.
|
|||
Miscellaneous notes
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Per default the :cmd:ref:`show` command outputs a temporary dot file and
|
||||
launches ``xdot`` to display it. The options ``-format``, ``-viewer`` and
|
||||
``-prefix`` can be used to change format, viewer and filename prefix. Note that
|
||||
the ``pdf`` and ``ps`` format are the only formats that support plotting
|
||||
multiple modules in one run. The ``dot`` format can be used to output multiple
|
||||
modules, however ``xdot`` will raise an error when trying to read them.
|
||||
Per default the `show` command outputs a temporary dot file and launches
|
||||
``xdot`` to display it. The options ``-format``, ``-viewer`` and ``-prefix`` can
|
||||
be used to change format, viewer and filename prefix. Note that the ``pdf`` and
|
||||
``ps`` format are the only formats that support plotting multiple modules in one
|
||||
run. The ``dot`` format can be used to output multiple modules, however
|
||||
``xdot`` will raise an error when trying to read them.
|
||||
|
||||
In densely connected circuits it is sometimes hard to keep track of the
|
||||
individual signal wires. For these cases it can be useful to call
|
||||
:cmd:ref:`show` with the ``-colors <integer>`` argument, which randomly assigns
|
||||
colors to the nets. The integer (> 0) is used as seed value for the random color
|
||||
assignments. Sometimes it is necessary it try some values to find an assignment
|
||||
of colors that looks good.
|
||||
individual signal wires. For these cases it can be useful to call `show` with
|
||||
the ``-colors <integer>`` argument, which randomly assigns colors to the nets.
|
||||
The integer (> 0) is used as seed value for the random color assignments.
|
||||
Sometimes it is necessary it try some values to find an assignment of colors
|
||||
that looks good.
|
||||
|
||||
The command :yoscrypt:`help show` prints a complete listing of all options
|
||||
supported by the :cmd:ref:`show` command.
|
||||
supported by the `show` command.
|
||||
|
||||
Navigating the design
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -244,10 +243,10 @@ relevant portions of the circuit.
|
|||
In addition to *what* to display one also needs to carefully decide *when* to
|
||||
display it, with respect to the synthesis flow. In general it is a good idea to
|
||||
troubleshoot a circuit in the earliest state in which a problem can be
|
||||
reproduced. So if, for example, the internal state before calling the
|
||||
:cmd:ref:`techmap` command already fails to verify, it is better to troubleshoot
|
||||
the coarse-grain version of the circuit before :cmd:ref:`techmap` than the
|
||||
gate-level circuit after :cmd:ref:`techmap`.
|
||||
reproduced. So if, for example, the internal state before calling the `techmap`
|
||||
command already fails to verify, it is better to troubleshoot the coarse-grain
|
||||
version of the circuit before `techmap` than the gate-level circuit after
|
||||
`techmap`.
|
||||
|
||||
.. Note::
|
||||
|
||||
|
|
@ -260,31 +259,29 @@ Interactive navigation
|
|||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once the right state within the synthesis flow for debugging the circuit has
|
||||
been identified, it is recommended to simply add the :cmd:ref:`shell` command to
|
||||
the matching place in the synthesis script. This command will stop the synthesis
|
||||
at the specified moment and go to shell mode, where the user can interactively
|
||||
been identified, it is recommended to simply add the `shell` command to the
|
||||
matching place in the synthesis script. This command will stop the synthesis at
|
||||
the specified moment and go to shell mode, where the user can interactively
|
||||
enter commands.
|
||||
|
||||
For most cases, the shell will start with the whole design selected (i.e. when
|
||||
the synthesis script does not already narrow the selection). The command
|
||||
:cmd:ref:`ls` can now be used to create a list of all modules. The command
|
||||
:cmd:ref:`cd` can be used to switch to one of the modules (type ``cd ..`` to
|
||||
switch back). Now the :cmd:ref:`ls` command lists the objects within that
|
||||
module. This is demonstrated below using :file:`example.v` from `A simple
|
||||
circuit`_:
|
||||
the synthesis script does not already narrow the selection). The command `ls`
|
||||
can now be used to create a list of all modules. The command `cd` can be used to
|
||||
switch to one of the modules (type ``cd ..`` to switch back). Now the `ls`
|
||||
command lists the objects within that module. This is demonstrated below using
|
||||
:file:`example.v` from `A simple circuit`_:
|
||||
|
||||
.. literalinclude:: /code_examples/show/example.out
|
||||
:language: doscon
|
||||
:start-at: yosys> ls
|
||||
:end-before: yosys [example]> dump
|
||||
:caption: Output of :cmd:ref:`ls` and :cmd:ref:`cd` after running :file:`yosys example.v`
|
||||
:caption: Output of `ls` and `cd` after running :file:`yosys example.v`
|
||||
:name: lscd
|
||||
|
||||
When a module is selected using the :cmd:ref:`cd` command, all commands (with a
|
||||
few exceptions, such as the ``read_`` and ``write_`` commands) operate only on
|
||||
the selected module. This can also be useful for synthesis scripts where
|
||||
different synthesis strategies should be applied to different modules in the
|
||||
design.
|
||||
When a module is selected using the `cd` command, all commands (with a few
|
||||
exceptions, such as the ``read_`` and ``write_`` commands) operate only on the
|
||||
selected module. This can also be useful for synthesis scripts where different
|
||||
synthesis strategies should be applied to different modules in the design.
|
||||
|
||||
We can see that the cell names from :numref:`example_out` are just abbreviations
|
||||
of the actual cell names, namely the part after the last dollar-sign. Most
|
||||
|
|
@ -292,15 +289,14 @@ auto-generated names (the ones starting with a dollar sign) are rather long and
|
|||
contains some additional information on the origin of the named object. But in
|
||||
most cases those names can simply be abbreviated using the last part.
|
||||
|
||||
Usually all interactive work is done with one module selected using the
|
||||
:cmd:ref:`cd` command. But it is also possible to work from the design-context
|
||||
(``cd ..``). In this case all object names must be prefixed with
|
||||
``<module_name>/``. For example ``a*/b*`` would refer to all objects whose names
|
||||
start with ``b`` from all modules whose names start with ``a``.
|
||||
Usually all interactive work is done with one module selected using the `cd`
|
||||
command. But it is also possible to work from the design-context (``cd ..``). In
|
||||
this case all object names must be prefixed with ``<module_name>/``. For example
|
||||
``a*/b*`` would refer to all objects whose names start with ``b`` from all
|
||||
modules whose names start with ``a``.
|
||||
|
||||
The :cmd:ref:`dump` command can be used to print all information about an
|
||||
object. For example, calling :yoscrypt:`dump $2` after the :yoscrypt:`cd
|
||||
example` above:
|
||||
The `dump` command can be used to print all information about an object. For
|
||||
example, calling :yoscrypt:`dump $2` after the :yoscrypt:`cd example` above:
|
||||
|
||||
.. literalinclude:: /code_examples/show/example.out
|
||||
:language: RTLIL
|
||||
|
|
@ -323,11 +319,10 @@ tools).
|
|||
|
||||
- The selection mechanism, especially patterns such as ``%ci`` and ``%co``, can
|
||||
be used to figure out how parts of the design are connected.
|
||||
- Commands such as :cmd:ref:`submod`, :cmd:ref:`expose`, and :cmd:ref:`splice`
|
||||
can be used to transform the design into an equivalent design that is easier
|
||||
to analyse.
|
||||
- Commands such as :cmd:ref:`eval` and :cmd:ref:`sat` can be used to investigate
|
||||
the behavior of the circuit.
|
||||
- Commands such as `submod`, `expose`, and `splice` can be used to transform the
|
||||
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
|
||||
|
|
@ -342,10 +337,10 @@ The code used is included in the Yosys code base under
|
|||
Changing design hierarchy
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Commands such as :cmd:ref:`flatten` and :cmd:ref:`submod` can be used to change
|
||||
the design hierarchy, i.e. flatten the hierarchy or moving parts of a module to
|
||||
a submodule. This has applications in synthesis scripts as well as in reverse
|
||||
engineering and analysis. An example using :cmd:ref:`submod` is shown below for
|
||||
Commands such as `flatten` and `submod` can be used to change the design
|
||||
hierarchy, i.e. flatten the hierarchy or moving parts of a module to a
|
||||
submodule. This has applications in synthesis scripts as well as in reverse
|
||||
engineering and analysis. An example using `submod` is shown below for
|
||||
reorganizing a module in Yosys and checking the resulting circuit.
|
||||
|
||||
.. literalinclude:: /code_examples/scrambler/scrambler.v
|
||||
|
|
@ -388,10 +383,10 @@ Analyzing the resulting circuit with :doc:`/cmd/eval`:
|
|||
Behavioral changes
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Commands such as :cmd:ref:`techmap` can be used to make behavioral changes to
|
||||
the design, for example changing asynchronous resets to synchronous resets. This
|
||||
has applications in design space exploration (evaluation of various
|
||||
architectures for one circuit).
|
||||
Commands such as `techmap` can be used to make behavioral changes to the design,
|
||||
for example changing asynchronous resets to synchronous resets. This has
|
||||
applications in design space exploration (evaluation of various architectures
|
||||
for one circuit).
|
||||
|
||||
The following techmap map file replaces all positive-edge async reset flip-flops
|
||||
with positive-edge sync reset flip-flops. The code is taken from the example
|
||||
|
|
@ -425,7 +420,7 @@ Yosys script for ASIC synthesis of the Amber ARMv2 CPU.
|
|||
|
||||
endmodule
|
||||
|
||||
For more on the :cmd:ref:`techmap` command, see the page on
|
||||
For more on the `techmap` command, see the page on
|
||||
:doc:`/yosys_internals/techmap`.
|
||||
|
||||
Advanced investigation techniques
|
||||
|
|
@ -448,12 +443,12 @@ Recall the ``memdemo`` design from :ref:`advanced_logic_cones`:
|
|||
|
||||
Because this produces a rather large circuit, it can be useful to split it into
|
||||
smaller parts for viewing and working with. :numref:`submod` does exactly that,
|
||||
utilising the :cmd:ref:`submod` command to split the circuit into three
|
||||
sections: ``outstage``, ``selstage``, and ``scramble``.
|
||||
utilising the `submod` command to split the circuit into three sections:
|
||||
``outstage``, ``selstage``, and ``scramble``.
|
||||
|
||||
.. literalinclude:: /code_examples/selections/submod.ys
|
||||
:language: yoscrypt
|
||||
:caption: Using :cmd:ref:`submod` to break up the circuit from :file:`memdemo.v`
|
||||
:caption: Using `submod` to break up the circuit from :file:`memdemo.v`
|
||||
:start-after: cd memdemo
|
||||
:end-before: cd ..
|
||||
:name: submod
|
||||
|
|
@ -481,9 +476,9 @@ below.
|
|||
Evaluation of combinatorial circuits
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :cmd:ref:`eval` command can be used to evaluate combinatorial circuits. As
|
||||
an example, we will use the ``selstage`` subnet of ``memdemo`` which we found
|
||||
above and is shown in :numref:`selstage`.
|
||||
The `eval` command can be used to evaluate combinatorial circuits. As an
|
||||
example, we will use the ``selstage`` subnet of ``memdemo`` which we found above
|
||||
and is shown in :numref:`selstage`.
|
||||
|
||||
.. todo:: replace inline code
|
||||
|
||||
|
|
@ -526,21 +521,21 @@ The ``-table`` option can be used to create a truth table. For example:
|
|||
|
||||
Assumed undef (x) value for the following signals: \s2
|
||||
|
||||
Note that the :cmd:ref:`eval` command (as well as the :cmd:ref:`sat` command
|
||||
discussed in the next sections) does only operate on flattened modules. It can
|
||||
not analyze signals that are passed through design hierarchy levels. So the
|
||||
:cmd:ref:`flatten` command must be used on modules that instantiate other
|
||||
modules before these commands can be applied.
|
||||
Note that the `eval` command (as well as the `sat` command discussed in the next
|
||||
sections) does only operate on flattened modules. It can not analyze signals
|
||||
that are passed through design hierarchy levels. So the `flatten` command must
|
||||
be used on modules that instantiate other modules before these commands can be
|
||||
applied.
|
||||
|
||||
Solving combinatorial SAT problems
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Often the opposite of the :cmd:ref:`eval` command is needed, i.e. the circuits
|
||||
output is given and we want to find the matching input signals. For small
|
||||
circuits with only a few input bits this can be accomplished by trying all
|
||||
possible input combinations, as it is done by the ``eval -table`` command. For
|
||||
larger circuits however, Yosys provides the :cmd:ref:`sat` command that uses a
|
||||
`SAT`_ solver, `MiniSAT`_, to solve this kind of problems.
|
||||
Often the opposite of the `eval` command is needed, i.e. the circuits output is
|
||||
given and we want to find the matching input signals. For small circuits with
|
||||
only a few input bits this can be accomplished by trying all possible input
|
||||
combinations, as it is done by the ``eval -table`` command. For larger circuits
|
||||
however, Yosys provides the `sat` command that uses a `SAT`_ solver, `MiniSAT`_,
|
||||
to solve this kind of problems.
|
||||
|
||||
.. _SAT: http://en.wikipedia.org/wiki/Circuit_satisfiability
|
||||
|
||||
|
|
@ -551,9 +546,9 @@ larger circuits however, Yosys provides the :cmd:ref:`sat` command that uses a
|
|||
While it is possible to perform model checking directly in Yosys, it
|
||||
is highly recommended to use SBY or EQY for formal hardware verification.
|
||||
|
||||
The :cmd:ref:`sat` command works very similar to the :cmd:ref:`eval` command.
|
||||
The main difference is that it is now also possible to set output values and
|
||||
find the corresponding input values. For Example:
|
||||
The `sat` command works very similar to the `eval` command. The main difference
|
||||
is that it is now also possible to set output values and find the corresponding
|
||||
input values. For Example:
|
||||
|
||||
.. todo:: replace inline code
|
||||
|
||||
|
|
@ -580,8 +575,8 @@ find the corresponding input values. For Example:
|
|||
\s1 0 0 00
|
||||
\s2 0 0 00
|
||||
|
||||
Note that the :cmd:ref:`sat` command supports signal names in both arguments to
|
||||
the ``-set`` option. In the above example we used ``-set s1 s2`` to constraint
|
||||
Note that the `sat` command supports signal names in both arguments to the
|
||||
``-set`` option. In the above example we used ``-set s1 s2`` to constraint
|
||||
``s1`` and ``s2`` to be equal. When more complex constraints are needed, a
|
||||
wrapper circuit must be constructed that checks the constraints and signals if
|
||||
the constraint was met using an extra output port, which then can be forced to a
|
||||
|
|
@ -642,8 +637,8 @@ of course be to perform the test in 32 bits, for example by replacing ``p !=
|
|||
a*b`` in the miter with ``p != {16'd0,a}b``, or by using a temporary variable
|
||||
for the 32 bit product ``a*b``. But as 31 fits well into 8 bits (and as the
|
||||
purpose of this document is to show off Yosys features) we can also simply force
|
||||
the upper 8 bits of ``a`` and ``b`` to zero for the :cmd:ref:`sat` call, as is
|
||||
done below.
|
||||
the upper 8 bits of ``a`` and ``b`` to zero for the `sat` call, as is done
|
||||
below.
|
||||
|
||||
.. todo:: replace inline code
|
||||
|
||||
|
|
@ -705,18 +700,18 @@ command:
|
|||
sat -seq 6 -show y -show d -set-init-undef \
|
||||
-max_undef -set-at 4 y 1 -set-at 5 y 2 -set-at 6 y 3
|
||||
|
||||
The ``-seq 6`` option instructs the :cmd:ref:`sat` command to solve a sequential
|
||||
problem in 6 time steps. (Experiments with lower number of steps have show that
|
||||
at least 3 cycles are necessary to bring the circuit in a state from which the
|
||||
sequence 1, 2, 3 can be produced.)
|
||||
The ``-seq 6`` option instructs the `sat` command to solve a sequential problem
|
||||
in 6 time steps. (Experiments with lower number of steps have show that at least
|
||||
3 cycles are necessary to bring the circuit in a state from which the sequence
|
||||
1, 2, 3 can be produced.)
|
||||
|
||||
The ``-set-init-undef`` option tells the :cmd:ref:`sat` command to initialize
|
||||
all registers to the undef (``x``) state. The way the ``x`` state is treated in
|
||||
The ``-set-init-undef`` option tells the `sat` command to initialize all
|
||||
registers to the undef (``x``) state. The way the ``x`` state is treated in
|
||||
Verilog will ensure that the solution will work for any initial state.
|
||||
|
||||
The ``-max_undef`` option instructs the :cmd:ref:`sat` command to find a
|
||||
solution with a maximum number of undefs. This way we can see clearly which
|
||||
inputs bits are relevant to the solution.
|
||||
The ``-max_undef`` option instructs the `sat` command to find a solution with a
|
||||
maximum number of undefs. This way we can see clearly which inputs bits are
|
||||
relevant to the solution.
|
||||
|
||||
Finally the three ``-set-at`` options add constraints for the ``y`` signal to
|
||||
play the 1, 2, 3 sequence, starting with time step 4.
|
||||
|
|
@ -807,7 +802,7 @@ is the only way of setting the ``s1`` and ``s2`` registers to a known value. The
|
|||
input values for the other steps are a bit harder to work out manually, but the
|
||||
SAT solver finds the correct solution in an instant.
|
||||
|
||||
There is much more to write about the :cmd:ref:`sat` command. For example, there
|
||||
is a set of options that can be used to performs sequential proofs using
|
||||
temporal induction :cite:p:`een2003temporal`. The command ``help sat`` can be
|
||||
used to print a list of all options with short descriptions of their functions.
|
||||
There is much more to write about the `sat` command. For example, there is a set
|
||||
of options that can be used to performs sequential proofs using temporal
|
||||
induction :cite:p:`een2003temporal`. The command ``help sat`` can be used to
|
||||
print a list of all options with short descriptions of their functions.
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ passes in Yosys.
|
|||
|
||||
Other applications include checking if a module conforms to interface standards.
|
||||
|
||||
The :cmd:ref:`sat` command in Yosys can be used to perform Symbolic Model
|
||||
Checking.
|
||||
The `sat` command in Yosys can be used to perform Symbolic Model Checking.
|
||||
|
||||
Checking techmap
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -9,33 +9,33 @@ The selection framework
|
|||
|
||||
.. todo:: reduce overlap with :doc:`/getting_started/scripting_intro` select section
|
||||
|
||||
The :cmd:ref:`select` command can be used to create a selection for subsequent
|
||||
commands. For example:
|
||||
The `select` command can be used to create a selection for subsequent commands.
|
||||
For example:
|
||||
|
||||
.. code:: yoscrypt
|
||||
|
||||
select foobar # select the module foobar
|
||||
delete # delete selected objects
|
||||
|
||||
Normally the :cmd:ref:`select` command overwrites a previous selection. The
|
||||
commands :yoscrypt:`select -add` and :yoscrypt:`select -del` can be used to add
|
||||
or remove objects from the current selection.
|
||||
Normally the `select` command overwrites a previous selection. The commands
|
||||
:yoscrypt:`select -add` and :yoscrypt:`select -del` can be used to add or remove
|
||||
objects from the current selection.
|
||||
|
||||
The command :yoscrypt:`select -clear` can be used to reset the selection to the
|
||||
default, which is a complete selection of everything in the current module.
|
||||
|
||||
This selection framework can also be used directly in many other commands.
|
||||
Whenever a command has ``[selection]`` as last argument in its usage help, this
|
||||
means that it will use the engine behind the :cmd:ref:`select` command to
|
||||
evaluate additional arguments and use the resulting selection instead of the
|
||||
selection created by the last :cmd:ref:`select` command.
|
||||
means that it will use the engine behind the `select` command to evaluate
|
||||
additional arguments and use the resulting selection instead of the selection
|
||||
created by the last `select` command.
|
||||
|
||||
For example, the command :cmd:ref:`delete` will delete everything in the current
|
||||
For example, the command `delete` will delete everything in the current
|
||||
selection; while :yoscrypt:`delete foobar` will only delete the module foobar.
|
||||
If no :cmd:ref:`select` command has been made, then the "current selection" will
|
||||
be the whole design.
|
||||
If no `select` command has been made, then the "current selection" will be the
|
||||
whole design.
|
||||
|
||||
.. note:: Many of the examples on this page make use of the :cmd:ref:`show`
|
||||
.. note:: Many of the examples on this page make use of the `show`
|
||||
command to visually demonstrate the effect of selections. For a more
|
||||
detailed look at this command, refer to :ref:`interactive_show`.
|
||||
|
||||
|
|
@ -59,8 +59,8 @@ Module and design context
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Commands can be executed in *module/* or *design/* context. Until now, all
|
||||
commands have been executed in design context. The :cmd:ref:`cd` command can be
|
||||
used to switch to module context.
|
||||
commands have been executed in design context. The `cd` command can be used to
|
||||
switch to module context.
|
||||
|
||||
In module context, all commands only effect the active module. Objects in the
|
||||
module are selected without the ``<module_name>/`` prefix. For example:
|
||||
|
|
@ -91,7 +91,7 @@ Special patterns can be used to select by object property or type. For example:
|
|||
a:foobar=42`
|
||||
- select all modules with the attribute ``blabla`` set: :yoscrypt:`select
|
||||
A:blabla`
|
||||
- select all $add cells from the module foo: :yoscrypt:`select foo/t:$add`
|
||||
- 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`.
|
||||
|
||||
|
|
@ -101,12 +101,12 @@ Operations on selections
|
|||
Combining selections
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :cmd:ref:`select` command is actually much more powerful than it might seem
|
||||
at first glance. When it is called with multiple arguments, each argument is
|
||||
evaluated and pushed separately on a stack. After all arguments have been
|
||||
processed it simply creates the union of all elements on the stack. So
|
||||
:yoscrypt:`select t:$add a:foo` will select all ``$add`` cells and all objects
|
||||
with the ``foo`` attribute set:
|
||||
The `select` command is actually much more powerful than it might seem at first
|
||||
glance. When it is called with multiple arguments, each argument is evaluated
|
||||
and pushed separately on a stack. After all arguments have been processed it
|
||||
simply creates the union of all elements on the stack. So :yoscrypt:`select
|
||||
t:$add a:foo` will select all `$add` cells and all objects with the ``foo``
|
||||
attribute set:
|
||||
|
||||
.. literalinclude:: /code_examples/selections/foobaraddsub.v
|
||||
:caption: Test module for operations on selections
|
||||
|
|
@ -126,7 +126,7 @@ ineffective way of selecting the interesting part of the design. Special
|
|||
arguments can be used to combine the elements on the stack. For example the
|
||||
``%i`` arguments pops the last two elements from the stack, intersects them, and
|
||||
pushes the result back on the stack. So :yoscrypt:`select t:$add a:foo %i` will
|
||||
select all ``$add`` cells that have the ``foo`` attribute set:
|
||||
select all `$add` cells that have the ``foo`` attribute set:
|
||||
|
||||
.. code-block::
|
||||
:caption: Output for command ``select t:$add a:foo %i -list`` on :numref:`foobaraddsub`
|
||||
|
|
@ -190,7 +190,7 @@ Selecting logic cones
|
|||
:numref:`sumprod_01` shows what is called the ``input cone`` of ``sum``, i.e.
|
||||
all cells and signals that are used to generate the signal ``sum``. The ``%ci``
|
||||
action can be used to select the input cones of all object in the top selection
|
||||
in the stack maintained by the :cmd:ref:`select` command.
|
||||
in the stack maintained by the `select` command.
|
||||
|
||||
As with the ``%x`` action, these commands broaden the selection by one "step".
|
||||
But this time the operation only works against the direction of data flow. That
|
||||
|
|
@ -220,11 +220,11 @@ The following sequence of diagrams demonstrates this step-wise expansion:
|
|||
Output of :yoscrypt:`show prod %ci %ci %ci` on :numref:`sumprod`
|
||||
|
||||
Notice the subtle difference between :yoscrypt:`show prod %ci` and
|
||||
:yoscrypt:`show prod %ci %ci`. Both images show the ``$mul`` cell driven by
|
||||
some inputs ``$3_Y`` and ``c``. However it is not until the second image,
|
||||
having called ``%ci`` the second time, that :cmd:ref:`show` is able to
|
||||
distinguish between ``$3_Y`` being a wire and ``c`` being an input. We can see
|
||||
this better with the :cmd:ref:`dump` command instead:
|
||||
:yoscrypt:`show prod %ci %ci`. Both images show the `$mul` cell driven by some
|
||||
inputs ``$3_Y`` and ``c``. However it is not until the second image, having
|
||||
called ``%ci`` the second time, that `show` is able to distinguish between
|
||||
``$3_Y`` being a wire and ``c`` being an input. We can see this better with the
|
||||
`dump` command instead:
|
||||
|
||||
.. literalinclude:: /code_examples/selections/sumprod.out
|
||||
:language: RTLIL
|
||||
|
|
@ -241,8 +241,8 @@ be a bit dull. So there is a shortcut for that: the number of iterations can be
|
|||
appended to the action. So for example the action ``%ci3`` is identical to
|
||||
performing the ``%ci`` action three times.
|
||||
|
||||
The action ``%ci*`` performs the ``%ci`` action over and over again until it
|
||||
has no effect anymore.
|
||||
The action ``%ci*`` performs the ``%ci`` action over and over again until it has
|
||||
no effect anymore.
|
||||
|
||||
.. _advanced_logic_cones:
|
||||
|
||||
|
|
@ -264,8 +264,8 @@ source repository.
|
|||
:name: memdemo_src
|
||||
:language: verilog
|
||||
|
||||
The script :file:`memdemo.ys` is used to generate the images included here. Let's
|
||||
look at the first section:
|
||||
The script :file:`memdemo.ys` is used to generate the images included here.
|
||||
Let's look at the first section:
|
||||
|
||||
.. literalinclude:: /code_examples/selections/memdemo.ys
|
||||
:caption: Synthesizing :ref:`memdemo_src`
|
||||
|
|
@ -276,8 +276,8 @@ look at the first section:
|
|||
This loads :numref:`memdemo_src` and synthesizes the included module. Note that
|
||||
this code can be copied and run directly in a Yosys command line session,
|
||||
provided :file:`memdemo.v` is in the same directory. We can now change to the
|
||||
``memdemo`` module with ``cd memdemo``, and call :cmd:ref:`show` to see the
|
||||
diagram in :numref:`memdemo_00`.
|
||||
``memdemo`` module with ``cd memdemo``, and call `show` to see the diagram in
|
||||
:numref:`memdemo_00`.
|
||||
|
||||
.. figure:: /_images/code_examples/selections/memdemo_00.*
|
||||
:class: width-helper invert-helper
|
||||
|
|
@ -296,7 +296,7 @@ cones`_ from above, we can use :yoscrypt:`show y %ci2`:
|
|||
|
||||
Output of :yoscrypt:`show y %ci2`
|
||||
|
||||
From this we would learn that ``y`` is driven by a ``$dff cell``, that ``y`` is
|
||||
From this we would learn that ``y`` is driven by a `$dff` cell, that ``y`` is
|
||||
connected to the output port ``Q``, that the ``clk`` signal goes into the
|
||||
``CLK`` input port of the cell, and that the data comes from an auto-generated
|
||||
wire into the input ``D`` of the flip-flop cell (indicated by the ``$`` at the
|
||||
|
|
@ -313,7 +313,7 @@ inputs. To add a pattern we add a colon followed by the pattern to the ``%ci``
|
|||
action. The pattern itself starts with ``-`` or ``+``, indicating if it is an
|
||||
include or exclude pattern, followed by an optional comma separated list of cell
|
||||
types, followed by an optional comma separated list of port names in square
|
||||
brackets. In this case, we want to exclude the ``S`` port of the ``$mux`` cell
|
||||
brackets. In this case, we want to exclude the ``S`` port of the `$mux` cell
|
||||
type with :yoscrypt:`show y %ci5:-$mux[S]`:
|
||||
|
||||
.. figure:: /_images/code_examples/selections/memdemo_03.*
|
||||
|
|
@ -334,7 +334,7 @@ multiplexer select inputs and flip-flop cells:
|
|||
Output of ``show y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff``
|
||||
|
||||
Or we could use :yoscrypt:`show y %ci*:-[CLK,S]:+$dff:+$mux` instead, following
|
||||
the input cone all the way but only following ``$dff`` and ``$mux`` cells, and
|
||||
the input cone all the way but only following `$dff` and `$mux` cells, and
|
||||
ignoring any ports named ``CLK`` or ``S``:
|
||||
|
||||
.. TODO:: pending discussion on whether rule ordering is a bug or a feature
|
||||
|
|
@ -371,8 +371,8 @@ selection instead of overwriting it.
|
|||
select -del reg_42 # but not this one
|
||||
select -add state %ci # and add more stuff
|
||||
|
||||
Within a select expression the token ``%`` can be used to push the previous selection
|
||||
on the stack.
|
||||
Within a select expression the token ``%`` can be used to push the previous
|
||||
selection on the stack.
|
||||
|
||||
.. code:: yoscrypt
|
||||
|
||||
|
|
@ -387,16 +387,16 @@ Storing and recalling selections
|
|||
The current selection can be stored in memory with the command ``select -set
|
||||
<name>``. It can later be recalled using ``select @<name>``. In fact, the
|
||||
``@<name>`` expression pushes the stored selection on the stack maintained by
|
||||
the :cmd:ref:`select` command. So for example :yoscrypt:`select @foo @bar %i`
|
||||
will select the intersection between the stored selections ``foo`` and ``bar``.
|
||||
the `select` command. So for example :yoscrypt:`select @foo @bar %i` will select
|
||||
the intersection between the stored selections ``foo`` and ``bar``.
|
||||
|
||||
In larger investigation efforts it is highly recommended to maintain a script
|
||||
that sets up relevant selections, so they can easily be recalled, for example
|
||||
when Yosys needs to be re-run after a design or source code change.
|
||||
|
||||
The :cmd:ref:`history` command can be used to list all recent interactive
|
||||
commands. This feature can be useful for creating such a script from the
|
||||
commands used in an interactive session.
|
||||
The `history` command can be used to list all recent interactive commands. This
|
||||
feature can be useful for creating such a script from the commands used in an
|
||||
interactive session.
|
||||
|
||||
Remember that select expressions can also be used directly as arguments to most
|
||||
commands. Some commands also accept a single select argument to some options. In
|
||||
|
|
|
|||
|
|
@ -10,20 +10,19 @@ fine-grained optimisation and LUT mapping.
|
|||
Yosys has two different commands, which both use this logic toolbox, but use it
|
||||
in different ways.
|
||||
|
||||
The :cmd:ref:`abc` pass can be used for both ASIC (e.g. :yoscrypt:`abc
|
||||
-liberty`) and FPGA (:yoscrypt:`abc -lut`) mapping, but this page will focus on
|
||||
FPGA mapping.
|
||||
The `abc` pass can be used for both ASIC (e.g. :yoscrypt:`abc -liberty`) and
|
||||
FPGA (:yoscrypt:`abc -lut`) mapping, but this page will focus on FPGA mapping.
|
||||
|
||||
The :cmd:ref:`abc9` pass generally provides superior mapping quality due to
|
||||
being aware of combination boxes and DFF and LUT timings, giving it a more
|
||||
global view of the mapping problem.
|
||||
The `abc9` pass generally provides superior mapping quality due to being aware
|
||||
of combination boxes and DFF and LUT timings, giving it a more global view of
|
||||
the mapping problem.
|
||||
|
||||
.. _ABC: https://github.com/berkeley-abc/abc
|
||||
|
||||
ABC: the unit delay model, simple and efficient
|
||||
-----------------------------------------------
|
||||
|
||||
The :cmd:ref:`abc` pass uses a highly simplified view of an FPGA:
|
||||
The `abc` pass uses a highly simplified view of an FPGA:
|
||||
|
||||
- An FPGA is made up of a network of inputs that connect through LUTs to a
|
||||
network of outputs. These inputs may actually be I/O pins, D flip-flops,
|
||||
|
|
@ -126,7 +125,7 @@ guide to the syntax:
|
|||
|
||||
By convention, all delays in ``specify`` blocks are in integer picoseconds.
|
||||
Files containing ``specify`` blocks should be read with the ``-specify`` option
|
||||
to :cmd:ref:`read_verilog` so that they aren't skipped.
|
||||
to `read_verilog` so that they aren't skipped.
|
||||
|
||||
LUTs
|
||||
^^^^
|
||||
|
|
@ -145,9 +144,9 @@ DFFs
|
|||
|
||||
DFFs should be annotated with an ``(* abc9_flop *)`` attribute, however ABC9 has
|
||||
some specific requirements for this to be valid: - the DFF must initialise to
|
||||
zero (consider using :cmd:ref:`dfflegalize` to ensure this). - the DFF cannot
|
||||
have any asynchronous resets/sets (see the simplification idiom and the Boxes
|
||||
section for what to do here).
|
||||
zero (consider using `dfflegalize` to ensure this). - the DFF cannot have any
|
||||
asynchronous resets/sets (see the simplification idiom and the Boxes section for
|
||||
what to do here).
|
||||
|
||||
It is worth noting that in pure ``abc9`` mode, only the setup and arrival times
|
||||
are passed to ABC9 (specifically, they are modelled as buffers with the given
|
||||
|
|
@ -158,9 +157,9 @@ Some vendors have universal DFF models which include async sets/resets even when
|
|||
they're unused. Therefore *the simplification idiom* exists to handle this: by
|
||||
using a ``techmap`` file to discover flops which have a constant driver to those
|
||||
asynchronous controls, they can be mapped into an intermediate, simplified flop
|
||||
which qualifies as an ``(* abc9_flop *)``, ran through :cmd:ref:`abc9`, and then
|
||||
mapped back to the original flop. This is used in :cmd:ref:`synth_intel_alm` and
|
||||
:cmd:ref:`synth_quicklogic` for the PolarPro3.
|
||||
which qualifies as an ``(* abc9_flop *)``, ran through `abc9`, and then mapped
|
||||
back to the original flop. This is used in `synth_intel_alm` and
|
||||
`synth_quicklogic` for the PolarPro3.
|
||||
|
||||
DFFs are usually specified to have setup constraints against the clock on the
|
||||
input signals, and an arrival time for the ``Q`` output.
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ Our circuit now looks like this:
|
|||
:class: width-helper invert-helper
|
||||
:name: counter-hierarchy
|
||||
|
||||
``counter`` after :cmd:ref:`hierarchy`
|
||||
``counter`` after `hierarchy`
|
||||
|
||||
Coarse-grain representation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -82,7 +82,7 @@ Logic gate mapping
|
|||
.. figure:: /_images/code_examples/intro/counter_02.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
``counter`` after :cmd:ref:`techmap`
|
||||
``counter`` after `techmap`
|
||||
|
||||
Mapping to hardware
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -98,11 +98,11 @@ our internal cell library will be mapped to:
|
|||
:name: mycells-lib
|
||||
:caption: :file:`mycells.lib`
|
||||
|
||||
Recall that the Yosys built-in logic gate types are ``$_NOT_``, ``$_AND_``,
|
||||
``$_OR_``, ``$_XOR_``, and ``$_MUX_`` with an assortment of dff memory types.
|
||||
Recall that the Yosys built-in logic gate types are `$_NOT_`, `$_AND_`, `$_OR_`,
|
||||
`$_XOR_`, and `$_MUX_` with an assortment of dff memory types.
|
||||
:ref:`mycells-lib` defines our target cells as ``BUF``, ``NOT``, ``NAND``,
|
||||
``NOR``, and ``DFF``. Mapping between these is performed with the commands
|
||||
:cmd:ref:`dfflibmap` and :cmd:ref:`abc` as follows:
|
||||
`dfflibmap` and `abc` as follows:
|
||||
|
||||
.. literalinclude:: /code_examples/intro/counter.ys
|
||||
:language: yoscrypt
|
||||
|
|
@ -117,8 +117,8 @@ The final version of our ``counter`` module looks like this:
|
|||
|
||||
``counter`` after hardware cell mapping
|
||||
|
||||
Before finally being output as a verilog file with :cmd:ref:`write_verilog`,
|
||||
which can then be loaded into another tool:
|
||||
Before finally being output as a verilog file with `write_verilog`, which can
|
||||
then be loaded into another tool:
|
||||
|
||||
.. literalinclude:: /code_examples/intro/counter.ys
|
||||
:language: yoscrypt
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
The extract pass
|
||||
----------------
|
||||
|
||||
- Like the :cmd:ref:`techmap` pass, the :cmd:ref:`extract` pass is called with a
|
||||
map file. It compares the circuits inside the modules of the map file with the
|
||||
design and looks for sub-circuits in the design that match any of the modules
|
||||
in the map file.
|
||||
- If a match is found, the :cmd:ref:`extract` pass will replace the matching
|
||||
subcircuit with an instance of the module from the map file.
|
||||
- In a way the :cmd:ref:`extract` pass is the inverse of the techmap pass.
|
||||
- Like the `techmap` pass, the `extract` pass is called with a map file. It
|
||||
compares the circuits inside the modules of the map file with the design and
|
||||
looks for sub-circuits in the design that match any of the modules in the map
|
||||
file.
|
||||
- If a match is found, the `extract` pass will replace the matching subcircuit
|
||||
with an instance of the module from the map file.
|
||||
- In a way the `extract` pass is the inverse of the techmap pass.
|
||||
|
||||
.. todo:: add/expand supporting text, also mention custom pattern matching and
|
||||
pmgen
|
||||
|
|
@ -25,7 +25,7 @@ Example code can be found in |code_examples/macc|_.
|
|||
.. figure:: /_images/code_examples/macc/macc_simple_test_00a.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
before :cmd:ref:`extract`
|
||||
before `extract`
|
||||
|
||||
.. literalinclude:: /code_examples/macc/macc_simple_test.ys
|
||||
:language: yoscrypt
|
||||
|
|
@ -34,7 +34,7 @@ Example code can be found in |code_examples/macc|_.
|
|||
.. figure:: /_images/code_examples/macc/macc_simple_test_00b.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
after :cmd:ref:`extract`
|
||||
after `extract`
|
||||
|
||||
.. literalinclude:: /code_examples/macc/macc_simple_test.v
|
||||
:language: verilog
|
||||
|
|
@ -68,26 +68,26 @@ The wrap-extract-unwrap method
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Often a coarse-grain element has a constant bit-width, but can be used to
|
||||
implement operations with a smaller bit-width. For example, a 18x25-bit multiplier
|
||||
can also be used to implement 16x20-bit multiplication.
|
||||
implement operations with a smaller bit-width. For example, a 18x25-bit
|
||||
multiplier can also be used to implement 16x20-bit multiplication.
|
||||
|
||||
A way of mapping such elements in coarse grain synthesis is the
|
||||
wrap-extract-unwrap method:
|
||||
|
||||
wrap
|
||||
Identify candidate-cells in the circuit and wrap them in a cell with a
|
||||
constant wider bit-width using :cmd:ref:`techmap`. The wrappers use the same
|
||||
parameters as the original cell, so the information about the original width
|
||||
of the ports is preserved. Then use the :cmd:ref:`connwrappers` command to
|
||||
connect up the bit-extended in- and outputs of the wrapper cells.
|
||||
constant wider bit-width using `techmap`. The wrappers use the same parameters
|
||||
as the original cell, so the information about the original width of the ports
|
||||
is preserved. Then use the `connwrappers` command to connect up the
|
||||
bit-extended in- and outputs of the wrapper cells.
|
||||
|
||||
extract
|
||||
Now all operations are encoded using the same bit-width as the coarse grain
|
||||
element. The :cmd:ref:`extract` command can be used to replace circuits with
|
||||
cells of the target architecture.
|
||||
element. The `extract` command can be used to replace circuits with cells of
|
||||
the target architecture.
|
||||
|
||||
unwrap
|
||||
The remaining wrapper cell can be unwrapped using :cmd:ref:`techmap`.
|
||||
The remaining wrapper cell can be unwrapped using `techmap`.
|
||||
|
||||
Example: DSP48_MACC
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -127,7 +127,7 @@ Extract: :file:`macc_xilinx_xmap.v`
|
|||
:caption: :file:`macc_xilinx_xmap.v`
|
||||
|
||||
... simply use the same wrapping commands on this module as on the design to
|
||||
create a template for the :cmd:ref:`extract` command.
|
||||
create a template for the `extract` command.
|
||||
|
||||
Unwrapping multipliers: :file:`macc_xilinx_unwrap_map.v`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
FSM handling
|
||||
============
|
||||
|
||||
The :cmd:ref:`fsm` command identifies, extracts, optimizes (re-encodes), and
|
||||
The `fsm` command identifies, extracts, optimizes (re-encodes), and
|
||||
re-synthesizes finite state machines. It again is a macro that calls a series of
|
||||
other commands:
|
||||
|
||||
.. literalinclude:: /code_examples/macro_commands/fsm.ys
|
||||
:language: yoscrypt
|
||||
:start-after: #end:
|
||||
:caption: Passes called by :cmd:ref:`fsm`
|
||||
:caption: Passes called by `fsm`
|
||||
|
||||
See also :doc:`/cmd/fsm`.
|
||||
|
||||
|
|
@ -18,34 +18,33 @@ general reported technique :cite:p:`fsmextract`.
|
|||
FSM detection
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The :cmd:ref:`fsm_detect` pass identifies FSM state registers. It sets the
|
||||
``\fsm_encoding = "auto"`` attribute on any (multi-bit) wire that matches the
|
||||
The `fsm_detect` pass identifies FSM state registers. It sets the
|
||||
``fsm_encoding = "auto"`` attribute on any (multi-bit) wire that matches the
|
||||
following description:
|
||||
|
||||
- Does not already have the ``\fsm_encoding`` attribute.
|
||||
- Does not already have the ``fsm_encoding`` attribute.
|
||||
- Is not an output of the containing module.
|
||||
- Is driven by single ``$dff`` or ``$adff`` cell.
|
||||
- The ``\D``-Input of this ``$dff`` or ``$adff`` cell is driven by a
|
||||
multiplexer tree that only has constants or the old state value on its
|
||||
leaves.
|
||||
- Is driven by single `$dff` or `$adff` cell.
|
||||
- The ``D``-Input of this `$dff` or `$adff` cell is driven by a multiplexer
|
||||
tree that only has constants or the old state value on its leaves.
|
||||
- The state value is only used in the said multiplexer tree or by simple
|
||||
relational cells that compare the state value to a constant (usually ``$eq``
|
||||
relational cells that compare the state value to a constant (usually `$eq`
|
||||
cells).
|
||||
|
||||
This heuristic has proven to work very well. It is possible to overwrite it by
|
||||
setting ``\fsm_encoding = "auto"`` on registers that should be considered FSM
|
||||
state registers and setting ``\fsm_encoding = "none"`` on registers that match
|
||||
setting ``fsm_encoding = "auto"`` on registers that should be considered FSM
|
||||
state registers and setting ``fsm_encoding = "none"`` on registers that match
|
||||
the above criteria but should not be considered FSM state registers.
|
||||
|
||||
Note however that marking state registers with ``\fsm_encoding`` that are not
|
||||
Note however that marking state registers with ``fsm_encoding`` that are not
|
||||
suitable for FSM recoding can cause synthesis to fail or produce invalid
|
||||
results.
|
||||
|
||||
FSM extraction
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The :cmd:ref:`fsm_extract` pass operates on all state signals marked with the
|
||||
(``\fsm_encoding != "none"``) attribute. For each state signal the following
|
||||
The `fsm_extract` pass operates on all state signals marked with the
|
||||
(``fsm_encoding != "none"``) attribute. For each state signal the following
|
||||
information is determined:
|
||||
|
||||
- The state registers
|
||||
|
|
@ -64,10 +63,10 @@ information is determined:
|
|||
The state registers (and asynchronous reset state, if applicable) is simply
|
||||
determined by identifying the driver for the state signal.
|
||||
|
||||
From there the ``$mux-tree`` driving the state register inputs is recursively
|
||||
traversed. All select inputs are control signals and the leaves of the
|
||||
``$mux-tree`` are the states. The algorithm fails if a non-constant leaf that is
|
||||
not the state signal itself is found.
|
||||
From there the `$mux`\ -tree driving the state register inputs is recursively
|
||||
traversed. All select inputs are control signals and the leaves of the `$mux`\
|
||||
-tree are the states. The algorithm fails if a non-constant leaf that is not the
|
||||
state signal itself is found.
|
||||
|
||||
The list of control outputs is initialized with the bits from the state signal.
|
||||
It is then extended by adding all values that are calculated by cells that
|
||||
|
|
@ -85,8 +84,8 @@ given set of result signals using a set of signal-value assignments. It can also
|
|||
be passed a list of stop-signals that abort the ConstEval algorithm if the value
|
||||
of a stop-signal is needed in order to calculate the result signals.
|
||||
|
||||
The :cmd:ref:`fsm_extract` pass uses the ConstEval class in the following way to
|
||||
create a transition table. For each state:
|
||||
The `fsm_extract` pass uses the ConstEval class in the following way to create a
|
||||
transition table. For each state:
|
||||
|
||||
1. Create a ConstEval object for the module containing the FSM
|
||||
2. Add all control inputs to the list of stop signals
|
||||
|
|
@ -99,20 +98,19 @@ create a transition table. For each state:
|
|||
|
||||
6. If step 4 was successful: Emit transition
|
||||
|
||||
Finally a ``$fsm`` cell is created with the generated transition table and added
|
||||
Finally a `$fsm` cell is created with the generated transition table and added
|
||||
to the module. This new cell is connected to the control signals and the old
|
||||
drivers for the control outputs are disconnected.
|
||||
|
||||
FSM optimization
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The :cmd:ref:`fsm_opt` pass performs basic optimizations on ``$fsm`` cells (not
|
||||
including state recoding). The following optimizations are performed (in this
|
||||
order):
|
||||
The `fsm_opt` pass performs basic optimizations on `$fsm` cells (not including
|
||||
state recoding). The following optimizations are performed (in this order):
|
||||
|
||||
- Unused control outputs are removed from the ``$fsm`` cell. The attribute
|
||||
``\unused_bits`` (that is usually set by the :cmd:ref:`opt_clean` pass) is
|
||||
used to determine which control outputs are unused.
|
||||
- Unused control outputs are removed from the `$fsm` cell. The attribute
|
||||
``unused_bits`` (that is usually set by the `opt_clean` pass) is used to
|
||||
determine which control outputs are unused.
|
||||
|
||||
- Control inputs that are connected to the same driver are merged.
|
||||
|
||||
|
|
@ -132,11 +130,10 @@ order):
|
|||
FSM recoding
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The :cmd:ref:`fsm_recode` pass assigns new bit pattern to the states. Usually
|
||||
this also implies a change in the width of the state signal. At the moment of
|
||||
this writing only one-hot encoding with all-zero for the reset state is
|
||||
supported.
|
||||
The `fsm_recode` pass assigns new bit pattern to the states. Usually this also
|
||||
implies a change in the width of the state signal. At the moment of this writing
|
||||
only one-hot encoding with all-zero for the reset state is supported.
|
||||
|
||||
The :cmd:ref:`fsm_recode` pass can also write a text file with the changes
|
||||
performed by it that can be used when verifying designs synthesized by Yosys
|
||||
using Synopsys Formality.
|
||||
The `fsm_recode` pass can also write a text file with the changes performed by
|
||||
it that can be used when verifying designs synthesized by Yosys using Synopsys
|
||||
Formality.
|
||||
|
|
|
|||
|
|
@ -8,17 +8,16 @@ coarse-grain optimizations before being mapped to hard blocks and fine-grain
|
|||
cells. Most commands in Yosys will target either coarse-grain representation or
|
||||
fine-grain representation, with only a select few compatible with both states.
|
||||
|
||||
Commands such as :cmd:ref:`proc`, :cmd:ref:`fsm`, and :cmd:ref:`memory` rely on
|
||||
the additional information in the coarse-grain representation, along with a
|
||||
number of optimizations such as :cmd:ref:`wreduce`, :cmd:ref:`share`, and
|
||||
:cmd:ref:`alumacc`. :cmd:ref:`opt` provides optimizations which are useful in
|
||||
both states, while :cmd:ref:`techmap` is used to convert coarse-grain cells
|
||||
to the corresponding fine-grain representation.
|
||||
Commands such as `proc`, `fsm`, and `memory` rely on the additional information
|
||||
in the coarse-grain representation, along with a number of optimizations such as
|
||||
`wreduce`, `share`, and `alumacc`. `opt` provides optimizations which are
|
||||
useful in both states, while `techmap` is used to convert coarse-grain cells to
|
||||
the corresponding fine-grain representation.
|
||||
|
||||
Single-bit cells (logic gates, FFs) as well as LUTs, half-adders, and
|
||||
full-adders make up the bulk of the fine-grain representation and are necessary
|
||||
for commands such as :cmd:ref:`abc`\ /:cmd:ref:`abc9`, :cmd:ref:`simplemap`,
|
||||
:cmd:ref:`dfflegalize`, and :cmd:ref:`memory_map`.
|
||||
for commands such as `abc`\ /`abc9`, `simplemap`, `dfflegalize`, and
|
||||
`memory_map`.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
|
|
|||
|
|
@ -1,32 +1,32 @@
|
|||
Memory handling
|
||||
===============
|
||||
|
||||
The :cmd:ref:`memory` command
|
||||
The `memory` command
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the RTL netlist, memory reads and writes are individual cells. This makes
|
||||
consolidating the number of ports for a memory easier. The :cmd:ref:`memory`
|
||||
pass transforms memories to an implementation. Per default that is logic for
|
||||
address decoders and registers. It also is a macro command that calls the other
|
||||
common ``memory_*`` passes in a sensible order:
|
||||
consolidating the number of ports for a memory easier. The `memory` pass
|
||||
transforms memories to an implementation. Per default that is logic for address
|
||||
decoders and registers. It also is a macro command that calls the other common
|
||||
``memory_*`` passes in a sensible order:
|
||||
|
||||
.. literalinclude:: /code_examples/macro_commands/memory.ys
|
||||
:language: yoscrypt
|
||||
:start-after: #end:
|
||||
:caption: Passes called by :cmd:ref:`memory`
|
||||
:caption: Passes called by `memory`
|
||||
|
||||
.. todo:: Make ``memory_*`` notes less quick
|
||||
|
||||
Some quick notes:
|
||||
|
||||
- :cmd:ref:`memory_dff` merges registers into the memory read- and write cells.
|
||||
- :cmd:ref:`memory_collect` collects all read and write cells for a memory and
|
||||
- `memory_dff` merges registers into the memory read- and write cells.
|
||||
- `memory_collect` collects all read and write cells for a memory and
|
||||
transforms them into one multi-port memory cell.
|
||||
- :cmd:ref:`memory_map` takes the multi-port memory cell and transforms it to
|
||||
address decoder logic and registers.
|
||||
- `memory_map` takes the multi-port memory cell and transforms it to address
|
||||
decoder logic and registers.
|
||||
|
||||
For more information about :cmd:ref:`memory`, such as disabling certain sub
|
||||
commands, see :doc:`/cmd/memory`.
|
||||
For more information about `memory`, such as disabling certain sub commands, see
|
||||
:doc:`/cmd/memory`.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
|
@ -75,22 +75,22 @@ For example:
|
|||
techmap -map my_memory_map.v
|
||||
memory_map
|
||||
|
||||
:cmd:ref:`memory_libmap` attempts to convert memory cells (``$mem_v2`` etc) into
|
||||
hardware supported memory using a provided library (:file:`my_memory_map.txt` in the
|
||||
`memory_libmap` attempts to convert memory cells (`$mem_v2` etc) into hardware
|
||||
supported memory using a provided library (:file:`my_memory_map.txt` in the
|
||||
example above). Where necessary, emulation logic is added to ensure functional
|
||||
equivalence before and after this conversion. :yoscrypt:`techmap -map
|
||||
my_memory_map.v` then uses :cmd:ref:`techmap` to map to hardware primitives. Any
|
||||
leftover memory cells unable to be converted are then picked up by
|
||||
:cmd:ref:`memory_map` and mapped to DFFs and address decoders.
|
||||
my_memory_map.v` then uses `techmap` to map to hardware primitives. Any leftover
|
||||
memory cells unable to be converted are then picked up by `memory_map` and
|
||||
mapped to DFFs and address decoders.
|
||||
|
||||
.. note::
|
||||
|
||||
More information about what mapping options are available and associated
|
||||
costs of each can be found by enabling debug outputs. This can be done with
|
||||
the :cmd:ref:`debug` command, or by using the ``-g`` flag when calling Yosys
|
||||
to globally enable debug messages.
|
||||
the `debug` command, or by using the ``-g`` flag when calling Yosys to
|
||||
globally enable debug messages.
|
||||
|
||||
For more on the lib format for :cmd:ref:`memory_libmap`, see
|
||||
For more on the lib format for `memory_libmap`, see
|
||||
`passes/memory/memlib.md
|
||||
<https://github.com/YosysHQ/yosys/blob/main/passes/memory/memlib.md>`_
|
||||
|
||||
|
|
@ -110,13 +110,15 @@ Notes
|
|||
Memory kind selection
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The memory inference code will automatically pick target memory primitive based on memory geometry
|
||||
and features used. Depending on the target, there can be up to four memory primitive classes
|
||||
available for selection:
|
||||
The memory inference code will automatically pick target memory primitive based
|
||||
on memory geometry and features used. Depending on the target, there can be up
|
||||
to four memory primitive classes available for selection:
|
||||
|
||||
- FF RAM (aka logic): no hardware primitive used, memory lowered to a bunch of FFs and multiplexers
|
||||
- FF RAM (aka logic): no hardware primitive used, memory lowered to a bunch of
|
||||
FFs and multiplexers
|
||||
|
||||
- Can handle arbitrary number of write ports, as long as all write ports are in the same clock domain
|
||||
- Can handle arbitrary number of write ports, as long as all write ports are
|
||||
in the same clock domain
|
||||
- Can handle arbitrary number and kind of read ports
|
||||
|
||||
- LUT RAM (aka distributed RAM): uses LUT storage as RAM
|
||||
|
|
@ -131,7 +133,8 @@ available for selection:
|
|||
- Supported on basically all FPGAs
|
||||
- Supports only synchronous reads
|
||||
- Two ports with separate clocks
|
||||
- Usually supports true dual port (with notable exception of ice40 that only supports SDP)
|
||||
- Usually supports true dual port (with notable exception of ice40 that only
|
||||
supports SDP)
|
||||
- Usually supports asymmetric memories and per-byte write enables
|
||||
- Several kilobits in size
|
||||
|
||||
|
|
@ -155,38 +158,43 @@ available for selection:
|
|||
- Two ports, both with mutually exclusive synchronous read and write
|
||||
- Single clock
|
||||
|
||||
- Will not be automatically selected by memory inference code, needs explicit opt-in via
|
||||
ram_style attribute
|
||||
- Will not be automatically selected by memory inference code, needs explicit
|
||||
opt-in via ram_style attribute
|
||||
|
||||
In general, you can expect the automatic selection process to work roughly like this:
|
||||
In general, you can expect the automatic selection process to work roughly like
|
||||
this:
|
||||
|
||||
- If any read port is asynchronous, only LUT RAM (or FF RAM) can be used.
|
||||
- If there is more than one write port, only block RAM can be used, and this needs to be a
|
||||
hardware-supported true dual port pattern
|
||||
- If there is more than one write port, only block RAM can be used, and this
|
||||
needs to be a hardware-supported true dual port pattern
|
||||
|
||||
- … unless all write ports are in the same clock domain, in which case FF RAM can also be used,
|
||||
but this is generally not what you want for anything but really small memories
|
||||
- … unless all write ports are in the same clock domain, in which case FF RAM
|
||||
can also be used, but this is generally not what you want for anything but
|
||||
really small memories
|
||||
|
||||
- Otherwise, either FF RAM, LUT RAM, or block RAM will be used, depending on memory size
|
||||
- Otherwise, either FF RAM, LUT RAM, or block RAM will be used, depending on
|
||||
memory size
|
||||
|
||||
This process can be overridden by attaching a ram_style attribute to the memory:
|
||||
|
||||
- `(* ram_style = "logic" *)` selects FF RAM
|
||||
- `(* ram_style = "distributed" *)` selects LUT RAM
|
||||
- `(* ram_style = "block" *)` selects block RAM
|
||||
- `(* ram_style = "huge" *)` selects huge RAM
|
||||
- ``(* ram_style = "logic" *)`` selects FF RAM
|
||||
- ``(* ram_style = "distributed" *)`` selects LUT RAM
|
||||
- ``(* ram_style = "block" *)`` selects block RAM
|
||||
- ``(* ram_style = "huge" *)`` selects huge RAM
|
||||
|
||||
It is an error if this override cannot be realized for the given target.
|
||||
|
||||
Many alternate spellings of the attribute are also accepted, for compatibility with other software.
|
||||
Many alternate spellings of the attribute are also accepted, for compatibility
|
||||
with other software.
|
||||
|
||||
Initial data
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Most FPGA targets support initializing all kinds of memory to user-provided values. If explicit
|
||||
initialization is not used the initial memory value is undefined. Initial data can be provided by
|
||||
either initial statements writing memory cells one by one of ``$readmemh`` or ``$readmemb`` system
|
||||
tasks. For an example pattern, see `sr_init`_.
|
||||
Most FPGA targets support initializing all kinds of memory to user-provided
|
||||
values. If explicit initialization is not used the initial memory value is
|
||||
undefined. Initial data can be provided by either initial statements writing
|
||||
memory cells one by one of ``$readmemh`` or ``$readmemb`` system tasks. For an
|
||||
example pattern, see `sr_init`_.
|
||||
|
||||
.. _wbe:
|
||||
|
||||
|
|
@ -194,12 +202,13 @@ Write port with byte enables
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Byte enables can be used with any supported pattern
|
||||
- To ensure that multiple writes will be merged into one port, they need to have disjoint bit
|
||||
ranges, have the same address, and the same clock
|
||||
- Any write enable granularity will be accepted (down to per-bit write enables), but using smaller
|
||||
granularity than natively supported by the target is very likely to be inefficient (eg. using
|
||||
4-bit bytes on ECP5 will result in either padding the bytes with 5 dummy bits to native 9-bit
|
||||
units or splitting the RAM into two block RAMs)
|
||||
- To ensure that multiple writes will be merged into one port, they need to have
|
||||
disjoint bit ranges, have the same address, and the same clock
|
||||
- Any write enable granularity will be accepted (down to per-bit write enables),
|
||||
but using smaller granularity than natively supported by the target is very
|
||||
likely to be inefficient (eg. using 4-bit bytes on ECP5 will result in either
|
||||
padding the bytes with 5 dummy bits to native 9-bit units or splitting the RAM
|
||||
into two block RAMs)
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -240,7 +249,8 @@ Synchronous SDP with clock domain crossing
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Will result in block RAM or LUT RAM depending on size
|
||||
- No behavior guarantees in case of simultaneous read and write to the same address
|
||||
- No behavior guarantees in case of simultaneous read and write to the same
|
||||
address
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -261,9 +271,9 @@ Synchronous SDP read first
|
|||
|
||||
- The read and write parts can be in the same or different processes.
|
||||
- Will result in block RAM or LUT RAM depending on size
|
||||
- As long as the same clock is used for both, yosys will ensure read-first behavior. This may
|
||||
require extra circuitry on some targets for block RAM. If this is not necessary, use one of the
|
||||
patterns below.
|
||||
- As long as the same clock is used for both, yosys will ensure read-first
|
||||
behavior. This may require extra circuitry on some targets for block RAM. If
|
||||
this is not necessary, use one of the patterns below.
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -281,8 +291,8 @@ Synchronous SDP read first
|
|||
Synchronous SDP with undefined collision behavior
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Like above, but the read value is undefined when read and write ports target the same address in
|
||||
the same cycle
|
||||
- Like above, but the read value is undefined when read and write ports target
|
||||
the same address in the same cycle
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -322,8 +332,8 @@ Synchronous SDP with write-first behavior
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Will result in block RAM or LUT RAM depending on size
|
||||
- May use additional circuitry for block RAM if write-first is not natively supported. Will always
|
||||
use additional circuitry for LUT RAM.
|
||||
- May use additional circuitry for block RAM if write-first is not natively
|
||||
supported. Will always use additional circuitry for LUT RAM.
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -343,7 +353,8 @@ Synchronous SDP with write-first behavior
|
|||
Synchronous SDP with write-first behavior (alternate pattern)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- This pattern is supported for compatibility, but is much less flexible than the above
|
||||
- This pattern is supported for compatibility, but is much less flexible than
|
||||
the above
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -378,8 +389,10 @@ Synchronous single-port RAM with mutually exclusive read/write
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Will result in single-port block RAM or LUT RAM depending on size
|
||||
- This is the correct pattern to infer ice40 SPRAM (with manual ram_style selection)
|
||||
- On targets that don't support read/write block RAM ports (eg. ice40), will result in SDP block RAM instead
|
||||
- This is the correct pattern to infer ice40 SPRAM (with manual ram_style
|
||||
selection)
|
||||
- On targets that don't support read/write block RAM ports (eg. ice40), will
|
||||
result in SDP block RAM instead
|
||||
- For block RAM, will use "NO_CHANGE" mode if available
|
||||
|
||||
.. code:: verilog
|
||||
|
|
@ -396,12 +409,14 @@ Synchronous single-port RAM with mutually exclusive read/write
|
|||
Synchronous single-port RAM with read-first behavior
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Will only result in single-port block RAM when read-first behavior is natively supported;
|
||||
otherwise, SDP RAM with additional circuitry will be used
|
||||
- Many targets (Xilinx, ECP5, …) can only natively support read-first/write-first single-port RAM
|
||||
(or TDP RAM) where the write_enable signal implies the read_enable signal (ie. can never write
|
||||
without reading). The memory inference code will run a simple SAT solver on the control signals to
|
||||
determine if this is the case, and insert emulation circuitry if it cannot be easily proven.
|
||||
- Will only result in single-port block RAM when read-first behavior is natively
|
||||
supported; otherwise, SDP RAM with additional circuitry will be used
|
||||
- Many targets (Xilinx, ECP5, …) can only natively support
|
||||
read-first/write-first single-port RAM (or TDP RAM) where the write_enable
|
||||
signal implies the read_enable signal (ie. can never write without reading).
|
||||
The memory inference code will run a simple SAT solver on the control signals
|
||||
to determine if this is the case, and insert emulation circuitry if it cannot
|
||||
be easily proven.
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -418,7 +433,8 @@ Synchronous single-port RAM with write-first behavior
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Will result in single-port block RAM or LUT RAM when supported
|
||||
- Block RAMs will require extra circuitry if write-first behavior not natively supported
|
||||
- Block RAMs will require extra circuitry if write-first behavior not natively
|
||||
supported
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -440,8 +456,8 @@ Synchronous read port with initial value
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Initial read port values can be combined with any other supported pattern
|
||||
- If block RAM is used and initial read port values are not natively supported by the target, small
|
||||
emulation circuit will be inserted
|
||||
- If block RAM is used and initial read port values are not natively supported
|
||||
by the target, small emulation circuit will be inserted
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -459,10 +475,11 @@ Synchronous read port with initial value
|
|||
Read register reset patterns
|
||||
----------------------------
|
||||
|
||||
Resets can be combined with any other supported pattern (except that synchronous reset and
|
||||
asynchronous reset cannot both be used on a single read port). If block RAM is used and the
|
||||
selected reset (synchronous or asynchronous) is used but not natively supported by the target, small
|
||||
emulation circuitry will be inserted.
|
||||
Resets can be combined with any other supported pattern (except that synchronous
|
||||
reset and asynchronous reset cannot both be used on a single read port). If
|
||||
block RAM is used and the selected reset (synchronous or asynchronous) is used
|
||||
but not natively supported by the target, small emulation circuitry will be
|
||||
inserted.
|
||||
|
||||
Synchronous reset, reset priority over enable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -520,22 +537,26 @@ Synchronous read port with asynchronous reset
|
|||
Asymmetric memory patterns
|
||||
--------------------------
|
||||
|
||||
To construct an asymmetric memory (memory with read/write ports of differing widths):
|
||||
To construct an asymmetric memory (memory with read/write ports of differing
|
||||
widths):
|
||||
|
||||
- Declare the memory with the width of the narrowest intended port
|
||||
- Split all wide ports into multiple narrow ports
|
||||
- To ensure the wide ports will be correctly merged:
|
||||
|
||||
- For the address, use a concatenation of actual address in the high bits and a constant in the
|
||||
low bits
|
||||
- Ensure the actual address is identical for all ports belonging to the wide port
|
||||
- For the address, use a concatenation of actual address in the high bits and
|
||||
a constant in the low bits
|
||||
- Ensure the actual address is identical for all ports belonging to the wide
|
||||
port
|
||||
- Ensure that clock is identical
|
||||
- For read ports, ensure that enable/reset signals are identical (for write ports, the enable
|
||||
signal may vary — this will result in using the byte enable functionality)
|
||||
- For read ports, ensure that enable/reset signals are identical (for write
|
||||
ports, the enable signal may vary — this will result in using the byte
|
||||
enable functionality)
|
||||
|
||||
Asymmetric memory is supported on all targets, but may require emulation circuitry where not
|
||||
natively supported. Note that when the memory is larger than the underlying block RAM primitive,
|
||||
hardware asymmetric memory support is likely not to be used even if present as it is more expensive.
|
||||
Asymmetric memory is supported on all targets, but may require emulation
|
||||
circuitry where not natively supported. Note that when the memory is larger
|
||||
than the underlying block RAM primitive, hardware asymmetric memory support is
|
||||
likely not to be used even if present as it is more expensive.
|
||||
|
||||
.. _wide_sr:
|
||||
|
||||
|
|
@ -615,20 +636,25 @@ Wide write port
|
|||
True dual port (TDP) patterns
|
||||
-----------------------------
|
||||
|
||||
- Many different variations of true dual port memory can be created by combining two single-port RAM
|
||||
patterns on the same memory
|
||||
- When TDP memory is used, memory inference code has much less maneuver room to create requested
|
||||
semantics compared to individual single-port patterns (which can end up lowered to SDP memory
|
||||
where necessary) — supported patterns depend strongly on the target
|
||||
- In particular, when both ports have the same clock, it's likely that "undefined collision" mode
|
||||
needs to be manually selected to enable TDP memory inference
|
||||
- The examples below are non-exhaustive — many more combinations of port types are possible
|
||||
- Note: if two write ports are in the same process, this defines a priority relation between them
|
||||
(if both ports are active in the same clock, the later one wins). On almost all targets, this will
|
||||
result in a bit of extra circuitry to ensure the priority semantics. If this is not what you want,
|
||||
put them in separate processes.
|
||||
- Many different variations of true dual port memory can be created by combining
|
||||
two single-port RAM patterns on the same memory
|
||||
- When TDP memory is used, memory inference code has much less maneuver room to
|
||||
create requested semantics compared to individual single-port patterns (which
|
||||
can end up lowered to SDP memory where necessary) — supported patterns depend
|
||||
strongly on the target
|
||||
- In particular, when both ports have the same clock, it's likely that
|
||||
"undefined collision" mode needs to be manually selected to enable TDP memory
|
||||
inference
|
||||
- The examples below are non-exhaustive — many more combinations of port types
|
||||
are possible
|
||||
- Note: if two write ports are in the same process, this defines a priority
|
||||
relation between them (if both ports are active in the same clock, the later
|
||||
one wins). On almost all targets, this will result in a bit of extra circuitry
|
||||
to ensure the priority semantics. If this is not what you want, put them in
|
||||
separate processes.
|
||||
|
||||
- Priority is not supported when using the verific front end and any priority semantics are ignored.
|
||||
- Priority is not supported when using the verific front end and any priority
|
||||
semantics are ignored.
|
||||
|
||||
TDP with different clocks, exclusive read/write
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -654,7 +680,8 @@ TDP with different clocks, exclusive read/write
|
|||
TDP with same clock, read-first behavior
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- This requires hardware inter-port read-first behavior, and will only work on some targets (Xilinx, Nexus)
|
||||
- This requires hardware inter-port read-first behavior, and will only work on
|
||||
some targets (Xilinx, Nexus)
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
@ -677,9 +704,10 @@ TDP with same clock, read-first behavior
|
|||
TDP with multiple read ports
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- The combination of a single write port with an arbitrary amount of read ports is supported on all
|
||||
targets — if a multi-read port primitive is available (like Xilinx RAM64M), it'll be used as
|
||||
appropriate. Otherwise, the memory will be automatically split into multiple primitives.
|
||||
- The combination of a single write port with an arbitrary amount of read ports
|
||||
is supported on all targets — if a multi-read port primitive is available
|
||||
(like Xilinx RAM64M), it'll be used as appropriate. Otherwise, the memory
|
||||
will be automatically split into multiple primitives.
|
||||
|
||||
.. code:: verilog
|
||||
|
||||
|
|
|
|||
|
|
@ -6,32 +6,32 @@ This chapter outlines these optimizations.
|
|||
|
||||
.. todo:: "outlines these optimizations" or "outlines *some*.."?
|
||||
|
||||
The :cmd:ref:`opt` macro command
|
||||
The `opt` macro command
|
||||
--------------------------------
|
||||
|
||||
The Yosys pass :cmd:ref:`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
|
||||
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:
|
||||
|
||||
.. literalinclude:: /code_examples/macro_commands/opt.ys
|
||||
:language: yoscrypt
|
||||
:start-after: #end:
|
||||
:caption: Passes called by :cmd:ref:`opt`
|
||||
:caption: Passes called by `opt`
|
||||
|
||||
.. _adv_opt_expr:
|
||||
|
||||
Constant folding and simple expression rewriting - :cmd:ref:`opt_expr`
|
||||
Constant folding and simple expression rewriting - `opt_expr`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. todo:: unsure if this is too much detail and should be in :doc:`/yosys_internals/index`
|
||||
|
||||
This pass performs constant folding on the internal combinational cell types
|
||||
described in :doc:`/yosys_internals/formats/cell_library`. This means a cell
|
||||
with all constant inputs is replaced with the constant value this cell drives.
|
||||
In some cases this pass can also optimize cells with some constant inputs.
|
||||
described in :doc:`/cell_index`. This means a cell with all
|
||||
constant inputs is replaced with the constant value this cell drives. In some
|
||||
cases this pass can also optimize cells with some constant inputs.
|
||||
|
||||
.. table:: Const folding rules for ``$_AND_`` cells as used in :cmd:ref:`opt_expr`.
|
||||
.. table:: Const folding rules for `$_AND_` cells as used in `opt_expr`.
|
||||
:name: tab:opt_expr_and
|
||||
:align: center
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ In some cases this pass can also optimize cells with some constant inputs.
|
|||
========= ========= ===========
|
||||
|
||||
:numref:`Table %s <tab:opt_expr_and>` shows the replacement rules used for
|
||||
optimizing an ``$_AND_`` gate. The first three rules implement the obvious const
|
||||
optimizing an `$_AND_` gate. The first three rules implement the obvious const
|
||||
folding rules. Note that 'any' might include dynamic values calculated by other
|
||||
parts of the circuit. The following three lines propagate undef (X) states.
|
||||
These are the only three cases in which it is allowed to propagate an undef
|
||||
|
|
@ -66,33 +66,33 @@ substitutions are possible they are performed first, in the hope that the 'any'
|
|||
will change to an undef value or a 1 and therefore the output can be set to
|
||||
undef.
|
||||
|
||||
The last two lines simply replace an ``$_AND_`` gate with one constant-1 input
|
||||
The last two lines simply replace an `$_AND_` gate with one constant-1 input
|
||||
with a buffer.
|
||||
|
||||
Besides this basic const folding the :cmd:ref:`opt_expr` pass can replace 1-bit
|
||||
wide ``$eq`` and ``$ne`` cells with buffers or not-gates if one input is
|
||||
constant. Equality checks may also be reduced in size if there are redundant
|
||||
bits in the arguments (i.e. bits which are constant on both inputs). This can,
|
||||
for example, result in a 32-bit wide constant like ``255`` being reduced to the
|
||||
8-bit value of ``8'11111111`` if the signal being compared is only 8-bit as in
|
||||
Besides this basic const folding the `opt_expr` pass can replace 1-bit wide
|
||||
`$eq` and `$ne` cells with buffers or not-gates if one input is constant.
|
||||
Equality checks may also be reduced in size if there are redundant bits in the
|
||||
arguments (i.e. bits which are constant on both inputs). This can, for example,
|
||||
result in a 32-bit wide constant like ``255`` being reduced to the 8-bit value
|
||||
of ``8'11111111`` if the signal being compared is only 8-bit as in
|
||||
:ref:`addr_gen_clean` of :doc:`/getting_started/example_synth`.
|
||||
|
||||
The :cmd:ref:`opt_expr` pass is very conservative regarding optimizing ``$mux``
|
||||
cells, as these cells are often used to model decision-trees and breaking these
|
||||
trees can interfere with other optimizations.
|
||||
The `opt_expr` pass is very conservative regarding optimizing `$mux` cells, as
|
||||
these cells are often used to model decision-trees and breaking these trees can
|
||||
interfere with other optimizations.
|
||||
|
||||
.. literalinclude:: /code_examples/opt/opt_expr.ys
|
||||
:language: Verilog
|
||||
:start-after: read_verilog <<EOT
|
||||
:end-before: EOT
|
||||
:caption: example verilog for demonstrating :cmd:ref:`opt_expr`
|
||||
:caption: example verilog for demonstrating `opt_expr`
|
||||
|
||||
.. figure:: /_images/code_examples/opt/opt_expr.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
Before and after :cmd:ref:`opt_expr`
|
||||
Before and after `opt_expr`
|
||||
|
||||
Merging identical cells - :cmd:ref:`opt_merge`
|
||||
Merging identical cells - `opt_merge`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This pass performs trivial resource sharing. This means that this pass
|
||||
|
|
@ -100,22 +100,22 @@ identifies cells with identical inputs and replaces them with a single instance
|
|||
of the cell.
|
||||
|
||||
The option ``-nomux`` can be used to disable resource sharing for multiplexer
|
||||
cells (``$mux`` and ``$pmux``.) This can be useful as it prevents multiplexer
|
||||
trees to be merged, which might prevent :cmd:ref:`opt_muxtree` to identify
|
||||
possible optimizations.
|
||||
cells (`$mux` and `$pmux`.) This can be useful as it prevents multiplexer trees
|
||||
to be merged, which might prevent `opt_muxtree` to identify possible
|
||||
optimizations.
|
||||
|
||||
.. literalinclude:: /code_examples/opt/opt_merge.ys
|
||||
:language: Verilog
|
||||
:start-after: read_verilog <<EOT
|
||||
:end-before: EOT
|
||||
:caption: example verilog for demonstrating :cmd:ref:`opt_merge`
|
||||
:caption: example verilog for demonstrating `opt_merge`
|
||||
|
||||
.. figure:: /_images/code_examples/opt/opt_merge.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
Before and after :cmd:ref:`opt_merge`
|
||||
Before and after `opt_merge`
|
||||
|
||||
Removing never-active branches from multiplexer tree - :cmd:ref:`opt_muxtree`
|
||||
Removing never-active branches from multiplexer tree - `opt_muxtree`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This pass optimizes trees of multiplexer cells by analyzing the select inputs.
|
||||
|
|
@ -125,95 +125,97 @@ Consider the following simple example:
|
|||
:language: Verilog
|
||||
:start-after: read_verilog <<EOT
|
||||
:end-before: EOT
|
||||
:caption: example verilog for demonstrating :cmd:ref:`opt_muxtree`
|
||||
:caption: example verilog for demonstrating `opt_muxtree`
|
||||
|
||||
The output can never be ``c``, as this would require ``a`` to be 1 for the outer
|
||||
multiplexer and 0 for the inner multiplexer. The :cmd:ref:`opt_muxtree` pass
|
||||
detects this contradiction and replaces the inner multiplexer with a constant 1,
|
||||
yielding the logic for ``y = a ? b : d``.
|
||||
multiplexer and 0 for the inner multiplexer. The `opt_muxtree` pass detects this
|
||||
contradiction and replaces the inner multiplexer with a constant 1, yielding the
|
||||
logic for ``y = a ? b : d``.
|
||||
|
||||
.. figure:: /_images/code_examples/opt/opt_muxtree.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
Before and after :cmd:ref:`opt_muxtree`
|
||||
Before and after `opt_muxtree`
|
||||
|
||||
Simplifying large MUXes and AND/OR gates - :cmd:ref:`opt_reduce`
|
||||
Simplifying large MUXes and AND/OR gates - `opt_reduce`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is a simple optimization pass that identifies and consolidates identical
|
||||
input bits to ``$reduce_and`` and ``$reduce_or`` cells. It also sorts the input
|
||||
bits to ease identification of shareable ``$reduce_and`` and ``$reduce_or``
|
||||
cells in other passes.
|
||||
input bits to `$reduce_and` and `$reduce_or` cells. It also sorts the input bits
|
||||
to ease identification of shareable `$reduce_and` and `$reduce_or` cells in
|
||||
other passes.
|
||||
|
||||
This pass also identifies and consolidates identical inputs to multiplexer
|
||||
cells. In this case the new shared select bit is driven using a ``$reduce_or``
|
||||
cells. In this case the new shared select bit is driven using a `$reduce_or`
|
||||
cell that combines the original select bits.
|
||||
|
||||
Lastly this pass consolidates trees of ``$reduce_and`` cells and trees of
|
||||
``$reduce_or`` cells to single large ``$reduce_and`` or ``$reduce_or`` cells.
|
||||
Lastly this pass consolidates trees of `$reduce_and` cells and trees of
|
||||
`$reduce_or` cells to single large `$reduce_and` or `$reduce_or` cells.
|
||||
|
||||
These three simple optimizations are performed in a loop until a stable result
|
||||
is produced.
|
||||
|
||||
Merging mutually exclusive cells with shared inputs - :cmd:ref:`opt_share`
|
||||
Merging mutually exclusive cells with shared inputs - `opt_share`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This pass identifies mutually exclusive cells of the same type that:
|
||||
a. share an input signal, and
|
||||
b. drive the same ``$mux``, ``$_MUX_``, or ``$pmux`` multiplexing cell,
|
||||
b. drive the same `$mux`, `$_MUX_`, or `$pmux` multiplexing cell,
|
||||
|
||||
allowing the cell to be merged and the multiplexer to be moved from
|
||||
multiplexing its output to multiplexing the non-shared input signals.
|
||||
allowing the cell to be merged and the multiplexer to be moved from multiplexing
|
||||
its output to multiplexing the non-shared input signals.
|
||||
|
||||
.. literalinclude:: /code_examples/opt/opt_share.ys
|
||||
:language: Verilog
|
||||
:start-after: read_verilog <<EOT
|
||||
:end-before: EOT
|
||||
:caption: example verilog for demonstrating :cmd:ref:`opt_share`
|
||||
:caption: example verilog for demonstrating `opt_share`
|
||||
|
||||
.. figure:: /_images/code_examples/opt/opt_share.*
|
||||
:class: width-helper invert-helper
|
||||
|
||||
Before and after :cmd:ref:`opt_share`
|
||||
Before and after `opt_share`
|
||||
|
||||
When running :cmd:ref:`opt` in full, the original ``$mux`` (labeled ``$3``) is
|
||||
optimized away by :cmd:ref:`opt_expr`.
|
||||
When running `opt` in full, the original `$mux` (labeled ``$3``) is optimized
|
||||
away by `opt_expr`.
|
||||
|
||||
Performing DFF optimizations - :cmd:ref:`opt_dff`
|
||||
Performing DFF optimizations - `opt_dff`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This pass identifies single-bit d-type flip-flops (``$_DFF_``, ``$dff``, and
|
||||
``$adff`` cells) with a constant data input and replaces them with a constant
|
||||
driver. It can also merge clock enables and synchronous reset multiplexers,
|
||||
removing unused control inputs.
|
||||
.. todo:: ``$_DFF_`` isn't a valid cell
|
||||
|
||||
This pass identifies single-bit d-type flip-flops (`$_DFF_`, `$dff`, and `$adff`
|
||||
cells) with a constant data input and replaces them with a constant driver. It
|
||||
can also merge clock enables and synchronous reset multiplexers, removing unused
|
||||
control inputs.
|
||||
|
||||
Called with ``-nodffe`` and ``-nosdff``, this pass is used to prepare a design
|
||||
for :doc:`/using_yosys/synthesis/fsm`.
|
||||
|
||||
Removing unused cells and wires - :cmd:ref:`opt_clean` pass
|
||||
Removing unused cells and wires - `opt_clean` pass
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This pass identifies unused signals and cells and removes them from the design.
|
||||
It also creates an ``\unused_bits`` attribute on wires with unused bits. This
|
||||
It also creates an ``unused_bits`` attribute on wires with unused bits. This
|
||||
attribute can be used for debugging or by other optimization passes.
|
||||
|
||||
When to use :cmd:ref:`opt` or :cmd:ref:`clean`
|
||||
When to use `opt` or `clean`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Usually it does not hurt to call :cmd:ref:`opt` after each regular command in
|
||||
the synthesis script. But it increases the synthesis time, so it is favourable
|
||||
to only call :cmd:ref:`opt` when an improvement can be achieved.
|
||||
Usually it does not hurt to call `opt` after each regular command in the
|
||||
synthesis script. But it increases the synthesis time, so it is favourable to
|
||||
only call `opt` when an improvement can be achieved.
|
||||
|
||||
It is generally a good idea to call :cmd:ref:`opt` before inherently expensive
|
||||
commands such as :cmd:ref:`sat` or :cmd:ref:`freduce`, as the possible gain is
|
||||
much higher in these cases as the possible loss.
|
||||
It is generally a good idea to call `opt` before inherently expensive commands
|
||||
such as `sat` or `freduce`, as the possible gain is much higher in these cases
|
||||
as the possible loss.
|
||||
|
||||
The :cmd:ref:`clean` command, which is an alias for :cmd:ref:`opt_clean` with
|
||||
fewer outputs, on the other hand is very fast and many commands leave a mess
|
||||
(dangling signal wires, etc). For example, most commands do not remove any wires
|
||||
or cells. They just change the connections and depend on a later call to clean
|
||||
to get rid of the now unused objects. So the occasional ``;;``, which itself is
|
||||
an alias for :cmd:ref:`clean`, is a good idea in every synthesis script, e.g:
|
||||
The `clean` command, which is an alias for `opt_clean` with fewer outputs, on
|
||||
the other hand is very fast and many commands leave a mess (dangling signal
|
||||
wires, etc). For example, most commands do not remove any wires or cells. They
|
||||
just change the connections and depend on a later call to clean to get rid of
|
||||
the now unused objects. So the occasional ``;;``, which itself is an alias for
|
||||
`clean`, is a good idea in every synthesis script, e.g:
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
|
||||
|
|
@ -227,4 +229,4 @@ Other optimizations
|
|||
- :doc:`/cmd/wreduce`
|
||||
- :doc:`/cmd/peepopt`
|
||||
- :doc:`/cmd/share`
|
||||
- :cmd:ref:`abc` and :cmd:ref:`abc9`, see also: :doc:`abc`.
|
||||
- `abc` and `abc9`, see also: :doc:`abc`.
|
||||
|
|
|
|||
|
|
@ -5,23 +5,23 @@ Converting process blocks
|
|||
:language: yoscrypt
|
||||
|
||||
The Verilog frontend converts ``always``-blocks to RTL netlists for the
|
||||
expressions and "processess" for the control- and memory elements. The
|
||||
:cmd:ref:`proc` command then transforms these "processess" to netlists of RTL
|
||||
multiplexer and register cells. It also is a macro command that calls the other
|
||||
``proc_*`` commands in a sensible order:
|
||||
expressions and "processess" for the control- and memory elements. The `proc`
|
||||
command then transforms these "processess" to netlists of RTL multiplexer and
|
||||
register cells. It also is a macro command that calls the other ``proc_*``
|
||||
commands in a sensible order:
|
||||
|
||||
.. literalinclude:: /code_examples/macro_commands/proc.ys
|
||||
:language: yoscrypt
|
||||
:start-after: #end:
|
||||
:caption: Passes called by :cmd:ref:`proc`
|
||||
:caption: Passes called by `proc`
|
||||
|
||||
After all the ``proc_*`` commands, :cmd:ref:`opt_expr` is called. This can be
|
||||
disabled by calling :yoscrypt:`proc -noopt`. For more information about
|
||||
:cmd:ref:`proc`, such as disabling certain sub commands, see :doc:`/cmd/proc`.
|
||||
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`.
|
||||
|
||||
Many commands can not operate on modules with "processess" in them. Usually a
|
||||
call to :cmd:ref:`proc` is the first command in the actual synthesis procedure
|
||||
after design elaboration.
|
||||
call to `proc` is the first command in the actual synthesis procedure after
|
||||
design elaboration.
|
||||
|
||||
Example
|
||||
^^^^^^^
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@ In addition to the above hardware-specific synth commands, there is also
|
|||
getting into any architecture-specific mappings or optimizations. Among other
|
||||
things, this is useful for design verification.
|
||||
|
||||
The following commands are executed by the :cmd:ref:`prep` command:
|
||||
The following commands are executed by the `prep` command:
|
||||
|
||||
.. literalinclude:: /cmd/prep.rst
|
||||
:start-at: begin:
|
||||
:end-before: .. raw:: latex
|
||||
:end-before: .. only:: latex
|
||||
:dedent:
|
||||
|
||||
:doc:`/getting_started/example_synth` covers most of these commands and what
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ provided implementation.
|
|||
|
||||
When no map file is provided, techmap uses a built-in map file that maps the
|
||||
Yosys RTL cell types to the internal gate library used by Yosys. The curious
|
||||
reader may find this map file as `techlibs/common/techmap.v` in the Yosys source
|
||||
tree.
|
||||
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
|
||||
|
|
|
|||
44
docs/source/yosys_internals/extending_yosys/contributing.rst
Normal file
44
docs/source/yosys_internals/extending_yosys/contributing.rst
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
Contributing to Yosys
|
||||
=====================
|
||||
|
||||
.. note::
|
||||
|
||||
For information on making a pull request on github, refer to our
|
||||
|CONTRIBUTING|_ file.
|
||||
|
||||
.. |CONTRIBUTING| replace:: :file:`CONTRIBUTING.md`
|
||||
.. _CONTRIBUTING: https://github.com/YosysHQ/yosys/CONTRIBUTING.md
|
||||
|
||||
Coding Style
|
||||
------------
|
||||
|
||||
Formatting of code
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Yosys code is using tabs for indentation. Tabs are 8 characters.
|
||||
|
||||
- A continuation of a statement in the following line is indented by two
|
||||
additional tabs.
|
||||
|
||||
- Lines are as long as you want them to be. A good rule of thumb is to break
|
||||
lines at about column 150.
|
||||
|
||||
- Opening braces can be put on the same or next line as the statement opening
|
||||
the block (if, switch, for, while, do). Put the opening brace on its own line
|
||||
for larger blocks, especially blocks that contains blank lines.
|
||||
|
||||
- Otherwise stick to the `Linux Kernel Coding Style`_.
|
||||
|
||||
.. _Linux Kernel Coding Style: https://www.kernel.org/doc/Documentation/process/coding-style.rst
|
||||
|
||||
|
||||
C++ Language
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Yosys is written in C++17.
|
||||
|
||||
In general Yosys uses ``int`` instead of ``size_t``. To avoid compiler warnings
|
||||
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.
|
||||
|
|
@ -11,17 +11,13 @@ Writing extensions
|
|||
This chapter contains some bits and pieces of information about programming
|
||||
yosys extensions. Don't be afraid to ask questions on the YosysHQ Slack.
|
||||
|
||||
The `guidelines/` directory of the Yosys source code contains notes on various
|
||||
aspects of Yosys development. In particular, the files GettingStarted and
|
||||
CodingStyle may be of interest.
|
||||
|
||||
.. todo:: what's in guidelines/GettingStarted that's missing from the manual?
|
||||
.. todo:: mention coding guide
|
||||
|
||||
Quick guide
|
||||
-----------
|
||||
|
||||
Code examples from this section are included in the
|
||||
|code_examples/extensions|_ directory of the Yosys source code.
|
||||
Code examples from this section are included in the |code_examples/extensions|_
|
||||
directory of the Yosys source code.
|
||||
|
||||
.. |code_examples/extensions| replace:: :file:`docs/source/code_examples/extensions`
|
||||
.. _code_examples/extensions: https://github.com/YosysHQ/yosys/tree/main/docs/source/code_examples/extensions
|
||||
|
|
@ -35,7 +31,7 @@ about the internal data storage format used in Yosys and the classes that it
|
|||
provides.
|
||||
|
||||
This document will focus on the much simpler version of RTLIL left after the
|
||||
commands :cmd:ref:`proc` and :cmd:ref:`memory` (or :yoscrypt:`memory -nomap`):
|
||||
commands `proc` and `memory` (or :yoscrypt:`memory -nomap`):
|
||||
|
||||
.. figure:: /_images/internals/simplified_rtlil.*
|
||||
:class: width-helper invert-helper
|
||||
|
|
@ -56,10 +52,9 @@ It is possible to only work on this simpler version:
|
|||
}
|
||||
|
||||
When trying to understand what a command does, creating a small test case to
|
||||
look at the output of :cmd:ref:`dump` and :cmd:ref:`show` before and after the
|
||||
command has been executed can be helpful.
|
||||
:doc:`/using_yosys/more_scripting/selections` has more information on using
|
||||
these commands.
|
||||
look at the output of `dump` and `show` before and after the command has been
|
||||
executed can be helpful. :doc:`/using_yosys/more_scripting/selections` has more
|
||||
information on using these commands.
|
||||
|
||||
Creating a command
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -151,8 +146,8 @@ Most commands modify existing modules, not create new ones.
|
|||
|
||||
When modifying existing modules, stick to the following DOs and DON'Ts:
|
||||
|
||||
- Do not remove wires. Simply disconnect them and let a successive
|
||||
:cmd:ref:`clean` command worry about removing it.
|
||||
- Do not remove wires. Simply disconnect them and let a successive `clean`
|
||||
command worry about removing it.
|
||||
- Use ``module->fixup_ports()`` after changing the ``port_*`` properties of
|
||||
wires.
|
||||
- You can safely remove cells or change the ``connections`` property of a cell,
|
||||
|
|
|
|||
|
|
@ -1,94 +1,524 @@
|
|||
Writing a new backend using FunctionalIR
|
||||
===========================================
|
||||
========================================
|
||||
|
||||
To simplify the writing of backends for functional languages or similar targets, Yosys provides an alternative intermediate representation called FunctionalIR which maps more directly on those targets.
|
||||
What is FunctionalIR
|
||||
--------------------
|
||||
|
||||
FunctionalIR represents the design as a function ``(inputs, current_state) -> (outputs, next_state)``.
|
||||
This function is broken down into a series of assignments to variables.
|
||||
Each assignment is a simple operation, such as an addition.
|
||||
Complex operations are broken up into multiple steps.
|
||||
For example, an RTLIL addition will be translated into a sign/zero extension of the inputs, followed by an addition.
|
||||
To simplify the writing of backends for functional languages or similar targets,
|
||||
Yosys provides an alternative intermediate representation called FunctionalIR
|
||||
which maps more directly on those targets.
|
||||
|
||||
Like SSA form, each variable is assigned to exactly once.
|
||||
We can thus treat variables and assignments as equivalent and, since this is a graph-like representation, those variables are also called "nodes".
|
||||
Unlike RTLIL's cells and wires representation, this representation is strictly ordered (topologically sorted) with definitions preceding their use.
|
||||
FunctionalIR represents the design as a function ``(inputs, current_state) ->
|
||||
(outputs, next_state)``. This function is broken down into a series of
|
||||
assignments to variables. Each assignment is a simple operation, such as an
|
||||
addition. Complex operations are broken up into multiple steps. For example, an
|
||||
RTLIL addition will be translated into a sign/zero extension of the inputs,
|
||||
followed by an addition.
|
||||
|
||||
Every node has a "sort" (the FunctionalIR term for what might otherwise be called a "type"). The sorts available are
|
||||
Like SSA form, each variable is assigned to exactly once. We can thus treat
|
||||
variables and assignments as equivalent and, since this is a graph-like
|
||||
representation, those variables are also called "nodes". Unlike RTLIL's cells
|
||||
and wires representation, this representation is strictly ordered (topologically
|
||||
sorted) with definitions preceding their use.
|
||||
|
||||
Every node has a "sort" (the FunctionalIR term for what might otherwise be
|
||||
called a "type"). The sorts available are
|
||||
|
||||
- ``bit[n]`` for an ``n``-bit bitvector, and
|
||||
- ``memory[n,m]`` for an immutable array of ``2**n`` values of sort ``bit[m]``.
|
||||
|
||||
In terms of actual code, Yosys provides a class ``Functional::IR`` that represents a design in FunctionalIR.
|
||||
``Functional::IR::from_module`` generates an instance from an RTLIL module.
|
||||
The entire design is stored as a whole in an internal data structure.
|
||||
To access the design, the ``Functional::Node`` class provides a reference to a particular node in the design.
|
||||
The ``Functional::IR`` class supports the syntax ``for(auto node : ir)`` to iterate over every node.
|
||||
In terms of actual code, Yosys provides a class ``Functional::IR`` that
|
||||
represents a design in FunctionalIR. ``Functional::IR::from_module`` generates
|
||||
an instance from an RTLIL module. The entire design is stored as a whole in an
|
||||
internal data structure. To access the design, the ``Functional::Node`` class
|
||||
provides a reference to a particular node in the design. The ``Functional::IR``
|
||||
class supports the syntax ``for(auto node : ir)`` to iterate over every node.
|
||||
|
||||
``Functional::IR`` also keeps track of inputs, outputs and states.
|
||||
By a "state" we mean a pair of a "current state" input and a "next state" output.
|
||||
One such pair is created for every register and for every memory.
|
||||
Every input, output and state has a name (equal to their name in RTLIL), a sort and a kind.
|
||||
The kind field usually remains as the default value ``$input``, ``$output`` or ``$state``, however some RTLIL cells such as ``$assert`` or ``$anyseq`` generate auxiliary inputs/outputs/states that are given a different kind to distinguish them from ordinary RTLIL inputs/outputs/states.
|
||||
``Functional::IR`` also keeps track of inputs, outputs and states. By a "state"
|
||||
we mean a pair of a "current state" input and a "next state" output. One such
|
||||
pair is created for every register and for every memory. Every input, output and
|
||||
state has a name (equal to their name in RTLIL), a sort and a kind. The kind
|
||||
field usually remains as the default value ``$input``, ``$output`` or
|
||||
``$state``, however some RTLIL cells such as ``$assert`` or ``$anyseq`` generate
|
||||
auxiliary inputs/outputs/states that are given a different kind to distinguish
|
||||
them from ordinary RTLIL inputs/outputs/states.
|
||||
|
||||
- To access an individual input/output/state, use ``ir.input(name, kind)``, ``ir.output(name, kind)`` or ``ir.state(name, kind)``. ``kind`` defaults to the default kind.
|
||||
- To iterate over all inputs/outputs/states of a certain kind, methods ``ir.inputs``, ``ir.outputs``, ``ir.states`` are provided. Their argument defaults to the default kinds mentioned.
|
||||
- To iterate over inputs/outputs/states of any kind, use ``ir.all_inputs``, ``ir.all_outputs`` and ``ir.all_states``.
|
||||
- Outputs have a node that indicate the value of the output, this can be retrieved via ``output.value()``.
|
||||
- States have a node that indicate the next value of the state, this can be retrieved via ``state.next_value()``.
|
||||
They also have an initial value that is accessed as either ``state.initial_value_signal()`` or ``state.initial_value_memory()``, depending on their sort.
|
||||
- To access an individual input/output/state, use ``ir.input(name, kind)``,
|
||||
``ir.output(name, kind)`` or ``ir.state(name, kind)``. ``kind`` defaults to
|
||||
the default kind.
|
||||
- To iterate over all inputs/outputs/states of a certain kind, methods
|
||||
``ir.inputs``, ``ir.outputs``, ``ir.states`` are provided. Their argument
|
||||
defaults to the default kinds mentioned.
|
||||
- To iterate over inputs/outputs/states of any kind, use ``ir.all_inputs``,
|
||||
``ir.all_outputs`` and ``ir.all_states``.
|
||||
- Outputs have a node that indicate the value of the output, this can be
|
||||
retrieved via ``output.value()``.
|
||||
- States have a node that indicate the next value of the state, this can be
|
||||
retrieved via ``state.next_value()``. They also have an initial value that is
|
||||
accessed as either ``state.initial_value_signal()`` or
|
||||
``state.initial_value_memory()``, depending on their sort.
|
||||
|
||||
Each node has a "function", which defines its operation (for a complete list of functions and a specification of their operation, see ``functional.h``).
|
||||
Functions are represented as an enum ``Functional::Fn`` and the function field can be accessed as ``node.fn()``.
|
||||
Since the most common operation is a switch over the function that also accesses the arguments, the ``Node`` class provides a method ``visit`` that implements the visitor pattern.
|
||||
For example, for an addition node ``node`` with arguments ``n1`` and ``n2``, ``node.visit(visitor)`` would call ``visitor.add(node, n1, n2)``.
|
||||
Thus typically one would implement a class with a method for every function.
|
||||
Visitors should inherit from either ``Functional::AbstractVisitor<ReturnType>`` or ``Functional::DefaultVisitor<ReturnType>``.
|
||||
The former will produce a compiler error if a case is unhandled, the latter will call ``default_handler(node)`` instead.
|
||||
Visitor methods should be marked as ``override`` to provide compiler errors if the arguments are wrong.
|
||||
Each node has a "function", which defines its operation (for a complete list of
|
||||
functions and a specification of their operation, see ``functional.h``).
|
||||
Functions are represented as an enum ``Functional::Fn`` and the function field
|
||||
can be accessed as ``node.fn()``. Since the most common operation is a switch
|
||||
over the function that also accesses the arguments, the ``Node`` class provides
|
||||
a method ``visit`` that implements the visitor pattern. For example, for an
|
||||
addition node ``node`` with arguments ``n1`` and ``n2``, ``node.visit(visitor)``
|
||||
would call ``visitor.add(node, n1, n2)``. Thus typically one would implement a
|
||||
class with a method for every function. Visitors should inherit from either
|
||||
``Functional::AbstractVisitor<ReturnType>`` or
|
||||
``Functional::DefaultVisitor<ReturnType>``. The former will produce a compiler
|
||||
error if a case is unhandled, the latter will call ``default_handler(node)``
|
||||
instead. Visitor methods should be marked as ``override`` to provide compiler
|
||||
errors if the arguments are wrong.
|
||||
|
||||
Utility classes
|
||||
-----------------
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
``functional.h`` also provides utility classes that are independent of the main FunctionalIR representation but are likely to be useful for backends.
|
||||
``functional.h`` also provides utility classes that are independent of the main
|
||||
FunctionalIR representation but are likely to be useful for backends.
|
||||
|
||||
``Functional::Writer`` provides a simple formatting class that wraps a ``std::ostream`` and provides the following methods:
|
||||
``Functional::Writer`` provides a simple formatting class that wraps a
|
||||
``std::ostream`` and provides the following methods:
|
||||
|
||||
- ``writer << value`` wraps ``os << value``.
|
||||
- ``writer.print(fmt, value0, value1, value2, ...)`` replaces ``{0}``, ``{1}``, ``{2}``, etc in the string ``fmt`` with ``value0``, ``value1``, ``value2``, resp.
|
||||
Each value is formatted using ``os << value``.
|
||||
It is also possible to write ``{}`` to refer to one past the last index, i.e. ``{1} {} {} {7} {}`` is equivalent to ``{1} {2} {3} {7} {8}``.
|
||||
- ``writer.print_with(fn, fmt, value0, value1, value2, ...)`` functions much the same as ``print`` but it uses ``os << fn(value)`` to print each value and falls back to ``os << value`` if ``fn(value)`` is not legal.
|
||||
- ``writer.print(fmt, value0, value1, value2, ...)`` replaces ``{0}``, ``{1}``,
|
||||
``{2}``, etc in the string ``fmt`` with ``value0``, ``value1``, ``value2``,
|
||||
resp. Each value is formatted using ``os << value``. It is also possible to
|
||||
write ``{}`` to refer to one past the last index, i.e. ``{1} {} {} {7} {}`` is
|
||||
equivalent to ``{1} {2} {3} {7} {8}``.
|
||||
- ``writer.print_with(fn, fmt, value0, value1, value2, ...)`` functions much the
|
||||
same as ``print`` but it uses ``os << fn(value)`` to print each value and
|
||||
falls back to ``os << value`` if ``fn(value)`` is not legal.
|
||||
|
||||
``Functional::Scope`` keeps track of variable names in a target language.
|
||||
It is used to translate between different sets of legal characters and to avoid accidentally re-defining identifiers.
|
||||
Users should derive a class from ``Scope`` and supply the following:
|
||||
``Functional::Scope`` keeps track of variable names in a target language. It is
|
||||
used to translate between different sets of legal characters and to avoid
|
||||
accidentally re-defining identifiers. Users should derive a class from ``Scope``
|
||||
and supply the following:
|
||||
|
||||
- ``Scope<Id>`` takes a template argument that specifies a type that's used to uniquely distinguish variables.
|
||||
Typically this would be ``int`` (if variables are used for ``Functional::IR`` nodes) or ``IdString``.
|
||||
- The derived class should provide a constructor that calls ``reserve`` for every reserved word in the target language.
|
||||
- A method ``bool is_legal_character(char c, int index)`` has to be provided that returns ``true`` iff ``c`` is legal in an identifier at position ``index``.
|
||||
- ``Scope<Id>`` takes a template argument that specifies a type that's used to
|
||||
uniquely distinguish variables. Typically this would be ``int`` (if variables
|
||||
are used for ``Functional::IR`` nodes) or ``IdString``.
|
||||
- The derived class should provide a constructor that calls ``reserve`` for
|
||||
every reserved word in the target language.
|
||||
- A method ``bool is_character_legal(char c, int index)`` has to be provided
|
||||
that returns ``true`` iff ``c`` is legal in an identifier at position
|
||||
``index``.
|
||||
|
||||
Given an instance ``scope`` of the derived class, the following methods are then available:
|
||||
Given an instance ``scope`` of the derived class, the following methods are then
|
||||
available:
|
||||
|
||||
- ``scope.reserve(std::string name)`` marks the given name as being in-use
|
||||
- ``scope.unique_name(IdString suggestion)`` generates a previously unused name and attempts to make it similar to ``suggestion``.
|
||||
- ``scope(Id id, IdString suggestion)`` functions similar to ``unique_name``, except that multiple calls with the same ``id`` are guaranteed to retrieve the same name (independent of ``suggestion``).
|
||||
- ``scope.unique_name(IdString suggestion)`` generates a previously unused name
|
||||
and attempts to make it similar to ``suggestion``.
|
||||
- ``scope(Id id, IdString suggestion)`` functions similar to ``unique_name``,
|
||||
except that multiple calls with the same ``id`` are guaranteed to retrieve the
|
||||
same name (independent of ``suggestion``).
|
||||
|
||||
``sexpr.h`` provides classes that represent and pretty-print s-expressions.
|
||||
S-expressions can be constructed with ``SExpr::list``, for example ``SExpr expr = SExpr::list("add", "x", SExpr::list("mul", "y", "z"))`` represents ``(add x (mul y z))``
|
||||
(by adding ``using SExprUtil::list`` to the top of the file, ``list`` can be used as shorthand for ``SExpr::list``).
|
||||
For prettyprinting, ``SExprWriter`` wraps an ``std::ostream`` and provides the following methods:
|
||||
S-expressions can be constructed with ``SExpr::list``, for example ``SExpr expr
|
||||
= SExpr::list("add", "x", SExpr::list("mul", "y", "z"))`` represents ``(add x
|
||||
(mul y z))`` (by adding ``using SExprUtil::list`` to the top of the file,
|
||||
``list`` can be used as shorthand for ``SExpr::list``). For prettyprinting,
|
||||
``SExprWriter`` wraps an ``std::ostream`` and provides the following methods:
|
||||
|
||||
- ``writer << sexpr`` writes the provided expression to the output, breaking long lines and adding appropriate indentation.
|
||||
- ``writer.open(sexpr)`` is similar to ``writer << sexpr`` but will omit the last closing parenthesis.
|
||||
Further arguments can then be added separately with ``<<`` or ``open``.
|
||||
This allows for printing large s-expressions without needing to construct the whole expression in memory first.
|
||||
- ``writer.open(sexpr, false)`` is similar to ``writer.open(sexpr)`` but further arguments will not be indented.
|
||||
This is used to avoid unlimited indentation on structures with unlimited nesting.
|
||||
- ``writer << sexpr`` writes the provided expression to the output, breaking
|
||||
long lines and adding appropriate indentation.
|
||||
- ``writer.open(sexpr)`` is similar to ``writer << sexpr`` but will omit the
|
||||
last closing parenthesis. Further arguments can then be added separately with
|
||||
``<<`` or ``open``. This allows for printing large s-expressions without
|
||||
needing to construct the whole expression in memory first.
|
||||
- ``writer.open(sexpr, false)`` is similar to ``writer.open(sexpr)`` but further
|
||||
arguments will not be indented. This is used to avoid unlimited indentation on
|
||||
structures with unlimited nesting.
|
||||
- ``writer.close(n = 1)`` closes the last ``n`` open s-expressions.
|
||||
- ``writer.push()`` and ``writer.pop()`` are used to automatically close s-expressions.
|
||||
``writer.pop()`` closes all s-expressions opened since the last call to ``writer.push()``.
|
||||
- ``writer.push()`` and ``writer.pop()`` are used to automatically close
|
||||
s-expressions. ``writer.pop()`` closes all s-expressions opened since the last
|
||||
call to ``writer.push()``.
|
||||
- ``writer.comment(string)`` writes a comment on a separate-line.
|
||||
``writer.comment(string, true)`` appends a comment to the last printed s-expression.
|
||||
- ``writer.flush()`` flushes any buffering and should be called before any direct access to the underlying ``std::ostream``. It does not close unclosed parentheses.
|
||||
``writer.comment(string, true)`` appends a comment to the last printed
|
||||
s-expression.
|
||||
- ``writer.flush()`` flushes any buffering and should be called before any
|
||||
direct access to the underlying ``std::ostream``. It does not close unclosed
|
||||
parentheses.
|
||||
- The destructor calls ``flush`` but also closes all unclosed parentheses.
|
||||
|
||||
.. _minimal backend:
|
||||
|
||||
Example: A minimal functional backend
|
||||
-------------------------------------
|
||||
|
||||
At its most basic, there are three steps we need to accomplish for a minimal
|
||||
functional backend. First, we need to convert our design into FunctionalIR.
|
||||
This is most easily done by calling the ``Functional::IR::from_module()`` static
|
||||
method with our top-level module, or iterating over and converting each of the
|
||||
modules in our design. Second, we need to handle each of the
|
||||
``Functional::Node``\ s in our design. Iterating over the ``Functional::IR``
|
||||
includes reading the module inputs and current state, but not writing the
|
||||
results. So our final step is to handle the outputs and next state.
|
||||
|
||||
In order to add an output command to Yosys, we implement the ``Yosys::Backend``
|
||||
class and provide an instance of it:
|
||||
|
||||
.. literalinclude:: /code_examples/functional/dummy.cc
|
||||
:language: c++
|
||||
:caption: Example source code for a minimal functional backend, ``dummy.cc``
|
||||
|
||||
Because we are using the ``Backend`` class, our ``"functional_dummy"`` is
|
||||
registered as the ``write_functional_dummy`` command. The ``execute`` method is
|
||||
the part that runs when the user calls the command, handling any options,
|
||||
preparing the output file for writing, and iterating over selected modules in
|
||||
the design. Since we don't have any options here, we set ``argidx = 1`` and
|
||||
call the ``extra_args()`` method. This method will read the command arguments,
|
||||
raising an error if there are any unexpected ones. It will also assign the
|
||||
pointer ``f`` to the output file, or stdout if none is given.
|
||||
|
||||
.. note::
|
||||
|
||||
For more on adding new commands to Yosys and how they work, refer to
|
||||
:doc:`/yosys_internals/extending_yosys/extensions`.
|
||||
|
||||
For this minimal example all we are doing is printing out each node. The
|
||||
``node.name()`` method returns an ``RTLIL::IdString``, which we convert for
|
||||
printing with ``id2cstr()``. Then, to print the function of the node, we use
|
||||
``node.to_string()`` which gives us a string of the form ``function(args)``. The
|
||||
``function`` part is the result of ``Functional::IR::fn_to_string(node.fn())``;
|
||||
while ``args`` is the zero or more arguments passed to the function, most
|
||||
commonly the name of another node. Behind the scenes, the ``node.to_string()``
|
||||
method actually wraps ``node.visit(visitor)`` with a private visitor whose
|
||||
return type is ``std::string``.
|
||||
|
||||
Finally we iterate over the module's outputs and states, using
|
||||
``Functional::IROutput::value()`` and ``Functional::IRState::next_value()``
|
||||
respectively in order to get the results of the transfer function.
|
||||
|
||||
Example: Adapting SMT-LIB backend for Rosette
|
||||
---------------------------------------------
|
||||
|
||||
This section will introduce the SMT-LIB functional backend
|
||||
(`write_functional_smt2`) and what changes are needed to work with another
|
||||
s-expression target, `Rosette`_ (`write_functional_rosette`).
|
||||
|
||||
.. _Rosette: http://emina.github.io/rosette/
|
||||
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
Rosette is a solver-aided programming language that extends `Racket`_ with
|
||||
language constructs for program synthesis, verification, and more. To verify
|
||||
or synthesize code, Rosette compiles it to logical constraints solved with
|
||||
off-the-shelf `SMT`_ solvers.
|
||||
|
||||
-- https://emina.github.io/rosette/
|
||||
|
||||
.. _Racket: http://racket-lang.org/
|
||||
.. _SMT: http://smtlib.cs.uiowa.edu/
|
||||
|
||||
Rosette, being backed by SMT solvers and written with s-expressions, uses code
|
||||
very similar to the `write_functional_smt2` output. As a result, the SMT-LIB
|
||||
functional backend can be used as a starting point for implementing a Rosette
|
||||
backend.
|
||||
|
||||
Full code listings for the initial SMT-LIB backend and the converted Rosette
|
||||
backend are included in the Yosys source repository under
|
||||
:file:`backends/functional` as ``smtlib.cc`` and ``smtlib_rosette.cc``
|
||||
respectively. Note that the Rosette language is an extension of the Racket
|
||||
language; this guide tends to refer to Racket when talking about the underlying
|
||||
semantics/syntax of the language.
|
||||
|
||||
The major changes from the SMT-LIB backend are as follows:
|
||||
|
||||
- all of the ``Smt`` prefixes in names are replaced with ``Smtr`` to mean
|
||||
``smtlib_rosette``;
|
||||
- syntax is adjusted for Racket;
|
||||
- data structures for input/output/state are changed from using
|
||||
``declare-datatype`` with statically typed fields, to using ``struct`` with no
|
||||
static typing;
|
||||
- the transfer function also loses its static typing;
|
||||
- sign/zero extension in Rosette use the output width instead of the number of
|
||||
extra bits, gaining static typing;
|
||||
- the single scope is traded for a global scope with local scope for each
|
||||
struct;
|
||||
- initial state is provided as a constant value instead of a set of assertions;
|
||||
- and the ``-provides`` option is introduced to more easily use generated code
|
||||
within Rosette based applications.
|
||||
|
||||
Scope
|
||||
~~~~~
|
||||
|
||||
Our first addition to the `minimal backend`_ above is that for both SMT-LIB and
|
||||
Rosette backends, we are now targetting real languages which bring with them
|
||||
their own sets of constraints with what we can use as identifiers. This is
|
||||
where the ``Functional::Scope`` class described above comes in; by using this
|
||||
class we can safely rename our identifiers in the generated output without
|
||||
worrying about collisions or illegal names/characters.
|
||||
|
||||
In the SMT-LIB version, the ``SmtScope`` class implements ``Scope<int>``;
|
||||
provides a constructor that iterates over a list of reserved keywords, calling
|
||||
``reserve`` on each; and defines the ``is_character_legal`` method to reject any
|
||||
characters which are not allowed in SMT-LIB variable names to then be replaced
|
||||
with underscores in the output. To use this scope we create an instance of it,
|
||||
and call the ``Scope::unique_name()`` method to generate a unique and legal name
|
||||
for each of our identifiers.
|
||||
|
||||
In the Rosette version we update the list of legal ascii characters in the
|
||||
``is_character_legal`` method to only those allowed in Racket variable names.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``Scope`` class
|
||||
:start-at: -struct SmtScope : public Functional::Scope<int> {
|
||||
:end-at: };
|
||||
|
||||
For the reserved keywords we trade the SMT-LIB specification for Racket to
|
||||
prevent parts of our design from accidentally being treated as Racket code. We
|
||||
also no longer need to reserve ``pair``, ``first``, and ``second``. In
|
||||
`write_functional_smt2` these are used for combining the ``(inputs,
|
||||
current_state)`` and ``(outputs, next_state)`` into a single variable. Racket
|
||||
provides this functionality natively with ``cons``, which we will see later.
|
||||
|
||||
.. inlined diff for skipping the actual lists
|
||||
.. code-block:: diff
|
||||
:caption: diff of ``reserved_keywords`` list
|
||||
|
||||
const char *reserved_keywords[] = {
|
||||
- // reserved keywords from the smtlib spec
|
||||
- ...
|
||||
+ // reserved keywords from the racket spec
|
||||
+ ...
|
||||
|
||||
// reserved for our own purposes
|
||||
- "pair", "Pair", "first", "second",
|
||||
- "inputs", "state",
|
||||
+ "inputs", "state", "name",
|
||||
nullptr
|
||||
};
|
||||
|
||||
.. note:: We skip over the actual list of reserved keywords from both the smtlib
|
||||
and racket specifications to save on space in this document.
|
||||
|
||||
Sort
|
||||
~~~~
|
||||
|
||||
Next up in `write_functional_smt2` we see the ``Sort`` class. This is a wrapper
|
||||
for the ``Functional::Sort`` class, providing the additional functionality of
|
||||
mapping variable declarations to s-expressions with the ``to_sexpr()`` method.
|
||||
The main change from ``SmtSort`` to ``SmtrSort`` is a syntactical one with
|
||||
signals represented as ``bitvector``\ s, and memories as ``list``\ s of signals.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``Sort`` wrapper
|
||||
:start-at: SExpr to_sexpr() const {
|
||||
:end-before: };
|
||||
|
||||
Struct
|
||||
~~~~~~
|
||||
|
||||
As we saw in the `minimal backend`_ above, the ``Functional::IR`` class tracks
|
||||
the set of inputs, the set of outputs, and the set of "state" variables. The
|
||||
SMT-LIB backend maps each of these sets into its own ``SmtStruct``, with each
|
||||
variable getting a corresponding field in the struct and a specified `Sort`_.
|
||||
`write_functional_smt2` then defines each of these structs as a new
|
||||
``datatype``, with each element being strongly-typed.
|
||||
|
||||
In Rosette, rather than defining new datatypes for our structs, we use the
|
||||
native ``struct``. We also only declare each field by name because Racket
|
||||
provides less static typing. For ease of use, we provide the expected type for
|
||||
each field as comments.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``write_definition`` method
|
||||
:start-at: void write_definition
|
||||
:end-before: template<typename Fn> void write_value
|
||||
|
||||
Each field is added to the ``SmtStruct`` with the ``insert`` method, which also
|
||||
reserves a unique name (or accessor) within the `Scope`_. These accessors
|
||||
combine the struct name and field name and are globally unique, being used in
|
||||
the ``access`` method for reading values from the input/current state.
|
||||
|
||||
.. literalinclude:: /generated/functional/smtlib.cc
|
||||
:language: c++
|
||||
:caption: ``Struct::access()`` method
|
||||
:start-at: SExpr access(
|
||||
:end-before: };
|
||||
|
||||
In Rosette, struct fields are accessed as ``<struct_name>-<field_name>`` so
|
||||
including the struct name in the field name would be redundant. For
|
||||
`write_functional_rosette` we instead choose to make field names unique only
|
||||
within the struct, while accessors are unique across the whole module. We thus
|
||||
modify the class constructor and ``insert`` method to support this; providing
|
||||
one scope that is local to the struct (``local_scope``) and one which is shared
|
||||
across the whole module (``global_scope``), leaving the ``access`` method
|
||||
unchanged.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of struct constructor
|
||||
:start-at: SmtStruct(std::string name, SmtScope &scope)
|
||||
:end-before: void write_definition
|
||||
|
||||
Finally, ``SmtStruct`` also provides a ``write_value`` template method which
|
||||
calls a provided function on each element in the struct. This is used later for
|
||||
assigning values to the output/next state pair. The only change here is to
|
||||
remove the check for zero-argument constructors since this is not necessary with
|
||||
Rosette ``struct``\ s.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``write_value`` method
|
||||
:start-at: template<typename Fn> void write_value
|
||||
:end-before: SExpr access
|
||||
|
||||
PrintVisitor
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Remember in the `minimal backend`_ we converted nodes into strings for writing
|
||||
using the ``node.to_string()`` method, which wrapped ``node.visit()`` with a
|
||||
private visitor. We now want a custom visitor which can convert nodes into
|
||||
s-expressions. This is where the ``PrintVisitor`` comes in, implementing the
|
||||
abstract ``Functional::AbstractVisitor`` class with a return type of ``SExpr``.
|
||||
For most functions, the Rosette output is very similar to the corresponding
|
||||
SMT-LIB function with minor adjustments for syntax.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: portion of ``Functional::AbstractVisitor`` implementation diff showing similarities
|
||||
:start-at: SExpr logical_shift_left
|
||||
:end-at: "list-set-bv"
|
||||
|
||||
However there are some differences in the two formats with regards to how
|
||||
booleans are handled, with Rosette providing built-in functions for conversion.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: portion of ``Functional::AbstractVisitor`` implementation diff showing differences
|
||||
:start-at: SExpr from_bool
|
||||
:end-before: SExpr extract
|
||||
|
||||
Of note here is the rare instance of the Rosette implementation *gaining* static
|
||||
typing rather than losing it. Where SMT_LIB calls zero/sign extension with the
|
||||
number of extra bits needed (given by ``out_width - a.width()``), Rosette
|
||||
instead specifies the type of the output (given by ``list("bitvector",
|
||||
out_width)``).
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: zero/sign extension implementation diff
|
||||
:start-after: SExpr buf(
|
||||
:end-before: SExpr concat(
|
||||
:lines: 2-3, 5-6
|
||||
|
||||
.. note:: Be sure to check the source code for the full list of differences here.
|
||||
|
||||
Module
|
||||
~~~~~~
|
||||
|
||||
With most of the supporting classes out of the way, we now reach our three main
|
||||
steps from the `minimal backend`_. These are all handled by the ``SmtModule``
|
||||
class, with the mapping from RTLIL module to FunctionalIR happening in the
|
||||
constructor. Each of the three ``SmtStruct``\ s; inputs, outputs, and state;
|
||||
are also created in the constructor, with each value in the corresponding lists
|
||||
in the IR being ``insert``\ ed.
|
||||
|
||||
.. literalinclude:: /generated/functional/smtlib.cc
|
||||
:language: c++
|
||||
:caption: ``SmtModule`` constructor
|
||||
:start-at: SmtModule(Module
|
||||
:end-at: }
|
||||
|
||||
Since Racket uses the ``-`` to access struct fields, the ``SmtrModule`` instead
|
||||
uses an underscore for the name of the initial state.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``Module`` constructor
|
||||
:start-at: scope.reserve(name
|
||||
:end-before: for (auto input
|
||||
|
||||
The ``write`` method is then responsible for writing the FunctionalIR to the
|
||||
output file, formatted for the corresponding backend. ``SmtModule::write()``
|
||||
breaks the output file down into four parts: defining the three structs,
|
||||
declaring the ``pair`` datatype, defining the transfer function ``(inputs,
|
||||
current_state) -> (outputs, next_state)`` with ``write_eval``, and declaring the
|
||||
initial state with ``write_initial``. The only change for the ``SmtrModule`` is
|
||||
that the ``pair`` declaration isn't needed.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``Module::write()`` method
|
||||
:start-at: void write(std::ostream &out)
|
||||
:end-at: }
|
||||
|
||||
The ``write_eval`` method is where the FunctionalIR nodes, outputs, and next
|
||||
state are handled. Just as with the `minimal backend`_, we iterate over the
|
||||
nodes with ``for(auto n : ir)``, and then use the ``Struct::write_value()``
|
||||
method for the ``output_struct`` and ``state_struct`` to iterate over the
|
||||
outputs and next state respectively.
|
||||
|
||||
.. literalinclude:: /generated/functional/smtlib.cc
|
||||
:language: c++
|
||||
:caption: iterating over FunctionalIR nodes in ``SmtModule::write_eval()``
|
||||
:start-at: for(auto n : ir)
|
||||
:end-at: }
|
||||
|
||||
The main differences between our two backends here are syntactical. First we
|
||||
change the ``define-fun`` for the Racket style ``define`` which drops the
|
||||
explicitly typed inputs/outputs. And then we change the final result from a
|
||||
``pair`` to the native ``cons`` which acts in much the same way, returning both
|
||||
the ``outputs`` and the ``next_state`` in a single variable.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``Module::write_eval()`` transfer function declaration
|
||||
:start-at: w.open(list("define-fun"
|
||||
:end-at: w.open(list("define"
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of output/next state handling ``Module::write_eval()``
|
||||
:start-at: w.open(list("pair"
|
||||
:end-at: w.pop();
|
||||
|
||||
For the ``write_initial`` method, the SMT-LIB backend uses ``declare-const`` and
|
||||
``assert``\ s which must always hold true. For Rosette we instead define the
|
||||
initial state as any other variable that can be used by external code. This
|
||||
variable, ``[name]_initial``, can then be used in the ``[name]`` function call;
|
||||
allowing the Rosette code to be used in the generation of the ``next_state``,
|
||||
whereas the SMT-LIB code can only verify that a given ``next_state`` is correct.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: diff of ``Module::write_initial()`` method
|
||||
:start-at: void write_initial
|
||||
:end-before: void write
|
||||
|
||||
Backend
|
||||
~~~~~~~
|
||||
|
||||
The final part is the ``Backend`` itself, with much of the same boiler plate as
|
||||
the `minimal backend`_. The main difference is that we use the `Module`_ to
|
||||
perform the actual processing.
|
||||
|
||||
.. literalinclude:: /generated/functional/smtlib.cc
|
||||
:language: c++
|
||||
:caption: The ``FunctionalSmtBackend``
|
||||
:start-at: struct FunctionalSmtBackend
|
||||
:end-at: } FunctionalSmtBackend;
|
||||
|
||||
There are two additions here for Rosette. The first is that the output file
|
||||
needs to start with the ``#lang`` definition which tells the
|
||||
compiler/interpreter that we want to use the Rosette language module. The
|
||||
second is that the `write_functional_rosette` command takes an optional
|
||||
argument, ``-provides``. If this argument is given, then the output file gets
|
||||
an additional line declaring that everything in the file should be exported for
|
||||
use; allowing the file to be treated as a Racket package with structs and
|
||||
mapping function available for use externally.
|
||||
|
||||
.. literalinclude:: /generated/functional/rosette.diff
|
||||
:language: diff
|
||||
:caption: relevant portion of diff of ``Backend::execute()`` method
|
||||
:start-at: lang rosette/safe
|
||||
:end-before: for (auto module
|
||||
|
|
|
|||
|
|
@ -11,5 +11,6 @@ of interest for developers looking to customise Yosys builds.
|
|||
extensions
|
||||
build_verific
|
||||
functional_ir
|
||||
contributing
|
||||
test_suites
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
Testing Yosys
|
||||
=============
|
||||
|
||||
.. todo:: more about the included test suite
|
||||
.. TODO:: more about the included test suite and how to add tests
|
||||
|
||||
Automatic testing
|
||||
-----------------
|
||||
|
|
@ -23,3 +23,79 @@ For up to date information, including OS versions, refer to `the git actions
|
|||
page`_.
|
||||
|
||||
.. _the git actions page: https://github.com/YosysHQ/yosys/actions
|
||||
|
||||
.. todo:: are unit tests currently working
|
||||
|
||||
..
|
||||
How to add a unit test
|
||||
----------------------
|
||||
|
||||
Unit test brings some advantages, briefly, we can list some of them (reference
|
||||
[1](https://en.wikipedia.org/wiki/Unit_testing)):
|
||||
|
||||
* Tests reduce bugs in new features;
|
||||
* Tests reduce bugs in existing features;
|
||||
* Tests are good documentation;
|
||||
* Tests reduce the cost of change;
|
||||
* Tests allow refactoring;
|
||||
|
||||
With those advantages in mind, it was required to choose a framework which fits
|
||||
well with C/C++ code. Hence, `google test`_ was chosen, because it is widely
|
||||
used and it is relatively easy learn.
|
||||
|
||||
.. _google test: https://github.com/google/googletest
|
||||
|
||||
Install and configure google test (manually)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In this section, you will see a brief description of how to install google test.
|
||||
However, it is strongly recommended that you take a look to the official
|
||||
repository (https://github.com/google/googletest) and refers to that if you have
|
||||
any problem to install it. Follow the steps below:
|
||||
|
||||
* Install: cmake and pthread
|
||||
* Clone google test project from: https://github.com/google/googletest and enter
|
||||
in the project directory
|
||||
* Inside project directory, type:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cmake -DBUILD_SHARED_LIBS=ON .
|
||||
make
|
||||
|
||||
* After compilation, copy all ``*.so`` inside directory ``googlemock`` and
|
||||
``googlemock/gtest`` to ``/usr/lib/``
|
||||
* Done! Now you can compile your tests.
|
||||
|
||||
If you have any problem, go to the official repository to find help.
|
||||
|
||||
Ps.: Some distros already have googletest packed. If your distro supports it,
|
||||
you can use it instead of compile.
|
||||
|
||||
Create a new unit test
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you want to add new unit tests for Yosys, just follow the steps below:
|
||||
|
||||
* Go to directory :file:`test/unit/`
|
||||
* In this directory you can find something similar Yosys's directory structure.
|
||||
To create your unit test file you have to follow this pattern:
|
||||
fileNameToImplementUnitTest + Test.cc. E.g.: if you want to implement the unit
|
||||
test for ``kernel/celledges.cc``, you will need to create a file like this:
|
||||
``tests/unit/kernel/celledgesTest.cc``;
|
||||
* Implement your unit test
|
||||
|
||||
Run unit tests
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
To compile and run all unit tests, just go to yosys root directory and type:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
make unit-test
|
||||
|
||||
If you want to remove all unit test files, type:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
make clean-unit-test
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ given in :doc:`/yosys_internals/formats/rtlil_rep`.
|
|||
|
||||
There is also a text representation of the RTLIL data structure that can be
|
||||
parsed using the RTLIL Frontend which is described in
|
||||
:doc:`/yosys_internals/formats/rtlil_text`.
|
||||
:doc:`/appendix/rtlil_text`.
|
||||
|
||||
The design data may then be transformed using a series of passes that all
|
||||
operate on the RTLIL representation of the design.
|
||||
|
|
|
|||
|
|
@ -599,16 +599,16 @@ The proc pass
|
|||
|
||||
The ProcessGenerator converts a behavioural model in AST representation to a
|
||||
behavioural model in ``RTLIL::Process`` representation. The actual conversion
|
||||
from a behavioural model to an RTL representation is performed by the
|
||||
:cmd:ref:`proc` pass and the passes it launches:
|
||||
from a behavioural model to an RTL representation is performed by the `proc`
|
||||
pass and the passes it launches:
|
||||
|
||||
- | :cmd:ref:`proc_clean` and :cmd:ref:`proc_rmdead`
|
||||
- | `proc_clean` and `proc_rmdead`
|
||||
| These two passes just clean up the ``RTLIL::Process`` structure. The
|
||||
:cmd:ref:`proc_clean` pass removes empty parts (eg. empty assignments) from
|
||||
the process and :cmd:ref:`proc_rmdead` detects and removes unreachable
|
||||
branches from the process's decision trees.
|
||||
`proc_clean` pass removes empty parts (eg. empty assignments) from the
|
||||
process and `proc_rmdead` detects and removes unreachable branches from the
|
||||
process's decision trees.
|
||||
|
||||
- | :cmd:ref:`proc_arst`
|
||||
- | `proc_arst`
|
||||
| This pass detects processes that describe d-type flip-flops with
|
||||
asynchronous resets and rewrites the process to better reflect what they
|
||||
are modelling: Before this pass, an asynchronous reset has two
|
||||
|
|
@ -616,22 +616,22 @@ from a behavioural model to an RTL representation is performed by the
|
|||
reset path. After this pass the sync rule for the reset is level-sensitive
|
||||
and the top-level ``RTLIL::SwitchRule`` has been removed.
|
||||
|
||||
- | :cmd:ref:`proc_mux`
|
||||
| This pass converts the ``RTLIL::CaseRule``/\ ``RTLIL::SwitchRule``-tree to a
|
||||
tree of multiplexers per written signal. After this, the ``RTLIL::Process``
|
||||
structure only contains the ``RTLIL::SyncRule`` s that describe the output
|
||||
registers.
|
||||
- | `proc_mux`
|
||||
| This pass converts the ``RTLIL::CaseRule``/\ ``RTLIL::SwitchRule``-tree to
|
||||
a tree of multiplexers per written signal. After this, the
|
||||
``RTLIL::Process`` structure only contains the ``RTLIL::SyncRule`` s that
|
||||
describe the output registers.
|
||||
|
||||
- | :cmd:ref:`proc_dff`
|
||||
- | `proc_dff`
|
||||
| This pass replaces the ``RTLIL::SyncRule``\ s to d-type flip-flops (with
|
||||
asynchronous resets if necessary).
|
||||
|
||||
- | :cmd:ref:`proc_dff`
|
||||
| This pass replaces the ``RTLIL::MemWriteAction``\ s with ``$memwr`` cells.
|
||||
- | `proc_dff`
|
||||
| This pass replaces the ``RTLIL::MemWriteAction``\ s with `$memwr` cells.
|
||||
|
||||
- | :cmd:ref:`proc_clean`
|
||||
| A final call to :cmd:ref:`proc_clean` removes the now empty
|
||||
``RTLIL::Process`` objects.
|
||||
- | `proc_clean`
|
||||
| A final call to `proc_clean` removes the now empty ``RTLIL::Process``
|
||||
objects.
|
||||
|
||||
Performing these last processing steps in passes instead of in the Verilog
|
||||
frontend has two important benefits:
|
||||
|
|
@ -646,8 +646,8 @@ to extend the actual Verilog frontend.
|
|||
|
||||
.. todo:: Synthesizing Verilog arrays
|
||||
|
||||
Add some information on the generation of ``$memrd`` and ``$memwr`` cells and
|
||||
how they are processed in the memory pass.
|
||||
Add some information on the generation of `$memrd` and `$memwr` cells and how
|
||||
they are processed in the memory pass.
|
||||
|
||||
|
||||
.. todo:: Synthesizing parametric designs
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,13 +1,59 @@
|
|||
Internal formats
|
||||
================
|
||||
|
||||
.. todo:: brief overview for the internal formats index
|
||||
Yosys uses two different internal formats. The first is used to store an
|
||||
abstract syntax tree (AST) of a Verilog input file. This format is simply called
|
||||
AST and is generated by the Verilog Frontend. This data structure is consumed by
|
||||
a subsystem called AST Frontend [1]_. This AST Frontend then generates a design
|
||||
in Yosys' main internal format, the
|
||||
Register-Transfer-Level-Intermediate-Language (RTLIL) representation. It does
|
||||
that by first performing a number of simplifications within the AST
|
||||
representation and then generating RTLIL from the simplified AST data structure.
|
||||
|
||||
The RTLIL representation is used by all passes as input and outputs. This has
|
||||
the following advantages over using different representational formats between
|
||||
different passes:
|
||||
|
||||
- The passes can be rearranged in a different order and passes can be removed
|
||||
or inserted.
|
||||
|
||||
- Passes can simply pass-thru the parts of the design they don't change without
|
||||
the need to convert between formats. In fact Yosys passes output the same
|
||||
data structure they received as input and performs all changes in place.
|
||||
|
||||
- All passes use the same interface, thus reducing the effort required to
|
||||
understand a pass when reading the Yosys source code, e.g. when adding
|
||||
additional features.
|
||||
|
||||
The RTLIL representation is basically a netlist representation with the
|
||||
following additional features:
|
||||
|
||||
- An internal cell library with fixed-function cells to represent RTL datapath
|
||||
and register cells as well as logical gate-level cells (single-bit gates and
|
||||
registers).
|
||||
|
||||
- Support for multi-bit values that can use individual bits from wires as well
|
||||
as constant bits to represent coarse-grain netlists.
|
||||
|
||||
- Support for basic behavioural constructs (if-then-else structures and
|
||||
multi-case switches with a sensitivity list for updating the outputs).
|
||||
|
||||
- Support for multi-port memories.
|
||||
|
||||
The use of RTLIL also has the disadvantage of having a very powerful format
|
||||
between all passes, even when doing gate-level synthesis where the more advanced
|
||||
features are not needed. In order to reduce complexity for passes that operate
|
||||
on a low-level representation, these passes check the features used in the input
|
||||
RTLIL and fail to run when unsupported high-level constructs are used. In such
|
||||
cases a pass that transforms the higher-level constructs to lower-level
|
||||
constructs must be called from the synthesis script first.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:maxdepth: 3
|
||||
|
||||
overview
|
||||
rtlil_rep
|
||||
rtlil_text
|
||||
cell_library
|
||||
rtlil_rep
|
||||
|
||||
.. [1]
|
||||
In Yosys the term pass is only used to refer to commands that operate on the
|
||||
RTLIL data structure.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
Format overview
|
||||
===============
|
||||
|
||||
Yosys uses two different internal formats. The first is used to store an
|
||||
abstract syntax tree (AST) of a Verilog input file. This format is simply called
|
||||
AST and is generated by the Verilog Frontend. This data structure is consumed by
|
||||
a subsystem called AST Frontend [1]_. This AST Frontend then generates a design
|
||||
in Yosys' main internal format, the
|
||||
Register-Transfer-Level-Intermediate-Language (RTLIL) representation. It does
|
||||
that by first performing a number of simplifications within the AST
|
||||
representation and then generating RTLIL from the simplified AST data structure.
|
||||
|
||||
The RTLIL representation is used by all passes as input and outputs. This has
|
||||
the following advantages over using different representational formats between
|
||||
different passes:
|
||||
|
||||
- The passes can be rearranged in a different order and passes can be removed
|
||||
or inserted.
|
||||
|
||||
- Passes can simply pass-thru the parts of the design they don't change without
|
||||
the need to convert between formats. In fact Yosys passes output the same
|
||||
data structure they received as input and performs all changes in place.
|
||||
|
||||
- All passes use the same interface, thus reducing the effort required to
|
||||
understand a pass when reading the Yosys source code, e.g. when adding
|
||||
additional features.
|
||||
|
||||
The RTLIL representation is basically a netlist representation with the
|
||||
following additional features:
|
||||
|
||||
- An internal cell library with fixed-function cells to represent RTL datapath
|
||||
and register cells as well as logical gate-level cells (single-bit gates and
|
||||
registers).
|
||||
|
||||
- Support for multi-bit values that can use individual bits from wires as well
|
||||
as constant bits to represent coarse-grain netlists.
|
||||
|
||||
- Support for basic behavioural constructs (if-then-else structures and
|
||||
multi-case switches with a sensitivity list for updating the outputs).
|
||||
|
||||
- Support for multi-port memories.
|
||||
|
||||
The use of RTLIL also has the disadvantage of having a very powerful format
|
||||
between all passes, even when doing gate-level synthesis where the more advanced
|
||||
features are not needed. In order to reduce complexity for passes that operate
|
||||
on a low-level representation, these passes check the features used in the input
|
||||
RTLIL and fail to run when unsupported high-level constructs are used. In such
|
||||
cases a pass that transforms the higher-level constructs to lower-level
|
||||
constructs must be called from the synthesis script first.
|
||||
|
||||
.. [1]
|
||||
In Yosys the term pass is only used to refer to commands that operate on the
|
||||
RTLIL data structure.
|
||||
|
|
@ -76,11 +76,10 @@ This has three advantages:
|
|||
|
||||
- Second, the information about which identifiers were originally provided by
|
||||
the user is always available which can help guide some optimizations. For
|
||||
example, :cmd:ref:`opt_clean` tries to preserve signals with a user-provided
|
||||
name but doesn't hesitate to delete signals that have auto-generated names
|
||||
when they just duplicate other signals. Note that this can be overridden
|
||||
with the `-purge` option to also delete internal nets with user-provided
|
||||
names.
|
||||
example, `opt_clean` tries to preserve signals with a user-provided name but
|
||||
doesn't hesitate to delete signals that have auto-generated names when they
|
||||
just duplicate other signals. Note that this can be overridden with the
|
||||
``-purge`` option to also delete internal nets with user-provided names.
|
||||
|
||||
- Third, the delicate job of finding suitable auto-generated public visible
|
||||
names is deferred to one central location. Internally auto-generated names
|
||||
|
|
@ -204,8 +203,8 @@ A "signal" is everything that can be applied to a cell port. I.e.
|
|||
- | Concatenations of the above
|
||||
| 1em For example: ``{16'd1337, mywire[15:8]}``
|
||||
|
||||
The ``RTLIL::SigSpec`` data type is used to represent signals. The ``RTLIL::Cell``
|
||||
object contains one ``RTLIL::SigSpec`` for each cell port.
|
||||
The ``RTLIL::SigSpec`` data type is used to represent signals. The
|
||||
``RTLIL::Cell`` object contains one ``RTLIL::SigSpec`` for each cell port.
|
||||
|
||||
In addition, connections between wires are represented using a pair of
|
||||
``RTLIL::SigSpec`` objects. Such pairs are needed in different locations.
|
||||
|
|
@ -234,9 +233,9 @@ control logic of the behavioural code. Let's consider a simple example:
|
|||
q <= d;
|
||||
endmodule
|
||||
|
||||
In this example there is no data path and therefore the ``RTLIL::Module`` generated
|
||||
by the frontend only contains a few ``RTLIL::Wire`` objects and an ``RTLIL::Process`` .
|
||||
The ``RTLIL::Process`` in RTLIL syntax:
|
||||
In this example there is no data path and therefore the ``RTLIL::Module``
|
||||
generated by the frontend only contains a few ``RTLIL::Wire`` objects and an
|
||||
``RTLIL::Process``. The ``RTLIL::Process`` in RTLIL syntax:
|
||||
|
||||
.. code:: RTLIL
|
||||
:number-lines:
|
||||
|
|
@ -320,8 +319,8 @@ trees before further processing them.
|
|||
|
||||
One of the first actions performed on a design in RTLIL representation in most
|
||||
synthesis scripts is identifying asynchronous resets. This is usually done using
|
||||
the :cmd:ref:`proc_arst` pass. This pass transforms the above example to the
|
||||
following ``RTLIL::Process``:
|
||||
the `proc_arst` pass. This pass transforms the above example to the following
|
||||
``RTLIL::Process``:
|
||||
|
||||
.. code:: RTLIL
|
||||
:number-lines:
|
||||
|
|
@ -340,9 +339,9 @@ following ``RTLIL::Process``:
|
|||
end
|
||||
|
||||
This pass has transformed the outer ``RTLIL::SwitchRule`` into a modified
|
||||
``RTLIL::SyncRule`` object for the ``\reset`` signal. Further processing converts the
|
||||
``RTLIL::Process`` into e.g. a d-type flip-flop with asynchronous reset and a
|
||||
multiplexer for the enable signal:
|
||||
``RTLIL::SyncRule`` object for the ``\reset`` signal. Further processing
|
||||
converts the ``RTLIL::Process`` into e.g. a d-type flip-flop with asynchronous
|
||||
reset and a multiplexer for the enable signal:
|
||||
|
||||
.. code:: RTLIL
|
||||
:number-lines:
|
||||
|
|
@ -365,11 +364,11 @@ multiplexer for the enable signal:
|
|||
connect \Y $0\q[0:0]
|
||||
end
|
||||
|
||||
Different combinations of passes may yield different results. Note that
|
||||
``$adff`` and ``$mux`` are internal cell types that still need to be mapped to
|
||||
cell types from the target cell library.
|
||||
Different combinations of passes may yield different results. Note that `$adff`
|
||||
and `$mux` are internal cell types that still need to be mapped to cell types
|
||||
from the target cell library.
|
||||
|
||||
Some passes refuse to operate on modules that still contain ``RTLIL::Process``
|
||||
Some passes refuse to operate on modules that still contain ``RTLIL::Process``
|
||||
objects as the presence of these objects in a module increases the complexity.
|
||||
Therefore the passes to translate processes to a netlist of cells are usually
|
||||
called early in a synthesis script. The proc pass calls a series of other passes
|
||||
|
|
@ -389,25 +388,25 @@ A memory object has the following properties:
|
|||
- The width of an addressable word
|
||||
- The size of the memory in number of words
|
||||
|
||||
All read accesses to the memory are transformed to ``$memrd`` cells and all
|
||||
write accesses to ``$memwr`` cells by the language frontend. These cells consist
|
||||
of independent read- and write-ports to the memory. Memory initialization is
|
||||
transformed to ``$meminit`` cells by the language frontend. The ``\MEMID``
|
||||
All read accesses to the memory are transformed to `$memrd` cells and all write
|
||||
accesses to `$memwr` cells by the language frontend. These cells consist of
|
||||
independent read- and write-ports to the memory. Memory initialization is
|
||||
transformed to `$meminit` cells by the language frontend. The ``\MEMID``
|
||||
parameter on these cells is used to link them together and to the
|
||||
``RTLIL::Memory`` object they belong to.
|
||||
|
||||
The rationale behind using separate cells for the individual ports versus
|
||||
creating a large multiport memory cell right in the language frontend is that
|
||||
the separate ``$memrd`` and ``$memwr`` cells can be consolidated using resource
|
||||
the separate `$memrd` and `$memwr` cells can be consolidated using resource
|
||||
sharing. As resource sharing is a non-trivial optimization problem where
|
||||
different synthesis tasks can have different requirements it lends itself to do
|
||||
the optimisation in separate passes and merge the ``RTLIL::Memory`` objects and
|
||||
``$memrd`` and ``$memwr`` cells to multiport memory blocks after resource
|
||||
sharing is completed.
|
||||
`$memrd` and `$memwr` cells to multiport memory blocks after resource sharing is
|
||||
completed.
|
||||
|
||||
The memory pass performs this conversion and can (depending on the options
|
||||
passed to it) transform the memories directly to d-type flip-flops and address
|
||||
logic or yield multiport memory blocks (represented using ``$mem`` cells).
|
||||
logic or yield multiport memory blocks (represented using `$mem` cells).
|
||||
|
||||
See :ref:`sec:memcells` for details about the memory cell types.
|
||||
|
||||
|
|
|
|||
166
docs/source/yosys_internals/hashing.rst
Normal file
166
docs/source/yosys_internals/hashing.rst
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
Hashing and associative data structures in Yosys
|
||||
------------------------------------------------
|
||||
|
||||
Container classes based on hashing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yosys uses ``dict<K, T>`` and ``pool<T>`` as main container classes.
|
||||
``dict<K, T>`` is essentially a replacement for ``std::unordered_map<K, T>``
|
||||
and ``pool<T>`` is a replacement for ``std::unordered_set<T>``.
|
||||
The main characteristics are:
|
||||
|
||||
* ``dict<K, T>`` and ``pool<T>`` are about 2x faster than the std containers
|
||||
(though this claim hasn't been verified for over 10 years)
|
||||
|
||||
* references to elements in a ``dict<K, T>`` or ``pool<T>`` are invalidated by
|
||||
insert and remove operations (similar to ``std::vector<T>`` on ``push_back()``).
|
||||
|
||||
* some iterators are invalidated by ``erase()``. specifically, iterators
|
||||
that have not passed the erased element yet are invalidated. (``erase()``
|
||||
itself returns valid iterator to the next element.)
|
||||
|
||||
* no iterators are invalidated by ``insert()``. elements are inserted at
|
||||
``begin()``. i.e. only a new iterator that starts at ``begin()`` will see the
|
||||
inserted elements.
|
||||
|
||||
* the method ``.count(key, iterator)`` is like ``.count(key)`` but only
|
||||
considers elements that can be reached via the iterator.
|
||||
|
||||
* iterators can be compared. ``it1 < it2`` means that the position of ``t2``
|
||||
can be reached via ``t1`` but not vice versa.
|
||||
|
||||
* the method ``.sort()`` can be used to sort the elements in the container
|
||||
the container stays sorted until elements are added or removed.
|
||||
|
||||
* ``dict<K, T>`` and ``pool<T>`` will have the same order of iteration across
|
||||
all compilers, standard libraries and architectures.
|
||||
|
||||
In addition to ``dict<K, T>`` and ``pool<T>`` there is also an ``idict<K>`` that
|
||||
creates a bijective map from ``K`` to the integers. For example:
|
||||
|
||||
::
|
||||
|
||||
idict<string, 42> si;
|
||||
log("%d\n", si("hello")); // will print 42
|
||||
log("%d\n", si("world")); // will print 43
|
||||
log("%d\n", si.at("world")); // will print 43
|
||||
log("%d\n", si.at("dummy")); // will throw exception
|
||||
log("%s\n", si[42].c_str())); // will print hello
|
||||
log("%s\n", si[43].c_str())); // will print world
|
||||
log("%s\n", si[44].c_str())); // will throw exception
|
||||
|
||||
It is not possible to remove elements from an idict.
|
||||
|
||||
Finally ``mfp<K>`` implements a merge-find set data structure (aka. disjoint-set
|
||||
or union-find) over the type ``K`` ("mfp" = merge-find-promote).
|
||||
|
||||
The hash function
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The hash function generally used in Yosys is the XOR version of DJB2:
|
||||
|
||||
::
|
||||
|
||||
state = ((state << 5) + state) ^ value
|
||||
|
||||
This is an old-school hash designed to hash ASCII characters. Yosys doesn't hash
|
||||
a lot of ASCII text, but it still happens to be a local optimum due to factors
|
||||
described later.
|
||||
|
||||
Hash function quality is multi-faceted and highly dependent on what is being
|
||||
hashed. Yosys isn't concerned by any cryptographic qualities, instead the goal
|
||||
is minimizing total hashing collision risk given the data patterns within Yosys.
|
||||
In general, a good hash function typically folds values into a state accumulator
|
||||
with a mathematical function that is fast to compute and has some beneficial
|
||||
properties. One of these is the avalanche property, which demands that a small
|
||||
change such as flipping a bit or incrementing by one in the input produces a
|
||||
large, unpredictable change in the output. Additionally, the bit independence
|
||||
criterion states that any pair of output bits should change independently when
|
||||
any single input bit is inverted. These properties are important for avoiding
|
||||
hash collision on data patterns like the hash of a sequence not colliding with
|
||||
its permutation, not losing from the state the information added by hashing
|
||||
preceding elements, etc.
|
||||
|
||||
DJB2 lacks these properties. Instead, since Yosys hashes large numbers of data
|
||||
structures composed of incrementing integer IDs, Yosys abuses the predictability
|
||||
of DJB2 to get lower hash collisions, with regular nature of the hashes
|
||||
surviving through the interaction with the "modulo prime" operations in the
|
||||
associative data structures. For example, some most common objects in Yosys are
|
||||
interned ``IdString``\ s of incrementing indices or ``SigBit``\ s with bit
|
||||
offsets into wire (represented by its unique ``IdString`` name) as the typical
|
||||
case. This is what makes DJB2 a local optimum. Additionally, the ADD version of
|
||||
DJB2 (like above but with addition instead of XOR) is used to this end for some
|
||||
types, abandoning the general pattern of folding values into a state value.
|
||||
|
||||
Making a type hashable
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's first take a look at the external interface on a simplified level.
|
||||
Generally, to get the hash for ``T obj``, you would call the utility function
|
||||
``run_hash<T>(const T& obj)``, corresponding to ``hash_ops<T>::hash(obj)``,
|
||||
the default implementation of which uses ``hash_ops<T>::hash_into(Hasher(), obj)``.
|
||||
``Hasher`` is the class actually implementing the hash function, hiding its
|
||||
initialized internal state, and passing it out on ``hash_t yield()`` with
|
||||
perhaps some finalization steps.
|
||||
|
||||
``hash_ops<T>`` is the star of the show. By default it pulls the ``Hasher h``
|
||||
through a ``Hasher T::hash_into(Hasher h)`` method. That's the method you have to
|
||||
implement to make a record (class or struct) type easily hashable with Yosys
|
||||
hashlib associative data structures.
|
||||
|
||||
``hash_ops<T>`` is specialized for built-in types like ``int`` or ``bool`` and
|
||||
treats pointers the same as integers, so it doesn't dereference pointers. Since
|
||||
many RTLIL data structures like ``RTLIL::Wire`` carry their own unique index
|
||||
``Hasher::hash_t hashidx_;``, there are specializations for ``hash_ops<Wire*>``
|
||||
and others in ``kernel/hashlib.h`` that actually dereference the pointers and
|
||||
call ``hash_into`` on the instances pointed to.
|
||||
|
||||
``hash_ops<T>`` is also specialized for simple compound types like
|
||||
``std::pair<U>`` by calling hash_into in sequence on its members. For flexible
|
||||
size containers like ``std::vector<U>`` the size of the container is hashed
|
||||
first. That is also how implementing hashing for a custom record data type
|
||||
should be - unless there is strong reason to do otherwise, call ``h.eat(m)`` on
|
||||
the ``Hasher h`` you have received for each member in sequence and ``return
|
||||
h;``.
|
||||
|
||||
The ``hash_ops<T>::hash(obj)`` method is not indended to be called when
|
||||
context of implementing the hashing for a record or other compound type.
|
||||
When writing it, you should connect it to ``hash_ops<T>::hash_into(Hasher h)``
|
||||
as shown below. If you have a strong reason to do so, and you have
|
||||
to create a special implementation for top-level hashing, look at how
|
||||
``hash_ops<RTLIL::SigBit>::hash(...)`` is implemented in ``kernel/rtlil.h``.
|
||||
|
||||
Porting plugins from the legacy interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Previously, the interface to implement hashing on custom types was just
|
||||
``unsigned int T::hash() const``. This meant hashes for members were computed
|
||||
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`.
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: Example hash compatibility wrapper
|
||||
:name: hash_plugin_compat
|
||||
|
||||
#ifndef YS_HASHING_VERSION
|
||||
unsigned int T::hash() const {
|
||||
return mkhash(a, b);
|
||||
}
|
||||
#elif YS_HASHING_VERSION == 1
|
||||
Hasher T::hash_into(Hasher h) const {
|
||||
h.eat(a);
|
||||
h.eat(b);
|
||||
return h;
|
||||
}
|
||||
Hasher T::hash() const {
|
||||
Hasher h;
|
||||
h.eat(*this);
|
||||
return h;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported hashing interface"
|
||||
#endif
|
||||
|
||||
Feel free to contact Yosys maintainers with related issues.
|
||||
|
|
@ -38,3 +38,5 @@ as reference to implement a similar system in any language.
|
|||
formats/index
|
||||
extending_yosys/index
|
||||
techmap
|
||||
verilog
|
||||
hashing
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
Techmap by example
|
||||
------------------
|
||||
|
||||
As a quick recap, the :cmd:ref:`techmap` command replaces cells in the design
|
||||
with implementations given as Verilog code (called "map files"). It can replace
|
||||
Yosys' internal cell types (such as ``$or``) as well as user-defined cell types.
|
||||
As a quick recap, the `techmap` command replaces cells in the design with
|
||||
implementations given as Verilog code (called "map files"). It can replace
|
||||
Yosys' internal cell types (such as `$or`) as well as user-defined cell types.
|
||||
|
||||
- Verilog parameters are used extensively to customize the internal cell types.
|
||||
- Additional special parameters are used by techmap to communicate meta-data to
|
||||
|
|
@ -87,15 +87,15 @@ Scripting in map modules
|
|||
- You can even call techmap recursively!
|
||||
- Example use-cases:
|
||||
|
||||
- Using always blocks in map module: call :cmd:ref:`proc`
|
||||
- Perform expensive optimizations (such as :cmd:ref:`freduce`) on cells
|
||||
- Using always blocks in map module: call `proc`
|
||||
- Perform expensive optimizations (such as `freduce`) on cells
|
||||
where this is known to work well.
|
||||
- Interacting with custom commands.
|
||||
|
||||
.. note:: PROTIP:
|
||||
|
||||
Commands such as :cmd:ref:`shell`, ``show -pause``, and :cmd:ref:`dump` can
|
||||
be used in the ``_TECHMAP_DO_*`` scripts for debugging map modules.
|
||||
Commands such as `shell`, ``show -pause``, and `dump` can be used in the
|
||||
``_TECHMAP_DO_*`` scripts for debugging map modules.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
|||
377
docs/source/yosys_internals/verilog.rst
Normal file
377
docs/source/yosys_internals/verilog.rst
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
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
|
||||
---------------------------------
|
||||
|
||||
The following Verilog-2005 features are not supported by
|
||||
Yosys and there are currently no plans to add support
|
||||
for them:
|
||||
|
||||
- Non-synthesizable language features as defined in
|
||||
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
|
||||
|
||||
- The ``tri``, ``triand`` and ``trior`` net types
|
||||
|
||||
- The ``config`` and ``disable`` keywords and library map files
|
||||
|
||||
|
||||
Verilog Attributes and non-standard features
|
||||
--------------------------------------------
|
||||
|
||||
- The ``full_case`` attribute on case statements is supported (also the
|
||||
non-standard ``// synopsys full_case`` directive)
|
||||
|
||||
- The ``parallel_case`` attribute on case statements is supported (also the
|
||||
non-standard ``// synopsys parallel_case`` directive)
|
||||
|
||||
- The ``// synopsys translate_off`` and ``// synopsys translate_on`` directives
|
||||
are also supported (but the use of ``` `ifdef .. `endif ``` is strongly
|
||||
recommended instead).
|
||||
|
||||
- The ``nomem2reg`` attribute on modules or arrays prohibits the automatic early
|
||||
conversion of arrays to separate registers. This is potentially dangerous.
|
||||
Usually the front-end has good reasons for converting an array to a list of
|
||||
registers. Prohibiting this step will likely result in incorrect synthesis
|
||||
results.
|
||||
|
||||
- The ``mem2reg`` attribute on modules or arrays forces the early conversion of
|
||||
arrays to separate registers.
|
||||
|
||||
- The ``nomeminit`` attribute on modules or arrays prohibits the creation of
|
||||
initialized memories. This effectively puts ``mem2reg`` on all memories that
|
||||
are written to in an ``initial`` block and are not ROMs.
|
||||
|
||||
- The ``nolatches`` attribute on modules or always-blocks prohibits the
|
||||
generation of logic-loops for latches. Instead all not explicitly assigned
|
||||
values default to x-bits. This does not affect clocked storage elements such
|
||||
as flip-flops.
|
||||
|
||||
- The ``nosync`` attribute on registers prohibits the generation of a storage
|
||||
element. The register itself will always have all bits set to 'x' (undefined).
|
||||
The variable may only be used as blocking assigned temporary variable within
|
||||
an always block. This is mostly used internally by Yosys to synthesize Verilog
|
||||
functions and access arrays.
|
||||
|
||||
- The ``nowrshmsk`` attribute on a register prohibits the generation of
|
||||
shift-and-mask type circuits for writing to bit slices of that register.
|
||||
|
||||
- The ``onehot`` attribute on wires mark them as one-hot state register. This is
|
||||
used for example for memory port sharing and set by the fsm_map pass.
|
||||
|
||||
- The ``blackbox`` attribute on modules is used to mark empty stub modules that
|
||||
have the same ports as the real thing but do not contain information on the
|
||||
internal configuration. This modules are only used by the synthesis passes to
|
||||
identify input and output ports of cells. The Verilog backend also does not
|
||||
output blackbox modules on default. `read_verilog`, unless called with
|
||||
``-noblackbox`` will automatically set the blackbox attribute on any empty
|
||||
module it reads.
|
||||
|
||||
- The ``noblackbox`` attribute set on an empty module prevents `read_verilog`
|
||||
from automatically setting the blackbox attribute on the module.
|
||||
|
||||
- The ``whitebox`` attribute on modules triggers the same behavior as
|
||||
``blackbox``, but is for whitebox modules, i.e. library modules that contain a
|
||||
behavioral model of the cell type.
|
||||
|
||||
- The ``lib_whitebox`` attribute overwrites ``whitebox`` when `read_verilog` is
|
||||
run in ``-lib`` mode. Otherwise it's automatically removed.
|
||||
|
||||
- The ``dynports`` attribute is used by the Verilog front-end to mark modules
|
||||
that have ports with a width that depends on a parameter.
|
||||
|
||||
- The ``hdlname`` attribute is used by some passes to document the original
|
||||
(HDL) name of a module when renaming a module. It should contain a single
|
||||
name, or, when describing a hierarchical name in a flattened design, multiple
|
||||
names separated by a single space character.
|
||||
|
||||
- The ``keep`` attribute on cells and wires is used to mark objects that should
|
||||
never be removed by the optimizer. This is used for example for cells that
|
||||
have hidden connections that are not part of the netlist, such as IO pads.
|
||||
Setting the ``keep`` attribute on a module has the same effect as setting it
|
||||
on all instances of the module.
|
||||
|
||||
- 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 estimated cost of the module as a number of basic gate instances. See
|
||||
the help message of command `keep_hierarchy` which interprets this
|
||||
attribute.
|
||||
|
||||
- The ``init`` attribute on wires is set by the frontend when a register is
|
||||
initialized "FPGA-style" with ``reg foo = val``. It can be used during
|
||||
synthesis to add the necessary reset logic.
|
||||
|
||||
- The ``top`` attribute on a module marks this module as the top of the design
|
||||
hierarchy. The `hierarchy` command sets this attribute when called with
|
||||
``-top``. Other commands, such as `flatten` and various backends use this
|
||||
attribute to determine the top module.
|
||||
|
||||
- The ``src`` attribute is set on cells and wires created by to the string
|
||||
``<hdl-file-name>:<line-number>`` by the HDL front-end and is then carried
|
||||
through the synthesis. When entities are combined, a new \|-separated string
|
||||
is created that contains all the strings from the original entities.
|
||||
|
||||
- The ``defaultvalue`` attribute is used to store default values for module
|
||||
inputs. The attribute is attached to the input wire by the HDL front-end when
|
||||
the input is declared with a default value.
|
||||
|
||||
- The ``parameter`` and ``localparam`` attributes are used to mark wires that
|
||||
represent module parameters or localparams (when the HDL front-end is run in
|
||||
``-pwires`` mode).
|
||||
|
||||
- Wires marked with the ``hierconn`` attribute are connected to wires with the
|
||||
same name (format ``cell_name.identifier``) when they are imported from
|
||||
sub-modules by `flatten`.
|
||||
|
||||
- The ``clkbuf_driver`` attribute can be set on an output port of a blackbox
|
||||
module to mark it as a clock buffer output, and thus prevent `clkbufmap` from
|
||||
inserting another clock buffer on a net driven by such output.
|
||||
|
||||
- The ``clkbuf_sink`` attribute can be set on an input port of a module to
|
||||
request clock buffer insertion by the `clkbufmap` pass.
|
||||
|
||||
- The ``clkbuf_inv`` attribute can be set on an output port of a module with the
|
||||
value set to the name of an input port of that module. When the `clkbufmap`
|
||||
would otherwise insert a clock buffer on this output, it will instead try
|
||||
inserting the clock buffer on the input port (this is used to implement clock
|
||||
inverter cells that clock buffer insertion will "see through").
|
||||
|
||||
- The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent
|
||||
automatic clock buffer insertion by `clkbufmap`. This behaviour can be
|
||||
overridden by providing a custom selection to `clkbufmap`.
|
||||
|
||||
- The ``invertible_pin`` attribute can be set on a port to mark it as invertible
|
||||
via a cell parameter. The name of the inversion parameter is specified as the
|
||||
value of this attribute. The value of the inversion parameter must be of the
|
||||
same width as the port, with 1 indicating an inverted bit and 0 indicating a
|
||||
non-inverted bit.
|
||||
|
||||
- The ``iopad_external_pin`` attribute on a blackbox module's port marks it as
|
||||
the external-facing pin of an I/O pad, and prevents `iopadmap` from inserting
|
||||
another pad cell on it.
|
||||
|
||||
- The module attribute ``abc9_lut`` is an integer attribute indicating to `abc9`
|
||||
that this module describes a LUT with an area cost of this value, and
|
||||
propagation delays described using ``specify`` statements.
|
||||
|
||||
- The module attribute ``abc9_box`` is a boolean specifying a black/white-box
|
||||
definition, with propagation delays described using ``specify`` statements,
|
||||
for use by `abc9`.
|
||||
|
||||
- The port attribute ``abc9_carry`` marks the carry-in (if an input port) and
|
||||
carry-out (if output port) ports of a box. This information is necessary for
|
||||
`abc9` to preserve the integrity of carry-chains. Specifying this attribute
|
||||
onto a bus port will affect only its most significant bit.
|
||||
|
||||
- The module attribute ``abc9_flop`` is a boolean marking the module as a
|
||||
flip-flop. This allows `abc9` to analyse its contents in order to perform
|
||||
sequential synthesis.
|
||||
|
||||
- The frontend sets attributes ``always_comb``, ``always_latch`` and
|
||||
``always_ff`` on processes derived from SystemVerilog style always blocks
|
||||
according to the type of the always. These are checked for correctness in
|
||||
``proc_dlatch``.
|
||||
|
||||
- The cell attribute ``wildcard_port_conns`` represents wildcard port
|
||||
connections (SystemVerilog ``.*``). These are resolved to concrete connections
|
||||
to matching wires in `hierarchy`.
|
||||
|
||||
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports the
|
||||
non-standard ``{* ... *}`` attribute syntax to set default attributes for
|
||||
everything that comes after the ``{* ... *}`` statement. (Reset by adding an
|
||||
empty ``{* *}`` statement.)
|
||||
|
||||
- In module parameter and port declarations, and cell port and parameter lists,
|
||||
a trailing comma is ignored. This simplifies writing Verilog code generators a
|
||||
bit in some cases.
|
||||
|
||||
- Modules can be declared with ``module mod_name(...);`` (with three dots
|
||||
instead of a list of module ports). With this syntax it is sufficient to
|
||||
simply declare a module port as 'input' or 'output' in the module body.
|
||||
|
||||
- When defining a macro with ``\`define``, all text between triple double quotes
|
||||
is interpreted as macro body, even if it contains unescaped newlines. The
|
||||
triple double quotes are removed from the macro body. For example:
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
`define MY_MACRO(a, b) """
|
||||
assign a = 23;
|
||||
assign b = 42;
|
||||
"""
|
||||
|
||||
- The attribute ``via_celltype`` can be used to implement a Verilog task or
|
||||
function by instantiating the specified cell type. The value is the name of
|
||||
the cell type to use. For functions the name of the output port can be
|
||||
specified by appending it to the cell type separated by a whitespace. The body
|
||||
of the task or function is unused in this case and can be used to specify a
|
||||
behavioral model of the cell type for simulation. For example:
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
module my_add3(A, B, C, Y);
|
||||
parameter WIDTH = 8;
|
||||
input [WIDTH-1:0] A, B, C;
|
||||
output [WIDTH-1:0] Y;
|
||||
...
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
...
|
||||
(* via_celltype = "my_add3 Y" *)
|
||||
(* via_celltype_defparam_WIDTH = 32 *)
|
||||
function [31:0] add3;
|
||||
input [31:0] A, B, C;
|
||||
begin
|
||||
add3 = A + B + C;
|
||||
end
|
||||
endfunction
|
||||
...
|
||||
endmodule
|
||||
|
||||
- The ``wiretype`` attribute is added by the verilog parser for wires of a
|
||||
typedef'd type to indicate the type identifier.
|
||||
|
||||
- Various ``enum_value_{value}`` attributes are added to wires of an enumerated
|
||||
type to give a map of possible enum items to their values.
|
||||
|
||||
- The ``enum_base_type`` attribute is added to enum items to indicate which enum
|
||||
they belong to (enums -- anonymous and otherwise -- are automatically named
|
||||
with an auto-incrementing counter). Note that enums are currently not strongly
|
||||
typed.
|
||||
|
||||
- A limited subset of DPI-C functions is supported. The plugin mechanism (see
|
||||
``help plugin``) can be used to load .so files with implementations of DPI-C
|
||||
routines. As a non-standard extension it is possible to specify a plugin alias
|
||||
using the ``<alias>:`` syntax. For example:
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
module dpitest;
|
||||
import "DPI-C" function foo:round = real my_round (real);
|
||||
parameter real r = my_round(12.345);
|
||||
endmodule
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
|
||||
|
||||
- Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant
|
||||
expressions as ``<size>``. If the expression is not a simple identifier, it
|
||||
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
|
||||
|
||||
- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
|
||||
initial blocks in an unconditional context (only if/case statements on
|
||||
expressions over parameters and constant values are allowed). The intended use
|
||||
for this is synthesis-time DRC.
|
||||
|
||||
- There is limited support for converting ``specify`` .. ``endspecify``
|
||||
statements to special ``$specify2``, ``$specify3``, and ``$specrule`` cells,
|
||||
for use in blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable
|
||||
this functionality. (By default these blocks are ignored.)
|
||||
|
||||
- The ``reprocess_after`` internal attribute is used by the Verilog frontend to
|
||||
mark cells with bindings which might depend on the specified instantiated
|
||||
module. Modules with such cells will be reprocessed during the `hierarchy`
|
||||
pass once the referenced module definition(s) become available.
|
||||
|
||||
- The ``smtlib2_module`` attribute can be set on a blackbox module to specify a
|
||||
formal model directly using SMT-LIB 2. For such a module, the
|
||||
``smtlib2_comb_expr`` attribute can be used on output ports to define their
|
||||
value using an SMT-LIB 2 expression. For example:
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
(* blackbox *)
|
||||
(* smtlib2_module *)
|
||||
module submod(a, b);
|
||||
input [7:0] a;
|
||||
(* smtlib2_comb_expr = "(bvnot a)" *)
|
||||
output [7:0] b;
|
||||
endmodule
|
||||
|
||||
Non-standard or SystemVerilog features for formal verification
|
||||
--------------------------------------------------------------
|
||||
|
||||
- Support for ``assert``, ``assume``, ``restrict``, and ``cover`` is enabled
|
||||
when `read_verilog` is called with ``-formal``.
|
||||
|
||||
- The system task ``$initstate`` evaluates to 1 in the initial state and to 0
|
||||
otherwise.
|
||||
|
||||
- The system function ``$anyconst`` evaluates to any constant value. This is
|
||||
equivalent to declaring a reg as ``rand const``, but also works outside of
|
||||
checkers. (Yosys also supports ``rand const`` outside checkers.)
|
||||
|
||||
- The system function ``$anyseq`` evaluates to any value, possibly a different
|
||||
value in each cycle. This is equivalent to declaring a reg as ``rand``, but
|
||||
also works outside of checkers. (Yosys also supports ``rand`` variables
|
||||
outside checkers.)
|
||||
|
||||
- The system functions ``$allconst`` and ``$allseq`` can be used to construct
|
||||
formal exist-forall problems. Assumptions only hold if the trace satisfies the
|
||||
assumption for all ``$allconst/$allseq`` values. For assertions and cover
|
||||
statements it is sufficient if just one ``$allconst/$allseq`` value triggers
|
||||
the property (similar to ``$anyconst/$anyseq``).
|
||||
|
||||
- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq``
|
||||
attribute (for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if
|
||||
driven by a ``$anyconst/$anyseq/$allconst/$allseq`` function.
|
||||
|
||||
- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
|
||||
supported in any clocked block.
|
||||
|
||||
- The syntax ``@($global_clock)`` can be used to create FFs that have no
|
||||
explicit clock input (``$ff`` cells). The same can be achieved by using
|
||||
``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>`` is
|
||||
marked with the ``(* gclk *)`` Verilog attribute.
|
||||
|
||||
|
||||
Supported features from SystemVerilog
|
||||
-------------------------------------
|
||||
|
||||
When `read_verilog` is called with ``-sv``, it accepts some language features
|
||||
from SystemVerilog:
|
||||
|
||||
- The ``assert`` statement from SystemVerilog is supported in its most basic
|
||||
form. In module context: ``assert property (<expression>);`` and within an
|
||||
always block: ``assert(<expression>);``. It is transformed to an ``$assert``
|
||||
cell.
|
||||
|
||||
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
|
||||
also supported. The same limitations as with the ``assert`` statement apply.
|
||||
|
||||
- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic``
|
||||
and ``bit`` are supported.
|
||||
|
||||
- Declaring free variables with ``rand`` and ``rand const`` is supported.
|
||||
|
||||
- Checkers without a port list that do not need to be instantiated (but instead
|
||||
behave like a named block) are supported.
|
||||
|
||||
- SystemVerilog packages are supported. Once a SystemVerilog file is read into a
|
||||
design with `read_verilog`, all its packages are available to SystemVerilog
|
||||
files being read into the same design afterwards.
|
||||
|
||||
- typedefs are supported (including inside packages)
|
||||
- type casts are currently not supported
|
||||
|
||||
- enums are supported (including inside packages)
|
||||
- but are currently not strongly typed
|
||||
|
||||
- packed structs and unions are supported
|
||||
- arrays of packed structs/unions are currently not supported
|
||||
- structure literals are currently not supported
|
||||
|
||||
- multidimensional arrays are supported
|
||||
- array assignment of unpacked arrays is currently not supported
|
||||
- array literals are currently not supported
|
||||
|
||||
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
|
||||
ports are inputs or outputs are supported.
|
||||
|
||||
- Assignments within expressions are supported.
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
from pygments.lexer import RegexLexer, bygroups, include
|
||||
from pygments.token import (Comment, Error, Keyword, Name, Number, Operator,
|
||||
String, Whitespace)
|
||||
|
||||
__all__ = ['YoscryptLexer']
|
||||
|
||||
class YoscryptLexer(RegexLexer):
|
||||
name = 'Yosys Script'
|
||||
aliases = ['yoscrypt']
|
||||
filenames = ['*.ys']
|
||||
|
||||
|
||||
|
||||
tokens = {
|
||||
'common': [
|
||||
(r'\s+', Whitespace),
|
||||
(r'#.*', Comment.Single),
|
||||
(r'"', String, 'string'),
|
||||
(r'(\d+)(\')([bdho]? ?\w+)', bygroups(Number, Operator, Number)),
|
||||
(r'(\d+\.\d+)', Number.Float),
|
||||
(r'(\d+)', Number),
|
||||
(r'(\$[A-Za-z_0-9]*)', Name.Builtin),
|
||||
(r'([A-Za-z_][A-Za-z_0-9\.\\/:-]*)', Name),
|
||||
(r'(\[)(-\S*)(\])', # optional command
|
||||
bygroups(Operator, Name.Attribute, Operator)),
|
||||
(r'([\[<]\w*[\]>])', Name), # arguments
|
||||
(r'[\{\}\|=\[\],]', Operator),
|
||||
(r'.', Comment),
|
||||
],
|
||||
'root': [
|
||||
(r'([A-Za-z_][A-Za-z_0-9]*)', Keyword, 'command'),
|
||||
(r'(-[A-Za-z_][A-Za-z_0-9]*)', Name.Attribute, 'command'), # shortcut for options
|
||||
include('common'),
|
||||
],
|
||||
'command': [
|
||||
(r'(-[A-Za-z_][A-Za-z_0-9]*)', Name.Attribute),
|
||||
(r'\+/[^\s]+', Name.Class),
|
||||
(r'$', Whitespace, '#pop'),
|
||||
(r';(?=\s)', Operator, '#pop'),
|
||||
(r';{2,3}(?=\s)', Name.Class, '#pop'),
|
||||
(r';{1,3}', Error, '#pop'),
|
||||
(r'([ANwismctparn]:)', Keyword.Type, 'pattern'),
|
||||
(r'@', Keyword.Type),
|
||||
(r'%(x|ci|co)e?', Keyword.Type, 'expansion'),
|
||||
(r'%[%nuidDcasmMCR]?', Keyword.Type),
|
||||
(r'/', Operator),
|
||||
include('common'),
|
||||
],
|
||||
'pattern': [
|
||||
(r'<<', Name), # Not an operator
|
||||
(r'(=|<|<=|>|>=)', Operator),
|
||||
(r':', Keyword.Type),
|
||||
(r'$', Whitespace, '#pop:2'),
|
||||
(r'\s+', Whitespace, '#pop'),
|
||||
include('common'),
|
||||
],
|
||||
'expansion': [
|
||||
(r'$', Name.Class, '#pop:2'),
|
||||
(r';(?=\s)', Operator, '#pop:2'),
|
||||
(r';{2,3}(?=\s)', Name.Class, '#pop:2'),
|
||||
(r'\s', Whitespace, '#pop'),
|
||||
(r'[0-9\*]{1,3}', Number),
|
||||
(r'[:+-,\[\]]', Operator),
|
||||
include('common'),
|
||||
],
|
||||
'string': [
|
||||
(r'"', String, '#pop'),
|
||||
(r'\\([\\abfnrtv"\']|x[a-fA-F0-9]{2,4}|[0-7]{1,3})', String.Escape),
|
||||
(r'[^\\"\n]+', String), # all other characters
|
||||
(r'(\\)(\n)', bygroups(String.Escape, Whitespace)), # line continuation
|
||||
(r'\\', String), # stray backslash
|
||||
]
|
||||
}
|
||||
415
docs/util/cellref.py
Normal file
415
docs/util/cellref.py
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
#!/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__)
|
||||
|
||||
# cell signature
|
||||
cell_ext_sig_re = re.compile(
|
||||
r'''^ ([^:\s]+::)? # optional group or file name
|
||||
([\w$._]+?) # module name
|
||||
(?:\.([\w_]+))? # optional: thing name
|
||||
(::[\w_]+)? # attribute
|
||||
\s* $ # and nothing more
|
||||
''', re.VERBOSE)
|
||||
|
||||
@dataclass
|
||||
class YosysCell:
|
||||
name: str
|
||||
title: str
|
||||
ports: str
|
||||
source: str
|
||||
desc: str
|
||||
code: str
|
||||
inputs: list[str]
|
||||
outputs: list[str]
|
||||
properties: list[str]
|
||||
|
||||
class YosysCellGroupDocumenter(Documenter):
|
||||
objtype = 'cellgroup'
|
||||
priority = 10
|
||||
object: tuple[str, list[str]]
|
||||
lib_key = 'groups'
|
||||
|
||||
option_spec = {
|
||||
'caption': autodoc.annotation_option,
|
||||
'members': autodoc.members_option,
|
||||
'source': autodoc.bool_option,
|
||||
'linenos': autodoc.bool_option,
|
||||
}
|
||||
|
||||
__cell_lib: dict[str, list[str] | dict[str]] | None = None
|
||||
@property
|
||||
def cell_lib(self) -> dict[str, list[str] | dict[str]]:
|
||||
if not self.__cell_lib:
|
||||
self.__cell_lib = {}
|
||||
cells_obj: dict[str, dict[str, list[str] | dict[str]]]
|
||||
try:
|
||||
with open(self.config.cells_json, "r") as f:
|
||||
cells_obj = json.loads(f.read())
|
||||
except FileNotFoundError:
|
||||
logger.warning(
|
||||
f"unable to find cell lib at {self.config.cells_json}",
|
||||
type = 'cellref',
|
||||
subtype = 'cell_lib'
|
||||
)
|
||||
else:
|
||||
for (name, obj) in cells_obj.get(self.lib_key, {}).items():
|
||||
self.__cell_lib[name] = obj
|
||||
return self.__cell_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 cell
|
||||
try:
|
||||
self.object = (self.modname, self.cell_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:
|
||||
domain = getattr(self, 'domain', 'cell')
|
||||
directive = getattr(self, 'directivetype', 'group')
|
||||
name = self.format_name()
|
||||
sourcename = self.get_sourcename()
|
||||
cell_list = self.object
|
||||
|
||||
# cell definition
|
||||
self.add_line(f'.. {domain}:{directive}:: {sig}', sourcename)
|
||||
self.add_line(f' :caption: {name}', sourcename)
|
||||
|
||||
if self.options.noindex:
|
||||
self.add_line(' :noindex:', sourcename)
|
||||
|
||||
def add_content(self, more_content: Any | None) -> None:
|
||||
# groups have no native content
|
||||
# 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 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='cellref')
|
||||
|
||||
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 cell lib to import from
|
||||
logger.warning(
|
||||
f"don't know which cell lib to import for autodocumenting {self.name}",
|
||||
type = 'cellref'
|
||||
)
|
||||
return
|
||||
|
||||
if not self.import_object():
|
||||
logger.warning(
|
||||
f"unable to load {self.name}",
|
||||
type = 'cellref'
|
||||
)
|
||||
return
|
||||
|
||||
# check __module__ of object (for members not given explicitly)
|
||||
# if check_module:
|
||||
# if not self.check_module():
|
||||
# return
|
||||
|
||||
sourcename = self.get_sourcename()
|
||||
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='cellref')
|
||||
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 YosysCellDocumenter(YosysCellGroupDocumenter):
|
||||
objtype = 'cell'
|
||||
priority = 15
|
||||
object: YosysCell
|
||||
lib_key = 'cells'
|
||||
|
||||
@classmethod
|
||||
def can_document_member(
|
||||
cls,
|
||||
member: Any,
|
||||
membername: str,
|
||||
isattr: bool,
|
||||
parent: Any
|
||||
) -> bool:
|
||||
if membername == "__source":
|
||||
return False
|
||||
if not membername.startswith('$'):
|
||||
return False
|
||||
return isinstance(parent, YosysCellGroupDocumenter)
|
||||
|
||||
def parse_name(self) -> bool:
|
||||
try:
|
||||
matched = cell_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='cellref')
|
||||
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 = YosysCell(self.modname, **self.object[1])
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_sourcename(self) -> str:
|
||||
return self.object.source.split(":")[0]
|
||||
|
||||
def format_name(self) -> str:
|
||||
return self.object.name
|
||||
|
||||
def format_signature(self, **kwargs: Any) -> str:
|
||||
return self.groupname + self.fullname + self.attribute
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
domain = getattr(self, 'domain', self.objtype)
|
||||
directive = getattr(self, 'directivetype', 'def')
|
||||
name = self.format_name()
|
||||
sourcename = self.get_sourcename()
|
||||
cell = self.object
|
||||
|
||||
# cell definition
|
||||
self.add_line(f'.. {domain}:{directive}:: {sig}', sourcename)
|
||||
|
||||
# options
|
||||
opt_attrs = ["title", "properties", ]
|
||||
for attr in opt_attrs:
|
||||
val = getattr(cell, attr, None)
|
||||
if isinstance(val, list):
|
||||
val = ' '.join(val)
|
||||
if val:
|
||||
self.add_line(f' :{attr}: {val}', sourcename)
|
||||
|
||||
self.add_line('\n', sourcename)
|
||||
|
||||
if self.options.noindex:
|
||||
self.add_line(' :noindex:', sourcename)
|
||||
|
||||
def add_content(self, more_content: Any | None) -> None:
|
||||
# set sourcename and add content from attribute documentation
|
||||
sourcename = self.get_sourcename()
|
||||
startline = int(self.object.source.split(":")[1])
|
||||
|
||||
for i, line in enumerate(self.object.desc.splitlines(), startline):
|
||||
self.add_line(line, sourcename, i)
|
||||
|
||||
# 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])
|
||||
|
||||
# fields
|
||||
self.add_line('\n', sourcename)
|
||||
field_attrs = ["properties", ]
|
||||
for field in field_attrs:
|
||||
attr = getattr(self.object, field, [])
|
||||
for val in attr:
|
||||
self.add_line(f':{field} {val}:', sourcename)
|
||||
|
||||
def get_object_members(
|
||||
self,
|
||||
want_all: bool
|
||||
) -> tuple[bool, list[tuple[str, Any]]]:
|
||||
ret: list[tuple[str, str]] = []
|
||||
|
||||
if self.options.source:
|
||||
ret.append(('__source', self.real_modname))
|
||||
|
||||
return False, ret
|
||||
|
||||
class YosysCellSourceDocumenter(YosysCellDocumenter):
|
||||
objtype = 'cellsource'
|
||||
priority = 20
|
||||
|
||||
@classmethod
|
||||
def can_document_member(
|
||||
cls,
|
||||
member: Any,
|
||||
membername: str,
|
||||
isattr: bool,
|
||||
parent: Any
|
||||
) -> bool:
|
||||
if membername != "__source":
|
||||
return False
|
||||
if isinstance(parent, YosysCellDocumenter):
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
domain = getattr(self, 'domain', 'cell')
|
||||
directive = getattr(self, 'directivetype', 'source')
|
||||
name = self.format_name()
|
||||
sourcename = self.get_sourcename()
|
||||
cell = self.object
|
||||
|
||||
# cell definition
|
||||
self.add_line(f'.. {domain}:{directive}:: {sig}', sourcename)
|
||||
|
||||
if self.options.linenos:
|
||||
self.add_line(f' :source: {cell.source.split(":")[0]}', sourcename)
|
||||
else:
|
||||
self.add_line(f' :source: {cell.source}', sourcename)
|
||||
self.add_line(f' :language: verilog', sourcename)
|
||||
|
||||
if self.options.linenos:
|
||||
startline = int(self.object.source.split(":")[1])
|
||||
self.add_line(f' :lineno-start: {startline}', sourcename)
|
||||
|
||||
if self.options.noindex:
|
||||
self.add_line(' :noindex:', sourcename)
|
||||
|
||||
def add_content(self, more_content: Any | None) -> None:
|
||||
# set sourcename and add content from attribute documentation
|
||||
sourcename = self.get_sourcename()
|
||||
startline = int(self.object.source.split(":")[1])
|
||||
|
||||
for i, line in enumerate(self.object.code.splitlines(), startline-1):
|
||||
self.add_line(line, sourcename, i)
|
||||
|
||||
# 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, []
|
||||
|
||||
def setup(app: Sphinx) -> dict[str, Any]:
|
||||
app.add_config_value('cells_json', False, 'html', [Path, PosixPath, WindowsPath])
|
||||
app.setup_extension('sphinx.ext.autodoc')
|
||||
app.add_autodocumenter(YosysCellDocumenter)
|
||||
app.add_autodocumenter(YosysCellSourceDocumenter)
|
||||
app.add_autodocumenter(YosysCellGroupDocumenter)
|
||||
return {
|
||||
'version': '1',
|
||||
'parallel_read_safe': True,
|
||||
}
|
||||
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