mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'YosysHQ:main' into new_peepopts
This commit is contained in:
commit
0ddb3d7d81
|
@ -32,9 +32,9 @@ jobs:
|
||||||
# oldest supported
|
# oldest supported
|
||||||
- 'clang-14'
|
- 'clang-14'
|
||||||
- 'gcc-10'
|
- 'gcc-10'
|
||||||
# newest
|
# newest, make sure to update maximum standard step to match
|
||||||
- 'clang'
|
- 'clang-18'
|
||||||
- 'gcc'
|
- 'gcc-13'
|
||||||
include:
|
include:
|
||||||
# macOS
|
# macOS
|
||||||
- os: macos-13
|
- os: macos-13
|
||||||
|
@ -72,7 +72,7 @@ jobs:
|
||||||
|
|
||||||
# maximum standard, only on newest compilers
|
# maximum standard, only on newest compilers
|
||||||
- name: Build C++20
|
- name: Build C++20
|
||||||
if: ${{ matrix.compiler == 'clang' || matrix.compiler == 'gcc'}}
|
if: ${{ matrix.compiler == 'clang-18' || matrix.compiler == 'gcc-13' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
make config-$CC_SHORT
|
make config-$CC_SHORT
|
||||||
|
|
29
CHANGELOG
29
CHANGELOG
|
@ -2,9 +2,36 @@
|
||||||
List of major changes and improvements between releases
|
List of major changes and improvements between releases
|
||||||
=======================================================
|
=======================================================
|
||||||
|
|
||||||
Yosys 0.47 .. Yosys 0.48-dev
|
Yosys 0.48 .. Yosys 0.49-dev
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
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
|
Yosys 0.46 .. Yosys 0.47
|
||||||
--------------------------
|
--------------------------
|
||||||
* Various
|
* Various
|
||||||
|
|
|
@ -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.
|
82
Makefile
82
Makefile
|
@ -2,9 +2,7 @@
|
||||||
CONFIG := none
|
CONFIG := none
|
||||||
# CONFIG := clang
|
# CONFIG := clang
|
||||||
# CONFIG := gcc
|
# CONFIG := gcc
|
||||||
# CONFIG := afl-gcc
|
|
||||||
# CONFIG := wasi
|
# CONFIG := wasi
|
||||||
# CONFIG := mxe
|
|
||||||
# CONFIG := msys2-32
|
# CONFIG := msys2-32
|
||||||
# CONFIG := msys2-64
|
# CONFIG := msys2-64
|
||||||
|
|
||||||
|
@ -155,7 +153,7 @@ ifeq ($(OS), Haiku)
|
||||||
CXXFLAGS += -D_DEFAULT_SOURCE
|
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
YOSYS_VER := 0.47+46
|
YOSYS_VER := 0.48+5
|
||||||
|
|
||||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
||||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
||||||
|
@ -171,7 +169,7 @@ endif
|
||||||
OBJS = kernel/version_$(GIT_REV).o
|
OBJS = kernel/version_$(GIT_REV).o
|
||||||
|
|
||||||
bumpversion:
|
bumpversion:
|
||||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 647d61d.. | wc -l`/;" Makefile
|
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline aaa5347.. | wc -l`/;" Makefile
|
||||||
|
|
||||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
||||||
|
|
||||||
|
@ -265,16 +263,6 @@ ifeq ($(DISABLE_ABC_THREADS),1)
|
||||||
ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
|
ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
|
||||||
endif
|
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)
|
else ifeq ($(CONFIG),wasi)
|
||||||
ifeq ($(WASI_SDK),)
|
ifeq ($(WASI_SDK),)
|
||||||
CXX = clang++
|
CXX = clang++
|
||||||
|
@ -302,18 +290,6 @@ LINK_ABC := 1
|
||||||
DISABLE_ABC_THREADS := 1
|
DISABLE_ABC_THREADS := 1
|
||||||
endif
|
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)
|
else ifeq ($(CONFIG),msys2-32)
|
||||||
CXX = i686-w64-mingw32-g++
|
CXX = i686-w64-mingw32-g++
|
||||||
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||||
|
@ -340,7 +316,7 @@ ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
||||||
LTOFLAGS =
|
LTOFLAGS =
|
||||||
|
|
||||||
else
|
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
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -392,16 +368,12 @@ ifeq ($(LINK_TERMCAP),1)
|
||||||
LIBS += -ltermcap
|
LIBS += -ltermcap
|
||||||
ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap"
|
ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap"
|
||||||
endif
|
endif
|
||||||
ifeq ($(CONFIG),mxe)
|
|
||||||
LIBS += -ltermcap
|
|
||||||
endif
|
|
||||||
else
|
else
|
||||||
ifeq ($(ENABLE_EDITLINE),1)
|
ifeq ($(ENABLE_EDITLINE),1)
|
||||||
CXXFLAGS += -DYOSYS_ENABLE_EDITLINE
|
CXXFLAGS += -DYOSYS_ENABLE_EDITLINE
|
||||||
LIBS += -ledit -ltinfo -lbsd
|
LIBS += -ledit
|
||||||
else
|
|
||||||
ABCMKARGS += "ABC_USE_NO_READLINE=1"
|
|
||||||
endif
|
endif
|
||||||
|
ABCMKARGS += "ABC_USE_NO_READLINE=1"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(DISABLE_ABC_THREADS),1)
|
ifeq ($(DISABLE_ABC_THREADS),1)
|
||||||
|
@ -444,12 +416,10 @@ TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
|
||||||
TCL_LIBS ?= -l$(TCL_VERSION)
|
TCL_LIBS ?= -l$(TCL_VERSION)
|
||||||
endif
|
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
|
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))
|
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
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -640,7 +610,7 @@ $(eval $(call add_include_file,frontends/blif/blifparse.h))
|
||||||
$(eval $(call add_include_file,backends/rtlil/rtlil_backend.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/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/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
|
OBJS += kernel/drivertools.o kernel/functional.o
|
||||||
ifeq ($(ENABLE_ZLIB),1)
|
ifeq ($(ENABLE_ZLIB),1)
|
||||||
|
@ -997,15 +967,12 @@ docs/source/cell/word_add.rst: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
|
docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
|
||||||
$(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@'
|
$(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@'
|
||||||
|
|
||||||
PHONY: docs/gen docs/guidelines docs/usage docs/reqs
|
PHONY: docs/gen docs/usage docs/reqs
|
||||||
docs/gen: $(TARGETS)
|
docs/gen: $(TARGETS)
|
||||||
$(Q) $(MAKE) -C docs gen
|
$(Q) $(MAKE) -C docs gen
|
||||||
|
|
||||||
DOCS_GUIDELINE_FILES := GettingStarted CodingStyle
|
docs/source/generated:
|
||||||
DOCS_GUIDELINE_SOURCE := $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES))
|
|
||||||
docs/guidelines docs/source/generated: $(DOCS_GUIDELINE_SOURCE)
|
|
||||||
$(Q) mkdir -p 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
|
# some commands return an error and print the usage text to stderr
|
||||||
define DOC_USAGE_STDERR
|
define DOC_USAGE_STDERR
|
||||||
|
@ -1035,7 +1002,7 @@ docs/reqs:
|
||||||
$(Q) $(MAKE) -C docs reqs
|
$(Q) $(MAKE) -C docs reqs
|
||||||
|
|
||||||
.PHONY: docs/prep
|
.PHONY: docs/prep
|
||||||
docs/prep: docs/source/cmd/abc.rst docs/source/generated/cells.json docs/gen docs/guidelines docs/usage
|
docs/prep: docs/source/cmd/abc.rst docs/source/generated/cells.json docs/gen docs/usage
|
||||||
|
|
||||||
DOC_TARGET ?= html
|
DOC_TARGET ?= html
|
||||||
docs: docs/prep
|
docs: docs/prep
|
||||||
|
@ -1102,19 +1069,6 @@ vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
|
||||||
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
|
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
|
||||||
rm -f srcfiles.txt kernel/version.cc
|
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
|
config-clean: clean
|
||||||
rm -f Makefile.conf
|
rm -f Makefile.conf
|
||||||
|
|
||||||
|
@ -1130,9 +1084,6 @@ config-gcc-static: clean
|
||||||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||||
|
|
||||||
config-afl-gcc: clean
|
|
||||||
echo 'CONFIG := afl-gcc' > Makefile.conf
|
|
||||||
|
|
||||||
config-wasi: clean
|
config-wasi: clean
|
||||||
echo 'CONFIG := wasi' > Makefile.conf
|
echo 'CONFIG := wasi' > Makefile.conf
|
||||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||||
|
@ -1141,10 +1092,6 @@ config-wasi: clean
|
||||||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||||
echo 'ENABLE_ZLIB := 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
|
config-msys2-32: clean
|
||||||
echo 'CONFIG := msys2-32' > Makefile.conf
|
echo 'CONFIG := msys2-32' > Makefile.conf
|
||||||
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
||||||
|
@ -1153,9 +1100,6 @@ config-msys2-64: clean
|
||||||
echo 'CONFIG := msys2-64' > Makefile.conf
|
echo 'CONFIG := msys2-64' > Makefile.conf
|
||||||
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf
|
||||||
|
|
||||||
config-cygwin: clean
|
|
||||||
echo 'CONFIG := cygwin' > Makefile.conf
|
|
||||||
|
|
||||||
config-gcov: clean
|
config-gcov: clean
|
||||||
echo 'CONFIG := gcc' > Makefile.conf
|
echo 'CONFIG := gcc' > Makefile.conf
|
||||||
echo 'ENABLE_GCOV := 1' >> Makefile.conf
|
echo 'ENABLE_GCOV := 1' >> Makefile.conf
|
||||||
|
@ -1184,5 +1128,5 @@ echo-cxx:
|
||||||
-include kernel/*.d
|
-include kernel/*.d
|
||||||
-include techlibs/*/*.d
|
-include techlibs/*/*.d
|
||||||
|
|
||||||
.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc mxebin
|
.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-afl-gcc config-gprof config-sudo
|
.PHONY: config-clean config-clang config-gcc config-gcc-static config-gprof config-sudo
|
||||||
|
|
480
README.md
480
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
|
yosys – Yosys Open SYnthesis Suite
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
|
@ -37,23 +18,21 @@ Third-party software distributed alongside this software
|
||||||
is licensed under compatible licenses.
|
is licensed under compatible licenses.
|
||||||
Please refer to `abc` and `libs` subdirectories for their license terms.
|
Please refer to `abc` and `libs` subdirectories for their license terms.
|
||||||
|
|
||||||
|
|
||||||
Web Site and Other Resources
|
Web Site and Other Resources
|
||||||
============================
|
============================
|
||||||
|
|
||||||
More information and documentation can be found on the Yosys web site:
|
More information and documentation can be found on the Yosys web site:
|
||||||
- https://yosyshq.net/yosys/
|
- https://yosyshq.net/yosys/
|
||||||
|
|
||||||
The "Documentation" page on the web site contains links to more resources,
|
Documentation from this repository is automatically built and available on Read
|
||||||
including a manual that even describes some of the Yosys internals:
|
the Docs:
|
||||||
- https://yosyshq.net/yosys/documentation.html
|
- https://yosyshq.readthedocs.io/projects/yosys
|
||||||
|
|
||||||
The directory `guidelines` contains additional information
|
Users interested in formal verification might want to use the formal
|
||||||
for people interested in using the Yosys C++ APIs.
|
verification front-end for Yosys, SBY:
|
||||||
|
- https://yosyshq.readthedocs.io/projects/sby/
|
||||||
Users interested in formal verification might want to use the formal verification
|
- https://github.com/YosysHQ/sby
|
||||||
front-end for Yosys, SymbiYosys:
|
|
||||||
- https://symbiyosys.readthedocs.io/en/latest/
|
|
||||||
- https://github.com/YosysHQ/SymbiYosys
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
|
@ -71,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!
|
Many Linux distributions also provide Yosys binaries, some more up to date than others. Check with your package manager!
|
||||||
|
|
||||||
|
|
||||||
Building from Source
|
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
|
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.
|
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).
|
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
|
||||||
|
@ -87,58 +82,22 @@ prerequisites for building yosys:
|
||||||
graphviz xdot pkg-config python3 libboost-system-dev \
|
graphviz xdot pkg-config python3 libboost-system-dev \
|
||||||
libboost-python-dev libboost-filesystem-dev zlib1g-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
|
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-clang
|
||||||
$ make config-gcc
|
$ make config-gcc
|
||||||
|
|
||||||
Note that these will result in `make` ignoring the `CXX` environment variable,
|
The Makefile has many variables influencing the build process. These can be
|
||||||
unless `CXX` is assigned in the call to make, e.g.
|
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
|
$ make CXX=$CXX
|
||||||
|
|
||||||
The Makefile has many variables influencing the build process. These can be
|
For other compilers and build configurations it might be necessary to make some
|
||||||
adjusted by modifying the Makefile.conf file which is created at the
|
changes to the config section of the Makefile. It's also an alternative way to
|
||||||
`make config-...` step (see above), or they can be set by passing an option
|
set the make variables mentioned above.
|
||||||
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
|
|
||||||
|
|
||||||
On macOS, LTO requires using clang from homebrew which isn't in PATH
|
|
||||||
rather than xcode clang.
|
|
||||||
|
|
||||||
$ make ENABLE_LTO=1 CXX=$(brew --prefix)/opt/llvm/bin/clang++
|
|
||||||
|
|
||||||
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 # ..or..
|
||||||
$ vi Makefile.conf
|
$ vi Makefile.conf
|
||||||
|
@ -148,10 +107,9 @@ To build Yosys simply type 'make' in this directory.
|
||||||
$ make
|
$ make
|
||||||
$ sudo make install
|
$ sudo make install
|
||||||
|
|
||||||
Note that this also downloads, builds and installs ABC (using yosys-abc
|
Tests are located in the tests subdirectory and can be executed using the test
|
||||||
as executable name).
|
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
|
$ make test
|
||||||
|
|
||||||
|
@ -162,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.
|
Out-of-tree builds require a clean source tree.
|
||||||
|
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
@ -266,365 +225,14 @@ The command ``prep`` provides a good default word-level synthesis script, as
|
||||||
used in SMT-based formal verification.
|
used in SMT-based formal verification.
|
||||||
|
|
||||||
|
|
||||||
Unsupported Verilog-2005 Features
|
Additional information
|
||||||
=================================
|
======================
|
||||||
|
|
||||||
The following Verilog-2005 features are not supported by
|
The ``read_verilog`` command, used by default when calling ``read`` with Verilog
|
||||||
Yosys and there are currently no plans to add support
|
source input, does not perform syntax checking. You should instead lint your
|
||||||
for them:
|
source with another tool such as
|
||||||
|
[Verilator](https://www.veripool.org/verilator/) first, e.g. by calling
|
||||||
- Non-synthesizable language features as defined in
|
``verilator --lint-only``.
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Building the documentation
|
Building the documentation
|
||||||
|
|
|
@ -262,7 +262,8 @@ struct Index {
|
||||||
if (cell->type.in(ID($gt), ID($ge)))
|
if (cell->type.in(ID($gt), ID($ge)))
|
||||||
std::swap(aport, bport);
|
std::swap(aport, bport);
|
||||||
int carry = cell->type.in(ID($le), ID($ge)) ? CFALSE : CTRUE;
|
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
|
// TODO: this might not be the most economic structure; revisit at a later date
|
||||||
for (int i = 0; i < width; i++) {
|
for (int i = 0; i < width; i++) {
|
||||||
a = visit(cursor, aport[i]);
|
a = visit(cursor, aport[i]);
|
||||||
|
@ -664,8 +665,6 @@ struct Index {
|
||||||
struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
||||||
typedef unsigned int Lit;
|
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();
|
const static constexpr Lit EMPTY_LIT = std::numeric_limits<Lit>::max();
|
||||||
|
|
||||||
static Lit negate(Lit lit) {
|
static Lit negate(Lit lit) {
|
||||||
|
@ -802,8 +801,6 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
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;
|
const static constexpr int EMPTY_LIT = -1;
|
||||||
|
|
||||||
XAigerAnalysis()
|
XAigerAnalysis()
|
||||||
|
@ -835,12 +832,8 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Cell *driver = bit.wire->driverCell();
|
Cell *driver = bit.wire->driverCell();
|
||||||
if (!driver->type.isPublic())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Module *mod = design->module(driver->type);
|
Module *mod = design->module(driver->type);
|
||||||
log_assert(mod);
|
if (!mod || !mod->has_attribute(ID::abc9_box_id))
|
||||||
if (!mod->has_attribute(ID::abc9_box_id))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int max = 1;
|
int max = 1;
|
||||||
|
@ -873,7 +866,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
||||||
HierCursor cursor;
|
HierCursor cursor;
|
||||||
for (auto box : top_minfo->found_blackboxes) {
|
for (auto box : top_minfo->found_blackboxes) {
|
||||||
Module *def = design->module(box->type);
|
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_)
|
for (auto &conn : box->connections_)
|
||||||
if (box->output(conn.first))
|
if (box->output(conn.first))
|
||||||
for (auto bit : conn.second)
|
for (auto bit : conn.second)
|
||||||
|
@ -888,7 +881,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
|
||||||
|
|
||||||
for (auto box : top_minfo->found_blackboxes) {
|
for (auto box : top_minfo->found_blackboxes) {
|
||||||
Module *def = design->module(box->type);
|
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_)
|
for (auto &conn : box->connections_)
|
||||||
if (box->input(conn.first))
|
if (box->input(conn.first))
|
||||||
for (auto bit : conn.second)
|
for (auto bit : conn.second)
|
||||||
|
@ -1109,7 +1102,7 @@ struct XAigerWriter : AigerWriter {
|
||||||
holes_module->ports.push_back(w->name);
|
holes_module->ports.push_back(w->name);
|
||||||
holes_pis.push_back(w);
|
holes_pis.push_back(w);
|
||||||
}
|
}
|
||||||
in_conn.append(holes_pis[i]);
|
in_conn.append(holes_pis[holes_pi_idx]);
|
||||||
holes_pi_idx++;
|
holes_pi_idx++;
|
||||||
}
|
}
|
||||||
holes_wb->setPort(port_id, in_conn);
|
holes_wb->setPort(port_id, in_conn);
|
||||||
|
|
|
@ -338,7 +338,7 @@ struct EdifBackend : public Backend {
|
||||||
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
|
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
|
||||||
else {
|
else {
|
||||||
std::string hex_string = "";
|
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;
|
int digit_value = 0;
|
||||||
if (i+0 < val.size() && val.at(i+0) == RTLIL::State::S1) digit_value |= 1;
|
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;
|
if (i+1 < val.size() && val.at(i+1) == RTLIL::State::S1) digit_value |= 2;
|
||||||
|
|
|
@ -353,6 +353,9 @@ struct JsonBackend : public Backend {
|
||||||
log(" emit 32-bit or smaller fully-defined parameter values directly\n");
|
log(" emit 32-bit or smaller fully-defined parameter values directly\n");
|
||||||
log(" as JSON numbers (for compatibility with old parsers)\n");
|
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -selected\n");
|
||||||
|
log(" output only select module\n");
|
||||||
|
log("\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("The general syntax of the JSON output created by this command is as follows:\n");
|
log("The general syntax of the JSON output created by this command is as follows:\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -597,6 +600,7 @@ struct JsonBackend : public Backend {
|
||||||
{
|
{
|
||||||
bool aig_mode = false;
|
bool aig_mode = false;
|
||||||
bool compat_int_mode = false;
|
bool compat_int_mode = false;
|
||||||
|
bool use_selection = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
@ -609,13 +613,17 @@ struct JsonBackend : public Backend {
|
||||||
compat_int_mode = true;
|
compat_int_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-selected") {
|
||||||
|
use_selection = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(f, filename, args, argidx);
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
||||||
log_header(design, "Executing JSON backend.\n");
|
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);
|
||||||
json_writer.write_design(design);
|
json_writer.write_design(design);
|
||||||
}
|
}
|
||||||
} JsonBackend;
|
} JsonBackend;
|
||||||
|
|
|
@ -1071,7 +1071,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->type == ID($_BUF_)) {
|
if (cell->type.in(ID($_BUF_), ID($buf))) {
|
||||||
f << stringf("%s" "assign ", indent.c_str());
|
f << stringf("%s" "assign ", indent.c_str());
|
||||||
dump_sigspec(f, cell->getPort(ID::Y));
|
dump_sigspec(f, cell->getPort(ID::Y));
|
||||||
f << stringf(" = ");
|
f << stringf(" = ");
|
||||||
|
@ -2332,19 +2332,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
||||||
|
|
||||||
dump_attributes(f, indent, module->attributes, "\n", /*modattr=*/true);
|
dump_attributes(f, indent, module->attributes, "\n", /*modattr=*/true);
|
||||||
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
|
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
|
||||||
bool keep_running = true;
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
for (int port_id = 1; keep_running; port_id++) {
|
for (auto port : module->ports) {
|
||||||
keep_running = false;
|
Wire *wire = module->wire(port);
|
||||||
for (auto wire : module->wires()) {
|
if (wire) {
|
||||||
if (wire->port_id == port_id) {
|
if (port != module->ports[0])
|
||||||
if (port_id != 1)
|
f << stringf(", ");
|
||||||
f << stringf(", ");
|
f << stringf("%s", id(wire->name).c_str());
|
||||||
f << stringf("%s", id(wire->name).c_str());
|
if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++;
|
||||||
keep_running = true;
|
continue;
|
||||||
if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f << stringf(");\n");
|
f << stringf(");\n");
|
||||||
|
|
|
@ -242,7 +242,7 @@ Processes
|
||||||
|
|
||||||
Declares a process, with zero or more attributes, with the given identifier in
|
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
|
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.
|
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>
|
<process> ::= <attr-stmt>* <proc-stmt> <process-body> <proc-end-stmt>
|
||||||
<proc-stmt> ::= process <id> <eol>
|
<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>
|
<assign-stmt> ::= assign <dest-sigspec> <src-sigspec> <eol>
|
||||||
<dest-sigspec> ::= <sigspec>
|
<dest-sigspec> ::= <sigspec>
|
||||||
<src-sigspec> ::= <sigspec>
|
<src-sigspec> ::= <sigspec>
|
||||||
|
@ -262,8 +262,8 @@ Switches
|
||||||
Switches test a signal for equality against a list of cases. Each case specifies
|
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
|
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
|
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
|
or more assignments followed by zero or more switches. Both switches and cases
|
||||||
attributes.
|
may have zero or more attributes.
|
||||||
|
|
||||||
.. code:: BNF
|
.. code:: BNF
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ attributes.
|
||||||
<case> ::= <attr-stmt>* <case-stmt> <case-body>
|
<case> ::= <attr-stmt>* <case-stmt> <case-body>
|
||||||
<case-stmt> ::= case <compare>? <eol>
|
<case-stmt> ::= case <compare>? <eol>
|
||||||
<compare> ::= <sigspec> (, <sigspec>)*
|
<compare> ::= <sigspec> (, <sigspec>)*
|
||||||
<case-body> ::= (<switch> | <assign-stmt>)*
|
<case-body> ::= <assign-stmt>* <switch>*
|
||||||
<switch-end-stmt> ::= end <eol>
|
<switch-end-stmt> ::= end <eol>
|
||||||
|
|
||||||
Syncs
|
Syncs
|
||||||
|
|
|
@ -5,7 +5,7 @@ module addr_gen
|
||||||
) ( input en, clk, rst,
|
) ( input en, clk, rst,
|
||||||
output reg [AWIDTH-1:0] addr
|
output reg [AWIDTH-1:0] addr
|
||||||
);
|
);
|
||||||
initial addr <= 0;
|
initial addr = 0;
|
||||||
|
|
||||||
// async reset
|
// async reset
|
||||||
// increment address when enabled
|
// increment address when enabled
|
||||||
|
@ -13,7 +13,7 @@ module addr_gen
|
||||||
if (rst)
|
if (rst)
|
||||||
addr <= 0;
|
addr <= 0;
|
||||||
else if (en) begin
|
else if (en) begin
|
||||||
if (addr == MAX_DATA-1)
|
if ({'0, addr} == MAX_DATA-1)
|
||||||
addr <= 0;
|
addr <= 0;
|
||||||
else
|
else
|
||||||
addr <= addr + 1;
|
addr <= addr + 1;
|
||||||
|
@ -57,7 +57,7 @@ module fifo
|
||||||
);
|
);
|
||||||
|
|
||||||
// status signals
|
// status signals
|
||||||
initial count <= 0;
|
initial count = 0;
|
||||||
|
|
||||||
always @(posedge clk or posedge rst) begin
|
always @(posedge clk or posedge rst) begin
|
||||||
if (rst)
|
if (rst)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import os
|
||||||
project = 'YosysHQ Yosys'
|
project = 'YosysHQ Yosys'
|
||||||
author = 'YosysHQ GmbH'
|
author = 'YosysHQ GmbH'
|
||||||
copyright ='2024 YosysHQ GmbH'
|
copyright ='2024 YosysHQ GmbH'
|
||||||
yosys_ver = "0.47"
|
yosys_ver = "0.48"
|
||||||
|
|
||||||
# select HTML theme
|
# select HTML theme
|
||||||
html_theme = 'furo-ys'
|
html_theme = 'furo-ys'
|
||||||
|
@ -56,6 +56,9 @@ if os.getenv("READTHEDOCS"):
|
||||||
else:
|
else:
|
||||||
release = yosys_ver
|
release = yosys_ver
|
||||||
todo_include_todos = False
|
todo_include_todos = False
|
||||||
|
elif os.getenv("YOSYS_DOCS_RELEASE") is not None:
|
||||||
|
release = yosys_ver
|
||||||
|
todo_include_todos = False
|
||||||
else:
|
else:
|
||||||
release = yosys_ver
|
release = yosys_ver
|
||||||
todo_include_todos = True
|
todo_include_todos = True
|
||||||
|
@ -87,5 +90,9 @@ def setup(app: Sphinx) -> None:
|
||||||
from util.RtlilLexer import RtlilLexer
|
from util.RtlilLexer import RtlilLexer
|
||||||
app.add_lexer("RTLIL", RtlilLexer)
|
app.add_lexer("RTLIL", RtlilLexer)
|
||||||
|
|
||||||
from furo_ys.lexers.YoscryptLexer import YoscryptLexer
|
try:
|
||||||
app.add_lexer("yoscrypt", YoscryptLexer)
|
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)
|
||||||
|
|
|
@ -30,6 +30,14 @@ First, let's quickly look at the design we'll be synthesizing:
|
||||||
|
|
||||||
.. todo:: fifo.v description
|
.. 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
|
Loading the design
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,25 @@ The `OSS CAD Suite`_ releases `nightly builds`_ for the following architectures:
|
||||||
Building from source
|
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
|
Supported platforms
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -94,17 +110,116 @@ Installing all prerequisites for Ubuntu 20.04:
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
sudo sudo apt-get install build-essential clang lld bison flex \
|
sudo apt-get install gperf build-essential bison flex \
|
||||||
libreadline-dev gawk tcl-dev libffi-dev git make \
|
libreadline-dev gawk tcl-dev libffi-dev git graphviz \
|
||||||
graphviz xdot pkg-config python3 libboost-system-dev \
|
xdot pkg-config python3 libboost-system-dev \
|
||||||
libboost-python-dev libboost-filesystem-dev zlib1g-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
|
.. code:: console
|
||||||
|
|
||||||
brew install bison flex gawk libffi git graphviz \
|
brew tap Homebrew/bundle && brew bundle
|
||||||
pkg-config python3 tcl-tk xdot bash boost-python3
|
|
||||||
|
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
|
Running the build system
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -116,25 +231,14 @@ From the root ``yosys`` directory, call the following commands:
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
This will build and then install Yosys, making it available on the command line
|
To use a separate (out-of-tree) build directory, provide a path to the Makefile.
|
||||||
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:
|
|
||||||
|
|
||||||
.. code:: console
|
.. code:: console
|
||||||
|
|
||||||
make config-clang
|
mkdir build; cd build
|
||||||
make config-gcc
|
make -f ../Makefile
|
||||||
|
|
||||||
To use a compiler different than the default, use:
|
Out-of-tree builds require a clean source tree.
|
||||||
|
|
||||||
.. code:: console
|
|
||||||
|
|
||||||
make CXX="g++-11"
|
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
|
@ -161,10 +265,6 @@ directories:
|
||||||
``frontends/``
|
``frontends/``
|
||||||
This directory contains a subdirectory for each of the frontend modules.
|
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/``
|
``kernel/``
|
||||||
This directory contains all the core functionality of Yosys. This includes
|
This directory contains all the core functionality of Yosys. This includes
|
||||||
the functions and definitions for working with the RTLIL data structures
|
the functions and definitions for working with the RTLIL data structures
|
||||||
|
@ -206,9 +306,6 @@ commands.
|
||||||
Good starting points for reading example source code to learn how to write
|
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`.
|
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
|
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
|
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
|
Code" project type in the Eclipse "New Project" dialog (only available after the
|
||||||
|
|
|
@ -69,9 +69,14 @@ Things you can't do
|
||||||
|
|
||||||
- Check out `nextpnr`_ for that
|
- 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
|
.. todo:: nextpnr for FPGAs, consider mentioning openlane, vpr, coriolis
|
||||||
|
|
||||||
.. _nextpnr: https://github.com/YosysHQ/nextpnr
|
.. _nextpnr: https://github.com/YosysHQ/nextpnr
|
||||||
|
.. _verilator: https://www.veripool.org/verilator/
|
||||||
|
|
||||||
The Yosys family
|
The Yosys family
|
||||||
----------------
|
----------------
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
Contributing to Yosys
|
||||||
|
=====================
|
||||||
|
|
||||||
|
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,11 +11,7 @@ Writing extensions
|
||||||
This chapter contains some bits and pieces of information about programming
|
This chapter contains some bits and pieces of information about programming
|
||||||
yosys extensions. Don't be afraid to ask questions on the YosysHQ Slack.
|
yosys extensions. Don't be afraid to ask questions on the YosysHQ Slack.
|
||||||
|
|
||||||
The :file:`guidelines/` directory of the Yosys source code contains notes on
|
.. todo:: mention coding guide
|
||||||
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?
|
|
||||||
|
|
||||||
Quick guide
|
Quick guide
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -11,5 +11,6 @@ of interest for developers looking to customise Yosys builds.
|
||||||
extensions
|
extensions
|
||||||
build_verific
|
build_verific
|
||||||
functional_ir
|
functional_ir
|
||||||
|
contributing
|
||||||
test_suites
|
test_suites
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Testing Yosys
|
Testing Yosys
|
||||||
=============
|
=============
|
||||||
|
|
||||||
.. todo:: more about the included test suite
|
.. TODO:: more about the included test suite and how to add tests
|
||||||
|
|
||||||
Automatic testing
|
Automatic testing
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -23,3 +23,79 @@ For up to date information, including OS versions, refer to `the git actions
|
||||||
page`_.
|
page`_.
|
||||||
|
|
||||||
.. _the git actions page: https://github.com/YosysHQ/yosys/actions
|
.. _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
|
||||||
|
|
|
@ -38,3 +38,4 @@ as reference to implement a similar system in any language.
|
||||||
formats/index
|
formats/index
|
||||||
extending_yosys/index
|
extending_yosys/index
|
||||||
techmap
|
techmap
|
||||||
|
verilog
|
||||||
|
|
|
@ -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.
|
|
@ -198,13 +198,11 @@ struct Xaiger2Frontend : public Frontend {
|
||||||
|
|
||||||
int ci_counter = 0;
|
int ci_counter = 0;
|
||||||
for (uint32_t i = 0; i < no_boxes; i++) {
|
for (uint32_t i = 0; i < no_boxes; i++) {
|
||||||
uint32_t box_inputs, box_outputs, box_id, box_seq;
|
/* unused box_inputs = */ read_be32(*f);
|
||||||
box_inputs = read_be32(*f);
|
YS_MAYBE_UNUSED auto box_outputs = read_be32(*f);
|
||||||
box_outputs = read_be32(*f);
|
/* unused box_id = */ read_be32(*f);
|
||||||
box_id = read_be32(*f);
|
auto box_seq = read_be32(*f);
|
||||||
box_seq = read_be32(*f);
|
|
||||||
|
|
||||||
log("box_seq=%d boxes.size=%d\n", box_seq, (int) boxes.size());
|
|
||||||
log_assert(box_seq < boxes.size());
|
log_assert(box_seq < boxes.size());
|
||||||
|
|
||||||
auto [cell, def] = boxes[box_seq];
|
auto [cell, def] = boxes[box_seq];
|
||||||
|
@ -337,13 +335,11 @@ struct Xaiger2Frontend : public Frontend {
|
||||||
len, ci_num, co_num, pi_num, po_num, no_boxes);
|
len, ci_num, co_num, pi_num, po_num, no_boxes);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < no_boxes; i++) {
|
for (uint32_t i = 0; i < no_boxes; i++) {
|
||||||
uint32_t box_inputs, box_outputs, box_id, box_seq;
|
YS_MAYBE_UNUSED auto box_inputs = read_be32(*f);
|
||||||
box_inputs = read_be32(*f);
|
/* unused box_outputs = */ read_be32(*f);
|
||||||
box_outputs = read_be32(*f);
|
/* unused box_id = */ read_be32(*f);
|
||||||
box_id = read_be32(*f);
|
auto box_seq = read_be32(*f);
|
||||||
box_seq = read_be32(*f);
|
|
||||||
|
|
||||||
log("box_seq=%d boxes.size=%d\n", box_seq, (int) boxes.size());
|
|
||||||
log_assert(box_seq < boxes.size());
|
log_assert(box_seq < boxes.size());
|
||||||
|
|
||||||
auto [cell, def] = boxes[box_seq];
|
auto [cell, def] = boxes[box_seq];
|
||||||
|
|
|
@ -931,7 +931,7 @@ bool AstNode::bits_only_01() const
|
||||||
RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
|
RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
|
||||||
{
|
{
|
||||||
RTLIL::State extbit = bits.back();
|
RTLIL::State extbit = bits.back();
|
||||||
while (width > int(bits.size()))
|
while (width > GetSize(bits))
|
||||||
bits.push_back(extbit);
|
bits.push_back(extbit);
|
||||||
return RTLIL::Const(bits);
|
return RTLIL::Const(bits);
|
||||||
}
|
}
|
||||||
|
@ -939,13 +939,13 @@ RTLIL::Const AstNode::bitsAsUnsizedConst(int width)
|
||||||
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
|
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
|
||||||
{
|
{
|
||||||
std::vector<RTLIL::State> bits = this->bits;
|
std::vector<RTLIL::State> bits = this->bits;
|
||||||
if (width >= 0 && width < int(bits.size()))
|
if (width >= 0 && width < GetSize(bits))
|
||||||
bits.resize(width);
|
bits.resize(width);
|
||||||
if (width >= 0 && width > int(bits.size())) {
|
if (width >= 0 && width > GetSize(bits)) {
|
||||||
RTLIL::State extbit = RTLIL::State::S0;
|
RTLIL::State extbit = RTLIL::State::S0;
|
||||||
if ((is_signed || is_unsized) && !bits.empty())
|
if ((is_signed || is_unsized) && !bits.empty())
|
||||||
extbit = bits.back();
|
extbit = bits.back();
|
||||||
while (width > int(bits.size()))
|
while (width > GetSize(bits))
|
||||||
bits.push_back(extbit);
|
bits.push_back(extbit);
|
||||||
}
|
}
|
||||||
return RTLIL::Const(bits);
|
return RTLIL::Const(bits);
|
||||||
|
@ -1029,7 +1029,7 @@ double AstNode::asReal(bool is_signed)
|
||||||
val = const_neg(val, val, false, false, val.size());
|
val = const_neg(val, val, false, false, val.size());
|
||||||
|
|
||||||
double v = 0;
|
double v = 0;
|
||||||
for (size_t i = 0; i < val.size(); i++)
|
for (auto i = 0; i < val.size(); i++)
|
||||||
// IEEE Std 1800-2012 Par 6.12.2: Individual bits that are x or z in
|
// IEEE Std 1800-2012 Par 6.12.2: Individual bits that are x or z in
|
||||||
// the net or the variable shall be treated as zero upon conversion.
|
// the net or the variable shall be treated as zero upon conversion.
|
||||||
if (val.at(i) == RTLIL::State::S1)
|
if (val.at(i) == RTLIL::State::S1)
|
||||||
|
|
|
@ -984,7 +984,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
||||||
// unallocated enum, ignore
|
// unallocated enum, ignore
|
||||||
break;
|
break;
|
||||||
case AST_CONSTANT:
|
case AST_CONSTANT:
|
||||||
width_hint = max(width_hint, int(bits.size()));
|
width_hint = max(width_hint, GetSize(bits));
|
||||||
if (!is_signed)
|
if (!is_signed)
|
||||||
sign_hint = false;
|
sign_hint = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3493,7 +3493,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
delete buf;
|
delete buf;
|
||||||
|
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
for (size_t i = 0; i < arg_value.size(); i++)
|
for (auto i = 0; i < arg_value.size(); i++)
|
||||||
if (arg_value.at(i) == RTLIL::State::S1)
|
if (arg_value.at(i) == RTLIL::State::S1)
|
||||||
result = i + 1;
|
result = i + 1;
|
||||||
|
|
||||||
|
@ -4339,7 +4339,7 @@ replace_fcall_later:;
|
||||||
RTLIL::Const a = children[1]->bitsAsConst(width_hint, sign_hint);
|
RTLIL::Const a = children[1]->bitsAsConst(width_hint, sign_hint);
|
||||||
RTLIL::Const b = children[2]->bitsAsConst(width_hint, sign_hint);
|
RTLIL::Const b = children[2]->bitsAsConst(width_hint, sign_hint);
|
||||||
log_assert(a.size() == b.size());
|
log_assert(a.size() == b.size());
|
||||||
for (size_t i = 0; i < a.size(); i++)
|
for (auto i = 0; i < a.size(); i++)
|
||||||
if (a[i] != b[i])
|
if (a[i] != b[i])
|
||||||
a.bits()[i] = RTLIL::State::Sx;
|
a.bits()[i] = RTLIL::State::Sx;
|
||||||
newNode = mkconst_bits(a.to_bits(), sign_hint);
|
newNode = mkconst_bits(a.to_bits(), sign_hint);
|
||||||
|
|
|
@ -462,6 +462,9 @@ struct LibertyFrontend : public Frontend {
|
||||||
log(" -ignore_miss_data_latch\n");
|
log(" -ignore_miss_data_latch\n");
|
||||||
log(" ignore latches with missing data and/or enable pins\n");
|
log(" ignore latches with missing data and/or enable pins\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -ignore_buses\n");
|
||||||
|
log(" ignore cells with bus interfaces (wide ports)\n");
|
||||||
|
log("\n");
|
||||||
log(" -setattr <attribute_name>\n");
|
log(" -setattr <attribute_name>\n");
|
||||||
log(" set the specified attribute (to the value 1) on all loaded modules\n");
|
log(" set the specified attribute (to the value 1) on all loaded modules\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -478,6 +481,7 @@ struct LibertyFrontend : public Frontend {
|
||||||
bool flag_ignore_miss_func = false;
|
bool flag_ignore_miss_func = false;
|
||||||
bool flag_ignore_miss_dir = false;
|
bool flag_ignore_miss_dir = false;
|
||||||
bool flag_ignore_miss_data_latch = false;
|
bool flag_ignore_miss_data_latch = false;
|
||||||
|
bool flag_ignore_buses = false;
|
||||||
bool flag_unit_delay = false;
|
bool flag_unit_delay = false;
|
||||||
std::vector<std::string> attributes;
|
std::vector<std::string> attributes;
|
||||||
|
|
||||||
|
@ -514,6 +518,10 @@ struct LibertyFrontend : public Frontend {
|
||||||
flag_ignore_miss_data_latch = true;
|
flag_ignore_miss_data_latch = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-ignore_buses") {
|
||||||
|
flag_ignore_buses = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-setattr" && argidx+1 < args.size()) {
|
if (arg == "-setattr" && argidx+1 < args.size()) {
|
||||||
attributes.push_back(RTLIL::escape_id(args[++argidx]));
|
attributes.push_back(RTLIL::escape_id(args[++argidx]));
|
||||||
continue;
|
continue;
|
||||||
|
@ -542,27 +550,13 @@ struct LibertyFrontend : public Frontend {
|
||||||
if (cell->id != "cell" || cell->args.size() != 1)
|
if (cell->id != "cell" || cell->args.size() != 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string cell_name = RTLIL::escape_id(cell->args.at(0));
|
|
||||||
|
|
||||||
if (design->has(cell_name)) {
|
|
||||||
Module *existing_mod = design->module(cell_name);
|
|
||||||
if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) {
|
|
||||||
log_error("Re-definition of cell/module %s!\n", log_id(cell_name));
|
|
||||||
} else if (flag_nooverwrite) {
|
|
||||||
log("Ignoring re-definition of module %s.\n", log_id(cell_name));
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", log_id(cell_name));
|
|
||||||
design->remove(existing_mod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
|
// log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
|
||||||
|
|
||||||
std::map<std::string, std::tuple<int, int, bool>> type_map = global_type_map;
|
std::map<std::string, std::tuple<int, int, bool>> type_map = global_type_map;
|
||||||
parse_type_map(type_map, cell);
|
parse_type_map(type_map, cell);
|
||||||
|
|
||||||
RTLIL::Module *module = new RTLIL::Module;
|
RTLIL::Module *module = new RTLIL::Module;
|
||||||
|
std::string cell_name = RTLIL::escape_id(cell->args.at(0));
|
||||||
module->name = cell_name;
|
module->name = cell_name;
|
||||||
|
|
||||||
if (flag_lib)
|
if (flag_lib)
|
||||||
|
@ -571,9 +565,15 @@ struct LibertyFrontend : public Frontend {
|
||||||
if (flag_wb)
|
if (flag_wb)
|
||||||
module->set_bool_attribute(ID::whitebox);
|
module->set_bool_attribute(ID::whitebox);
|
||||||
|
|
||||||
|
const LibertyAst *area = cell->find("area");
|
||||||
|
if (area)
|
||||||
|
module->attributes[ID::area] = area->value;
|
||||||
|
|
||||||
for (auto &attr : attributes)
|
for (auto &attr : attributes)
|
||||||
module->attributes[attr] = 1;
|
module->attributes[attr] = 1;
|
||||||
|
|
||||||
|
bool simple_comb_cell = true, has_outputs = false;
|
||||||
|
|
||||||
for (auto node : cell->children)
|
for (auto node : cell->children)
|
||||||
{
|
{
|
||||||
if (node->id == "pin" && node->args.size() == 1) {
|
if (node->id == "pin" && node->args.size() == 1) {
|
||||||
|
@ -595,6 +595,12 @@ struct LibertyFrontend : public Frontend {
|
||||||
|
|
||||||
if (node->id == "bus" && node->args.size() == 1)
|
if (node->id == "bus" && node->args.size() == 1)
|
||||||
{
|
{
|
||||||
|
if (flag_ignore_buses) {
|
||||||
|
log("Ignoring cell %s with a bus interface %s.\n", log_id(module->name), node->args.at(0).c_str());
|
||||||
|
delete module;
|
||||||
|
goto skip_cell;
|
||||||
|
}
|
||||||
|
|
||||||
if (!flag_lib)
|
if (!flag_lib)
|
||||||
log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name));
|
log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name));
|
||||||
|
|
||||||
|
@ -609,6 +615,8 @@ struct LibertyFrontend : public Frontend {
|
||||||
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
|
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
|
||||||
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
|
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
|
||||||
|
|
||||||
|
simple_comb_cell = false;
|
||||||
|
|
||||||
if (dir->value == "internal")
|
if (dir->value == "internal")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -656,12 +664,19 @@ struct LibertyFrontend : public Frontend {
|
||||||
{
|
{
|
||||||
const LibertyAst *dir = node->find("direction");
|
const LibertyAst *dir = node->find("direction");
|
||||||
|
|
||||||
|
if (dir->value == "internal" || dir->value == "inout")
|
||||||
|
simple_comb_cell = false;
|
||||||
|
|
||||||
if (flag_lib && dir->value == "internal")
|
if (flag_lib && dir->value == "internal")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RTLIL::Wire *wire = module->wires_.at(RTLIL::escape_id(node->args.at(0)));
|
RTLIL::Wire *wire = module->wires_.at(RTLIL::escape_id(node->args.at(0)));
|
||||||
log_assert(wire);
|
log_assert(wire);
|
||||||
|
|
||||||
|
const LibertyAst *capacitance = node->find("capacitance");
|
||||||
|
if (capacitance)
|
||||||
|
wire->attributes[ID::capacitance] = capacitance->value;
|
||||||
|
|
||||||
if (dir && dir->value == "inout") {
|
if (dir && dir->value == "inout") {
|
||||||
wire->port_input = true;
|
wire->port_input = true;
|
||||||
wire->port_output = true;
|
wire->port_output = true;
|
||||||
|
@ -672,8 +687,10 @@ struct LibertyFrontend : public Frontend {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir && dir->value == "output")
|
if (dir && dir->value == "output") {
|
||||||
|
has_outputs = true;
|
||||||
wire->port_output = true;
|
wire->port_output = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (flag_lib)
|
if (flag_lib)
|
||||||
continue;
|
continue;
|
||||||
|
@ -691,36 +708,35 @@ struct LibertyFrontend : public Frontend {
|
||||||
goto skip_cell;
|
goto skip_cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
simple_comb_cell = false;
|
||||||
} else {
|
} else {
|
||||||
RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str());
|
RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str());
|
||||||
const LibertyAst *three_state = node->find("three_state");
|
const LibertyAst *three_state = node->find("three_state");
|
||||||
if (three_state) {
|
if (three_state) {
|
||||||
out_sig = create_tristate(module, out_sig, three_state->value.c_str());
|
out_sig = create_tristate(module, out_sig, three_state->value.c_str());
|
||||||
|
simple_comb_cell = false;
|
||||||
}
|
}
|
||||||
module->connect(RTLIL::SigSig(wire, out_sig));
|
module->connect(RTLIL::SigSig(wire, out_sig));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flag_unit_delay) {
|
if (node->id == "ff" || node->id == "ff_bank" ||
|
||||||
pool<Wire *> done;
|
node->id == "latch" || node->id == "latch_bank" ||
|
||||||
|
node->id == "statetable")
|
||||||
|
simple_comb_cell = false;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto timing : node->children)
|
if (simple_comb_cell && has_outputs) {
|
||||||
if (timing->id == "timing" && timing->args.empty()) {
|
module->set_bool_attribute(ID::abc9_box);
|
||||||
auto type = timing->find("timing_type");
|
|
||||||
auto related_pin = timing->find("related_pin");
|
|
||||||
if (!type || type->value != "combinational" || !related_pin)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Wire *related = module->wire(RTLIL::escape_id(related_pin->value));
|
|
||||||
if (!related)
|
|
||||||
log_error("Failed to find related pin %s for timing of pin %s on %s\n",
|
|
||||||
related_pin->value.c_str(), log_id(wire), log_id(module));
|
|
||||||
|
|
||||||
if (done.count(related))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
if (flag_unit_delay) {
|
||||||
|
for (auto wi : module->wires())
|
||||||
|
if (wi->port_input) {
|
||||||
|
for (auto wo : module->wires())
|
||||||
|
if (wo->port_output) {
|
||||||
RTLIL::Cell *spec = module->addCell(NEW_ID, ID($specify2));
|
RTLIL::Cell *spec = module->addCell(NEW_ID, ID($specify2));
|
||||||
spec->setParam(ID::SRC_WIDTH, 1);
|
spec->setParam(ID::SRC_WIDTH, wi->width);
|
||||||
spec->setParam(ID::DST_WIDTH, 1);
|
spec->setParam(ID::DST_WIDTH, wo->width);
|
||||||
spec->setParam(ID::T_FALL_MAX, 1000);
|
spec->setParam(ID::T_FALL_MAX, 1000);
|
||||||
spec->setParam(ID::T_FALL_TYP, 1000);
|
spec->setParam(ID::T_FALL_TYP, 1000);
|
||||||
spec->setParam(ID::T_FALL_MIN, 1000);
|
spec->setParam(ID::T_FALL_MIN, 1000);
|
||||||
|
@ -729,16 +745,29 @@ struct LibertyFrontend : public Frontend {
|
||||||
spec->setParam(ID::T_RISE_MIN, 1000);
|
spec->setParam(ID::T_RISE_MIN, 1000);
|
||||||
spec->setParam(ID::SRC_DST_POL, false);
|
spec->setParam(ID::SRC_DST_POL, false);
|
||||||
spec->setParam(ID::SRC_DST_PEN, false);
|
spec->setParam(ID::SRC_DST_PEN, false);
|
||||||
spec->setParam(ID::FULL, false);
|
spec->setParam(ID::FULL, true);
|
||||||
spec->setPort(ID::EN, Const(1, 1));
|
spec->setPort(ID::EN, Const(1, 1));
|
||||||
spec->setPort(ID::SRC, related);
|
spec->setPort(ID::SRC, wi);
|
||||||
spec->setPort(ID::DST, wire);
|
spec->setPort(ID::DST, wo);
|
||||||
done.insert(related);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (design->has(cell_name)) {
|
||||||
|
Module *existing_mod = design->module(cell_name);
|
||||||
|
if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) {
|
||||||
|
log_error("Re-definition of cell/module %s!\n", log_id(cell_name));
|
||||||
|
} else if (flag_nooverwrite) {
|
||||||
|
log("Ignoring re-definition of module %s.\n", log_id(cell_name));
|
||||||
|
delete module;
|
||||||
|
goto skip_cell;
|
||||||
|
} else {
|
||||||
|
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", log_id(cell_name));
|
||||||
|
design->remove(existing_mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module->fixup_ports();
|
module->fixup_ports();
|
||||||
design->add(module);
|
design->add(module);
|
||||||
cell_count++;
|
cell_count++;
|
||||||
|
|
|
@ -31,6 +31,11 @@ void rtlil_frontend_yyerror(char const *s)
|
||||||
YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s);
|
YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rtlil_frontend_yywarning(char const *s)
|
||||||
|
{
|
||||||
|
YOSYS_NAMESPACE_PREFIX log_warning("In line %d: %s\n", rtlil_frontend_yyget_lineno(), s);
|
||||||
|
}
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct RTLILFrontend : public Frontend {
|
struct RTLILFrontend : public Frontend {
|
||||||
|
|
|
@ -42,6 +42,7 @@ YOSYS_NAMESPACE_END
|
||||||
extern int rtlil_frontend_yydebug;
|
extern int rtlil_frontend_yydebug;
|
||||||
int rtlil_frontend_yylex(void);
|
int rtlil_frontend_yylex(void);
|
||||||
void rtlil_frontend_yyerror(char const *s);
|
void rtlil_frontend_yyerror(char const *s);
|
||||||
|
void rtlil_frontend_yywarning(char const *s);
|
||||||
void rtlil_frontend_yyrestart(FILE *f);
|
void rtlil_frontend_yyrestart(FILE *f);
|
||||||
int rtlil_frontend_yyparse(void);
|
int rtlil_frontend_yyparse(void);
|
||||||
int rtlil_frontend_yylex_destroy(void);
|
int rtlil_frontend_yylex_destroy(void);
|
||||||
|
|
|
@ -344,6 +344,16 @@ assign_stmt:
|
||||||
TOK_ASSIGN sigspec sigspec EOL {
|
TOK_ASSIGN sigspec sigspec EOL {
|
||||||
if (attrbuf.size() != 0)
|
if (attrbuf.size() != 0)
|
||||||
rtlil_frontend_yyerror("dangling attribute");
|
rtlil_frontend_yyerror("dangling attribute");
|
||||||
|
|
||||||
|
// See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this
|
||||||
|
// warning
|
||||||
|
if (!switch_stack.back()->empty()) {
|
||||||
|
rtlil_frontend_yywarning(
|
||||||
|
"case rule assign statements after switch statements may cause unexpected behaviour. "
|
||||||
|
"The assign statement is reordered to come before all switch statements."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
|
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
|
||||||
delete $2;
|
delete $2;
|
||||||
delete $3;
|
delete $3;
|
||||||
|
|
|
@ -407,7 +407,7 @@ static const std::string verific_unescape(const char *value)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj, Netlist *nl)
|
void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj, Netlist *nl, int wire_width_hint)
|
||||||
{
|
{
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return;
|
return;
|
||||||
|
@ -433,10 +433,18 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att
|
||||||
auto type_range = nl->GetTypeRange(obj->Name());
|
auto type_range = nl->GetTypeRange(obj->Name());
|
||||||
if (!type_range)
|
if (!type_range)
|
||||||
return;
|
return;
|
||||||
if (type_range->IsTypeScalar()) {
|
if (nl->IsFromVhdl() && type_range->IsTypeScalar()) {
|
||||||
const long long bottom_bound = type_range->GetScalarRangeLeftBound();
|
const long long bottom_bound = type_range->GetScalarRangeLeftBound();
|
||||||
const long long top_bound = type_range->GetScalarRangeRightBound();
|
const long long top_bound = type_range->GetScalarRangeRightBound();
|
||||||
const unsigned bit_width = type_range->NumElements();
|
int bit_width = type_range->LeftRangeBound()+1;
|
||||||
|
if (bit_width <= 0) { // VHDL null range
|
||||||
|
if (wire_width_hint >= 0)
|
||||||
|
bit_width = wire_width_hint;
|
||||||
|
else
|
||||||
|
bit_width = 64; //fallback, currently largest integer width that verific will allow (in vhdl2019 mode)
|
||||||
|
} else {
|
||||||
|
if (wire_width_hint >= 0) log_assert(bit_width == wire_width_hint);
|
||||||
|
}
|
||||||
RTLIL::Const bottom_const(bottom_bound, bit_width);
|
RTLIL::Const bottom_const(bottom_bound, bit_width);
|
||||||
RTLIL::Const top_const(top_bound, bit_width);
|
RTLIL::Const top_const(top_bound, bit_width);
|
||||||
if (bottom_bound < 0 || top_bound < 0) {
|
if (bottom_bound < 0 || top_bound < 0) {
|
||||||
|
@ -1471,7 +1479,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) {
|
FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) {
|
||||||
module->avail_parameters(RTLIL::escape_id(param_name));
|
module->avail_parameters(RTLIL::escape_id(param_name));
|
||||||
const TypeRange *tr = nl->GetTypeRange(param_name) ;
|
const TypeRange *tr = nl->GetTypeRange(param_name) ;
|
||||||
module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(tr->GetTypeName(), param_value, nl);
|
const char* type_name = (tr) ? tr->GetTypeName() : nullptr;
|
||||||
|
module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(type_name, param_value, nl);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetIter si;
|
SetIter si;
|
||||||
|
@ -1498,7 +1507,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
log(" importing port %s.\n", port->Name());
|
log(" importing port %s.\n", port->Name());
|
||||||
|
|
||||||
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name()));
|
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name()));
|
||||||
import_attributes(wire->attributes, port, nl);
|
import_attributes(wire->attributes, port, nl, 1);
|
||||||
|
|
||||||
wire->port_id = nl->IndexOf(port) + 1;
|
wire->port_id = nl->IndexOf(port) + 1;
|
||||||
|
|
||||||
|
@ -1526,11 +1535,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
|
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
|
||||||
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
|
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
|
||||||
wire->upto = portbus->IsUp();
|
wire->upto = portbus->IsUp();
|
||||||
import_attributes(wire->attributes, portbus, nl);
|
import_attributes(wire->attributes, portbus, nl, portbus->Size());
|
||||||
SetIter si ;
|
SetIter si ;
|
||||||
Port *port ;
|
Port *port ;
|
||||||
FOREACH_PORT_OF_PORTBUS(portbus, si, port) {
|
FOREACH_PORT_OF_PORTBUS(portbus, si, port) {
|
||||||
import_attributes(wire->attributes, port->GetNet(), nl);
|
import_attributes(wire->attributes, port->GetNet(), nl, portbus->Size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN;
|
bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN;
|
||||||
|
@ -1692,7 +1701,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
log(" importing net %s as %s.\n", net->Name(), log_id(wire_name));
|
log(" importing net %s as %s.\n", net->Name(), log_id(wire_name));
|
||||||
|
|
||||||
RTLIL::Wire *wire = module->addWire(wire_name);
|
RTLIL::Wire *wire = module->addWire(wire_name);
|
||||||
import_attributes(wire->attributes, net, nl);
|
import_attributes(wire->attributes, net, nl, 1);
|
||||||
|
|
||||||
net_map[net] = wire;
|
net_map[net] = wire;
|
||||||
}
|
}
|
||||||
|
@ -1721,10 +1730,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
MapIter mibus;
|
MapIter mibus;
|
||||||
FOREACH_NET_OF_NETBUS(netbus, mibus, net) {
|
FOREACH_NET_OF_NETBUS(netbus, mibus, net) {
|
||||||
if (net)
|
if (net)
|
||||||
import_attributes(wire->attributes, net, nl);
|
import_attributes(wire->attributes, net, nl, netbus->Size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
import_attributes(wire->attributes, netbus, nl);
|
import_attributes(wire->attributes, netbus, nl, netbus->Size());
|
||||||
|
|
||||||
RTLIL::Const initval = Const(State::Sx, GetSize(wire));
|
RTLIL::Const initval = Const(State::Sx, GetSize(wire));
|
||||||
bool initval_valid = false;
|
bool initval_valid = false;
|
||||||
|
@ -2126,12 +2135,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
log(" assert condition %s.\n", log_signal(cond));
|
log(" assert condition %s.\n", log_signal(cond));
|
||||||
|
|
||||||
Cell *cell = module->addAssert(new_verific_id(inst), cond, State::S1);
|
Cell *cell = module->addAssert(new_verific_id(inst), cond, State::S1);
|
||||||
// Initialize FF feeding condition to 1, in case it is not
|
|
||||||
// used by rest of design logic, to prevent failing on
|
|
||||||
// initial uninitialized state
|
|
||||||
if (cond.is_wire() && !cond.wire->name.isPublic())
|
|
||||||
cond.wire->attributes[ID::init] = Const(1,1);
|
|
||||||
|
|
||||||
import_attributes(cell->attributes, inst);
|
import_attributes(cell->attributes, inst);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2177,7 +2180,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
if (is_blackbox(inst->View())) {
|
if (is_blackbox(inst->View())) {
|
||||||
FOREACH_PARAMETER_OF_INST(inst, mi2, param_name, param_value) {
|
FOREACH_PARAMETER_OF_INST(inst, mi2, param_name, param_value) {
|
||||||
const TypeRange *tr = inst->View()->GetTypeRange(param_name) ;
|
const TypeRange *tr = inst->View()->GetTypeRange(param_name) ;
|
||||||
cell->setParam(RTLIL::escape_id(param_name), verific_const(tr->GetTypeName(), param_value, inst->View()));
|
const char* type_name = (tr) ? tr->GetTypeName() : nullptr;
|
||||||
|
cell->setParam(RTLIL::escape_id(param_name), verific_const(type_name, param_value, inst->View()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2692,11 +2696,51 @@ struct VerificExtNets
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||||
|
static msg_type_t prev_1063;
|
||||||
|
#endif
|
||||||
|
#ifdef VERIFIC_VHDL_SUPPORT
|
||||||
|
static msg_type_t prev_1240 ;
|
||||||
|
static msg_type_t prev_1241 ;
|
||||||
|
#endif
|
||||||
|
void save_blackbox_msg_state()
|
||||||
|
{
|
||||||
|
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||||
|
prev_1063 = Message::GetMessageType("VERI-1063") ;
|
||||||
|
Message::SetMessageType("VERI-1063", VERIFIC_INFO);
|
||||||
|
#endif
|
||||||
|
#ifdef VERIFIC_VHDL_SUPPORT
|
||||||
|
prev_1240 = Message::GetMessageType("VHDL-1240") ;
|
||||||
|
prev_1241 = Message::GetMessageType("VHDL-1241") ;
|
||||||
|
Message::SetMessageType("VHDL-1240", VERIFIC_INFO);
|
||||||
|
Message::SetMessageType("VHDL-1241", VERIFIC_INFO);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_blackbox_msg_state()
|
||||||
|
{
|
||||||
|
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||||
|
Message::ClearMessageType("VERI-1063") ;
|
||||||
|
if (Message::GetMessageType("VERI-1063")!=prev_1063)
|
||||||
|
Message::SetMessageType("VERI-1063", prev_1063);
|
||||||
|
#endif
|
||||||
|
#ifdef VERIFIC_VHDL_SUPPORT
|
||||||
|
Message::ClearMessageType("VHDL-1240") ;
|
||||||
|
Message::ClearMessageType("VHDL-1241") ;
|
||||||
|
if (Message::GetMessageType("VHDL-1240")!=prev_1240)
|
||||||
|
Message::SetMessageType("VHDL-1240", prev_1240);
|
||||||
|
if (Message::GetMessageType("VHDL-1241")!=prev_1241)
|
||||||
|
Message::SetMessageType("VHDL-1241", prev_1241);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void import_all(const char* work, std::map<std::string,Netlist*> *nl_todo, Map *parameters, bool show_message, std::string ppfile YS_MAYBE_UNUSED)
|
void import_all(const char* work, std::map<std::string,Netlist*> *nl_todo, Map *parameters, bool show_message, std::string ppfile YS_MAYBE_UNUSED)
|
||||||
{
|
{
|
||||||
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
||||||
|
save_blackbox_msg_state();
|
||||||
VerificExtensions::ElaborateAndRewrite(work, parameters);
|
VerificExtensions::ElaborateAndRewrite(work, parameters);
|
||||||
verific_error_msg.clear();
|
verific_error_msg.clear();
|
||||||
|
restore_blackbox_msg_state();
|
||||||
#endif
|
#endif
|
||||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||||
if (!ppfile.empty())
|
if (!ppfile.empty())
|
||||||
|
@ -2827,8 +2871,10 @@ std::set<std::string> import_tops(const char* work, std::map<std::string,Netlist
|
||||||
|
|
||||||
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
#ifdef YOSYSHQ_VERIFIC_EXTENSIONS
|
||||||
if (static_elaborate) {
|
if (static_elaborate) {
|
||||||
|
save_blackbox_msg_state();
|
||||||
VerificExtensions::ElaborateAndRewrite(work, &veri_modules, &vhdl_units, parameters);
|
VerificExtensions::ElaborateAndRewrite(work, &veri_modules, &vhdl_units, parameters);
|
||||||
verific_error_msg.clear();
|
verific_error_msg.clear();
|
||||||
|
restore_blackbox_msg_state();
|
||||||
#endif
|
#endif
|
||||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||||
if (!ppfile.empty())
|
if (!ppfile.empty())
|
||||||
|
@ -3294,10 +3340,8 @@ struct VerificPass : public Pass {
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VERIFIC_VHDL_SUPPORT
|
|
||||||
msg_type_t prev_1240 ;
|
|
||||||
msg_type_t prev_1241 ;
|
|
||||||
|
|
||||||
|
#ifdef VERIFIC_VHDL_SUPPORT
|
||||||
void add_units_to_map(Map &map, std::string work, bool flag_lib)
|
void add_units_to_map(Map &map, std::string work, bool flag_lib)
|
||||||
{
|
{
|
||||||
MapIter mi ;
|
MapIter mi ;
|
||||||
|
@ -3310,11 +3354,7 @@ struct VerificPass : public Pass {
|
||||||
map.Insert(unit,unit);
|
map.Insert(unit,unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
save_blackbox_msg_state();
|
||||||
prev_1240 = Message::GetMessageType("VHDL-1240") ;
|
|
||||||
prev_1241 = Message::GetMessageType("VHDL-1241") ;
|
|
||||||
Message::SetMessageType("VHDL-1240", VERIFIC_INFO);
|
|
||||||
Message::SetMessageType("VHDL-1241", VERIFIC_INFO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_units_to_blackbox(Map &map, std::string work, bool flag_lib)
|
void set_units_to_blackbox(Map &map, std::string work, bool flag_lib)
|
||||||
|
@ -3329,17 +3369,10 @@ struct VerificPass : public Pass {
|
||||||
unit->SetCompileAsBlackbox();
|
unit->SetCompileAsBlackbox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ClearMessageType("VHDL-1240") ;
|
restore_blackbox_msg_state();
|
||||||
Message::ClearMessageType("VHDL-1241") ;
|
|
||||||
if (Message::GetMessageType("VHDL-1240")!=prev_1240)
|
|
||||||
Message::SetMessageType("VHDL-1240", prev_1240);
|
|
||||||
if (Message::GetMessageType("VHDL-1241")!=prev_1241)
|
|
||||||
Message::SetMessageType("VHDL-1241", prev_1241);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
msg_type_t prev_1063;
|
|
||||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
|
||||||
void add_modules_to_map(Map &map, std::string work, bool flag_lib)
|
void add_modules_to_map(Map &map, std::string work, bool flag_lib)
|
||||||
{
|
{
|
||||||
|
@ -3353,9 +3386,7 @@ struct VerificPass : public Pass {
|
||||||
map.Insert(veri_module,veri_module);
|
map.Insert(veri_module,veri_module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
save_blackbox_msg_state();
|
||||||
prev_1063 = Message::GetMessageType("VERI-1063") ;
|
|
||||||
Message::SetMessageType("VERI-1063", VERIFIC_INFO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_modules_to_blackbox(Map &map, std::string work, bool flag_lib)
|
void set_modules_to_blackbox(Map &map, std::string work, bool flag_lib)
|
||||||
|
@ -3370,9 +3401,6 @@ struct VerificPass : public Pass {
|
||||||
veri_module->SetCompileAsBlackbox();
|
veri_module->SetCompileAsBlackbox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ClearMessageType("VERI-1063") ;
|
|
||||||
if (Message::GetMessageType("VERI-1063")!=prev_1063)
|
|
||||||
Message::SetMessageType("VERI-1063", prev_1063);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -4184,7 +4212,7 @@ struct VerificPass : public Pass {
|
||||||
}
|
}
|
||||||
if (v[0] == '"') {
|
if (v[0] == '"') {
|
||||||
std::string s = v.substr(1, GetSize(v)-2);
|
std::string s = v.substr(1, GetSize(v)-2);
|
||||||
RuntimeFlags::SetStringVar(k.c_str(), v.c_str());
|
RuntimeFlags::SetStringVar(k.c_str(), s.c_str());
|
||||||
goto check_error;
|
goto check_error;
|
||||||
}
|
}
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|
|
@ -81,7 +81,7 @@ struct VerificImporter
|
||||||
RTLIL::SigBit net_map_at(Verific::Net *net);
|
RTLIL::SigBit net_map_at(Verific::Net *net);
|
||||||
|
|
||||||
RTLIL::IdString new_verific_id(Verific::DesignObj *obj);
|
RTLIL::IdString new_verific_id(Verific::DesignObj *obj);
|
||||||
void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr);
|
void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr, int wire_width_hint = -1);
|
||||||
|
|
||||||
RTLIL::SigBit netToSigBit(Verific::Net *net);
|
RTLIL::SigBit netToSigBit(Verific::Net *net);
|
||||||
RTLIL::SigSpec operatorInput(Verific::Instance *inst);
|
RTLIL::SigSpec operatorInput(Verific::Instance *inst);
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
Checklist for adding internal cell types
|
|
||||||
========================================
|
|
||||||
|
|
||||||
Things to do right away:
|
|
||||||
|
|
||||||
- Add to kernel/celltypes.h (incl. eval() handling for non-mem cells)
|
|
||||||
- Add to InternalCellChecker::check() in kernel/rtlil.cc
|
|
||||||
- Add to techlibs/common/simlib.v
|
|
||||||
- Add to techlibs/common/techmap.v
|
|
||||||
|
|
||||||
Things to do after finalizing the cell interface:
|
|
||||||
|
|
||||||
- Add support to kernel/satgen.h for the new cell type
|
|
||||||
- Add to docs/source/CHAPTER_CellLib.rst (or just add a fixme to the bottom)
|
|
||||||
- Maybe add support to the Verilog backend for dumping such cells as expression
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Checklist for creating Yosys releases
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
Update the CHANGELOG file:
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
gitk &
|
|
||||||
vi CHANGELOG
|
|
||||||
|
|
||||||
|
|
||||||
Update and check documentation:
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
make docs
|
|
||||||
- sanity check the figures in docs/images
|
|
||||||
- if there are any odd things -> investigate
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
vi README guidelines/*
|
|
||||||
- is the information provided in those file still up to date
|
|
||||||
|
|
||||||
|
|
||||||
Then with default config setting:
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
make vgtest
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
|
|
||||||
./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
|
|
||||||
./yosys -p 'synth; show' tests/simple/fiedler-cooley.v
|
|
||||||
./yosys -p 'synth_xilinx -top up3down5; show' tests/simple/fiedler-cooley.v
|
|
||||||
|
|
||||||
cd ~yosys/examples/cmos
|
|
||||||
bash testbench.sh
|
|
||||||
|
|
||||||
cd ~yosys/examples/basys3
|
|
||||||
bash run.sh
|
|
||||||
|
|
||||||
|
|
||||||
Test building plugins with various of the standard passes:
|
|
||||||
|
|
||||||
yosys-config --build test.so equiv_simple.cc
|
|
||||||
- also check the code examples in guidelines/GettingStarted
|
|
||||||
|
|
||||||
|
|
||||||
And if a version of the verific library is currently available:
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
cat frontends/verific/build_amd64.txt
|
|
||||||
- follow instructions
|
|
||||||
|
|
||||||
cd frontends/verific
|
|
||||||
../../yosys test_navre.ys
|
|
||||||
|
|
||||||
|
|
||||||
Finally run all tests with "make config-{clang,gcc}":
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
make clean
|
|
||||||
make test
|
|
||||||
make ystests
|
|
||||||
make vloghtb
|
|
||||||
make install
|
|
||||||
|
|
||||||
cd ~yosys-bigsim
|
|
||||||
make clean
|
|
||||||
make full
|
|
||||||
|
|
||||||
cd ~vloghammer
|
|
||||||
make purge gen_issues gen_samples
|
|
||||||
make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" REPORT_FULL=1 world
|
|
||||||
chromium-browser report.html
|
|
||||||
|
|
||||||
|
|
||||||
Release:
|
|
||||||
|
|
||||||
- set YOSYS_VER to x.y.z in Makefile
|
|
||||||
- remove "bumpversion" target from Makefile
|
|
||||||
- update version string in CHANGELOG
|
|
||||||
git commit -am "Yosys x.y.z"
|
|
||||||
|
|
||||||
- push tag to github
|
|
||||||
- post changelog on github
|
|
||||||
- post short release note on reddit
|
|
||||||
|
|
||||||
|
|
||||||
Updating the website:
|
|
||||||
|
|
||||||
cd ~yosys
|
|
||||||
make install
|
|
||||||
|
|
||||||
cd ~yosys-web
|
|
||||||
make update_show
|
|
||||||
git commit -am update
|
|
||||||
make push
|
|
||||||
|
|
||||||
- Read the Docs updates handled by Jenkins on source change
|
|
|
@ -1,72 +0,0 @@
|
||||||
Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
Our Pledge
|
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as
|
|
||||||
contributors and maintainers pledge to making participation in our project and
|
|
||||||
our community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
||||||
nationality, personal appearance, race, religion, or sexual identity and
|
|
||||||
orientation.
|
|
||||||
|
|
||||||
Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment
|
|
||||||
include:
|
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
|
||||||
* Being respectful of differing viewpoints and experiences
|
|
||||||
* Gracefully accepting constructive criticism
|
|
||||||
* Focusing on what is best for the community
|
|
||||||
* Showing empathy towards other community members
|
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
||||||
advances
|
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or electronic
|
|
||||||
address, without explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
Our Responsibilities
|
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable
|
|
||||||
behavior and are expected to take appropriate and fair corrective action in
|
|
||||||
response to any instances of unacceptable behavior.
|
|
||||||
|
|
||||||
Project maintainers 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, or to ban temporarily or
|
|
||||||
permanently any contributor for other behaviors that they deem inappropriate,
|
|
||||||
threatening, offensive, or harmful.
|
|
||||||
|
|
||||||
Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces
|
|
||||||
when an individual is representing the project or its community. Examples of
|
|
||||||
representing a project or community include using an official project e-mail
|
|
||||||
address, posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event. Representation of a project may be
|
|
||||||
further defined and clarified by project maintainers.
|
|
||||||
|
|
||||||
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 and
|
|
||||||
will result in a response that is deemed necessary and appropriate to the
|
|
||||||
circumstances. The project team is obligated to maintain confidentiality with
|
|
||||||
regard to the reporter of an incident. Further details of specific enforcement
|
|
||||||
policies may be posted separately.
|
|
||||||
|
|
||||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
||||||
faith may face temporary or permanent repercussions as determined by other
|
|
||||||
members of the project's leadership.
|
|
||||||
|
|
||||||
Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
|
|
||||||
available at http://contributor-covenant.org/version/1/4/
|
|
|
@ -1,34 +0,0 @@
|
||||||
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:
|
|
||||||
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 kernel/yosys.h)
|
|
||||||
|
|
||||||
Use range-based for loops whenever applicable.
|
|
|
@ -1,69 +0,0 @@
|
||||||
How to add 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, it was chosen (google test)
|
|
||||||
[https://github.com/google/googletest], because it is largely used and it is
|
|
||||||
relatively easy learn.
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```
|
|
||||||
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 new unit test
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
If you want to add new unit tests for Yosys, just follow the steps below:
|
|
||||||
|
|
||||||
* Go to directory "yosys/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 test
|
|
||||||
-------------
|
|
||||||
|
|
||||||
To compile and run all unit tests, just go to yosys root directory and type:
|
|
||||||
```
|
|
||||||
make unit-test
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to remove all unit test files, type:
|
|
||||||
```
|
|
||||||
make clean-unit-test
|
|
||||||
```
|
|
|
@ -1,83 +0,0 @@
|
||||||
Creating the Visual Studio Template Project
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
1. Create an empty Visual C++ Win32 Console App project
|
|
||||||
|
|
||||||
Microsoft Visual Studio Express 2013 for Windows Desktop
|
|
||||||
Open New Project Wizard (File -> New Project..)
|
|
||||||
|
|
||||||
Project Name: YosysVS
|
|
||||||
Solution Name: YosysVS
|
|
||||||
[X] Create directory for solution
|
|
||||||
[ ] Add to source control
|
|
||||||
|
|
||||||
[X] Console applications
|
|
||||||
[X] Empty Project
|
|
||||||
[ ] SDL checks
|
|
||||||
|
|
||||||
2. Open YosysVS Project Properties
|
|
||||||
|
|
||||||
Select Configuration: All Configurations
|
|
||||||
|
|
||||||
C/C++ -> General -> Additional Include Directories
|
|
||||||
Add: ..\yosys
|
|
||||||
|
|
||||||
C/C++ -> Preprocessor -> Preprocessor Definitions
|
|
||||||
Add: _YOSYS_;_CRT_SECURE_NO_WARNINGS
|
|
||||||
|
|
||||||
3. Resulting file system tree:
|
|
||||||
|
|
||||||
YosysVS/
|
|
||||||
YosysVS/YosysVS
|
|
||||||
YosysVS/YosysVS/YosysVS.vcxproj
|
|
||||||
YosysVS/YosysVS/YosysVS.vcxproj.filters
|
|
||||||
YosysVS/YosysVS.sdf
|
|
||||||
YosysVS/YosysVS.sln
|
|
||||||
YosysVS/YosysVS.v12.suo
|
|
||||||
|
|
||||||
4. Zip YosysVS as YosysVS-Tpl-v1.zip
|
|
||||||
|
|
||||||
Compiling with Visual Studio
|
|
||||||
============================
|
|
||||||
|
|
||||||
Visual Studio builds are not directly supported by build scripts, but they are still possible.
|
|
||||||
|
|
||||||
1. Easy way
|
|
||||||
|
|
||||||
- Go to https://github.com/YosysHQ/yosys/actions/workflows/vs.yml?query=branch%3Amain
|
|
||||||
- Click on the most recent completed run
|
|
||||||
- In Artifacts region find vcxsrc and click on it to download
|
|
||||||
- Unpack downloaded ZIP file
|
|
||||||
- Open YosysVS.sln with Visual Studio
|
|
||||||
|
|
||||||
2. Using WSL or MSYS2
|
|
||||||
|
|
||||||
- Make sure to have make, python3 and git available
|
|
||||||
- Git clone yosys repository
|
|
||||||
- Execute ```make vcxsrc YOSYS_VER=latest```
|
|
||||||
- File yosys-win32-vcxsrc-latest.zip will be created
|
|
||||||
- Transfer that file to location visible by Windows application
|
|
||||||
- Unpack ZIP
|
|
||||||
- Open YosysVS.sln with Visual Studio
|
|
||||||
|
|
||||||
Cross-Building for Windows with MXE
|
|
||||||
===================================
|
|
||||||
|
|
||||||
Check http://mxe.cc/#requirements and install all missing requirements.
|
|
||||||
|
|
||||||
As root (or other user with write access to /usr/local/src):
|
|
||||||
|
|
||||||
cd /usr/local/src
|
|
||||||
git clone https://github.com/mxe/mxe.git
|
|
||||||
cd mxe
|
|
||||||
|
|
||||||
make -j$(nproc) MXE_PLUGIN_DIRS="plugins/tcl.tk" \
|
|
||||||
MXE_TARGETS="i686-w64-mingw32.static" \
|
|
||||||
gcc tcl readline
|
|
||||||
|
|
||||||
Then as regular user in some directory where you build stuff:
|
|
||||||
|
|
||||||
git clone https://github.com/YosysHQ/yosys.git yosys-win32
|
|
||||||
cd yosys-win32
|
|
||||||
make config-mxe
|
|
||||||
make -j$(nproc) mxebin
|
|
|
@ -33,7 +33,7 @@ static void extend_u0(RTLIL::Const &arg, int width, bool is_signed)
|
||||||
if (arg.size() > 0 && is_signed)
|
if (arg.size() > 0 && is_signed)
|
||||||
padding = arg.back();
|
padding = arg.back();
|
||||||
|
|
||||||
while (int(arg.size()) < width)
|
while (GetSize(arg) < width)
|
||||||
arg.bits().push_back(padding);
|
arg.bits().push_back(padding);
|
||||||
|
|
||||||
arg.bits().resize(width);
|
arg.bits().resize(width);
|
||||||
|
@ -45,7 +45,7 @@ static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_
|
||||||
|
|
||||||
BigInteger::Sign sign = BigInteger::positive;
|
BigInteger::Sign sign = BigInteger::positive;
|
||||||
State inv_sign_bit = RTLIL::State::S1;
|
State inv_sign_bit = RTLIL::State::S1;
|
||||||
size_t num_bits = val.size();
|
auto num_bits = val.size();
|
||||||
|
|
||||||
if (as_signed && num_bits && val[num_bits-1] == RTLIL::State::S1) {
|
if (as_signed && num_bits && val[num_bits-1] == RTLIL::State::S1) {
|
||||||
inv_sign_bit = RTLIL::State::S0;
|
inv_sign_bit = RTLIL::State::S0;
|
||||||
|
@ -53,7 +53,7 @@ static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_
|
||||||
num_bits--;
|
num_bits--;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < num_bits; i++)
|
for (auto i = 0; i < num_bits; i++)
|
||||||
if (val[i] == RTLIL::State::S0 || val[i] == RTLIL::State::S1)
|
if (val[i] == RTLIL::State::S0 || val[i] == RTLIL::State::S1)
|
||||||
mag.setBit(i, val[i] == inv_sign_bit);
|
mag.setBit(i, val[i] == inv_sign_bit);
|
||||||
else if (undef_bit_pos < 0)
|
else if (undef_bit_pos < 0)
|
||||||
|
@ -78,12 +78,12 @@ static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_b
|
||||||
if (val.getSign() < 0)
|
if (val.getSign() < 0)
|
||||||
{
|
{
|
||||||
mag--;
|
mag--;
|
||||||
for (int i = 0; i < result_len; i++)
|
for (auto i = 0; i < result_len; i++)
|
||||||
result.bits()[i] = mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1;
|
result.bits()[i] = mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < result_len; i++)
|
for (auto i = 0; i < result_len; i++)
|
||||||
result.bits()[i] = mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0;
|
result.bits()[i] = mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,14 +132,14 @@ static RTLIL::State logic_xnor(RTLIL::State a, RTLIL::State b)
|
||||||
RTLIL::Const RTLIL::const_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
RTLIL::Const RTLIL::const_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
||||||
{
|
{
|
||||||
if (result_len < 0)
|
if (result_len < 0)
|
||||||
result_len = arg1.size();
|
result_len = GetSize(arg1);
|
||||||
|
|
||||||
RTLIL::Const arg1_ext = arg1;
|
RTLIL::Const arg1_ext = arg1;
|
||||||
extend_u0(arg1_ext, result_len, signed1);
|
extend_u0(arg1_ext, result_len, signed1);
|
||||||
|
|
||||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||||
for (size_t i = 0; i < size_t(result_len); i++) {
|
for (auto i = 0; i < result_len; i++) {
|
||||||
if (i >= arg1_ext.size())
|
if (i >= GetSize(arg1_ext))
|
||||||
result.bits()[i] = RTLIL::State::S0;
|
result.bits()[i] = RTLIL::State::S0;
|
||||||
else if (arg1_ext.bits()[i] == RTLIL::State::S0)
|
else if (arg1_ext.bits()[i] == RTLIL::State::S0)
|
||||||
result.bits()[i] = RTLIL::State::S1;
|
result.bits()[i] = RTLIL::State::S1;
|
||||||
|
@ -154,15 +154,15 @@ static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL:
|
||||||
RTLIL::Const arg1, RTLIL::Const arg2, bool signed1, bool signed2, int result_len = -1)
|
RTLIL::Const arg1, RTLIL::Const arg2, bool signed1, bool signed2, int result_len = -1)
|
||||||
{
|
{
|
||||||
if (result_len < 0)
|
if (result_len < 0)
|
||||||
result_len = max(arg1.size(), arg2.size());
|
result_len = max(GetSize(arg1), GetSize(arg2));
|
||||||
|
|
||||||
extend_u0(arg1, result_len, signed1);
|
extend_u0(arg1, result_len, signed1);
|
||||||
extend_u0(arg2, result_len, signed2);
|
extend_u0(arg2, result_len, signed2);
|
||||||
|
|
||||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||||
for (size_t i = 0; i < size_t(result_len); i++) {
|
for (auto i = 0; i < result_len; i++) {
|
||||||
RTLIL::State a = i < arg1.size() ? arg1.bits()[i] : RTLIL::State::S0;
|
RTLIL::State a = i < GetSize(arg1) ? arg1.bits()[i] : RTLIL::State::S0;
|
||||||
RTLIL::State b = i < arg2.size() ? arg2.bits()[i] : RTLIL::State::S0;
|
RTLIL::State b = i < GetSize(arg2) ? arg2.bits()[i] : RTLIL::State::S0;
|
||||||
result.bits()[i] = logic_func(a, b);
|
result.bits()[i] = logic_func(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,11 +193,11 @@ static RTLIL::Const logic_reduce_wrapper(RTLIL::State initial, RTLIL::State(*log
|
||||||
{
|
{
|
||||||
RTLIL::State temp = initial;
|
RTLIL::State temp = initial;
|
||||||
|
|
||||||
for (size_t i = 0; i < arg1.size(); i++)
|
for (auto i = 0; i < arg1.size(); i++)
|
||||||
temp = logic_func(temp, arg1[i]);
|
temp = logic_func(temp, arg1[i]);
|
||||||
|
|
||||||
RTLIL::Const result(temp);
|
RTLIL::Const result(temp);
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ RTLIL::Const RTLIL::const_logic_not(const RTLIL::Const &arg1, const RTLIL::Const
|
||||||
BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
|
BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
|
||||||
RTLIL::Const result(a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S1 : RTLIL::State::S0);
|
RTLIL::Const result(a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S1 : RTLIL::State::S0);
|
||||||
|
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,7 @@ RTLIL::Const RTLIL::const_logic_and(const RTLIL::Const &arg1, const RTLIL::Const
|
||||||
RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
||||||
RTLIL::Const result(logic_and(bit_a, bit_b));
|
RTLIL::Const result(logic_and(bit_a, bit_b));
|
||||||
|
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const
|
||||||
RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1;
|
||||||
RTLIL::Const result(logic_or(bit_a, bit_b));
|
RTLIL::Const result(logic_or(bit_a, bit_b));
|
||||||
|
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,7 @@ static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Co
|
||||||
BigInteger offset = const2big(arg2, signed2, undef_bit_pos) * direction;
|
BigInteger offset = const2big(arg2, signed2, undef_bit_pos) * direction;
|
||||||
|
|
||||||
if (result_len < 0)
|
if (result_len < 0)
|
||||||
result_len = arg1.size();
|
result_len = GetSize(arg1);
|
||||||
|
|
||||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
||||||
if (undef_bit_pos >= 0)
|
if (undef_bit_pos >= 0)
|
||||||
|
@ -296,7 +296,7 @@ static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Co
|
||||||
BigInteger pos = BigInteger(i) + offset;
|
BigInteger pos = BigInteger(i) + offset;
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
result.bits()[i] = vacant_bits;
|
result.bits()[i] = vacant_bits;
|
||||||
else if (pos >= BigInteger(int(arg1.size())))
|
else if (pos >= BigInteger(GetSize(arg1)))
|
||||||
result.bits()[i] = sign_ext ? arg1.back() : vacant_bits;
|
result.bits()[i] = sign_ext ? arg1.back() : vacant_bits;
|
||||||
else
|
else
|
||||||
result.bits()[i] = arg1[pos.toInt()];
|
result.bits()[i] = arg1[pos.toInt()];
|
||||||
|
@ -347,7 +347,7 @@ RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
||||||
bool y = const2big(arg1, signed1, undef_bit_pos) < const2big(arg2, signed2, undef_bit_pos);
|
bool y = const2big(arg1, signed1, undef_bit_pos) < const2big(arg2, signed2, undef_bit_pos);
|
||||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||||
|
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ RTLIL::Const RTLIL::const_le(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
||||||
bool y = const2big(arg1, signed1, undef_bit_pos) <= const2big(arg2, signed2, undef_bit_pos);
|
bool y = const2big(arg1, signed1, undef_bit_pos) <= const2big(arg2, signed2, undef_bit_pos);
|
||||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||||
|
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -369,12 +369,12 @@ RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
||||||
RTLIL::Const arg2_ext = arg2;
|
RTLIL::Const arg2_ext = arg2;
|
||||||
RTLIL::Const result(RTLIL::State::S0, result_len);
|
RTLIL::Const result(RTLIL::State::S0, result_len);
|
||||||
|
|
||||||
int width = max(arg1_ext.size(), arg2_ext.size());
|
int width = max(GetSize(arg1_ext), GetSize(arg2_ext));
|
||||||
extend_u0(arg1_ext, width, signed1 && signed2);
|
extend_u0(arg1_ext, width, signed1 && signed2);
|
||||||
extend_u0(arg2_ext, width, signed1 && signed2);
|
extend_u0(arg2_ext, width, signed1 && signed2);
|
||||||
|
|
||||||
RTLIL::State matched_status = RTLIL::State::S1;
|
RTLIL::State matched_status = RTLIL::State::S1;
|
||||||
for (size_t i = 0; i < arg1_ext.size(); i++) {
|
for (auto i = 0; i < arg1_ext.size(); i++) {
|
||||||
if (arg1_ext.at(i) == RTLIL::State::S0 && arg2_ext.at(i) == RTLIL::State::S1)
|
if (arg1_ext.at(i) == RTLIL::State::S0 && arg2_ext.at(i) == RTLIL::State::S1)
|
||||||
return result;
|
return result;
|
||||||
if (arg1_ext.at(i) == RTLIL::State::S1 && arg2_ext.at(i) == RTLIL::State::S0)
|
if (arg1_ext.at(i) == RTLIL::State::S1 && arg2_ext.at(i) == RTLIL::State::S0)
|
||||||
|
@ -403,11 +403,11 @@ RTLIL::Const RTLIL::const_eqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
||||||
RTLIL::Const arg2_ext = arg2;
|
RTLIL::Const arg2_ext = arg2;
|
||||||
RTLIL::Const result(RTLIL::State::S0, result_len);
|
RTLIL::Const result(RTLIL::State::S0, result_len);
|
||||||
|
|
||||||
int width = max(arg1_ext.size(), arg2_ext.size());
|
int width = max(GetSize(arg1_ext), GetSize(arg2_ext));
|
||||||
extend_u0(arg1_ext, width, signed1 && signed2);
|
extend_u0(arg1_ext, width, signed1 && signed2);
|
||||||
extend_u0(arg2_ext, width, signed1 && signed2);
|
extend_u0(arg2_ext, width, signed1 && signed2);
|
||||||
|
|
||||||
for (size_t i = 0; i < arg1_ext.size(); i++) {
|
for (auto i = 0; i < arg1_ext.size(); i++) {
|
||||||
if (arg1_ext.at(i) != arg2_ext.at(i))
|
if (arg1_ext.at(i) != arg2_ext.at(i))
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ RTLIL::Const RTLIL::const_ge(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
||||||
bool y = const2big(arg1, signed1, undef_bit_pos) >= const2big(arg2, signed2, undef_bit_pos);
|
bool y = const2big(arg1, signed1, undef_bit_pos) >= const2big(arg2, signed2, undef_bit_pos);
|
||||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||||
|
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -443,7 +443,7 @@ RTLIL::Const RTLIL::const_gt(const RTLIL::Const &arg1, const RTLIL::Const &arg2,
|
||||||
bool y = const2big(arg1, signed1, undef_bit_pos) > const2big(arg2, signed2, undef_bit_pos);
|
bool y = const2big(arg1, signed1, undef_bit_pos) > const2big(arg2, signed2, undef_bit_pos);
|
||||||
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
|
||||||
|
|
||||||
while (int(result.size()) < result_len)
|
while (GetSize(result) < result_len)
|
||||||
result.bits().push_back(RTLIL::State::S0);
|
result.bits().push_back(RTLIL::State::S0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -452,21 +452,21 @@ RTLIL::Const RTLIL::const_add(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
||||||
{
|
{
|
||||||
int undef_bit_pos = -1;
|
int undef_bit_pos = -1;
|
||||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) + const2big(arg2, signed2, undef_bit_pos);
|
BigInteger y = const2big(arg1, signed1, undef_bit_pos) + const2big(arg2, signed2, undef_bit_pos);
|
||||||
return big2const(y, result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), undef_bit_pos);
|
return big2const(y, result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), undef_bit_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_sub(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_sub(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||||
{
|
{
|
||||||
int undef_bit_pos = -1;
|
int undef_bit_pos = -1;
|
||||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) - const2big(arg2, signed2, undef_bit_pos);
|
BigInteger y = const2big(arg1, signed1, undef_bit_pos) - const2big(arg2, signed2, undef_bit_pos);
|
||||||
return big2const(y, result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), undef_bit_pos);
|
return big2const(y, result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), undef_bit_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||||
{
|
{
|
||||||
int undef_bit_pos = -1;
|
int undef_bit_pos = -1;
|
||||||
BigInteger y = const2big(arg1, signed1, undef_bit_pos) * const2big(arg2, signed2, undef_bit_pos);
|
BigInteger y = const2big(arg1, signed1, undef_bit_pos) * const2big(arg2, signed2, undef_bit_pos);
|
||||||
return big2const(y, result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), min(undef_bit_pos, 0));
|
return big2const(y, result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), min(undef_bit_pos, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// truncating division
|
// truncating division
|
||||||
|
@ -480,7 +480,7 @@ RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
||||||
bool result_neg = (a.getSign() == BigInteger::negative) != (b.getSign() == BigInteger::negative);
|
bool result_neg = (a.getSign() == BigInteger::negative) != (b.getSign() == BigInteger::negative);
|
||||||
a = a.getSign() == BigInteger::negative ? -a : a;
|
a = a.getSign() == BigInteger::negative ? -a : a;
|
||||||
b = b.getSign() == BigInteger::negative ? -b : b;
|
b = b.getSign() == BigInteger::negative ? -b : b;
|
||||||
return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), min(undef_bit_pos, 0));
|
return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), min(undef_bit_pos, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// truncating modulo
|
// truncating modulo
|
||||||
|
@ -494,7 +494,7 @@ RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
||||||
bool result_neg = a.getSign() == BigInteger::negative;
|
bool result_neg = a.getSign() == BigInteger::negative;
|
||||||
a = a.getSign() == BigInteger::negative ? -a : a;
|
a = a.getSign() == BigInteger::negative ? -a : a;
|
||||||
b = b.getSign() == BigInteger::negative ? -b : b;
|
b = b.getSign() == BigInteger::negative ? -b : b;
|
||||||
return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), min(undef_bit_pos, 0));
|
return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), min(undef_bit_pos, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_divfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_divfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||||
|
@ -516,7 +516,7 @@ RTLIL::Const RTLIL::const_divfloor(const RTLIL::Const &arg1, const RTLIL::Const
|
||||||
// bigint division with negative numbers is wonky, make sure we only negate at the very end
|
// bigint division with negative numbers is wonky, make sure we only negate at the very end
|
||||||
result = -((a + b - 1) / b);
|
result = -((a + b - 1) / b);
|
||||||
}
|
}
|
||||||
return big2const(result, result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), min(undef_bit_pos, 0));
|
return big2const(result, result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), min(undef_bit_pos, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_modfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_modfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||||
|
@ -539,7 +539,7 @@ RTLIL::Const RTLIL::const_modfloor(const RTLIL::Const &arg1, const RTLIL::Const
|
||||||
} else {
|
} else {
|
||||||
modulo = b_sign == BigInteger::negative ? truncated - b : truncated + b;
|
modulo = b_sign == BigInteger::negative ? truncated - b : truncated + b;
|
||||||
}
|
}
|
||||||
return big2const(modulo, result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), min(undef_bit_pos, 0));
|
return big2const(modulo, result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), min(undef_bit_pos, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||||
|
@ -590,7 +590,7 @@ RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
||||||
y *= -1;
|
y *= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return big2const(y, result_len >= 0 ? result_len : max(arg1.size(), arg2.size()), min(undef_bit_pos, 0));
|
return big2const(y, result_len >= 0 ? result_len : max(GetSize(arg1), GetSize(arg2)), min(undef_bit_pos, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
|
||||||
|
@ -626,7 +626,7 @@ RTLIL::Const RTLIL::const_mux(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
||||||
return arg2;
|
return arg2;
|
||||||
|
|
||||||
RTLIL::Const ret = arg1;
|
RTLIL::Const ret = arg1;
|
||||||
for (int i = 0; i < ret.size(); i++)
|
for (auto i = 0; i < ret.size(); i++)
|
||||||
if (ret[i] != arg2[i])
|
if (ret[i] != arg2[i])
|
||||||
ret.bits()[i] = State::Sx;
|
ret.bits()[i] = State::Sx;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -640,7 +640,7 @@ RTLIL::Const RTLIL::const_pmux(const RTLIL::Const &arg1, const RTLIL::Const &arg
|
||||||
if (!arg3.is_onehot())
|
if (!arg3.is_onehot())
|
||||||
return RTLIL::Const(State::Sx, arg1.size());
|
return RTLIL::Const(State::Sx, arg1.size());
|
||||||
|
|
||||||
for (int i = 0; i < arg3.size(); i++)
|
for (auto i = 0; i < arg3.size(); i++)
|
||||||
if (arg3[i] == State::S1)
|
if (arg3[i] == State::S1)
|
||||||
return RTLIL::Const(std::vector<RTLIL::State>(arg2.begin() + i*arg1.size(), arg2.begin() + (i+1)*arg1.size()));
|
return RTLIL::Const(std::vector<RTLIL::State>(arg2.begin() + i*arg1.size(), arg2.begin() + (i+1)*arg1.size()));
|
||||||
|
|
||||||
|
@ -702,7 +702,7 @@ RTLIL::Const RTLIL::const_bweqx(const RTLIL::Const &arg1, const RTLIL::Const &ar
|
||||||
{
|
{
|
||||||
log_assert(arg2.size() == arg1.size());
|
log_assert(arg2.size() == arg1.size());
|
||||||
RTLIL::Const result(RTLIL::State::S0, arg1.size());
|
RTLIL::Const result(RTLIL::State::S0, arg1.size());
|
||||||
for (int i = 0; i < arg1.size(); i++)
|
for (auto i = 0; i < arg1.size(); i++)
|
||||||
result.bits()[i] = arg1[i] == arg2[i] ? State::S1 : State::S0;
|
result.bits()[i] = arg1[i] == arg2[i] ? State::S1 : State::S0;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -713,7 +713,7 @@ RTLIL::Const RTLIL::const_bwmux(const RTLIL::Const &arg1, const RTLIL::Const &ar
|
||||||
log_assert(arg2.size() == arg1.size());
|
log_assert(arg2.size() == arg1.size());
|
||||||
log_assert(arg3.size() == arg1.size());
|
log_assert(arg3.size() == arg1.size());
|
||||||
RTLIL::Const result(RTLIL::State::Sx, arg1.size());
|
RTLIL::Const result(RTLIL::State::Sx, arg1.size());
|
||||||
for (int i = 0; i < arg1.size(); i++) {
|
for (auto i = 0; i < arg1.size(); i++) {
|
||||||
if (arg3[i] != State::Sx || arg1[i] == arg2[i])
|
if (arg3[i] != State::Sx || arg1[i] == arg2[i])
|
||||||
result.bits()[i] = arg3[i] == State::S1 ? arg2[i] : arg1[i];
|
result.bits()[i] = arg3[i] == State::S1 ? arg2[i] : arg1[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,3 +274,5 @@ X(X)
|
||||||
X(xprop_decoder)
|
X(xprop_decoder)
|
||||||
X(Y)
|
X(Y)
|
||||||
X(Y_WIDTH)
|
X(Y_WIDTH)
|
||||||
|
X(area)
|
||||||
|
X(capacitance)
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
# include <editline/readline.h>
|
# include <editline/readline.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
|
# include <tcl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -276,6 +280,8 @@ int main(int argc, char **argv)
|
||||||
options.add_options("developer")
|
options.add_options("developer")
|
||||||
("X,trace", "enable tracing of core data structure changes. for debugging")
|
("X,trace", "enable tracing of core data structure changes. for debugging")
|
||||||
("M,randomize-pointers", "will slightly randomize allocated pointer addresses. for debugging")
|
("M,randomize-pointers", "will slightly randomize allocated pointer addresses. for debugging")
|
||||||
|
("autoidx", "start counting autoidx up from <seed>, similar effect to --hash-seed",
|
||||||
|
cxxopts::value<uint64_t>(), "<idx>")
|
||||||
("A,abort", "will call abort() at the end of the script. for debugging")
|
("A,abort", "will call abort() at the end of the script. for debugging")
|
||||||
("x,experimental", "do not print warnings for the experimental <feature>",
|
("x,experimental", "do not print warnings for the experimental <feature>",
|
||||||
cxxopts::value<std::vector<std::string>>(), "<feature>")
|
cxxopts::value<std::vector<std::string>>(), "<feature>")
|
||||||
|
@ -427,6 +433,10 @@ int main(int argc, char **argv)
|
||||||
if (result.count("infile")) {
|
if (result.count("infile")) {
|
||||||
frontend_files = result["infile"].as<std::vector<std::string>>();
|
frontend_files = result["infile"].as<std::vector<std::string>>();
|
||||||
}
|
}
|
||||||
|
if (result.count("autoidx")) {
|
||||||
|
int idx = result["autoidx"].as<uint64_t>();
|
||||||
|
autoidx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
if (log_errfile == NULL) {
|
if (log_errfile == NULL) {
|
||||||
log_files.push_back(stdout);
|
log_files.push_back(stdout);
|
||||||
|
|
|
@ -364,7 +364,7 @@ public:
|
||||||
|
|
||||||
unsigned int hash() const
|
unsigned int hash() const
|
||||||
{
|
{
|
||||||
unsigned int inner;
|
unsigned int inner = 0;
|
||||||
switch (type_)
|
switch (type_)
|
||||||
{
|
{
|
||||||
case DriveType::NONE:
|
case DriveType::NONE:
|
||||||
|
@ -385,6 +385,9 @@ public:
|
||||||
case DriveType::MULTIPLE:
|
case DriveType::MULTIPLE:
|
||||||
inner = multiple_.hash();
|
inner = multiple_.hash();
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
log_abort();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return mkhash((unsigned int)type_, inner);
|
return mkhash((unsigned int)type_, inner);
|
||||||
}
|
}
|
||||||
|
@ -912,7 +915,7 @@ public:
|
||||||
|
|
||||||
unsigned int hash() const
|
unsigned int hash() const
|
||||||
{
|
{
|
||||||
unsigned int inner;
|
unsigned int inner = 0;
|
||||||
switch (type_)
|
switch (type_)
|
||||||
{
|
{
|
||||||
case DriveType::NONE:
|
case DriveType::NONE:
|
||||||
|
@ -933,6 +936,9 @@ public:
|
||||||
case DriveType::MULTIPLE:
|
case DriveType::MULTIPLE:
|
||||||
inner = multiple_.hash();
|
inner = multiple_.hash();
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
log_abort();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return mkhash((unsigned int)type_, inner);
|
return mkhash((unsigned int)type_, inner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,6 +228,14 @@ struct Macc
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_simple_product()
|
||||||
|
{
|
||||||
|
return bit_ports.empty() &&
|
||||||
|
ports.size() == 1 &&
|
||||||
|
!ports[0].in_b.empty() &&
|
||||||
|
!ports[0].do_subtract;
|
||||||
|
}
|
||||||
|
|
||||||
Macc(RTLIL::Cell *cell = nullptr)
|
Macc(RTLIL::Cell *cell = nullptr)
|
||||||
{
|
{
|
||||||
if (cell != nullptr)
|
if (cell != nullptr)
|
||||||
|
|
|
@ -1680,8 +1680,6 @@ SigSpec MemWr::decompress_en(const std::vector<int> &swizzle, SigSpec sig) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
using addr_t = MemContents::addr_t;
|
|
||||||
|
|
||||||
MemContents::MemContents(Mem *mem) :
|
MemContents::MemContents(Mem *mem) :
|
||||||
MemContents(ceil_log2(mem->size), mem->width)
|
MemContents(ceil_log2(mem->size), mem->width)
|
||||||
{
|
{
|
||||||
|
@ -1758,7 +1756,7 @@ bool MemContents::_range_overlaps(std::map<addr_t, RTLIL::Const>::iterator it, a
|
||||||
return !(top1 < begin_addr || top2 < _range_begin(it));
|
return !(top1 < begin_addr || top2 < _range_begin(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<addr_t, RTLIL::Const>::iterator MemContents::_range_at(addr_t addr) const {
|
std::map<MemContents::addr_t, RTLIL::Const>::iterator MemContents::_range_at(addr_t addr) const {
|
||||||
// allow addr == 1<<_addr_width (which will just return end())
|
// allow addr == 1<<_addr_width (which will just return end())
|
||||||
log_assert(addr <= (addr_t)(1<<_addr_width));
|
log_assert(addr <= (addr_t)(1<<_addr_width));
|
||||||
// get the first range with base > addr
|
// get the first range with base > addr
|
||||||
|
@ -1786,7 +1784,7 @@ RTLIL::Const MemContents::operator[](addr_t addr) const {
|
||||||
return _default_value;
|
return _default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t MemContents::count_range(addr_t begin_addr, addr_t end_addr) const {
|
MemContents::addr_t MemContents::count_range(addr_t begin_addr, addr_t end_addr) const {
|
||||||
addr_t count = 0;
|
addr_t count = 0;
|
||||||
for(auto it = _range_at(begin_addr); _range_overlaps(it, begin_addr, end_addr); it++) {
|
for(auto it = _range_at(begin_addr); _range_overlaps(it, begin_addr, end_addr); it++) {
|
||||||
auto first = std::max(_range_begin(it), begin_addr);
|
auto first = std::max(_range_begin(it), begin_addr);
|
||||||
|
@ -1829,7 +1827,7 @@ void MemContents::clear_range(addr_t begin_addr, addr_t end_addr) {
|
||||||
_values.erase(begin_it, end_it);
|
_values.erase(begin_it, end_it);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<addr_t, RTLIL::Const>::iterator MemContents::_reserve_range(addr_t begin_addr, addr_t end_addr) {
|
std::map<MemContents::addr_t, RTLIL::Const>::iterator MemContents::_reserve_range(addr_t begin_addr, addr_t end_addr) {
|
||||||
if(begin_addr >= end_addr)
|
if(begin_addr >= end_addr)
|
||||||
return _values.end(); // need a dummy value to return, end() is cheap
|
return _values.end(); // need a dummy value to return, end() is cheap
|
||||||
// find the first range containing any addr >= begin_addr - 1
|
// find the first range containing any addr >= begin_addr - 1
|
||||||
|
|
|
@ -380,7 +380,7 @@ int RTLIL::Const::as_int(bool is_signed) const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RTLIL::Const::get_min_size(bool is_signed) const
|
int RTLIL::Const::get_min_size(bool is_signed) const
|
||||||
{
|
{
|
||||||
if (empty()) return 0;
|
if (empty()) return 0;
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@ size_t RTLIL::Const::get_min_size(bool is_signed) const
|
||||||
else
|
else
|
||||||
leading_bit = RTLIL::State::S0;
|
leading_bit = RTLIL::State::S0;
|
||||||
|
|
||||||
size_t idx = size();
|
auto idx = size();
|
||||||
while (idx > 0 && (*this)[idx -1] == leading_bit) {
|
while (idx > 0 && (*this)[idx -1] == leading_bit) {
|
||||||
idx--;
|
idx--;
|
||||||
}
|
}
|
||||||
|
@ -406,22 +406,22 @@ size_t RTLIL::Const::get_min_size(bool is_signed) const
|
||||||
|
|
||||||
void RTLIL::Const::compress(bool is_signed)
|
void RTLIL::Const::compress(bool is_signed)
|
||||||
{
|
{
|
||||||
size_t idx = get_min_size(is_signed);
|
auto idx = get_min_size(is_signed);
|
||||||
bits().erase(bits().begin() + idx, bits().end());
|
bits().erase(bits().begin() + idx, bits().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const
|
std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const
|
||||||
{
|
{
|
||||||
size_t size = get_min_size(is_signed);
|
auto size = get_min_size(is_signed);
|
||||||
if(size == 0 || size > 32)
|
if(size == 0 || size > 32)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
int32_t ret = 0;
|
int32_t ret = 0;
|
||||||
for (size_t i = 0; i < size && i < 32; i++)
|
for (auto i = 0; i < size && i < 32; i++)
|
||||||
if ((*this)[i] == State::S1)
|
if ((*this)[i] == State::S1)
|
||||||
ret |= 1 << i;
|
ret |= 1 << i;
|
||||||
if (is_signed && (*this)[size-1] == State::S1)
|
if (is_signed && (*this)[size-1] == State::S1)
|
||||||
for (size_t i = size; i < 32; i++)
|
for (auto i = size; i < 32; i++)
|
||||||
ret |= 1 << i;
|
ret |= 1 << i;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1856,9 +1856,9 @@ namespace {
|
||||||
param_bits(ID::RD_COLLISION_X_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS)));
|
param_bits(ID::RD_COLLISION_X_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS)));
|
||||||
param_bits(ID::RD_WIDE_CONTINUATION, max(1, param(ID::RD_PORTS)));
|
param_bits(ID::RD_WIDE_CONTINUATION, max(1, param(ID::RD_PORTS)));
|
||||||
param_bits(ID::RD_CE_OVER_SRST, max(1, param(ID::RD_PORTS)));
|
param_bits(ID::RD_CE_OVER_SRST, max(1, param(ID::RD_PORTS)));
|
||||||
param_bits(ID::RD_ARST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
|
param_bits(ID::RD_ARST_VALUE, max(1, param(ID::RD_PORTS) * param(ID::WIDTH)));
|
||||||
param_bits(ID::RD_SRST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
|
param_bits(ID::RD_SRST_VALUE, max(1, param(ID::RD_PORTS) * param(ID::WIDTH)));
|
||||||
param_bits(ID::RD_INIT_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH));
|
param_bits(ID::RD_INIT_VALUE, max(1, param(ID::RD_PORTS) * param(ID::WIDTH)));
|
||||||
param_bits(ID::WR_CLK_ENABLE, max(1, param(ID::WR_PORTS)));
|
param_bits(ID::WR_CLK_ENABLE, max(1, param(ID::WR_PORTS)));
|
||||||
param_bits(ID::WR_CLK_POLARITY, max(1, param(ID::WR_PORTS)));
|
param_bits(ID::WR_CLK_POLARITY, max(1, param(ID::WR_PORTS)));
|
||||||
param_bits(ID::WR_WIDE_CONTINUATION, max(1, param(ID::WR_PORTS)));
|
param_bits(ID::WR_WIDE_CONTINUATION, max(1, param(ID::WR_PORTS)));
|
||||||
|
@ -2147,6 +2147,21 @@ namespace {
|
||||||
check_expected();
|
check_expected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Checklist for adding internal cell types
|
||||||
|
* ========================================
|
||||||
|
* Things to do right away:
|
||||||
|
* - Add to kernel/celltypes.h (incl. eval() handling for non-mem cells)
|
||||||
|
* - Add to InternalCellChecker::check() in kernel/rtlil.cc
|
||||||
|
* - Add to techlibs/common/simlib.v
|
||||||
|
* - Add to techlibs/common/techmap.v
|
||||||
|
*
|
||||||
|
* Things to do after finalizing the cell interface:
|
||||||
|
* - Add support to kernel/satgen.h for the new cell type
|
||||||
|
* - Add to docs/source/CHAPTER_CellLib.rst (or just add a fixme to the bottom)
|
||||||
|
* - Maybe add support to the Verilog backend for dumping such cells as expression
|
||||||
|
*
|
||||||
|
*/
|
||||||
error(__LINE__);
|
error(__LINE__);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -780,7 +780,7 @@ public:
|
||||||
RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const;
|
RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const;
|
||||||
|
|
||||||
// find the MSB without redundant leading bits
|
// find the MSB without redundant leading bits
|
||||||
size_t get_min_size(bool is_signed) const;
|
int get_min_size(bool is_signed) const;
|
||||||
|
|
||||||
// compress representation to the minimum required bits
|
// compress representation to the minimum required bits
|
||||||
void compress(bool is_signed = false);
|
void compress(bool is_signed = false);
|
||||||
|
@ -814,6 +814,7 @@ struct RTLIL::AttrObject
|
||||||
void set_bool_attribute(const RTLIL::IdString &id, bool value=true);
|
void set_bool_attribute(const RTLIL::IdString &id, bool value=true);
|
||||||
bool get_bool_attribute(const RTLIL::IdString &id) const;
|
bool get_bool_attribute(const RTLIL::IdString &id) const;
|
||||||
|
|
||||||
|
[[deprecated("Use Module::get_blackbox_attribute() instead.")]]
|
||||||
bool get_blackbox_attribute(bool ignore_wb=false) const {
|
bool get_blackbox_attribute(bool ignore_wb=false) const {
|
||||||
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
|
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
|
||||||
}
|
}
|
||||||
|
@ -1291,6 +1292,10 @@ public:
|
||||||
virtual void optimize();
|
virtual void optimize();
|
||||||
virtual void makeblackbox();
|
virtual void makeblackbox();
|
||||||
|
|
||||||
|
bool get_blackbox_attribute(bool ignore_wb=false) const {
|
||||||
|
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
|
||||||
|
}
|
||||||
|
|
||||||
void connect(const RTLIL::SigSig &conn);
|
void connect(const RTLIL::SigSig &conn);
|
||||||
void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);
|
void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);
|
||||||
void new_connections(const std::vector<RTLIL::SigSig> &new_conn);
|
void new_connections(const std::vector<RTLIL::SigSig> &new_conn);
|
||||||
|
|
|
@ -169,6 +169,10 @@ public:
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hash() const {
|
||||||
|
return mkhash(scope_name.hash(), hash_ptr_ops::hash(target));
|
||||||
|
}
|
||||||
|
|
||||||
bool valid() const {
|
bool valid() const {
|
||||||
return target != nullptr;
|
return target != nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,574 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/rtlil.h"
|
||||||
|
#include "libs/json11/json11.hpp"
|
||||||
|
|
||||||
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
|
#include <tcl.h>
|
||||||
|
#include <tclTomMath.h>
|
||||||
|
#include <tclTomMathDecls.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
|
bool yosys_tcl_repl_active = false;
|
||||||
|
|
||||||
|
void yosys_tcl_activate_repl()
|
||||||
|
{
|
||||||
|
yosys_tcl_repl_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Tcl_Obj *json_to_tcl(Tcl_Interp *interp, const json11::Json &json)
|
||||||
|
{
|
||||||
|
if (json.is_null())
|
||||||
|
return Tcl_NewStringObj("null", 4);
|
||||||
|
else if (json.is_string()) {
|
||||||
|
auto string = json.string_value();
|
||||||
|
return Tcl_NewStringObj(string.data(), string.size());
|
||||||
|
} else if (json.is_number()) {
|
||||||
|
double value = json.number_value();
|
||||||
|
double round_val = std::nearbyint(value);
|
||||||
|
if (std::isfinite(round_val) && value == round_val && value >= LONG_MIN && value < -double(LONG_MIN))
|
||||||
|
return Tcl_NewLongObj((long)round_val);
|
||||||
|
else
|
||||||
|
return Tcl_NewDoubleObj(value);
|
||||||
|
} else if (json.is_bool()) {
|
||||||
|
return Tcl_NewBooleanObj(json.bool_value());
|
||||||
|
} else if (json.is_array()) {
|
||||||
|
auto list = json.array_items();
|
||||||
|
Tcl_Obj *result = Tcl_NewListObj(list.size(), nullptr);
|
||||||
|
for (auto &item : list)
|
||||||
|
Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item));
|
||||||
|
return result;
|
||||||
|
} else if (json.is_object()) {
|
||||||
|
auto map = json.object_items();
|
||||||
|
Tcl_Obj *result = Tcl_NewListObj(map.size() * 2, nullptr);
|
||||||
|
for (auto &item : map) {
|
||||||
|
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(item.first.data(), item.first.size()));
|
||||||
|
Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item.second));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
log_abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
std::vector<std::string> args;
|
||||||
|
for (int i = 1; i < argc; i++)
|
||||||
|
args.push_back(argv[i]);
|
||||||
|
|
||||||
|
if (args.size() >= 1 && args[0] == "-import") {
|
||||||
|
for (auto &it : pass_register) {
|
||||||
|
std::string tcl_command_name = it.first;
|
||||||
|
if (tcl_command_name == "proc")
|
||||||
|
tcl_command_name = "procs";
|
||||||
|
else if (tcl_command_name == "rename")
|
||||||
|
tcl_command_name = "renames";
|
||||||
|
Tcl_CmdInfo info;
|
||||||
|
if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
|
||||||
|
log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
|
||||||
|
} else {
|
||||||
|
std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
|
||||||
|
Tcl_Eval(interp, tcl_script.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
yosys_get_design()->scratchpad_unset("result.json");
|
||||||
|
yosys_get_design()->scratchpad_unset("result.string");
|
||||||
|
|
||||||
|
bool in_repl = yosys_tcl_repl_active;
|
||||||
|
bool restore_log_cmd_error_throw = log_cmd_error_throw;
|
||||||
|
|
||||||
|
log_cmd_error_throw = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (args.size() == 1) {
|
||||||
|
Pass::call(yosys_get_design(), args[0]);
|
||||||
|
} else {
|
||||||
|
Pass::call(yosys_get_design(), args);
|
||||||
|
}
|
||||||
|
} catch (log_cmd_error_exception) {
|
||||||
|
if (in_repl) {
|
||||||
|
auto design = yosys_get_design();
|
||||||
|
while (design->selection_stack.size() > 1)
|
||||||
|
design->selection_stack.pop_back();
|
||||||
|
log_reset_stack();
|
||||||
|
}
|
||||||
|
Tcl_SetResult(interp, (char *)"Yosys command produced an error", TCL_STATIC);
|
||||||
|
|
||||||
|
yosys_tcl_repl_active = in_repl;
|
||||||
|
log_cmd_error_throw = restore_log_cmd_error_throw;
|
||||||
|
return TCL_ERROR;
|
||||||
|
} catch (...) {
|
||||||
|
log_error("uncaught exception during Yosys command invoked from TCL\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
yosys_tcl_repl_active = in_repl;
|
||||||
|
log_cmd_error_throw = restore_log_cmd_error_throw;
|
||||||
|
|
||||||
|
auto &scratchpad = yosys_get_design()->scratchpad;
|
||||||
|
auto result = scratchpad.find("result.json");
|
||||||
|
if (result != scratchpad.end()) {
|
||||||
|
std::string err;
|
||||||
|
auto json = json11::Json::parse(result->second, err);
|
||||||
|
if (err.empty()) {
|
||||||
|
Tcl_SetObjResult(interp, json_to_tcl(interp, json));
|
||||||
|
} else
|
||||||
|
log_warning("Ignoring result.json scratchpad value due to parse error: %s\n", err.c_str());
|
||||||
|
} else if ((result = scratchpad.find("result.string")) != scratchpad.end()) {
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewStringObj(result->second.data(), result->second.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FLAG(name) \
|
||||||
|
if (!strcmp(argv[i], "-" #name)) { \
|
||||||
|
name##_flag = true; \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
#define FLAG2(name) \
|
||||||
|
if (!strcmp(Tcl_GetString(objv[i]), "-" #name)) { \
|
||||||
|
name##_flag = true; \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
#define ERROR(str) \
|
||||||
|
{ \
|
||||||
|
Tcl_SetResult(interp, (char *)(str), TCL_STATIC); \
|
||||||
|
return TCL_ERROR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
bool const_to_mp_int(const Const &a, mp_int *b, bool force_signed, bool force_unsigned)
|
||||||
|
{
|
||||||
|
if (!a.is_fully_def())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mp_init(b))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool negative = ((a.flags & RTLIL::CONST_FLAG_SIGNED) || force_signed) &&
|
||||||
|
!force_unsigned &&
|
||||||
|
!a.empty() && (a.back() == RTLIL::S1);
|
||||||
|
|
||||||
|
for (int i = a.size() - 1; i >= 0; i--) {
|
||||||
|
if (mp_mul_2d(b, 1, b)) {
|
||||||
|
mp_clear(b);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((a[i] == RTLIL::S1) ^ negative) {
|
||||||
|
if (mp_add_d(b, 1, b)) {
|
||||||
|
mp_clear(b);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negative) {
|
||||||
|
if (mp_add_d(b, 1, b) || mp_neg(b, b)) {
|
||||||
|
mp_clear(b);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mp_int_to_const(mp_int *a, Const &b, bool is_signed)
|
||||||
|
{
|
||||||
|
bool negative = (mp_cmp_d(a, 0) == MP_LT);
|
||||||
|
if (negative && !is_signed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (negative) {
|
||||||
|
mp_neg(a, a);
|
||||||
|
mp_sub_d(a, 1, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> buf;
|
||||||
|
buf.resize(mp_unsigned_bin_size(a));
|
||||||
|
mp_to_unsigned_bin(a, buf.data());
|
||||||
|
|
||||||
|
b.bits().reserve(mp_count_bits(a) + is_signed);
|
||||||
|
for (int i = 0; i < mp_count_bits(a);) {
|
||||||
|
for (int j = 0; j < 8 && i < mp_count_bits(a); j++, i++) {
|
||||||
|
bool bv = ((buf.back() & (1 << j)) != 0) ^ negative;
|
||||||
|
b.bits().push_back(bv ? RTLIL::S1 : RTLIL::S0);
|
||||||
|
}
|
||||||
|
buf.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_signed) {
|
||||||
|
b.bits().push_back(negative ? RTLIL::S1 : RTLIL::S0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcl_get_attr(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool mod_flag = false, string_flag = false, bool_flag = false;
|
||||||
|
bool int_flag = false, sint_flag = false, uint_flag = false;
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
FLAG(mod)
|
||||||
|
FLAG(string)
|
||||||
|
FLAG(int)
|
||||||
|
FLAG(sint)
|
||||||
|
FLAG(uint)
|
||||||
|
FLAG(bool)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mod_flag && i != argc - 2) ||
|
||||||
|
(!mod_flag && i != argc - 3) ||
|
||||||
|
(string_flag + int_flag + sint_flag + uint_flag + bool_flag > 1))
|
||||||
|
ERROR("bad usage: expected \"get_attr -mod [-string|-int|-sint|-uint|-bool] <module> <attrname>\""
|
||||||
|
" or \"get_attr [-string|-int|-sint|-uint|-bool] <module> <identifier> <attrname>\"")
|
||||||
|
|
||||||
|
IdString mod_id, obj_id, attr_id;
|
||||||
|
mod_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
if (!mod_flag)
|
||||||
|
obj_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
attr_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
|
||||||
|
RTLIL::Module *mod = yosys_design->module(mod_id);
|
||||||
|
if (!mod)
|
||||||
|
ERROR("module not found")
|
||||||
|
|
||||||
|
RTLIL::AttrObject *obj = nullptr;
|
||||||
|
if (mod_flag) {
|
||||||
|
obj = mod;
|
||||||
|
} else {
|
||||||
|
obj = mod->wire(obj_id);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->memories.at(obj_id, nullptr);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->cell(obj_id);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->processes.at(obj_id, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj)
|
||||||
|
ERROR("object not found")
|
||||||
|
|
||||||
|
if (string_flag) {
|
||||||
|
Tcl_SetResult(interp, (char *) obj->get_string_attribute(attr_id).c_str(), TCL_VOLATILE);
|
||||||
|
} else if (int_flag || uint_flag || sint_flag) {
|
||||||
|
if (!obj->has_attribute(attr_id))
|
||||||
|
ERROR("attribute missing (required for -int)");
|
||||||
|
RTLIL::Const &value = obj->attributes.at(attr_id);
|
||||||
|
|
||||||
|
mp_int value_mp;
|
||||||
|
if (!const_to_mp_int(value, &value_mp, sint_flag, uint_flag))
|
||||||
|
ERROR("bignum manipulation failed");
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewBignumObj(&value_mp));
|
||||||
|
} else if (bool_flag) {
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(obj->get_bool_attribute(attr_id)));
|
||||||
|
} else {
|
||||||
|
if (!obj->has_attribute(attr_id))
|
||||||
|
ERROR("attribute missing (required unless -bool or -string)")
|
||||||
|
|
||||||
|
Tcl_SetResult(interp, (char *) obj->attributes.at(attr_id).as_string().c_str(), TCL_VOLATILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcl_has_attr(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool mod_flag = false;
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
FLAG(mod)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mod_flag && i != argc - 2) ||
|
||||||
|
(!mod_flag && i != argc - 3))
|
||||||
|
ERROR("bad usage: expected \"has_attr -mod <module> <attrname>\""
|
||||||
|
" or \"has_attr <module> <identifier> <attrname>\"")
|
||||||
|
|
||||||
|
IdString mod_id, obj_id, attr_id;
|
||||||
|
mod_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
if (!mod_flag)
|
||||||
|
obj_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
attr_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
|
||||||
|
RTLIL::Module *mod = yosys_design->module(mod_id);
|
||||||
|
if (!mod)
|
||||||
|
ERROR("module not found")
|
||||||
|
|
||||||
|
RTLIL::AttrObject *obj = nullptr;
|
||||||
|
if (mod_flag) {
|
||||||
|
obj = mod;
|
||||||
|
} else {
|
||||||
|
obj = mod->wire(obj_id);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->memories.at(obj_id, nullptr);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->cell(obj_id);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->processes.at(obj_id, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj)
|
||||||
|
ERROR("object not found")
|
||||||
|
|
||||||
|
Tcl_SetResult(interp, (char *) std::to_string(obj->has_attribute(attr_id)).c_str(), TCL_VOLATILE);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcl_set_attr(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool mod_flag = false, string_flag = false, bool_flag = false;
|
||||||
|
bool true_flag = false, false_flag = false, sint_flag = false, uint_flag = false;
|
||||||
|
for (i = 1; i < objc; i++) {
|
||||||
|
FLAG2(mod)
|
||||||
|
FLAG2(string)
|
||||||
|
FLAG2(true)
|
||||||
|
FLAG2(false)
|
||||||
|
FLAG2(sint)
|
||||||
|
FLAG2(uint)
|
||||||
|
FLAG2(bool)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i != objc - (2 + !mod_flag + !(true_flag || false_flag))) ||
|
||||||
|
(string_flag + sint_flag + uint_flag + bool_flag + true_flag + false_flag > 1))
|
||||||
|
ERROR("bad usage: expected \"set_attr -mod [-string|-sint|-uint|-bool] <module> <attrname> <value>\""
|
||||||
|
" or \"set_attr [-string|-sint|-uint|-bool] <module> <identifier> <attrname> <value>\""
|
||||||
|
" or \"set_attr [-true|-false] <module> <identifier> <attrname>\""
|
||||||
|
" or \"set_attr -mod [-true|-false| <module> <attrname>\"")
|
||||||
|
|
||||||
|
IdString mod_id, obj_id, attr_id;
|
||||||
|
mod_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
|
||||||
|
if (!mod_flag)
|
||||||
|
obj_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
|
||||||
|
attr_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
|
||||||
|
|
||||||
|
RTLIL::Module *mod = yosys_design->module(mod_id);
|
||||||
|
if (!mod)
|
||||||
|
ERROR("module not found")
|
||||||
|
|
||||||
|
RTLIL::AttrObject *obj = nullptr;
|
||||||
|
if (mod_flag) {
|
||||||
|
obj = mod;
|
||||||
|
} else {
|
||||||
|
obj = mod->wire(obj_id);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->memories.at(obj_id, nullptr);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->cell(obj_id);
|
||||||
|
if (!obj)
|
||||||
|
obj = mod->processes.at(obj_id, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj)
|
||||||
|
ERROR("object not found")
|
||||||
|
|
||||||
|
if (string_flag) {
|
||||||
|
obj->set_string_attribute(attr_id, Tcl_GetString(objv[i++]));
|
||||||
|
} else if (sint_flag || uint_flag) {
|
||||||
|
RTLIL::Const const_;
|
||||||
|
mp_int value_mp;
|
||||||
|
|
||||||
|
if (Tcl_TakeBignumFromObj(interp, objv[i++], &value_mp))
|
||||||
|
ERROR("non-integral value")
|
||||||
|
|
||||||
|
if (!mp_int_to_const(&value_mp, const_, sint_flag))
|
||||||
|
ERROR("bignum manipulation failed");
|
||||||
|
|
||||||
|
if (sint_flag) {
|
||||||
|
const_.flags |= RTLIL::CONST_FLAG_SIGNED;
|
||||||
|
if (const_.size() < 32)
|
||||||
|
const_.exts(32);
|
||||||
|
} else {
|
||||||
|
if (const_.size() < 32)
|
||||||
|
const_.extu(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->attributes[attr_id] = const_;
|
||||||
|
} else if (bool_flag) {
|
||||||
|
obj->set_bool_attribute(attr_id, atoi(Tcl_GetString(objv[i++])) != 0);
|
||||||
|
} else if (true_flag) {
|
||||||
|
obj->set_bool_attribute(attr_id, true);
|
||||||
|
} else if (false_flag) {
|
||||||
|
obj->set_bool_attribute(attr_id, false);
|
||||||
|
} else {
|
||||||
|
obj->attributes[attr_id] = Const::from_string(std::string(Tcl_GetString(objv[i++])));
|
||||||
|
}
|
||||||
|
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcl_get_param(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool string_flag = false;
|
||||||
|
bool int_flag = false, sint_flag = false, uint_flag = false;
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
FLAG(string)
|
||||||
|
FLAG(int)
|
||||||
|
FLAG(sint)
|
||||||
|
FLAG(uint)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i != argc - 3) ||
|
||||||
|
(string_flag + int_flag > 1))
|
||||||
|
ERROR("bad usage: expected \"get_param [-string|-int|-sint|-uint] <module> <cellid> <paramname>")
|
||||||
|
|
||||||
|
IdString mod_id, cell_id, param_id;
|
||||||
|
mod_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
cell_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
param_id = RTLIL::escape_id(argv[i++]);
|
||||||
|
|
||||||
|
RTLIL::Module *mod = yosys_design->module(mod_id);
|
||||||
|
if (!mod)
|
||||||
|
ERROR("module not found")
|
||||||
|
|
||||||
|
RTLIL::Cell *cell = mod->cell(cell_id);
|
||||||
|
if (!cell)
|
||||||
|
ERROR("object not found")
|
||||||
|
|
||||||
|
if (!cell->hasParam(param_id))
|
||||||
|
ERROR("parameter missing")
|
||||||
|
|
||||||
|
const RTLIL::Const &value = cell->getParam(param_id);
|
||||||
|
|
||||||
|
if (string_flag) {
|
||||||
|
Tcl_SetResult(interp, (char *) value.decode_string().c_str(), TCL_VOLATILE);
|
||||||
|
} else if (int_flag || uint_flag || sint_flag) {
|
||||||
|
mp_int value_mp;
|
||||||
|
if (!const_to_mp_int(value, &value_mp, sint_flag, uint_flag))
|
||||||
|
ERROR("bignum manipulation failed");
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewBignumObj(&value_mp));
|
||||||
|
} else {
|
||||||
|
Tcl_SetResult(interp, (char *) value.as_string().c_str(), TCL_VOLATILE);
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcl_set_param(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bool string_flag = false, sint_flag = false, uint_flag = false;
|
||||||
|
for (i = 1; i < objc; i++) {
|
||||||
|
FLAG2(string)
|
||||||
|
FLAG2(sint)
|
||||||
|
FLAG2(uint)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i != objc - 4) ||
|
||||||
|
(string_flag + sint_flag + uint_flag > 1))
|
||||||
|
ERROR("bad usage: expected \"set_param [-string|-sint|-uint] <module> <cellid> <paramname> <value>")
|
||||||
|
|
||||||
|
IdString mod_id, cell_id, param_id;
|
||||||
|
mod_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
|
||||||
|
cell_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
|
||||||
|
param_id = RTLIL::escape_id(Tcl_GetString(objv[i++]));
|
||||||
|
|
||||||
|
RTLIL::Module *mod = yosys_design->module(mod_id);
|
||||||
|
if (!mod)
|
||||||
|
ERROR("module not found")
|
||||||
|
|
||||||
|
RTLIL::Cell *cell = mod->cell(cell_id);
|
||||||
|
if (!cell)
|
||||||
|
ERROR("object not found")
|
||||||
|
|
||||||
|
if (string_flag) {
|
||||||
|
cell->setParam(param_id, Const(std::string(Tcl_GetString(objv[i++]))));
|
||||||
|
} else if (sint_flag || uint_flag) {
|
||||||
|
RTLIL::Const const_;
|
||||||
|
mp_int value_mp;
|
||||||
|
|
||||||
|
if (Tcl_TakeBignumFromObj(interp, objv[i++], &value_mp))
|
||||||
|
ERROR("non-integral value")
|
||||||
|
|
||||||
|
if (!mp_int_to_const(&value_mp, const_, sint_flag))
|
||||||
|
ERROR("bignum manipulation failed");
|
||||||
|
|
||||||
|
if (sint_flag) {
|
||||||
|
const_.flags |= RTLIL::CONST_FLAG_SIGNED;
|
||||||
|
if (const_.size() < 32)
|
||||||
|
const_.exts(32);
|
||||||
|
} else {
|
||||||
|
if (const_.size() < 32)
|
||||||
|
const_.extu(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell->setParam(param_id, const_);
|
||||||
|
} else {
|
||||||
|
cell->setParam(param_id, Const::from_string(std::string(Tcl_GetString(objv[i++]))));
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yosys_tcl_iterp_init(Tcl_Interp *interp)
|
||||||
|
{
|
||||||
|
if (Tcl_Init(interp)!=TCL_OK)
|
||||||
|
log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
|
||||||
|
Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL);
|
||||||
|
Tcl_CreateCommand(interp, "rtlil::get_attr", tcl_get_attr, NULL, NULL);
|
||||||
|
Tcl_CreateCommand(interp, "rtlil::has_attr", tcl_has_attr, NULL, NULL);
|
||||||
|
Tcl_CreateObjCommand(interp, "rtlil::set_attr", tcl_set_attr, NULL, NULL);
|
||||||
|
Tcl_CreateCommand(interp, "rtlil::get_param", tcl_get_param, NULL, NULL);
|
||||||
|
Tcl_CreateObjCommand(interp, "rtlil::set_param", tcl_set_param, NULL, NULL);
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
//
|
||||||
|
// port_list
|
||||||
|
// wire_list
|
||||||
|
// cell_list
|
||||||
|
// wire_width
|
||||||
|
//
|
||||||
|
// add_wire
|
||||||
|
// add_cell
|
||||||
|
// rename_wire
|
||||||
|
// rename_cell
|
||||||
|
// remove
|
||||||
|
//
|
||||||
|
// SigSpec land
|
||||||
|
//
|
||||||
|
// get_conn
|
||||||
|
// set_conn
|
||||||
|
// unpack
|
||||||
|
// pack
|
||||||
|
|
||||||
|
// Note (dev jf 24-12-02): Make log_id escape everything that’s not a valid
|
||||||
|
// verilog identifier before adding any tcl API that returns IdString values
|
||||||
|
// to avoid -option injection
|
||||||
|
|
||||||
|
return TCL_OK ;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
129
kernel/yosys.cc
129
kernel/yosys.cc
|
@ -29,6 +29,10 @@
|
||||||
# include <editline/readline.h>
|
# include <editline/readline.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
|
# include <tcl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef YOSYS_ENABLE_PLUGINS
|
#ifdef YOSYS_ENABLE_PLUGINS
|
||||||
# include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,8 +77,6 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "libs/json11/json11.hpp"
|
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
int autoidx = 1;
|
int autoidx = 1;
|
||||||
|
@ -84,7 +86,6 @@ CellTypes yosys_celltypes;
|
||||||
|
|
||||||
#ifdef YOSYS_ENABLE_TCL
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
Tcl_Interp *yosys_tcl_interp = NULL;
|
Tcl_Interp *yosys_tcl_interp = NULL;
|
||||||
bool yosys_tcl_repl_active = false;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::set<std::string> yosys_input_files, yosys_output_files;
|
std::set<std::string> yosys_input_files, yosys_output_files;
|
||||||
|
@ -722,126 +723,8 @@ void rewrite_filename(std::string &filename)
|
||||||
|
|
||||||
#ifdef YOSYS_ENABLE_TCL
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
|
|
||||||
static Tcl_Obj *json_to_tcl(Tcl_Interp *interp, const json11::Json &json)
|
// defined in tclapi.cc
|
||||||
{
|
extern int yosys_tcl_iterp_init(Tcl_Interp *interp);
|
||||||
if (json.is_null())
|
|
||||||
return Tcl_NewStringObj("null", 4);
|
|
||||||
else if (json.is_string()) {
|
|
||||||
auto string = json.string_value();
|
|
||||||
return Tcl_NewStringObj(string.data(), string.size());
|
|
||||||
} else if (json.is_number()) {
|
|
||||||
double value = json.number_value();
|
|
||||||
double round_val = std::nearbyint(value);
|
|
||||||
if (std::isfinite(round_val) && value == round_val && value >= LONG_MIN && value < -double(LONG_MIN))
|
|
||||||
return Tcl_NewLongObj((long)round_val);
|
|
||||||
else
|
|
||||||
return Tcl_NewDoubleObj(value);
|
|
||||||
} else if (json.is_bool()) {
|
|
||||||
return Tcl_NewBooleanObj(json.bool_value());
|
|
||||||
} else if (json.is_array()) {
|
|
||||||
auto list = json.array_items();
|
|
||||||
Tcl_Obj *result = Tcl_NewListObj(list.size(), nullptr);
|
|
||||||
for (auto &item : list)
|
|
||||||
Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item));
|
|
||||||
return result;
|
|
||||||
} else if (json.is_object()) {
|
|
||||||
auto map = json.object_items();
|
|
||||||
Tcl_Obj *result = Tcl_NewListObj(map.size() * 2, nullptr);
|
|
||||||
for (auto &item : map) {
|
|
||||||
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(item.first.data(), item.first.size()));
|
|
||||||
Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item.second));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
log_abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
|
|
||||||
{
|
|
||||||
std::vector<std::string> args;
|
|
||||||
for (int i = 1; i < argc; i++)
|
|
||||||
args.push_back(argv[i]);
|
|
||||||
|
|
||||||
if (args.size() >= 1 && args[0] == "-import") {
|
|
||||||
for (auto &it : pass_register) {
|
|
||||||
std::string tcl_command_name = it.first;
|
|
||||||
if (tcl_command_name == "proc")
|
|
||||||
tcl_command_name = "procs";
|
|
||||||
else if (tcl_command_name == "rename")
|
|
||||||
tcl_command_name = "renames";
|
|
||||||
Tcl_CmdInfo info;
|
|
||||||
if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
|
|
||||||
log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
|
|
||||||
} else {
|
|
||||||
std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
|
|
||||||
Tcl_Eval(interp, tcl_script.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TCL_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
yosys_get_design()->scratchpad_unset("result.json");
|
|
||||||
yosys_get_design()->scratchpad_unset("result.string");
|
|
||||||
|
|
||||||
bool in_repl = yosys_tcl_repl_active;
|
|
||||||
bool restore_log_cmd_error_throw = log_cmd_error_throw;
|
|
||||||
|
|
||||||
log_cmd_error_throw = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (args.size() == 1) {
|
|
||||||
Pass::call(yosys_get_design(), args[0]);
|
|
||||||
} else {
|
|
||||||
Pass::call(yosys_get_design(), args);
|
|
||||||
}
|
|
||||||
} catch (log_cmd_error_exception) {
|
|
||||||
if (in_repl) {
|
|
||||||
auto design = yosys_get_design();
|
|
||||||
while (design->selection_stack.size() > 1)
|
|
||||||
design->selection_stack.pop_back();
|
|
||||||
log_reset_stack();
|
|
||||||
}
|
|
||||||
Tcl_SetResult(interp, (char *)"Yosys command produced an error", TCL_STATIC);
|
|
||||||
|
|
||||||
yosys_tcl_repl_active = in_repl;
|
|
||||||
log_cmd_error_throw = restore_log_cmd_error_throw;
|
|
||||||
return TCL_ERROR;
|
|
||||||
} catch (...) {
|
|
||||||
log_error("uncaught exception during Yosys command invoked from TCL\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
yosys_tcl_repl_active = in_repl;
|
|
||||||
log_cmd_error_throw = restore_log_cmd_error_throw;
|
|
||||||
|
|
||||||
auto &scratchpad = yosys_get_design()->scratchpad;
|
|
||||||
auto result = scratchpad.find("result.json");
|
|
||||||
if (result != scratchpad.end()) {
|
|
||||||
std::string err;
|
|
||||||
auto json = json11::Json::parse(result->second, err);
|
|
||||||
if (err.empty()) {
|
|
||||||
Tcl_SetObjResult(interp, json_to_tcl(interp, json));
|
|
||||||
} else
|
|
||||||
log_warning("Ignoring result.json scratchpad value due to parse error: %s\n", err.c_str());
|
|
||||||
} else if ((result = scratchpad.find("result.string")) != scratchpad.end()) {
|
|
||||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(result->second.data(), result->second.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return TCL_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int yosys_tcl_iterp_init(Tcl_Interp *interp)
|
|
||||||
{
|
|
||||||
if (Tcl_Init(interp)!=TCL_OK)
|
|
||||||
log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
|
|
||||||
Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL);
|
|
||||||
return TCL_OK ;
|
|
||||||
}
|
|
||||||
|
|
||||||
void yosys_tcl_activate_repl()
|
|
||||||
{
|
|
||||||
yosys_tcl_repl_active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern Tcl_Interp *yosys_get_tcl_interp()
|
extern Tcl_Interp *yosys_get_tcl_interp()
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,8 +32,6 @@
|
||||||
//
|
//
|
||||||
// This header is very boring. It just defines some general things that
|
// This header is very boring. It just defines some general things that
|
||||||
// belong nowhere else and includes the interesting headers.
|
// belong nowhere else and includes the interesting headers.
|
||||||
//
|
|
||||||
// Find more information in the "guidelines/GettingStarted" file.
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef YOSYS_H
|
#ifndef YOSYS_H
|
||||||
|
@ -45,6 +43,10 @@
|
||||||
#include "kernel/rtlil.h"
|
#include "kernel/rtlil.h"
|
||||||
#include "kernel/register.h"
|
#include "kernel/register.h"
|
||||||
|
|
||||||
|
#ifdef YOSYS_ENABLE_TCL
|
||||||
|
struct Tcl_Interp;
|
||||||
|
#endif
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void yosys_setup();
|
void yosys_setup();
|
||||||
|
|
|
@ -65,29 +65,6 @@
|
||||||
#define FRIEND_TEST(test_case_name, test_name) \
|
#define FRIEND_TEST(test_case_name, test_name) \
|
||||||
friend class test_case_name##_##test_name##_Test
|
friend class test_case_name##_##test_name##_Test
|
||||||
|
|
||||||
#ifdef YOSYS_ENABLE_TCL
|
|
||||||
# include <tcl.h>
|
|
||||||
# ifdef YOSYS_MXE_HACKS
|
|
||||||
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
|
|
||||||
extern Tcl_Interp *Tcl_CreateInterp(void);
|
|
||||||
extern void Tcl_Preserve(ClientData data);
|
|
||||||
extern void Tcl_Release(ClientData clientData);
|
|
||||||
extern int Tcl_InterpDeleted(Tcl_Interp *interp);
|
|
||||||
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
|
|
||||||
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
|
|
||||||
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
|
|
||||||
extern void Tcl_Finalize(void);
|
|
||||||
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
|
|
||||||
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
|
|
||||||
extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
|
|
||||||
extern Tcl_Obj *Tcl_NewIntObj(int intValue);
|
|
||||||
extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
|
|
||||||
extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
|
|
||||||
# endif
|
|
||||||
# undef CONST
|
|
||||||
# undef INLINE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# undef NOMINMAX
|
# undef NOMINMAX
|
||||||
# define NOMINMAX 1
|
# define NOMINMAX 1
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "ezminisat.h"
|
#include "ezminisat.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define INIT_X 123456789
|
#define INIT_X 123456789
|
||||||
#define INIT_Y 362436069
|
#define INIT_Y 362436069
|
||||||
|
@ -143,4 +144,3 @@ int main()
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "ezminisat.h"
|
#include "ezminisat.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define INIT_X 123456789
|
#define INIT_X 123456789
|
||||||
#define INIT_Y 362436069
|
#define INIT_Y 362436069
|
||||||
|
@ -109,4 +110,3 @@ int main()
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
* mmap compatibility
|
* mmap compatibility
|
||||||
*/
|
*/
|
||||||
-#if defined __MINGW32__
|
-#if defined __MINGW32__
|
||||||
+#if defined __CYGWIN__ || defined __MINGW32__ || defined _MSC_VER
|
+#if defined __MINGW32__ || defined _MSC_VER
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
|
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
|
||||||
#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr)
|
#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr)
|
||||||
|
|
|
@ -341,7 +341,7 @@ return(NULL);
|
||||||
/*
|
/*
|
||||||
* mmap compatibility
|
* mmap compatibility
|
||||||
*/
|
*/
|
||||||
#if defined __CYGWIN__ || defined __MINGW32__ || defined _MSC_VER
|
#if defined __MINGW32__ || defined _MSC_VER
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
|
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
|
||||||
#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr)
|
#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr)
|
||||||
|
|
|
@ -1273,6 +1273,11 @@ class WFunction:
|
||||||
func.duplicate = False
|
func.duplicate = False
|
||||||
func.namespace = namespace
|
func.namespace = namespace
|
||||||
str_def = str_def.replace("operator ","operator")
|
str_def = str_def.replace("operator ","operator")
|
||||||
|
|
||||||
|
# remove attributes from the start
|
||||||
|
if str.startswith(str_def, "[[") and "]]" in str_def:
|
||||||
|
str_def = str_def[str_def.find("]]")+2:]
|
||||||
|
|
||||||
if str.startswith(str_def, "static "):
|
if str.startswith(str_def, "static "):
|
||||||
func.is_static = True
|
func.is_static = True
|
||||||
str_def = str_def[7:]
|
str_def = str_def[7:]
|
||||||
|
@ -1574,10 +1579,15 @@ class WFunction:
|
||||||
return_stmt = "return " if self.ret_type.name != "void" else ""
|
return_stmt = "return " if self.ret_type.name != "void" else ""
|
||||||
|
|
||||||
text += ")\n\t\t{"
|
text += ")\n\t\t{"
|
||||||
text += "\n\t\t\tif (boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))"
|
text += "\n\t\t\tif (boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\")) {"
|
||||||
text += f"\n\t\t\t\t{return_stmt}" + call_string
|
text += "\n\t\t\t\ttry {"
|
||||||
text += "\n\t\t\telse"
|
text += f"\n\t\t\t\t\t{return_stmt}" + call_string
|
||||||
|
text += "\n\t\t\t\t} catch (boost::python::error_already_set &) {"
|
||||||
|
text += "\n\t\t\t\t\tlog_python_exception_as_error();"
|
||||||
|
text += "\n\t\t\t\t}"
|
||||||
|
text += "\n\t\t\t} else {"
|
||||||
text += f"\n\t\t\t\t{return_stmt}" + self.member_of.name + "::" + call_string
|
text += f"\n\t\t\t\t{return_stmt}" + self.member_of.name + "::" + call_string
|
||||||
|
text += "\n\t\t\t}"
|
||||||
text += "\n\t\t}"
|
text += "\n\t\t}"
|
||||||
|
|
||||||
text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "("
|
text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "("
|
||||||
|
@ -2330,6 +2340,11 @@ USING_YOSYS_NAMESPACE
|
||||||
|
|
||||||
namespace YOSYS_PYTHON {
|
namespace YOSYS_PYTHON {
|
||||||
|
|
||||||
|
[[noreturn]] static void log_python_exception_as_error() {
|
||||||
|
PyErr_Print();
|
||||||
|
log_error("Python interpreter encountered an exception.\\n");
|
||||||
|
}
|
||||||
|
|
||||||
struct YosysStatics{};
|
struct YosysStatics{};
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
|
@ -51,3 +51,5 @@ OBJS += passes/cmds/future.o
|
||||||
OBJS += passes/cmds/box_derive.o
|
OBJS += passes/cmds/box_derive.o
|
||||||
OBJS += passes/cmds/example_dt.o
|
OBJS += passes/cmds/example_dt.o
|
||||||
OBJS += passes/cmds/portarcs.o
|
OBJS += passes/cmds/portarcs.o
|
||||||
|
OBJS += passes/cmds/wrapcell.o
|
||||||
|
OBJS += passes/cmds/setenv.o
|
||||||
|
|
|
@ -192,16 +192,18 @@ struct PortarcsPass : Pass {
|
||||||
if (annotations.count(bit)) {
|
if (annotations.count(bit)) {
|
||||||
// consistency check
|
// consistency check
|
||||||
log_assert(annotations.at(bit)[0] == ((int) (intptr_t) bit.wire));
|
log_assert(annotations.at(bit)[0] == ((int) (intptr_t) bit.wire));
|
||||||
|
} else {
|
||||||
recycling.push_back(annotations.at(ordering[i]));
|
alloc_for_bit(bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recycling.push_back(annotations.at(ordering[i]));
|
||||||
}
|
}
|
||||||
log_debug("Allocated %lux%d\n", allocated.size(), inputs.size());
|
log_debug("Allocated %lux%d\n", allocated.size(), inputs.size());
|
||||||
|
|
||||||
for (auto bit : outputs) {
|
for (auto bit : outputs) {
|
||||||
int *p = annotations.at(canonical_bit(bit));
|
int *p = annotations.at(canonical_bit(bit));
|
||||||
for (int i = 0; i < inputs.size(); i++)
|
for (int i = 0; i < inputs.size(); i++)
|
||||||
p[i] = 0;
|
p[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ordering.size(); i++) {
|
for (int i = 0; i < ordering.size(); i++) {
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 N. Engelhardt <nak@yosyshq.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/register.h"
|
||||||
|
#include "kernel/rtlil.h"
|
||||||
|
#include "kernel/log.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
struct SetenvPass : public Pass {
|
||||||
|
SetenvPass() : Pass("setenv", "set an environment variable") { }
|
||||||
|
void help() override
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" setenv name value\n");
|
||||||
|
log("\n");
|
||||||
|
log("Set the given environment variable on the current process. Values containing\n");
|
||||||
|
log("whitespace must be passed in double quotes (\").\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, [[maybe_unused]] RTLIL::Design *design) override
|
||||||
|
{
|
||||||
|
if(args.size() != 3)
|
||||||
|
log_cmd_error("Wrong number of arguments given.\n");
|
||||||
|
|
||||||
|
std::string name = args[1];
|
||||||
|
std::string value = args[2];
|
||||||
|
if (value.front() == '\"' && value.back() == '\"') value = value.substr(1, value.size() - 2);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
_putenv_s(name.c_str(), value.c_str());
|
||||||
|
#else
|
||||||
|
if (setenv(name.c_str(), value.c_str(), 1))
|
||||||
|
log_cmd_error("Invalid name \"%s\".\n", name.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
} SetenvPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,302 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 Martin Povišer <povik@cutebit.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/celltypes.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "backends/rtlil/rtlil_backend.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
bool has_fmt_field(std::string fmt, std::string field_name)
|
||||||
|
{
|
||||||
|
auto it = fmt.begin();
|
||||||
|
while (it != fmt.end()) {
|
||||||
|
if (*it == '{') {
|
||||||
|
it++;
|
||||||
|
auto beg = it;
|
||||||
|
while (it != fmt.end() && *it != '}') it++;
|
||||||
|
if (it == fmt.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (std::string(beg, it) == field_name)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContextData {
|
||||||
|
std::string unused_outputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<std::string> format(std::string fmt, const dict<IdString, Const> ¶meters,
|
||||||
|
const ContextData &context)
|
||||||
|
{
|
||||||
|
std::stringstream result;
|
||||||
|
|
||||||
|
auto it = fmt.begin();
|
||||||
|
while (it != fmt.end()) {
|
||||||
|
if (*it == '{') {
|
||||||
|
it++;
|
||||||
|
auto beg = it;
|
||||||
|
while (it != fmt.end() && *it != '}') it++;
|
||||||
|
if (it == fmt.end()) {
|
||||||
|
log("Unclosed curly brackets in format string '%s'\n", fmt.c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string param_name = {beg, it};
|
||||||
|
|
||||||
|
if (param_name == "%unused") {
|
||||||
|
result << context.unused_outputs;
|
||||||
|
} else {
|
||||||
|
auto id = RTLIL::escape_id(std::string(beg, it));
|
||||||
|
if (!parameters.count(id)) {
|
||||||
|
log("Parameter %s referenced in format string '%s' not found\n", log_id(id), fmt.c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RTLIL_BACKEND::dump_const(result, parameters.at(id));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result << *it;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result.str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Chunk {
|
||||||
|
IdString port;
|
||||||
|
int base, len;
|
||||||
|
|
||||||
|
Chunk(IdString id, int base, int len)
|
||||||
|
: port(id), base(base), len(len) {}
|
||||||
|
|
||||||
|
IdString format(Cell *cell)
|
||||||
|
{
|
||||||
|
if (len == cell->getPort(port).size())
|
||||||
|
return port;
|
||||||
|
else if (len == 1)
|
||||||
|
return stringf("%s[%d]", port.c_str(), base);
|
||||||
|
else
|
||||||
|
return stringf("%s[%d:%d]", port.c_str(), base + len - 1, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec sample(Cell *cell)
|
||||||
|
{
|
||||||
|
return cell->getPort(port).extract(base, len);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Joins contiguous runs of bits into a 'Chunk'
|
||||||
|
std::vector<Chunk> collect_chunks(std::vector<std::pair<IdString, int>> bits)
|
||||||
|
{
|
||||||
|
std::vector<Chunk> ret;
|
||||||
|
std::sort(bits.begin(), bits.end());
|
||||||
|
for (auto it = bits.begin(); it != bits.end();) {
|
||||||
|
auto sep = it + 1;
|
||||||
|
for (; sep != bits.end() &&
|
||||||
|
sep->first == it->first &&
|
||||||
|
sep->second == (sep - 1)->second + 1; sep++);
|
||||||
|
ret.emplace_back(it->first, it->second, sep - it);
|
||||||
|
it = sep;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WrapcellPass : Pass {
|
||||||
|
WrapcellPass() : Pass("wrapcell", "wrap individual cells into new modules") {}
|
||||||
|
|
||||||
|
void help() override
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" wrapcell -name <format> [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This command wraps the selected cells individually into modules. The name for\n");
|
||||||
|
log("each wrapper module is derived from the template <format> by substituting\n");
|
||||||
|
log("parameter values as specified in curly brackets. If the named module already\n");
|
||||||
|
log("exists, it is reused.\n");
|
||||||
|
log("\n");
|
||||||
|
log("If the template contains the special string '{%%unused}', the command tracks\n");
|
||||||
|
log("unused output ports -- specialized wrapper modules will be generated per every\n");
|
||||||
|
log("distinct set of unused port bits as appearing on any selected cell.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -setattr <attribute-name>\n");
|
||||||
|
log(" set the given boolean attribute on each created wrapper module\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -formatattr <attribute-name> <format>\n");
|
||||||
|
log(" set a string attribute on the created wrapper module by substituting\n");
|
||||||
|
log(" parameter values into <format>\n");
|
||||||
|
log("\n");
|
||||||
|
log("Currently this command only supports wrapping internal cell types.\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(std::vector<std::string> args, Design *d) override
|
||||||
|
{
|
||||||
|
log_header(d, "Executing WRAPCELL pass. (wrap selected cells)\n");
|
||||||
|
|
||||||
|
struct AttrRule {
|
||||||
|
IdString name;
|
||||||
|
std::string value_fmt;
|
||||||
|
|
||||||
|
AttrRule(IdString name, std::string value_fmt)
|
||||||
|
: name(name), value_fmt(value_fmt) {}
|
||||||
|
};
|
||||||
|
std::vector<AttrRule> attributes;
|
||||||
|
std::string name_fmt;
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
if (args[argidx] == "-setattr" && argidx+1 < args.size()) {
|
||||||
|
attributes.emplace_back(RTLIL::escape_id(args[++argidx]), "");
|
||||||
|
} else if (args[argidx] == "-formatattr" && argidx+2 < args.size()) {
|
||||||
|
IdString id = RTLIL::escape_id(args[++argidx]);
|
||||||
|
attributes.emplace_back(id, args[++argidx]);
|
||||||
|
} else if (args[argidx] == "-name" && argidx+1 < args.size()) {
|
||||||
|
name_fmt = args[++argidx];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, d);
|
||||||
|
|
||||||
|
if (name_fmt.empty())
|
||||||
|
log_cmd_error("Argument -name required");
|
||||||
|
|
||||||
|
CellTypes ct;
|
||||||
|
ct.setup();
|
||||||
|
|
||||||
|
bool tracking_unused = has_fmt_field(name_fmt, "%unused");
|
||||||
|
|
||||||
|
for (auto module : d->selected_modules()) {
|
||||||
|
SigPool unused;
|
||||||
|
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->has_attribute(ID::unused_bits)) {
|
||||||
|
std::string str = wire->get_string_attribute(ID::unused_bits);
|
||||||
|
for (auto it = str.begin(); it != str.end();) {
|
||||||
|
auto sep = it;
|
||||||
|
for (; sep != str.end() && *sep != ' '; sep++);
|
||||||
|
unused.add(SigBit(wire, std::stoi(std::string(it, sep))));
|
||||||
|
for (it = sep; it != str.end() && *it == ' '; it++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : module->selected_cells()) {
|
||||||
|
Module *subm;
|
||||||
|
Cell *subcell;
|
||||||
|
|
||||||
|
if (!ct.cell_known(cell->type))
|
||||||
|
log_error("Non-internal cell type '%s' on cell '%s' in module '%s' unsupported\n",
|
||||||
|
log_id(cell->type), log_id(cell), log_id(module));
|
||||||
|
|
||||||
|
std::vector<std::pair<IdString, int>> unused_outputs, used_outputs;
|
||||||
|
for (auto conn : cell->connections()) {
|
||||||
|
if (ct.cell_output(cell->type, conn.first))
|
||||||
|
for (int i = 0; i < conn.second.size(); i++) {
|
||||||
|
if (tracking_unused && unused.check(conn.second[i]))
|
||||||
|
unused_outputs.emplace_back(conn.first, i);
|
||||||
|
else
|
||||||
|
used_outputs.emplace_back(conn.first, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextData context;
|
||||||
|
if (!unused_outputs.empty()) {
|
||||||
|
context.unused_outputs += "_unused";
|
||||||
|
for (auto chunk : collect_chunks(unused_outputs))
|
||||||
|
context.unused_outputs += "_" + RTLIL::unescape_id(chunk.format(cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> unescaped_name = format(name_fmt, cell->parameters, context);
|
||||||
|
if (!unescaped_name)
|
||||||
|
log_error("Formatting error when processing cell '%s' in module '%s'\n",
|
||||||
|
log_id(cell), log_id(module));
|
||||||
|
|
||||||
|
IdString name = RTLIL::escape_id(unescaped_name.value());
|
||||||
|
if (d->module(name))
|
||||||
|
goto replace_cell;
|
||||||
|
|
||||||
|
subm = d->addModule(name);
|
||||||
|
subcell = subm->addCell("$1", cell->type);
|
||||||
|
for (auto conn : cell->connections()) {
|
||||||
|
if (ct.cell_output(cell->type, conn.first)) {
|
||||||
|
// Insert marker bits as placehodlers which need to be replaced
|
||||||
|
subcell->setPort(conn.first, SigSpec(RTLIL::Sm, conn.second.size()));
|
||||||
|
} else {
|
||||||
|
Wire *w = subm->addWire(conn.first, conn.second.size());
|
||||||
|
w->port_input = true;
|
||||||
|
subcell->setPort(conn.first, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto chunk : collect_chunks(used_outputs)) {
|
||||||
|
Wire *w = subm->addWire(chunk.format(cell), chunk.len);
|
||||||
|
w->port_output = true;
|
||||||
|
subcell->connections_[chunk.port].replace(chunk.base, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto chunk : collect_chunks(unused_outputs)) {
|
||||||
|
Wire *w = subm->addWire(chunk.format(cell), chunk.len);
|
||||||
|
subcell->connections_[chunk.port].replace(chunk.base, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
subcell->parameters = cell->parameters;
|
||||||
|
subm->fixup_ports();
|
||||||
|
|
||||||
|
for (auto rule : attributes) {
|
||||||
|
if (rule.value_fmt.empty()) {
|
||||||
|
subm->set_bool_attribute(rule.name);
|
||||||
|
} else {
|
||||||
|
std::optional<std::string> value = format(rule.value_fmt, cell->parameters, context);
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
log_error("Formatting error when processing cell '%s' in module '%s'\n",
|
||||||
|
log_id(cell), log_id(module));
|
||||||
|
|
||||||
|
subm->set_string_attribute(rule.name, value.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
replace_cell:
|
||||||
|
cell->parameters.clear();
|
||||||
|
|
||||||
|
dict<IdString, SigSpec> new_connections;
|
||||||
|
|
||||||
|
for (auto conn : cell->connections())
|
||||||
|
if (!ct.cell_output(cell->type, conn.first))
|
||||||
|
new_connections[conn.first] = conn.second;
|
||||||
|
|
||||||
|
for (auto chunk : collect_chunks(used_outputs))
|
||||||
|
new_connections[chunk.format(cell)] = chunk.sample(cell);
|
||||||
|
|
||||||
|
cell->type = name;
|
||||||
|
cell->connections_ = new_connections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} WrapcellPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -54,7 +54,7 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
|
||||||
RTLIL::Const pattern = it.first;
|
RTLIL::Const pattern = it.first;
|
||||||
RTLIL::SigSpec eq_sig_a, eq_sig_b, or_sig;
|
RTLIL::SigSpec eq_sig_a, eq_sig_b, or_sig;
|
||||||
|
|
||||||
for (size_t j = 0; j < pattern.size(); j++)
|
for (auto j = 0; j < pattern.size(); j++)
|
||||||
if (pattern[j] == RTLIL::State::S0 || pattern[j] == RTLIL::State::S1) {
|
if (pattern[j] == RTLIL::State::S0 || pattern[j] == RTLIL::State::S1) {
|
||||||
eq_sig_a.append(ctrl_in.extract(j, 1));
|
eq_sig_a.append(ctrl_in.extract(j, 1));
|
||||||
eq_sig_b.append(RTLIL::SigSpec(pattern[j]));
|
eq_sig_b.append(RTLIL::SigSpec(pattern[j]));
|
||||||
|
@ -198,7 +198,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
|
||||||
RTLIL::Const state = fsm_data.state_table[i];
|
RTLIL::Const state = fsm_data.state_table[i];
|
||||||
RTLIL::SigSpec sig_a, sig_b;
|
RTLIL::SigSpec sig_a, sig_b;
|
||||||
|
|
||||||
for (size_t j = 0; j < state.size(); j++)
|
for (auto j = 0; j < state.size(); j++)
|
||||||
if (state[j] == RTLIL::State::S0 || state[j] == RTLIL::State::S1) {
|
if (state[j] == RTLIL::State::S0 || state[j] == RTLIL::State::S1) {
|
||||||
sig_a.append(RTLIL::SigSpec(state_wire, j));
|
sig_a.append(RTLIL::SigSpec(state_wire, j));
|
||||||
sig_b.append(RTLIL::SigSpec(state[j]));
|
sig_b.append(RTLIL::SigSpec(state[j]));
|
||||||
|
@ -261,7 +261,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
|
||||||
for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
|
for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
|
||||||
RTLIL::Const state = fsm_data.state_table[i];
|
RTLIL::Const state = fsm_data.state_table[i];
|
||||||
int bit_idx = -1;
|
int bit_idx = -1;
|
||||||
for (size_t j = 0; j < state.size(); j++)
|
for (auto j = 0; j < state.size(); j++)
|
||||||
if (state[j] == RTLIL::State::S1)
|
if (state[j] == RTLIL::State::S1)
|
||||||
bit_idx = j;
|
bit_idx = j;
|
||||||
if (bit_idx >= 0)
|
if (bit_idx >= 0)
|
||||||
|
|
|
@ -1003,8 +1003,10 @@ struct HierarchyPass : public Pass {
|
||||||
|
|
||||||
if (top_mod == nullptr)
|
if (top_mod == nullptr)
|
||||||
for (auto mod : design->modules())
|
for (auto mod : design->modules())
|
||||||
if (mod->get_bool_attribute(ID::top))
|
if (mod->get_bool_attribute(ID::top)) {
|
||||||
|
log("Attribute `top' found on module `%s'. Setting top module to %s.\n", log_id(mod), log_id(mod));
|
||||||
top_mod = mod;
|
top_mod = mod;
|
||||||
|
}
|
||||||
|
|
||||||
if (top_mod == nullptr)
|
if (top_mod == nullptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,20 +23,80 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct ThresholdHierarchyKeeping {
|
||||||
|
Design *design;
|
||||||
|
CellCosts costs;
|
||||||
|
dict<Module *, int> done;
|
||||||
|
pool<Module *> in_progress;
|
||||||
|
uint64_t threshold;
|
||||||
|
|
||||||
|
ThresholdHierarchyKeeping(Design *design, uint64_t threshold)
|
||||||
|
: design(design), costs(design), threshold(threshold) {}
|
||||||
|
|
||||||
|
uint64_t visit(RTLIL::Module *module) {
|
||||||
|
if (module->has_attribute(ID(gate_cost_equivalent)))
|
||||||
|
return module->attributes[ID(gate_cost_equivalent)].as_int();
|
||||||
|
|
||||||
|
if (module->has_attribute(ID(keep_hierarchy)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (module->get_blackbox_attribute())
|
||||||
|
log_error("Missing cost information on instanced blackbox %s\n", log_id(module));
|
||||||
|
|
||||||
|
if (done.count(module))
|
||||||
|
return done.at(module);
|
||||||
|
|
||||||
|
if (in_progress.count(module))
|
||||||
|
log_error("Circular hierarchy\n");
|
||||||
|
in_progress.insert(module);
|
||||||
|
|
||||||
|
uint64_t size = 0;
|
||||||
|
module->has_processes_warn();
|
||||||
|
|
||||||
|
for (auto cell : module->cells()) {
|
||||||
|
if (!cell->type.isPublic()) {
|
||||||
|
size += costs.get(cell);
|
||||||
|
} else {
|
||||||
|
RTLIL::Module *submodule = design->module(cell->type);
|
||||||
|
if (!submodule)
|
||||||
|
log_error("Hierarchy contains unknown module '%s' (instanced as %s in %s)\n",
|
||||||
|
log_id(cell->type), log_id(cell), log_id(module));
|
||||||
|
size += visit(submodule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > threshold) {
|
||||||
|
log("Keeping %s (estimated size above threshold: %llu > %llu).\n", log_id(module), size, threshold);
|
||||||
|
module->set_bool_attribute(ID::keep_hierarchy);
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_progress.erase(module);
|
||||||
|
done[module] = size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct KeepHierarchyPass : public Pass {
|
struct KeepHierarchyPass : public Pass {
|
||||||
KeepHierarchyPass() : Pass("keep_hierarchy", "add the keep_hierarchy attribute") {}
|
KeepHierarchyPass() : Pass("keep_hierarchy", "selectively add the keep_hierarchy attribute") {}
|
||||||
void help() override
|
void help() override
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" keep_hierarchy [options]\n");
|
log(" keep_hierarchy [options] [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Add the keep_hierarchy attribute.\n");
|
log("Add the keep_hierarchy attribute.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -min_cost <min_cost>\n");
|
log(" -min_cost <min_cost>\n");
|
||||||
log(" only add the attribute to modules estimated to have more\n");
|
log(" only add the attribute to modules estimated to have more than <min_cost>\n");
|
||||||
log(" than <min_cost> gates after simple techmapping. Intended\n");
|
log(" gates after simple techmapping. Intended for tuning trade-offs between\n");
|
||||||
log(" for tuning trade-offs between quality and yosys runtime.\n");
|
log(" quality and yosys runtime.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" When evaluating a module's cost, gates which are within a submodule\n");
|
||||||
|
log(" which is marked with the keep_hierarchy attribute are not counted\n");
|
||||||
|
log(" towards the upper module's cost. This applies to both when the attribute\n");
|
||||||
|
log(" was added by this command or was pre-existing.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
{
|
{
|
||||||
|
@ -54,16 +114,15 @@ struct KeepHierarchyPass : public Pass {
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
CellCosts costs(design);
|
if (min_cost) {
|
||||||
|
RTLIL::Module *top = design->top_module();
|
||||||
|
if (!top)
|
||||||
|
log_cmd_error("'-min_cost' mode requires a single top module in the design\n");
|
||||||
|
|
||||||
for (auto module : design->selected_modules()) {
|
ThresholdHierarchyKeeping worker(design, min_cost);
|
||||||
if (min_cost) {
|
worker.visit(top);
|
||||||
unsigned int cost = costs.get(module);
|
} else {
|
||||||
if (cost > min_cost) {
|
for (auto module : design->selected_modules()) {
|
||||||
log("Marking %s (module too big: %d > %d).\n", log_id(module), cost, min_cost);
|
|
||||||
module->set_bool_attribute(ID::keep_hierarchy);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log("Marking %s.\n", log_id(module));
|
log("Marking %s.\n", log_id(module));
|
||||||
module->set_bool_attribute(ID::keep_hierarchy);
|
module->set_bool_attribute(ID::keep_hierarchy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,10 @@ void demorgan_worker(
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto insig = sigmap(cell->getPort(ID::A));
|
auto insig = sigmap(cell->getPort(ID::A));
|
||||||
|
|
||||||
|
if (GetSize(insig) < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig));
|
log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig));
|
||||||
int num_inverted = 0;
|
int num_inverted = 0;
|
||||||
for(int i=0; i<GetSize(insig); i++)
|
for(int i=0; i<GetSize(insig); i++)
|
||||||
|
|
|
@ -89,6 +89,9 @@ struct OptReduceWorker
|
||||||
RTLIL::SigSpec new_sig_a(new_sig_a_bits);
|
RTLIL::SigSpec new_sig_a(new_sig_a_bits);
|
||||||
new_sig_a.sort_and_unify();
|
new_sig_a.sort_and_unify();
|
||||||
|
|
||||||
|
if (GetSize(new_sig_a) == 0)
|
||||||
|
new_sig_a = (cell->type == ID($reduce_or)) ? State::S0 : State::S1;
|
||||||
|
|
||||||
if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) {
|
if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) {
|
||||||
log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
|
log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
|
||||||
did_something = true;
|
did_something = true;
|
||||||
|
|
|
@ -53,6 +53,11 @@ match add
|
||||||
select port(add, constport).is_fully_const()
|
select port(add, constport).is_fully_const()
|
||||||
define <IdString> varport (constport == \A ? \B : \A)
|
define <IdString> varport (constport == \A ? \B : \A)
|
||||||
|
|
||||||
|
// only optimize for constants up to a fixed width. this prevents cases
|
||||||
|
// with a blowup in internal term size and prevents larger constants being
|
||||||
|
// casted to int incorrectly
|
||||||
|
select (GetSize(port(add, constport)) <= 24)
|
||||||
|
|
||||||
// if a value of var is able to wrap the output, the transformation might give wrong results
|
// if a value of var is able to wrap the output, the transformation might give wrong results
|
||||||
// an addition/substraction can at most flip one more bit than the largest operand (the carry bit)
|
// an addition/substraction can at most flip one more bit than the largest operand (the carry bit)
|
||||||
// as long as the output can show this bit, no wrap should occur (assuming all signed-ness make sense)
|
// as long as the output can show this bit, no wrap should occur (assuming all signed-ness make sense)
|
||||||
|
|
|
@ -262,7 +262,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
|
||||||
{
|
{
|
||||||
log_warning("Complex async reset for dff `%s'.\n", log_signal(sig));
|
log_warning("Complex async reset for dff `%s'.\n", log_signal(sig));
|
||||||
gen_dffsr_complex(mod, insig, sig, sync_edge->signal, sync_edge->type == RTLIL::SyncType::STp, async_rules, proc);
|
gen_dffsr_complex(mod, insig, sig, sync_edge->signal, sync_edge->type == RTLIL::SyncType::STp, async_rules, proc);
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a reset condition in the async rules, use it
|
// If there is a reset condition in the async rules, use it
|
||||||
|
@ -277,7 +277,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
|
||||||
sync_edge->type == RTLIL::SyncType::STp,
|
sync_edge->type == RTLIL::SyncType::STp,
|
||||||
sync_level && sync_level->type == RTLIL::SyncType::ST1,
|
sync_level && sync_level->type == RTLIL::SyncType::ST1,
|
||||||
sync_edge->signal, sync_level->signal, proc);
|
sync_edge->signal, sync_level->signal, proc);
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_dff(mod, insig, rstval.as_const(), sig_q,
|
gen_dff(mod, insig, rstval.as_const(), sig_q,
|
||||||
|
|
|
@ -969,13 +969,10 @@ void prep_box(RTLIL::Design *design)
|
||||||
if (it == module->attributes.end())
|
if (it == module->attributes.end())
|
||||||
continue;
|
continue;
|
||||||
bool box = it->second.as_bool();
|
bool box = it->second.as_bool();
|
||||||
module->attributes.erase(it);
|
|
||||||
if (!box)
|
if (!box)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto r = module->attributes.insert(ID::abc9_box_id);
|
auto r = module->attributes.insert(ID::abc9_box_id);
|
||||||
if (!r.second)
|
|
||||||
continue;
|
|
||||||
r.first->second = abc9_box_id++;
|
r.first->second = abc9_box_id++;
|
||||||
|
|
||||||
if (module->get_bool_attribute(ID::abc9_flop)) {
|
if (module->get_bool_attribute(ID::abc9_flop)) {
|
||||||
|
@ -1078,7 +1075,8 @@ void prep_box(RTLIL::Design *design)
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
|
ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
|
||||||
ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
|
bool has_model = module->get_bool_attribute(ID::whitebox) || !module->get_bool_attribute(ID::blackbox);
|
||||||
|
ss << " " << (has_model ? "1" : "0");
|
||||||
ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
|
ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -1096,8 +1094,9 @@ void prep_box(RTLIL::Design *design)
|
||||||
ss << std::endl;
|
ss << std::endl;
|
||||||
|
|
||||||
auto &t = timing.setup_module(module);
|
auto &t = timing.setup_module(module);
|
||||||
if (t.comb.empty())
|
if (t.comb.empty() && !outputs.empty() && !inputs.empty()) {
|
||||||
log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module));
|
log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module));
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &o : outputs) {
|
for (const auto &o : outputs) {
|
||||||
first = true;
|
first = true;
|
||||||
|
|
|
@ -19,10 +19,29 @@
|
||||||
|
|
||||||
#include "kernel/register.h"
|
#include "kernel/register.h"
|
||||||
#include "kernel/rtlil.h"
|
#include "kernel/rtlil.h"
|
||||||
|
#include "kernel/utils.h"
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
std::vector<Module*> order_modules(Design *design, std::vector<Module *> modules)
|
||||||
|
{
|
||||||
|
std::set<Module *> modules_set(modules.begin(), modules.end());
|
||||||
|
TopoSort<Module*> sort;
|
||||||
|
|
||||||
|
for (auto m : modules) {
|
||||||
|
sort.node(m);
|
||||||
|
|
||||||
|
for (auto cell : m->cells()) {
|
||||||
|
Module *submodule = design->module(cell->type);
|
||||||
|
if (modules_set.count(submodule))
|
||||||
|
sort.edge(submodule, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_assert(sort.sort());
|
||||||
|
return sort.sorted;
|
||||||
|
}
|
||||||
|
|
||||||
struct AbcNewPass : public ScriptPass {
|
struct AbcNewPass : public ScriptPass {
|
||||||
AbcNewPass() : ScriptPass("abc_new", "(experimental) use ABC for SC technology mapping (new)")
|
AbcNewPass() : ScriptPass("abc_new", "(experimental) use ABC for SC technology mapping (new)")
|
||||||
{
|
{
|
||||||
|
@ -101,6 +120,15 @@ struct AbcNewPass : public ScriptPass {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("prep_boxes")) {
|
if (check_label("prep_boxes")) {
|
||||||
|
if (!help_mode) {
|
||||||
|
for (auto mod : active_design->selected_whole_modules_warn()) {
|
||||||
|
if (mod->get_bool_attribute(ID::abc9_box)) {
|
||||||
|
mod->set_bool_attribute(ID::abc9_box, false);
|
||||||
|
mod->set_bool_attribute(ID(abc9_deferred_box), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
run("box_derive");
|
run("box_derive");
|
||||||
run("abc9_ops -prep_box");
|
run("abc9_ops -prep_box");
|
||||||
}
|
}
|
||||||
|
@ -109,7 +137,8 @@ struct AbcNewPass : public ScriptPass {
|
||||||
std::vector<Module *> selected_modules;
|
std::vector<Module *> selected_modules;
|
||||||
|
|
||||||
if (!help_mode) {
|
if (!help_mode) {
|
||||||
selected_modules = active_design->selected_whole_modules_warn();
|
selected_modules = order_modules(active_design,
|
||||||
|
active_design->selected_whole_modules_warn());
|
||||||
active_design->selection_stack.emplace_back(false);
|
active_design->selection_stack.emplace_back(false);
|
||||||
} else {
|
} else {
|
||||||
selected_modules = {nullptr};
|
selected_modules = {nullptr};
|
||||||
|
@ -131,15 +160,36 @@ struct AbcNewPass : public ScriptPass {
|
||||||
active_design->selection().select(mod);
|
active_design->selection().select(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string script_save;
|
||||||
|
if (!help_mode && mod->has_attribute(ID(abc9_script))) {
|
||||||
|
script_save = active_design->scratchpad_get_string("abc9.script");
|
||||||
|
active_design->scratchpad_set_string("abc9.script",
|
||||||
|
mod->get_string_attribute(ID(abc9_script)));
|
||||||
|
}
|
||||||
|
|
||||||
run(stringf(" abc9_ops -write_box %s/input.box", tmpdir.c_str()));
|
run(stringf(" abc9_ops -write_box %s/input.box", tmpdir.c_str()));
|
||||||
run(stringf(" write_xaiger2 -mapping_prep -map2 %s/input.map2 %s/input.xaig", tmpdir.c_str(), tmpdir.c_str()));
|
run(stringf(" write_xaiger2 -mapping_prep -map2 %s/input.map2 %s/input.xaig", tmpdir.c_str(), tmpdir.c_str()));
|
||||||
run(stringf(" abc9_exe %s -cwd %s -box %s/input.box", exe_options.c_str(), tmpdir.c_str(), tmpdir.c_str()));
|
run(stringf(" abc9_exe %s -cwd %s -box %s/input.box", exe_options.c_str(), tmpdir.c_str(), tmpdir.c_str()));
|
||||||
run(stringf(" read_xaiger2 -sc_mapping -module_name %s -map2 %s/input.map2 %s/output.aig",
|
run(stringf(" read_xaiger2 -sc_mapping -module_name %s -map2 %s/input.map2 %s/output.aig",
|
||||||
modname.c_str(), tmpdir.c_str(), tmpdir.c_str()));
|
modname.c_str(), tmpdir.c_str(), tmpdir.c_str()));
|
||||||
|
|
||||||
|
if (!help_mode && mod->has_attribute(ID(abc9_script))) {
|
||||||
|
if (script_save.empty())
|
||||||
|
active_design->scratchpad_unset("abc9.script");
|
||||||
|
else
|
||||||
|
active_design->scratchpad_set_string("abc9.script", script_save);
|
||||||
|
}
|
||||||
|
|
||||||
if (!help_mode) {
|
if (!help_mode) {
|
||||||
active_design->selection().selected_modules.clear();
|
active_design->selection().selected_modules.clear();
|
||||||
log_pop();
|
log_pop();
|
||||||
|
|
||||||
|
if (mod->get_bool_attribute(ID(abc9_deferred_box))) {
|
||||||
|
mod->set_bool_attribute(ID(abc9_deferred_box), false);
|
||||||
|
mod->set_bool_attribute(ID::abc9_box, true);
|
||||||
|
Pass::call_on_module(active_design, mod, "portarcs -draw -write");
|
||||||
|
run("abc9_ops -prep_box");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ synth -top my_design -booth
|
||||||
|
|
||||||
#include "kernel/sigtools.h"
|
#include "kernel/sigtools.h"
|
||||||
#include "kernel/yosys.h"
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/macc.h"
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
@ -207,12 +208,33 @@ struct BoothPassWorker {
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
for (auto cell : module->selected_cells()) {
|
for (auto cell : module->selected_cells()) {
|
||||||
if (cell->type != ID($mul))
|
SigSpec A, B, Y;
|
||||||
continue;
|
bool is_signed;
|
||||||
|
|
||||||
|
if (cell->type == ID($mul)) {
|
||||||
|
A = cell->getPort(ID::A);
|
||||||
|
B = cell->getPort(ID::B);
|
||||||
|
Y = cell->getPort(ID::Y);
|
||||||
|
|
||||||
|
log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool());
|
||||||
|
is_signed = cell->getParam(ID::A_SIGNED).as_bool();
|
||||||
|
} else if (cell->type == ID($macc)) {
|
||||||
|
Macc macc;
|
||||||
|
macc.from_cell(cell);
|
||||||
|
|
||||||
|
if (!macc.is_simple_product()) {
|
||||||
|
log_debug("Not mapping cell %s: not a simple macc cell\n", log_id(cell));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
A = macc.ports[0].in_a;
|
||||||
|
B = macc.ports[0].in_b;
|
||||||
|
is_signed = macc.ports[0].is_signed;
|
||||||
|
Y = cell->getPort(ID::Y);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SigSpec A = cell->getPort(ID::A);
|
|
||||||
SigSpec B = cell->getPort(ID::B);
|
|
||||||
SigSpec Y = cell->getPort(ID::Y);
|
|
||||||
int x_sz = GetSize(A), y_sz = GetSize(B), z_sz = GetSize(Y);
|
int x_sz = GetSize(A), y_sz = GetSize(B), z_sz = GetSize(Y);
|
||||||
|
|
||||||
if (x_sz < 4 || y_sz < 4 || z_sz < 8) {
|
if (x_sz < 4 || y_sz < 4 || z_sz < 8) {
|
||||||
|
@ -221,9 +243,6 @@ struct BoothPassWorker {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool());
|
|
||||||
bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
|
|
||||||
|
|
||||||
log("Mapping cell %s to %s Booth multiplier\n", log_id(cell), is_signed ? "signed" : "unsigned");
|
log("Mapping cell %s to %s Booth multiplier\n", log_id(cell), is_signed ? "signed" : "unsigned");
|
||||||
|
|
||||||
// To simplify the generator size the arguments
|
// To simplify the generator size the arguments
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "kernel/yosys.h"
|
#include "kernel/yosys.h"
|
||||||
#include "kernel/ff.h"
|
#include "kernel/ff.h"
|
||||||
|
#include "libparse.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
|
@ -10,6 +11,7 @@ struct ClockGateCell {
|
||||||
IdString ce_pin;
|
IdString ce_pin;
|
||||||
IdString clk_in_pin;
|
IdString clk_in_pin;
|
||||||
IdString clk_out_pin;
|
IdString clk_out_pin;
|
||||||
|
std::vector<IdString> tie_lo_pins;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
||||||
|
@ -37,6 +39,152 @@ ClockGateCell icg_from_arg(std::string& name, std::string& str) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::pair<std::optional<ClockGateCell>, std::optional<ClockGateCell>>
|
||||||
|
find_icgs(std::vector<const LibertyAst *> cells, std::vector<std::string> const& dont_use_cells) {
|
||||||
|
// We will pick the most suitable ICG absed on tie_lo count and area
|
||||||
|
struct ICGRankable : public ClockGateCell { double area; };
|
||||||
|
std::optional<ICGRankable> best_pos;
|
||||||
|
std::optional<ICGRankable> best_neg;
|
||||||
|
|
||||||
|
// This is a lot of boilerplate, isn't it?
|
||||||
|
for (auto cell : cells)
|
||||||
|
{
|
||||||
|
const LibertyAst *dn = cell->find("dont_use");
|
||||||
|
if (dn != nullptr && dn->value == "true")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool dont_use = false;
|
||||||
|
for (auto dont_use_cell : dont_use_cells)
|
||||||
|
{
|
||||||
|
if (patmatch(dont_use_cell.c_str(), cell->args[0].c_str()))
|
||||||
|
{
|
||||||
|
dont_use = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dont_use)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const LibertyAst *icg_kind_ast = cell->find("clock_gating_integrated_cell");
|
||||||
|
if (icg_kind_ast == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto cell_name = cell->args[0];
|
||||||
|
auto icg_kind = icg_kind_ast->value;
|
||||||
|
auto starts_with = [&](std::string prefix) {
|
||||||
|
return icg_kind.compare(0, prefix.size(), prefix) == 0;
|
||||||
|
};
|
||||||
|
bool clk_pol;
|
||||||
|
if (icg_kind == "latch_posedge" || starts_with("latch_posedge_")) {
|
||||||
|
clk_pol = true;
|
||||||
|
} else if (icg_kind == "latch_negedge" || starts_with("latch_negedge_")) {
|
||||||
|
clk_pol = false;
|
||||||
|
} else {
|
||||||
|
log("Ignoring ICG primitive %s of kind '%s'\n", cell_name.c_str(), icg_kind.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("maybe valid icg: %s\n", cell_name.c_str());
|
||||||
|
ClockGateCell icg_interface;
|
||||||
|
icg_interface.name = RTLIL::escape_id(cell_name);
|
||||||
|
|
||||||
|
for (auto pin : cell->children) {
|
||||||
|
if (pin->id != "pin" || pin->args.size() != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pin->find("clock_gate_clock_pin")) {
|
||||||
|
if (!icg_interface.clk_in_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - multiple clock_gate_clock_pin in cell %s\n",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
icg_interface.clk_in_pin = RTLIL::escape_id(pin->args[0]);
|
||||||
|
} else if (pin->find("clock_gate_out_pin")) {
|
||||||
|
if (!icg_interface.clk_out_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - multiple clock_gate_out_pin in cell %s\n",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
icg_interface.clk_out_pin = RTLIL::escape_id(pin->args[0]);
|
||||||
|
} else if (pin->find("clock_gate_enable_pin")) {
|
||||||
|
if (!icg_interface.ce_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - multiple clock_gate_enable_pin in cell %s\n",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
icg_interface.ce_pin = RTLIL::escape_id(pin->args[0]);
|
||||||
|
} else if (pin->find("clock_gate_test_pin")) {
|
||||||
|
icg_interface.tie_lo_pins.push_back(RTLIL::escape_id(pin->args[0]));
|
||||||
|
} else {
|
||||||
|
const LibertyAst *dir = pin->find("direction");
|
||||||
|
if (dir->value == "internal")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log_warning("Malformed liberty file - extra pin %s in cell %s\n",
|
||||||
|
pin->args[0].c_str(), cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icg_interface.clk_in_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - missing clock_gate_clock_pin in cell %s",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (icg_interface.clk_out_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - missing clock_gate_out_pin in cell %s",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (icg_interface.ce_pin.empty()) {
|
||||||
|
log_warning("Malformed liberty file - missing clock_gate_enable_pin in cell %s",
|
||||||
|
cell_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double area = 0;
|
||||||
|
const LibertyAst *ar = cell->find("area");
|
||||||
|
if (ar != nullptr && !ar->value.empty())
|
||||||
|
area = atof(ar->value.c_str());
|
||||||
|
|
||||||
|
std::optional<ICGRankable>& icg_to_beat = clk_pol ? best_pos : best_neg;
|
||||||
|
|
||||||
|
bool winning = false;
|
||||||
|
if (icg_to_beat) {
|
||||||
|
log_debug("ties: %zu ? %zu\n", icg_to_beat->tie_lo_pins.size(),
|
||||||
|
icg_interface.tie_lo_pins.size());
|
||||||
|
log_debug("area: %f ? %f\n", icg_to_beat->area, area);
|
||||||
|
|
||||||
|
// Prefer fewer test enables over area reduction (unlikely to matter)
|
||||||
|
auto goal = std::make_pair(icg_to_beat->tie_lo_pins.size(), icg_to_beat->area);
|
||||||
|
auto cost = std::make_pair(icg_interface.tie_lo_pins.size(), area);
|
||||||
|
winning = cost < goal;
|
||||||
|
|
||||||
|
if (winning)
|
||||||
|
log_debug("%s beats %s\n", icg_interface.name.c_str(), icg_to_beat->name.c_str());
|
||||||
|
} else {
|
||||||
|
log_debug("%s is the first of its polarity\n", icg_interface.name.c_str());
|
||||||
|
winning = true;
|
||||||
|
}
|
||||||
|
if (winning) {
|
||||||
|
ICGRankable new_icg {icg_interface, area};
|
||||||
|
icg_to_beat.emplace(new_icg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ClockGateCell> pos;
|
||||||
|
std::optional<ClockGateCell> neg;
|
||||||
|
if (best_pos) {
|
||||||
|
log("Selected rising edge ICG %s from Liberty file\n", best_pos->name.c_str());
|
||||||
|
pos.emplace(*best_pos);
|
||||||
|
}
|
||||||
|
if (best_neg) {
|
||||||
|
log("Selected falling edge ICG %s from Liberty file\n", best_neg->name.c_str());
|
||||||
|
neg.emplace(*best_neg);
|
||||||
|
}
|
||||||
|
return std::make_pair(pos, neg);
|
||||||
|
}
|
||||||
|
|
||||||
struct ClockgatePass : public Pass {
|
struct ClockgatePass : public Pass {
|
||||||
ClockgatePass() : Pass("clockgate", "extract clock gating out of flip flops") { }
|
ClockgatePass() : Pass("clockgate", "extract clock gating out of flip flops") { }
|
||||||
void help() override {
|
void help() override {
|
||||||
|
@ -60,12 +208,20 @@ struct ClockgatePass : public Pass {
|
||||||
log(" user-specified <celltype> ICG (integrated clock gating)\n");
|
log(" user-specified <celltype> ICG (integrated clock gating)\n");
|
||||||
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
|
log(" cell with ports named <ce>, <clk>, <gclk>.\n");
|
||||||
log(" The ICG's clock enable pin must be active high.\n");
|
log(" The ICG's clock enable pin must be active high.\n");
|
||||||
|
log(" -liberty <filename>\n");
|
||||||
|
log(" If specified, ICGs will be selected from the liberty files\n");
|
||||||
|
log(" if available. Priority is given to cells with fewer tie_lo\n");
|
||||||
|
log(" inputs and smaller size. This removes the need to manually\n");
|
||||||
|
log(" specify -pos or -neg and -tie_lo.\n");
|
||||||
|
log(" -dont_use <celltype>\n");
|
||||||
|
log(" Cells <celltype> won't be considered when searching for ICGs\n");
|
||||||
|
log(" in the liberty file specified by -liberty.\n");
|
||||||
log(" -tie_lo <port_name>\n");
|
log(" -tie_lo <port_name>\n");
|
||||||
log(" Port <port_name> of the ICG will be tied to zero.\n");
|
log(" Port <port_name> of the ICG will be tied to zero.\n");
|
||||||
log(" Intended for DFT scan-enable pins.\n");
|
log(" Intended for DFT scan-enable pins.\n");
|
||||||
log(" -min_net_size <n>\n");
|
log(" -min_net_size <n>\n");
|
||||||
log(" Only transform sets of at least <n> eligible FFs.\n");
|
log(" Only transform sets of at least <n> eligible FFs.\n");
|
||||||
// log(" \n");
|
log(" \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// One ICG will be generated per ClkNetInfo
|
// One ICG will be generated per ClkNetInfo
|
||||||
|
@ -110,7 +266,9 @@ struct ClockgatePass : public Pass {
|
||||||
|
|
||||||
std::optional<ClockGateCell> pos_icg_desc;
|
std::optional<ClockGateCell> pos_icg_desc;
|
||||||
std::optional<ClockGateCell> neg_icg_desc;
|
std::optional<ClockGateCell> neg_icg_desc;
|
||||||
std::vector<std::string> tie_lo_ports;
|
std::vector<std::string> tie_lo_pins;
|
||||||
|
std::vector<std::string> liberty_files;
|
||||||
|
std::vector<std::string> dont_use_cells;
|
||||||
int min_net_size = 0;
|
int min_net_size = 0;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
|
@ -119,17 +277,54 @@ struct ClockgatePass : public Pass {
|
||||||
auto name = args[++argidx];
|
auto name = args[++argidx];
|
||||||
auto rest = args[++argidx];
|
auto rest = args[++argidx];
|
||||||
pos_icg_desc = icg_from_arg(name, rest);
|
pos_icg_desc = icg_from_arg(name, rest);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-neg" && argidx+2 < args.size()) {
|
if (args[argidx] == "-neg" && argidx+2 < args.size()) {
|
||||||
auto name = args[++argidx];
|
auto name = args[++argidx];
|
||||||
auto rest = args[++argidx];
|
auto rest = args[++argidx];
|
||||||
neg_icg_desc = icg_from_arg(name, rest);
|
neg_icg_desc = icg_from_arg(name, rest);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) {
|
if (args[argidx] == "-tie_lo" && argidx+1 < args.size()) {
|
||||||
tie_lo_ports.push_back(RTLIL::escape_id(args[++argidx]));
|
tie_lo_pins.push_back(RTLIL::escape_id(args[++argidx]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
|
||||||
|
std::string liberty_file = args[++argidx];
|
||||||
|
rewrite_filename(liberty_file);
|
||||||
|
liberty_files.push_back(liberty_file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-dont_use" && argidx+1 < args.size()) {
|
||||||
|
dont_use_cells.push_back(args[++argidx]);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-min_net_size" && argidx+1 < args.size()) {
|
if (args[argidx] == "-min_net_size" && argidx+1 < args.size()) {
|
||||||
min_net_size = atoi(args[++argidx].c_str());
|
min_net_size = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!liberty_files.empty()) {
|
||||||
|
LibertyMergedCells merged;
|
||||||
|
for (auto path : liberty_files) {
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(path.c_str());
|
||||||
|
if (f.fail())
|
||||||
|
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
|
||||||
|
LibertyParser p(f);
|
||||||
|
merged.merge(p);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
std::tie(pos_icg_desc, neg_icg_desc) =
|
||||||
|
find_icgs(merged.cells, dont_use_cells);
|
||||||
|
} else {
|
||||||
|
for (auto pin : tie_lo_pins) {
|
||||||
|
if (pos_icg_desc)
|
||||||
|
pos_icg_desc->tie_lo_pins.push_back(pin);
|
||||||
|
if (neg_icg_desc)
|
||||||
|
neg_icg_desc->tie_lo_pins.push_back(pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +380,7 @@ struct ClockgatePass : public Pass {
|
||||||
gclk.new_net = module->addWire(NEW_ID);
|
gclk.new_net = module->addWire(NEW_ID);
|
||||||
icg->setPort(matching_icg_desc->clk_out_pin, gclk.new_net);
|
icg->setPort(matching_icg_desc->clk_out_pin, gclk.new_net);
|
||||||
// Tie low DFT ports like scan chain enable
|
// Tie low DFT ports like scan chain enable
|
||||||
for (auto port : tie_lo_ports)
|
for (auto port : matching_icg_desc->tie_lo_pins)
|
||||||
icg->setPort(port, Const(0, 1));
|
icg->setPort(port, Const(0, 1));
|
||||||
// Fix CE polarity if needed
|
// Fix CE polarity if needed
|
||||||
if (!clk.pol_ce) {
|
if (!clk.pol_ce) {
|
||||||
|
|
|
@ -116,7 +116,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std
|
||||||
|
|
||||||
if (tree.kind == LibertyExpression::Kind::EMPTY) {
|
if (tree.kind == LibertyExpression::Kind::EMPTY) {
|
||||||
if (!warned_cells.count(cell_name)) {
|
if (!warned_cells.count(cell_name)) {
|
||||||
log_warning("Invalid expression '%s' in next_state attribute of cell '%s' - skipping.\n", expr.c_str(), cell_name.c_str());
|
log_debug("Invalid expression '%s' in next_state attribute of cell '%s' - skipping.\n", expr.c_str(), cell_name.c_str());
|
||||||
warned_cells.insert(cell_name);
|
warned_cells.insert(cell_name);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -135,7 +135,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std
|
||||||
// position that gives better diagnostics here.
|
// position that gives better diagnostics here.
|
||||||
if (!pin_names.count(ff_output)) {
|
if (!pin_names.count(ff_output)) {
|
||||||
if (!warned_cells.count(cell_name)) {
|
if (!warned_cells.count(cell_name)) {
|
||||||
log_warning("Inference failed on expression '%s' in next_state attribute of cell '%s' because it does not contain ff output '%s' - skipping.\n", expr.c_str(), cell_name.c_str(), ff_output.c_str());
|
log_debug("Inference failed on expression '%s' in next_state attribute of cell '%s' because it does not contain ff output '%s' - skipping.\n", expr.c_str(), cell_name.c_str(), ff_output.c_str());
|
||||||
warned_cells.insert(cell_name);
|
warned_cells.insert(cell_name);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -184,7 +184,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!warned_cells.count(cell_name)) {
|
if (!warned_cells.count(cell_name)) {
|
||||||
log_warning("Inference failed on expression '%s' in next_state attribute of cell '%s' because it does not evaluate to an enable flop - skipping.\n", expr.c_str(), cell_name.c_str());
|
log_debug("Inference failed on expression '%s' in next_state attribute of cell '%s' because it does not evaluate to an enable flop - skipping.\n", expr.c_str(), cell_name.c_str());
|
||||||
warned_cells.insert(cell_name);
|
warned_cells.insert(cell_name);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -220,16 +220,16 @@ static bool parse_pin(const LibertyAst *cell, const LibertyAst *attr, std::strin
|
||||||
For now, we'll simply produce a warning to let the user know something is up.
|
For now, we'll simply produce a warning to let the user know something is up.
|
||||||
*/
|
*/
|
||||||
if (pin_name.find_first_of("^*|&") == std::string::npos) {
|
if (pin_name.find_first_of("^*|&") == std::string::npos) {
|
||||||
log_warning("Malformed liberty file - cannot find pin '%s' in cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
|
log_debug("Malformed liberty file - cannot find pin '%s' in cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log_warning("Found unsupported expression '%s' in pin attribute of cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
|
log_debug("Found unsupported expression '%s' in pin attribute of cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
static void find_cell(std::vector<const LibertyAst *> cells, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
||||||
{
|
{
|
||||||
const LibertyAst *best_cell = nullptr;
|
const LibertyAst *best_cell = nullptr;
|
||||||
std::map<std::string, char> best_cell_ports;
|
std::map<std::string, char> best_cell_ports;
|
||||||
|
@ -237,14 +237,8 @@ static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bo
|
||||||
bool best_cell_noninv = false;
|
bool best_cell_noninv = false;
|
||||||
double best_cell_area = 0;
|
double best_cell_area = 0;
|
||||||
|
|
||||||
if (ast->id != "library")
|
for (auto cell : cells)
|
||||||
log_error("Format error in liberty file.\n");
|
|
||||||
|
|
||||||
for (auto cell : ast->children)
|
|
||||||
{
|
{
|
||||||
if (cell->id != "cell" || cell->args.size() != 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const LibertyAst *dn = cell->find("dont_use");
|
const LibertyAst *dn = cell->find("dont_use");
|
||||||
if (dn != nullptr && dn->value == "true")
|
if (dn != nullptr && dn->value == "true")
|
||||||
continue;
|
continue;
|
||||||
|
@ -355,7 +349,7 @@ static void find_cell(const LibertyAst *ast, IdString cell_type, bool clkpol, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_cell_sr(const LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
static void find_cell_sr(std::vector<const LibertyAst *> cells, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool has_enable, bool enapol, std::vector<std::string> &dont_use_cells)
|
||||||
{
|
{
|
||||||
const LibertyAst *best_cell = nullptr;
|
const LibertyAst *best_cell = nullptr;
|
||||||
std::map<std::string, char> best_cell_ports;
|
std::map<std::string, char> best_cell_ports;
|
||||||
|
@ -365,14 +359,8 @@ static void find_cell_sr(const LibertyAst *ast, IdString cell_type, bool clkpol,
|
||||||
|
|
||||||
log_assert(!enapol && "set/reset cell with enable is unimplemented due to lack of cells for testing");
|
log_assert(!enapol && "set/reset cell with enable is unimplemented due to lack of cells for testing");
|
||||||
|
|
||||||
if (ast->id != "library")
|
for (auto cell : cells)
|
||||||
log_error("Format error in liberty file.\n");
|
|
||||||
|
|
||||||
for (auto cell : ast->children)
|
|
||||||
{
|
{
|
||||||
if (cell->id != "cell" || cell->args.size() != 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const LibertyAst *dn = cell->find("dont_use");
|
const LibertyAst *dn = cell->find("dont_use");
|
||||||
if (dn != nullptr && dn->value == "true")
|
if (dn != nullptr && dn->value == "true")
|
||||||
continue;
|
continue;
|
||||||
|
@ -561,7 +549,7 @@ struct DfflibmapPass : public Pass {
|
||||||
log(" dfflibmap [-prepare] [-map-only] [-info] [-dont_use <cell_name>] -liberty <file> [selection]\n");
|
log(" dfflibmap [-prepare] [-map-only] [-info] [-dont_use <cell_name>] -liberty <file> [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
|
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
|
||||||
log("library specified in the given liberty file.\n");
|
log("library specified in the given liberty files.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass may add inverters as needed. Therefore it is recommended to\n");
|
log("This pass may add inverters as needed. Therefore it is recommended to\n");
|
||||||
log("first run this pass and then map the logic paths to the target technology.\n");
|
log("first run this pass and then map the logic paths to the target technology.\n");
|
||||||
|
@ -590,11 +578,11 @@ struct DfflibmapPass : public Pass {
|
||||||
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
|
log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
|
||||||
log_push();
|
log_push();
|
||||||
|
|
||||||
std::string liberty_file;
|
|
||||||
bool prepare_mode = false;
|
bool prepare_mode = false;
|
||||||
bool map_only_mode = false;
|
bool map_only_mode = false;
|
||||||
bool info_mode = false;
|
bool info_mode = false;
|
||||||
|
|
||||||
|
std::vector<std::string> liberty_files;
|
||||||
std::vector<std::string> dont_use_cells;
|
std::vector<std::string> dont_use_cells;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
|
@ -602,8 +590,9 @@ struct DfflibmapPass : public Pass {
|
||||||
{
|
{
|
||||||
std::string arg = args[argidx];
|
std::string arg = args[argidx];
|
||||||
if (arg == "-liberty" && argidx+1 < args.size()) {
|
if (arg == "-liberty" && argidx+1 < args.size()) {
|
||||||
liberty_file = args[++argidx];
|
std::string liberty_file = args[++argidx];
|
||||||
rewrite_filename(liberty_file);
|
rewrite_filename(liberty_file);
|
||||||
|
liberty_files.push_back(liberty_file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg == "-prepare") {
|
if (arg == "-prepare") {
|
||||||
|
@ -636,41 +625,45 @@ struct DfflibmapPass : public Pass {
|
||||||
if (modes > 1)
|
if (modes > 1)
|
||||||
log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n");
|
log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n");
|
||||||
|
|
||||||
if (liberty_file.empty())
|
if (liberty_files.empty())
|
||||||
log_cmd_error("Missing `-liberty liberty_file' option!\n");
|
log_cmd_error("Missing `-liberty liberty_file' option!\n");
|
||||||
|
|
||||||
std::ifstream f;
|
LibertyMergedCells merged;
|
||||||
f.open(liberty_file.c_str());
|
for (auto path : liberty_files) {
|
||||||
if (f.fail())
|
std::ifstream f;
|
||||||
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
|
f.open(path.c_str());
|
||||||
LibertyParser libparser(f);
|
if (f.fail())
|
||||||
f.close();
|
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
|
||||||
|
LibertyParser p(f);
|
||||||
|
merged.merge(p);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_N_), false, false, false, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_P_), true, false, false, false, false, false, dont_use_cells);
|
||||||
|
|
||||||
find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NN0_), false, true, false, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NN1_), false, true, false, true, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NP0_), false, true, true, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_NP1_), false, true, true, true, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PN0_), true, true, false, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PN1_), true, true, false, true, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PP0_), true, true, true, false, false, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, false, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFF_PP1_), true, true, true, true, false, false, dont_use_cells);
|
||||||
|
|
||||||
find_cell(libparser.ast, ID($_DFFE_NN_), false, false, false, false, true, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_NN_), false, false, false, false, true, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFFE_NP_), false, false, false, false, true, true, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_NP_), false, false, false, false, true, true, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFFE_PN_), true, false, false, false, true, false, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_PN_), true, false, false, false, true, false, dont_use_cells);
|
||||||
find_cell(libparser.ast, ID($_DFFE_PP_), true, false, false, false, true, true, dont_use_cells);
|
find_cell(merged.cells, ID($_DFFE_PP_), true, false, false, false, true, true, dont_use_cells);
|
||||||
|
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NNN_), false, false, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NNP_), false, false, true, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NPN_), false, true, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_NPP_), false, true, true, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PNN_), true, false, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PNP_), true, false, true, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PPN_), true, true, false, false, false, dont_use_cells);
|
||||||
find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, false, false, dont_use_cells);
|
find_cell_sr(merged.cells, ID($_DFFSR_PPP_), true, true, true, false, false, dont_use_cells);
|
||||||
|
|
||||||
log(" final dff cell mappings:\n");
|
log(" final dff cell mappings:\n");
|
||||||
logmap_all();
|
logmap_all();
|
||||||
|
|
|
@ -503,12 +503,12 @@ LibertyAst *LibertyParser::parse()
|
||||||
|
|
||||||
#ifndef FILTERLIB
|
#ifndef FILTERLIB
|
||||||
|
|
||||||
void LibertyParser::error()
|
void LibertyParser::error() const
|
||||||
{
|
{
|
||||||
log_error("Syntax error in liberty file on line %d.\n", line);
|
log_error("Syntax error in liberty file on line %d.\n", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibertyParser::error(const std::string &str)
|
void LibertyParser::error(const std::string &str) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Syntax error in liberty file on line " << line << ".\n";
|
ss << "Syntax error in liberty file on line " << line << ".\n";
|
||||||
|
@ -518,13 +518,13 @@ void LibertyParser::error(const std::string &str)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void LibertyParser::error()
|
void LibertyParser::error() const
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
|
fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibertyParser::error(const std::string &str)
|
void LibertyParser::error(const std::string &str) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Syntax error in liberty file on line " << line << ".\n";
|
ss << "Syntax error in liberty file on line " << line << ".\n";
|
||||||
|
|
|
@ -86,8 +86,10 @@ namespace Yosys
|
||||||
bool eval(dict<std::string, bool>& values);
|
bool eval(dict<std::string, bool>& values);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LibertyMergedCells;
|
||||||
class LibertyParser
|
class LibertyParser
|
||||||
{
|
{
|
||||||
|
friend class LibertyMergedCells;
|
||||||
private:
|
private:
|
||||||
std::istream &f;
|
std::istream &f;
|
||||||
int line;
|
int line;
|
||||||
|
@ -100,8 +102,8 @@ namespace Yosys
|
||||||
int lexer(std::string &str);
|
int lexer(std::string &str);
|
||||||
|
|
||||||
LibertyAst *parse();
|
LibertyAst *parse();
|
||||||
void error();
|
void error() const;
|
||||||
void error(const std::string &str);
|
void error(const std::string &str) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const LibertyAst *ast;
|
const LibertyAst *ast;
|
||||||
|
@ -109,6 +111,35 @@ namespace Yosys
|
||||||
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
|
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
|
||||||
~LibertyParser() { if (ast) delete ast; }
|
~LibertyParser() { if (ast) delete ast; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LibertyMergedCells
|
||||||
|
{
|
||||||
|
std::vector<const LibertyAst *> asts;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<const LibertyAst *> cells;
|
||||||
|
void merge(LibertyParser &parser)
|
||||||
|
{
|
||||||
|
if (parser.ast) {
|
||||||
|
const LibertyAst *ast = parser.ast;
|
||||||
|
asts.push_back(ast);
|
||||||
|
// The parser no longer owns its top level ast, but we do.
|
||||||
|
// sketchy zone
|
||||||
|
parser.ast = nullptr;
|
||||||
|
if (ast->id != "library")
|
||||||
|
parser.error("Top level entity isn't \"library\".\n");
|
||||||
|
for (const LibertyAst *cell : ast->children)
|
||||||
|
if (cell->id == "cell" && cell->args.size() == 1)
|
||||||
|
cells.push_back(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~LibertyMergedCells()
|
||||||
|
{
|
||||||
|
for (auto ast : asts)
|
||||||
|
delete ast;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1028,6 +1028,9 @@ struct TechmapPass : public Pass {
|
||||||
log(" map file. Note that the Verilog frontend is also called with the\n");
|
log(" map file. Note that the Verilog frontend is also called with the\n");
|
||||||
log(" '-nooverwrite' option set.\n");
|
log(" '-nooverwrite' option set.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -dont_map <celltype>\n");
|
||||||
|
log(" leave the given cell type unmapped by ignoring any mapping rules for it\n");
|
||||||
|
log("\n");
|
||||||
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
|
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
|
||||||
log("match cells with a type that match the text value of this attribute. Otherwise\n");
|
log("match cells with a type that match the text value of this attribute. Otherwise\n");
|
||||||
log("the module name will be used to match the cell. Multiple space-separated cell\n");
|
log("the module name will be used to match the cell. Multiple space-separated cell\n");
|
||||||
|
@ -1159,6 +1162,7 @@ struct TechmapPass : public Pass {
|
||||||
simplemap_get_mappers(worker.simplemap_mappers);
|
simplemap_get_mappers(worker.simplemap_mappers);
|
||||||
|
|
||||||
std::vector<std::string> map_files;
|
std::vector<std::string> map_files;
|
||||||
|
std::vector<RTLIL::IdString> dont_map;
|
||||||
std::string verilog_frontend = "verilog -nooverwrite -noblackbox";
|
std::string verilog_frontend = "verilog -nooverwrite -noblackbox";
|
||||||
int max_iter = -1;
|
int max_iter = -1;
|
||||||
|
|
||||||
|
@ -1200,6 +1204,10 @@ struct TechmapPass : public Pass {
|
||||||
worker.ignore_wb = true;
|
worker.ignore_wb = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-dont_map" && argidx+1 < args.size()) {
|
||||||
|
dont_map.push_back(RTLIL::escape_id(args[++argidx]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -1256,6 +1264,11 @@ struct TechmapPass : public Pass {
|
||||||
celltypeMap[module_name].insert(module->name);
|
celltypeMap[module_name].insert(module->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Erase any rules disabled with a -dont_map argument
|
||||||
|
for (auto type : dont_map)
|
||||||
|
celltypeMap.erase(type);
|
||||||
|
|
||||||
log_debug("Cell type mappings to use:\n");
|
log_debug("Cell type mappings to use:\n");
|
||||||
for (auto &i : celltypeMap) {
|
for (auto &i : celltypeMap) {
|
||||||
i.second.sort(RTLIL::sort_by_id_str());
|
i.second.sort(RTLIL::sort_by_id_str());
|
||||||
|
|
|
@ -36,3 +36,5 @@ $(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v))
|
||||||
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v))
|
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v))
|
||||||
$(eval $(call add_share_file,share,techlibs/common/cmp2softlogic.v))
|
$(eval $(call add_share_file,share,techlibs/common/cmp2softlogic.v))
|
||||||
$(eval $(call add_share_file,share/choices,techlibs/common/choices/kogge-stone.v))
|
$(eval $(call add_share_file,share/choices,techlibs/common/choices/kogge-stone.v))
|
||||||
|
$(eval $(call add_share_file,share/choices,techlibs/common/choices/han-carlson.v))
|
||||||
|
$(eval $(call add_share_file,share/choices,techlibs/common/choices/sklansky.v))
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
(* techmap_celltype = "$lcu" *)
|
||||||
|
module _80_lcu_han_carlson (P, G, CI, CO);
|
||||||
|
parameter WIDTH = 2;
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
input [WIDTH-1:0] P, G;
|
||||||
|
input CI;
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
output [WIDTH-1:0] CO;
|
||||||
|
|
||||||
|
integer i, j;
|
||||||
|
(* force_downto *)
|
||||||
|
reg [WIDTH-1:0] p, g;
|
||||||
|
|
||||||
|
wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
i = 0;
|
||||||
|
p = P;
|
||||||
|
g = G;
|
||||||
|
|
||||||
|
// in almost all cases CI will be constant zero
|
||||||
|
g[0] = g[0] | (p[0] & CI);
|
||||||
|
if (i < $clog2(WIDTH)) begin
|
||||||
|
|
||||||
|
// First layer: BK
|
||||||
|
for (j = WIDTH - 1; j >= 0; j = j - 1) begin
|
||||||
|
if (j % 2 == 1) begin
|
||||||
|
g[j] = g[j] | p[j] & g[j - 1];
|
||||||
|
p[j] = p[j] & p[j - 1];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Inner (log(WIDTH) - 1) layers: KS
|
||||||
|
for (i = 1; i < $clog2(WIDTH); i = i + 1) begin
|
||||||
|
for (j = WIDTH - 1; j >= 2**i; j = j - 1) begin
|
||||||
|
if (j % 2 == 1) begin
|
||||||
|
g[j] = g[j] | p[j] & g[j - 2**i];
|
||||||
|
p[j] = p[j] & p[j - 2**i];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Last layer: BK
|
||||||
|
if (i < ($clog2(WIDTH) + 1)) begin
|
||||||
|
for (j = WIDTH - 1; j >= 0; j = j - 1) begin
|
||||||
|
if ((j % 2 == 0) && (j > 0)) begin
|
||||||
|
g[j] = g[j] | p[j] & g[j - 1];
|
||||||
|
p[j] = p[j] & p[j - 1];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign CO = g;
|
||||||
|
endmodule
|
|
@ -0,0 +1,37 @@
|
||||||
|
(* techmap_celltype = "$lcu" *)
|
||||||
|
module _80_lcu_sklansky (P, G, CI, CO);
|
||||||
|
parameter WIDTH = 2;
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
input [WIDTH-1:0] P, G;
|
||||||
|
input CI;
|
||||||
|
|
||||||
|
(* force_downto *)
|
||||||
|
output [WIDTH-1:0] CO;
|
||||||
|
|
||||||
|
integer i, j;
|
||||||
|
(* force_downto *)
|
||||||
|
reg [WIDTH-1:0] p, g;
|
||||||
|
|
||||||
|
wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
p = P;
|
||||||
|
g = G;
|
||||||
|
|
||||||
|
// in almost all cases CI will be constant zero
|
||||||
|
g[0] = g[0] | (p[0] & CI);
|
||||||
|
|
||||||
|
for (i = 0; i < $clog2(WIDTH); i = i + 1) begin
|
||||||
|
// iterate in reverse so we don't confuse a result from this stage and the previous
|
||||||
|
for (j = WIDTH - 1; j >= 0; j = j - 1) begin
|
||||||
|
if (j & 2**i) begin
|
||||||
|
g[j] = g[j] | p[j] & g[(j & ~(2**i - 1)) - 1];
|
||||||
|
p[j] = p[j] & p[(j & ~(2**i - 1)) - 1];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign CO = g;
|
||||||
|
endmodule
|
|
@ -301,6 +301,7 @@ struct SynthGateMatePass : public ScriptPass
|
||||||
}
|
}
|
||||||
run("muxcover " + muxcover_args);
|
run("muxcover " + muxcover_args);
|
||||||
run("opt -full");
|
run("opt -full");
|
||||||
|
run("simplemap");
|
||||||
run("techmap -map +/gatemate/mux_map.v");
|
run("techmap -map +/gatemate/mux_map.v");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@ OBJS += techlibs/gowin/synth_gowin.o
|
||||||
|
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra.v))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra_gw1n.v))
|
||||||
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra_gw2a.v))
|
||||||
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra_gw5a.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v))
|
||||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt))
|
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt))
|
||||||
|
|
|
@ -63,14 +63,17 @@ if __name__ == '__main__':
|
||||||
parser.add_argument('gowin_dir', nargs='?', default='/opt/gowin/')
|
parser.add_argument('gowin_dir', nargs='?', default='/opt/gowin/')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
dirs = [
|
families = {
|
||||||
os.path.join(args.gowin_dir, 'IDE/simlib/gw1n/'),
|
'gw1n': os.path.join(args.gowin_dir, 'IDE/simlib/gw1n/'),
|
||||||
]
|
'gw2a': os.path.join(args.gowin_dir, 'IDE/simlib/gw2a/'),
|
||||||
|
'gw5a': os.path.join(args.gowin_dir, 'IDE/simlib/gw5a/'),
|
||||||
|
}
|
||||||
|
|
||||||
with open('cells_xtra.v', 'w') as fout:
|
for family, dir in families.items():
|
||||||
fout.write('// Created by cells_xtra.py\n')
|
if not os.path.isdir(dir):
|
||||||
fout.write('\n')
|
print(f'{dir} is not a directory')
|
||||||
for dir in dirs:
|
else:
|
||||||
if not os.path.isdir(dir):
|
with open(f'cells_xtra_{family}.v', 'w') as fout:
|
||||||
print(f'{dir} is not a directory')
|
fout.write('// Created by cells_xtra.py\n')
|
||||||
xtract_cells_decl(dir, fout)
|
fout.write('\n')
|
||||||
|
xtract_cells_decl(dir, fout)
|
||||||
|
|
|
@ -1465,12 +1465,22 @@ output O, OB;
|
||||||
input I, IB, IL, MODESEL;
|
input I, IB, IL, MODESEL;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module ELVDS_IBUF_MIPI (...);
|
||||||
|
output OH, OL;
|
||||||
|
input I, IB;
|
||||||
|
endmodule
|
||||||
|
|
||||||
module I3C_IOBUF (...);
|
module I3C_IOBUF (...);
|
||||||
output O;
|
output O;
|
||||||
inout IO;
|
inout IO;
|
||||||
input I, MODESEL;
|
input I, MODESEL;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module TLVDS_OEN_BK (...);
|
||||||
|
input OEN;
|
||||||
|
parameter OEN_BANK = "0";
|
||||||
|
endmodule
|
||||||
|
|
||||||
module CLKDIV (...);
|
module CLKDIV (...);
|
||||||
input HCLKIN;
|
input HCLKIN;
|
||||||
input RESETN;
|
input RESETN;
|
||||||
|
@ -1570,117 +1580,6 @@ input CE;
|
||||||
output CLKOUT;
|
output CLKOUT;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module FLASH128K (...);
|
|
||||||
input [31:0] DIN;
|
|
||||||
input [14:0] ADDR;
|
|
||||||
input CS,AE,OE;
|
|
||||||
input PCLK;
|
|
||||||
input PROG, SERA, MASE;
|
|
||||||
input NVSTR;
|
|
||||||
input IFREN;
|
|
||||||
input RESETN;
|
|
||||||
output [31:0] DOUT;
|
|
||||||
output TBIT;
|
|
||||||
parameter IDLE = 4'd0,
|
|
||||||
READ_S1 = 4'd1,
|
|
||||||
READ_S2 = 4'd2,
|
|
||||||
PROG_S1 = 4'd3,
|
|
||||||
PROG_S2 = 4'd4,
|
|
||||||
PROG_S3 = 4'd5,
|
|
||||||
PROG_S4 = 4'd6,
|
|
||||||
SERA_S1 = 4'd7,
|
|
||||||
SERA_S2 = 4'd8,
|
|
||||||
SERA_S3 = 4'd9,
|
|
||||||
SERA_S4 = 4'd10,
|
|
||||||
MASE_S1 = 4'd11,
|
|
||||||
MASE_S2 = 4'd12,
|
|
||||||
MASE_S3 = 4'd13,
|
|
||||||
MASE_S4 = 4'd14;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module MCU (...);
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module USB20_PHY (...);
|
|
||||||
parameter DATABUS16_8 = 1'b0;
|
|
||||||
parameter ADP_PRBEN = 1'b0;
|
|
||||||
parameter TEST_MODE = 5'b00000;
|
|
||||||
parameter HSDRV1 = 1'b0;
|
|
||||||
parameter HSDRV0 = 1'b0;
|
|
||||||
parameter CLK_SEL = 1'b0;
|
|
||||||
parameter M = 4'b0000;
|
|
||||||
parameter N = 6'b101000;
|
|
||||||
parameter C = 2'b01;
|
|
||||||
parameter FOC_LOCK = 1'b0;
|
|
||||||
input [15:0] DATAIN;
|
|
||||||
input TXVLD;
|
|
||||||
input TXVLDH;
|
|
||||||
input RESET;
|
|
||||||
input SUSPENDM;
|
|
||||||
input [1:0] XCVRSEL;
|
|
||||||
input TERMSEL;
|
|
||||||
input [1:0] OPMODE;
|
|
||||||
output [15:0] DATAOUT;
|
|
||||||
output TXREADY;
|
|
||||||
output RXACTIVE;
|
|
||||||
output RXVLD;
|
|
||||||
output RXVLDH;
|
|
||||||
output CLK;
|
|
||||||
output RXERROR;
|
|
||||||
inout DP;
|
|
||||||
inout DM;
|
|
||||||
output [1:0] LINESTATE;
|
|
||||||
input IDPULLUP;
|
|
||||||
input DPPD;
|
|
||||||
input DMPD;
|
|
||||||
input CHARGVBUS;
|
|
||||||
input DISCHARGVBUS;
|
|
||||||
input TXBITSTUFFEN;
|
|
||||||
input TXBITSTUFFENH;
|
|
||||||
input TXENN;
|
|
||||||
input TXDAT;
|
|
||||||
input TXSE0;
|
|
||||||
input FSLSSERIAL;
|
|
||||||
output HOSTDIS;
|
|
||||||
output IDDIG;
|
|
||||||
output ADPPRB;
|
|
||||||
output ADPSNS;
|
|
||||||
output SESSVLD;
|
|
||||||
output VBUSVLD;
|
|
||||||
output RXDP;
|
|
||||||
output RXDM;
|
|
||||||
output RXRCV;
|
|
||||||
output LBKERR;
|
|
||||||
output CLKRDY;
|
|
||||||
input INTCLK;
|
|
||||||
inout ID;
|
|
||||||
inout VBUS;
|
|
||||||
inout REXT;
|
|
||||||
input XIN;
|
|
||||||
inout XOUT;
|
|
||||||
input TEST;
|
|
||||||
output CLK480PAD;
|
|
||||||
input SCANCLK;
|
|
||||||
input SCANEN;
|
|
||||||
input SCANMODE;
|
|
||||||
input TRESETN;
|
|
||||||
input SCANIN1;
|
|
||||||
output SCANOUT1;
|
|
||||||
input SCANIN2;
|
|
||||||
output SCANOUT2;
|
|
||||||
input SCANIN3;
|
|
||||||
output SCANOUT3;
|
|
||||||
input SCANIN4;
|
|
||||||
output SCANOUT4;
|
|
||||||
input SCANIN5;
|
|
||||||
output SCANOUT5;
|
|
||||||
input SCANIN6;
|
|
||||||
output SCANOUT6;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module ADC (...);
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module CLKDIV2 (...);
|
module CLKDIV2 (...);
|
||||||
parameter GSREN = "false";
|
parameter GSREN = "false";
|
||||||
input HCLKIN, RESETN;
|
input HCLKIN, RESETN;
|
||||||
|
@ -1977,7 +1876,7 @@ parameter MIPI_LANE1_EN = 1'b0;
|
||||||
parameter MIPI_LANE2_EN = 1'b0;
|
parameter MIPI_LANE2_EN = 1'b0;
|
||||||
parameter MIPI_LANE3_EN = 1'b0;
|
parameter MIPI_LANE3_EN = 1'b0;
|
||||||
parameter MIPI_CK_EN = 1'b1;
|
parameter MIPI_CK_EN = 1'b1;
|
||||||
parameter SYNC_CLK_SEL = 1'b1;
|
parameter SYNC_CLK_SEL = 1'b0;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module CLKDIVG (...);
|
module CLKDIVG (...);
|
||||||
|
@ -1988,3 +1887,7 @@ output CLKOUT;
|
||||||
parameter DIV_MODE = "2";
|
parameter DIV_MODE = "2";
|
||||||
parameter GSREN = "false";
|
parameter GSREN = "false";
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module PWRGRD (...);
|
||||||
|
input PDEN;
|
||||||
|
endmodule
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -86,17 +86,22 @@ struct SynthGowinPass : public ScriptPass
|
||||||
log(" read/write collision\" (same result as setting the no_rw_check\n");
|
log(" read/write collision\" (same result as setting the no_rw_check\n");
|
||||||
log(" attribute on all memories).\n");
|
log(" attribute on all memories).\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -family <family>\n");
|
||||||
|
log(" sets the gowin family to the specified value. The default is 'gw1n'.\n");
|
||||||
|
log(" The following families are supported:\n");
|
||||||
|
log(" 'gw1n', 'gw2a', 'gw5a'.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("The following commands are executed by this synthesis command:\n");
|
log("The following commands are executed by this synthesis command:\n");
|
||||||
help_script();
|
help_script();
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
string top_opt, vout_file, json_file;
|
string top_opt, vout_file, json_file, family;
|
||||||
bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads, noalu, no_rw_check;
|
bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads, noalu, no_rw_check;
|
||||||
|
|
||||||
void clear_flags() override
|
void clear_flags() override
|
||||||
{
|
{
|
||||||
|
family = "gw1n";
|
||||||
top_opt = "-auto-top";
|
top_opt = "-auto-top";
|
||||||
vout_file = "";
|
vout_file = "";
|
||||||
json_file = "";
|
json_file = "";
|
||||||
|
@ -132,6 +137,10 @@ struct SynthGowinPass : public ScriptPass
|
||||||
json_file = args[++argidx];
|
json_file = args[++argidx];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-family" && argidx+1 < args.size()) {
|
||||||
|
family = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-run" && argidx+1 < args.size()) {
|
if (args[argidx] == "-run" && argidx+1 < args.size()) {
|
||||||
size_t pos = args[argidx+1].find(':');
|
size_t pos = args[argidx+1].find(':');
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
|
@ -210,7 +219,7 @@ struct SynthGowinPass : public ScriptPass
|
||||||
if (check_label("begin"))
|
if (check_label("begin"))
|
||||||
{
|
{
|
||||||
run("read_verilog -specify -lib +/gowin/cells_sim.v");
|
run("read_verilog -specify -lib +/gowin/cells_sim.v");
|
||||||
run("read_verilog -specify -lib +/gowin/cells_xtra.v");
|
run(stringf("read_verilog -specify -lib +/gowin/cells_xtra_%s.v", help_mode ? "<family>" : family.c_str()));
|
||||||
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
|
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ struct QlDspSimdPass : public Pass {
|
||||||
|
|
||||||
// ..........................................
|
// ..........................................
|
||||||
|
|
||||||
const size_t m_ModeBitsSize = 80;
|
const int m_ModeBitsSize = 80;
|
||||||
|
|
||||||
// DSP parameters
|
// DSP parameters
|
||||||
const std::vector<std::string> m_DspParams = {"COEFF_3", "COEFF_2", "COEFF_1", "COEFF_0"};
|
const std::vector<std::string> m_DspParams = {"COEFF_3", "COEFF_2", "COEFF_1", "COEFF_0"};
|
||||||
|
|
|
@ -10,8 +10,11 @@ module sync_rom #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
reg [WORD:0] data_out_r;
|
reg [WORD:0] data_out_r;
|
||||||
reg [WORD:0] memory [0:DEPTH];
|
reg [WORD:0] memory [0:DEPTH];
|
||||||
|
|
||||||
integer i,j = 64'hF4B1CA8127865242;
|
integer i,j;
|
||||||
initial
|
// Initialize in initial block as a workaround for
|
||||||
|
// https://github.com/YosysHQ/yosys/issues/4792
|
||||||
|
initial begin
|
||||||
|
j = 64'hF4B1CA8127865242;
|
||||||
for (i = 0; i <= DEPTH; i++) begin
|
for (i = 0; i <= DEPTH; i++) begin
|
||||||
// In case this ROM will be implemented in fabric: fill the memory with some data
|
// In case this ROM will be implemented in fabric: fill the memory with some data
|
||||||
// uncorrelated with the address, or Yosys might see through the ruse and e.g. not
|
// uncorrelated with the address, or Yosys might see through the ruse and e.g. not
|
||||||
|
@ -21,6 +24,7 @@ module sync_rom #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
|
||||||
j = j ^ (j << 25);
|
j = j ^ (j << 25);
|
||||||
j = j ^ (j >> 27);
|
j = j ^ (j >> 27);
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
data_out_r <= memory[address_in];
|
data_out_r <= memory[address_in];
|
||||||
|
|
|
@ -20,6 +20,13 @@ generate_ys_test() {
|
||||||
generate_target "$ys_file" "\"$YOSYS_BASEDIR/yosys\" -ql ${ys_file%.*}.log $yosys_args_ $ys_file"
|
generate_target "$ys_file" "\"$YOSYS_BASEDIR/yosys\" -ql ${ys_file%.*}.log $yosys_args_ $ys_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# $ generate_tcl_test tcl_file [yosys_args]
|
||||||
|
generate_tcl_test() {
|
||||||
|
tcl_file=$1
|
||||||
|
yosys_args_=${2:-}
|
||||||
|
generate_target "$tcl_file" "\"$YOSYS_BASEDIR/yosys\" -ql ${tcl_file%.*}.log $yosys_args_ $tcl_file"
|
||||||
|
}
|
||||||
|
|
||||||
# $ generate_bash_test bash_file
|
# $ generate_bash_test bash_file
|
||||||
generate_bash_test() {
|
generate_bash_test() {
|
||||||
bash_file=$1
|
bash_file=$1
|
||||||
|
@ -29,6 +36,7 @@ generate_bash_test() {
|
||||||
# $ generate_tests [-y|--yosys-scripts] [-s|--prove-sv] [-b|--bash] [-a|--yosys-args yosys_args]
|
# $ generate_tests [-y|--yosys-scripts] [-s|--prove-sv] [-b|--bash] [-a|--yosys-args yosys_args]
|
||||||
generate_tests() {
|
generate_tests() {
|
||||||
do_ys=false
|
do_ys=false
|
||||||
|
do_tcl=false
|
||||||
do_sv=false
|
do_sv=false
|
||||||
do_sh=false
|
do_sh=false
|
||||||
yosys_args=""
|
yosys_args=""
|
||||||
|
@ -40,6 +48,10 @@ generate_tests() {
|
||||||
do_ys=true
|
do_ys=true
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
-t|--tcl-scripts)
|
||||||
|
do_tcl=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-s|--prove-sv)
|
-s|--prove-sv)
|
||||||
do_sv=true
|
do_sv=true
|
||||||
shift
|
shift
|
||||||
|
@ -59,7 +71,7 @@ generate_tests() {
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ! ( $do_ys = true || $do_sv = true || $do_sh = true ) ]]; then
|
if [[ ! ( $do_ys = true || $do_tcl = true || $do_sv = true || $do_sh = true ) ]]; then
|
||||||
echo >&2 "Error: No file types selected"
|
echo >&2 "Error: No file types selected"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -72,6 +84,11 @@ generate_tests() {
|
||||||
generate_ys_test "$x" "$yosys_args"
|
generate_ys_test "$x" "$yosys_args"
|
||||||
done
|
done
|
||||||
fi;
|
fi;
|
||||||
|
if [[ $do_tcl = true ]]; then
|
||||||
|
for x in *.tcl; do
|
||||||
|
generate_tcl_test "$x" "$yosys_args"
|
||||||
|
done
|
||||||
|
fi;
|
||||||
if [[ $do_sv = true ]]; then
|
if [[ $do_sv = true ]]; then
|
||||||
for x in *.sv; do
|
for x in *.sv; do
|
||||||
if [ ! -f "${x%.sv}.ys" ]; then
|
if [ ! -f "${x%.sv}.ys" ]; then
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
*.log
|
*.log
|
||||||
*.filtered
|
/*.filtered
|
||||||
*.verilogsim
|
*.verilogsim
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
*.lib
|
||||||
|
*.lib.filtered
|
Binary file not shown.
|
@ -0,0 +1,16 @@
|
||||||
|
-wire_load
|
||||||
|
-wire_load_selection
|
||||||
|
-default_wire_load
|
||||||
|
-default_wire_load_area
|
||||||
|
-default_wire_load_capacitance
|
||||||
|
-default_wire_load_mode
|
||||||
|
-default_wire_load_resistance
|
||||||
|
-default_cell_leakage_power
|
||||||
|
-default_wire_load_selection
|
||||||
|
-default_leakage_power_density
|
||||||
|
-lu_table_template
|
||||||
|
-power_lut_template
|
||||||
|
-leakage_power
|
||||||
|
-cell_leakage_power
|
||||||
|
-leakage_power
|
||||||
|
-internal_power
|
Binary file not shown.
|
@ -0,0 +1,23 @@
|
||||||
|
# Test memory macro gets ignored due to -ignore_buses
|
||||||
|
read_verilog -noblackbox <<EOF
|
||||||
|
module RM_IHPSG13_1P_64x64_c2_bm_bist();
|
||||||
|
endmodule
|
||||||
|
EOF
|
||||||
|
read_liberty -lib -ignore_buses foundry_data/RM_IHPSG13_1P_64x64_c2_bm_bist_typ_1p20V_25C.lib.filtered.gz
|
||||||
|
|
||||||
|
# Test memory macro doesn't get ignored without -ignore_buses
|
||||||
|
# and check the area and capacitance attributes are populated
|
||||||
|
design -reset
|
||||||
|
read_liberty -lib foundry_data/RM_IHPSG13_1P_64x64_c2_bm_bist_typ_1p20V_25C.lib.filtered.gz
|
||||||
|
select -assert-mod-count 1 =RM_IHPSG13_1P_64x64_c2_bm_bist =A:area=50489.1328 %i
|
||||||
|
select -assert-any =*/i:A_BIST_EN =*/a:capacitance=0.00401111 %i
|
||||||
|
|
||||||
|
# Test import of unit delay arcs
|
||||||
|
design -reset
|
||||||
|
read_liberty -wb -unit_delay -ignore_miss_func foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz
|
||||||
|
|
||||||
|
# A->Y arc on nand2_1 exists
|
||||||
|
select -assert-any =sg13g2_nand2_1/i:A %co1:+$specify2[SRC] =sg13g2_nand2_1/o:Y %co1:+$specify2[DST] %i
|
||||||
|
|
||||||
|
# D->Q arc on sdfbbp_1 doesn't
|
||||||
|
select -assert-none =sg13g2_sdfbbp_1/i:D %co1:+$specify2[SRC] =sg13g2_nand2_1/o:Q %co1:+$specify2[DST] %i
|
|
@ -1,3 +0,0 @@
|
||||||
# Nothing gets imported: the file lacks timing data
|
|
||||||
read_liberty -wb -unit_delay normal.lib
|
|
||||||
select -assert-none =*/t:$specify*
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# check memory_collect doesn't produce invalid RTLIL on a memory w/o read ports
|
||||||
|
read_rtlil <<EOF
|
||||||
|
autoidx 1
|
||||||
|
attribute \top 1
|
||||||
|
module \top
|
||||||
|
memory width 4 size 3 \foo
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
memory_collect
|
|
@ -0,0 +1,15 @@
|
||||||
|
read_rtlil <<EOT
|
||||||
|
autoidx 1
|
||||||
|
module \top
|
||||||
|
wire output 1 \Y
|
||||||
|
cell $reduce_or $reduce_or$rtl.v:29$20
|
||||||
|
parameter \A_SIGNED 0
|
||||||
|
parameter \A_WIDTH 0
|
||||||
|
parameter \Y_WIDTH 1
|
||||||
|
connect \A { }
|
||||||
|
connect \Y \Y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOT
|
||||||
|
|
||||||
|
equiv_opt -assert opt_demorgan
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Check that opt_reduce doesn't produce zero width $reduce_or/$reduce_and,
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module reduce_const(output wire o, output wire a);
|
||||||
|
wire [3:0] zero = 4'b0000;
|
||||||
|
wire [3:0] ones = 4'b1111;
|
||||||
|
assign o = |zero;
|
||||||
|
assign a = &ones;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
equiv_opt -assert opt_reduce
|
||||||
|
design -load postopt
|
||||||
|
select -assert-none r:A_WIDTH=0
|
|
@ -0,0 +1,31 @@
|
||||||
|
read_rtlil <<EOT
|
||||||
|
autoidx 1
|
||||||
|
module \top
|
||||||
|
wire input 1 \clk
|
||||||
|
wire input 2 \rst
|
||||||
|
|
||||||
|
wire input 3 \a_r
|
||||||
|
wire input 4 \a_n
|
||||||
|
wire input 5 \b_n
|
||||||
|
|
||||||
|
wire \a
|
||||||
|
wire \b
|
||||||
|
|
||||||
|
process $proc
|
||||||
|
sync high \rst
|
||||||
|
update \a \a_r
|
||||||
|
update \b \b
|
||||||
|
sync posedge \clk
|
||||||
|
update \a \a_n
|
||||||
|
update \b \b_n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOT
|
||||||
|
|
||||||
|
proc_dff
|
||||||
|
proc_clean
|
||||||
|
|
||||||
|
# Processes should have been converted to one aldff and one dff
|
||||||
|
select -assert-none p:*
|
||||||
|
select -assert-count 1 t:$aldff
|
||||||
|
select -assert-count 1 t:$dff
|
|
@ -10,6 +10,19 @@ endmodule
|
||||||
EOF
|
EOF
|
||||||
booth
|
booth
|
||||||
sat -verify -set a 0 -set b 0 -prove y 0
|
sat -verify -set a 0 -set b 0 -prove y 0
|
||||||
design -reset
|
|
||||||
|
|
||||||
|
design -reset
|
||||||
test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul
|
test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOF
|
||||||
|
module top(a,b,y);
|
||||||
|
input wire [4:0] a;
|
||||||
|
input wire [5:0] b;
|
||||||
|
output wire [6:0] y;
|
||||||
|
assign y = a * b;
|
||||||
|
endmodule
|
||||||
|
EOF
|
||||||
|
synth -run :fine
|
||||||
|
# test compatibility with alumacc
|
||||||
|
equiv_opt -assert booth
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
library(test) {
|
||||||
|
/* Integrated clock gating cells */
|
||||||
|
cell (pos_small_tielo) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_posedge_precontrol;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (SE) {
|
||||||
|
clock_gate_test_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (pos_big) {
|
||||||
|
area : 10;
|
||||||
|
clock_gating_integrated_cell : latch_posedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (pos_small) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_posedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (neg_big) {
|
||||||
|
area : 10;
|
||||||
|
clock_gating_integrated_cell : latch_negedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (neg_small_tielo) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_negedge_precontrol;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (SE) {
|
||||||
|
clock_gate_test_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell (neg_small) {
|
||||||
|
area : 1;
|
||||||
|
clock_gating_integrated_cell : latch_negedge;
|
||||||
|
pin (GCLK) {
|
||||||
|
clock_gate_out_pin : true;
|
||||||
|
direction : output;
|
||||||
|
}
|
||||||
|
pin (CLK) {
|
||||||
|
clock_gate_clock_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
pin (CE) {
|
||||||
|
clock_gate_enable_pin : true;
|
||||||
|
direction : input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ clockgate -pos pdk_icg ce:clkin:clkout -tie_lo scanen
|
||||||
# falling edge clock flops don't get matched on -pos
|
# falling edge clock flops don't get matched on -pos
|
||||||
select -module dffe_00 -assert-count 0 t:\\pdk_icg
|
select -module dffe_00 -assert-count 0 t:\\pdk_icg
|
||||||
select -module dffe_01 -assert-count 0 t:\\pdk_icg
|
select -module dffe_01 -assert-count 0 t:\\pdk_icg
|
||||||
# falling edge clock flops do get matched on -pos
|
# rising edge clock flops do get matched on -pos
|
||||||
select -module dffe_10 -assert-count 1 t:\\pdk_icg
|
select -module dffe_10 -assert-count 1 t:\\pdk_icg
|
||||||
select -module dffe_11 -assert-count 1 t:\\pdk_icg
|
select -module dffe_11 -assert-count 1 t:\\pdk_icg
|
||||||
# if necessary, EN is inverted, since the given ICG
|
# if necessary, EN is inverted, since the given ICG
|
||||||
|
@ -79,10 +79,10 @@ select -module dffe_wide_11 -assert-count 1 t:\\pdk_icg
|
||||||
design -load before
|
design -load before
|
||||||
clockgate -min_net_size 1 -neg pdk_icg ce:clkin:clkout -tie_lo scanen
|
clockgate -min_net_size 1 -neg pdk_icg ce:clkin:clkout -tie_lo scanen
|
||||||
|
|
||||||
# rising edge clock flops don't get matched on -neg
|
# falling edge clock flops do get matched on -neg
|
||||||
select -module dffe_00 -assert-count 1 t:\\pdk_icg
|
select -module dffe_00 -assert-count 1 t:\\pdk_icg
|
||||||
select -module dffe_01 -assert-count 1 t:\\pdk_icg
|
select -module dffe_01 -assert-count 1 t:\\pdk_icg
|
||||||
# rising edge clock flops do get matched on -neg
|
# rising edge clock flops don't get matched on -neg
|
||||||
select -module dffe_10 -assert-count 0 t:\\pdk_icg
|
select -module dffe_10 -assert-count 0 t:\\pdk_icg
|
||||||
select -module dffe_11 -assert-count 0 t:\\pdk_icg
|
select -module dffe_11 -assert-count 0 t:\\pdk_icg
|
||||||
# if necessary, EN is inverted, since the given ICG
|
# if necessary, EN is inverted, since the given ICG
|
||||||
|
@ -193,4 +193,98 @@ select -assert-count 1 t:\\pdk_icg
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
# TODO test -tie_lo
|
design -load before
|
||||||
|
clockgate -liberty clockgate.lib
|
||||||
|
|
||||||
|
# rising edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_small
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_small
|
||||||
|
|
||||||
|
select -module dffe_10 -assert-count 1 t:\\pos_small
|
||||||
|
select -module dffe_11 -assert-count 1 t:\\pos_small
|
||||||
|
|
||||||
|
# falling edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 1 t:\\neg_small
|
||||||
|
select -module dffe_01 -assert-count 1 t:\\neg_small
|
||||||
|
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_small
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_small
|
||||||
|
|
||||||
|
# and nothing else
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
|
||||||
|
# if necessary, EN is inverted, since the given ICG
|
||||||
|
# is assumed to have an active-high EN
|
||||||
|
select -module dffe_10 -assert-count 1 t:\$_NOT_
|
||||||
|
select -module dffe_11 -assert-count 0 t:\$_NOT_
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# test multiple liberty files to behave the same way
|
||||||
|
design -load before
|
||||||
|
clockgate -liberty clockgate_pos.lib -liberty clockgate_neg.lib
|
||||||
|
|
||||||
|
# rising edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_small
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_small
|
||||||
|
|
||||||
|
select -module dffe_10 -assert-count 1 t:\\pos_small
|
||||||
|
select -module dffe_11 -assert-count 1 t:\\pos_small
|
||||||
|
|
||||||
|
# falling edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 1 t:\\neg_small
|
||||||
|
select -module dffe_01 -assert-count 1 t:\\neg_small
|
||||||
|
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_small
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_small
|
||||||
|
|
||||||
|
# and nothing else
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\pos_big
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\pos_small_tielo
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_big
|
||||||
|
select -module dffe_00 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_01 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_10 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
select -module dffe_11 -assert-count 0 t:\\neg_small_tielo
|
||||||
|
|
||||||
|
# if necessary, EN is inverted, since the given ICG
|
||||||
|
# is assumed to have an active-high EN
|
||||||
|
select -module dffe_10 -assert-count 1 t:\$_NOT_
|
||||||
|
select -module dffe_11 -assert-count 0 t:\$_NOT_
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
design -load before
|
||||||
|
clockgate -liberty clockgate.lib -dont_use pos_small -dont_use neg_small
|
||||||
|
|
||||||
|
# rising edge ICGs
|
||||||
|
select -module dffe_10 -assert-count 1 t:\\pos_big
|
||||||
|
select -module dffe_11 -assert-count 1 t:\\pos_big
|
||||||
|
|
||||||
|
# falling edge ICGs
|
||||||
|
select -module dffe_00 -assert-count 1 t:\\neg_big
|
||||||
|
select -module dffe_01 -assert-count 1 t:\\neg_big
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue