Compare commits
121 commits
Author | SHA1 | Date | |
---|---|---|---|
422ffd5c06 | |||
9eca3671ab | |||
a3f19f047c | |||
94c76f85da | |||
b8d531957d | |||
7e08e37961 | |||
19f36271c2 | |||
44b47b57e3 | |||
![]() |
7481ba4750 | ||
![]() |
18ea65ef04 | ||
![]() |
fe29869ec5 | ||
![]() |
e54c355b41 | ||
![]() |
45e10c1c89 | ||
![]() |
49b8160488 | ||
![]() |
b0a430f601 | ||
![]() |
b54972c112 | ||
![]() |
fea528280b | ||
![]() |
87fe8ab3f2 | ||
![]() |
6781543244 | ||
![]() |
78f65f89ff | ||
![]() |
b7cfb7dbd2 | ||
![]() |
8953a55cd8 | ||
![]() |
8012de40b9 | ||
![]() |
2d32c6c4f6 | ||
![]() |
0cac95ea94 | ||
![]() |
81a9ee2360 | ||
![]() |
b9ad91b93e | ||
![]() |
080004b19a | ||
![]() |
ed812ea39c | ||
![]() |
dfb461fe52 | ||
![]() |
81bb952e5d | ||
![]() |
f0df7dd796 | ||
![]() |
a7fb64efe6 | ||
![]() |
6b2c23c721 | ||
![]() |
7da7a6d1df | ||
![]() |
2198948398 | ||
![]() |
4f5efc3416 | ||
![]() |
4cf3170194 | ||
![]() |
5ffede5c0e | ||
![]() |
9f69a70d74 | ||
![]() |
33a22f8768 | ||
![]() |
a0dff87a57 | ||
![]() |
f144adec58 | ||
![]() |
f31e6a7174 | ||
![]() |
3d0e51f813 | ||
![]() |
ada98844b9 | ||
![]() |
6b526e9382 | ||
![]() |
638f3e3b12 | ||
![]() |
073e8df9f1 | ||
![]() |
d4a05b499e | ||
![]() |
eb80ec84aa | ||
![]() |
fcd40fd41e | ||
![]() |
de1d81511a | ||
![]() |
7cdba8432c | ||
![]() |
3886669ab6 | ||
![]() |
bea6e2f11f | ||
![]() |
3690aa556c | ||
![]() |
3491d33863 | ||
![]() |
ea787e6be3 | ||
![]() |
58da621ac3 | ||
![]() |
262f8f913c | ||
![]() |
c77e6e6114 | ||
![]() |
00761de1b7 | ||
![]() |
01d8278e53 | ||
![]() |
a61c88f122 | ||
![]() |
8a717ae1dc | ||
![]() |
71c47f13ed | ||
![]() |
5c96982522 | ||
![]() |
c3c2983d12 | ||
![]() |
b932e2355d | ||
![]() |
8f3d1f8fcf | ||
![]() |
c53a33143e | ||
![]() |
797c03997e | ||
![]() |
8767cdcac9 | ||
![]() |
981f014301 | ||
![]() |
e6ab00d419 | ||
![]() |
3f2f64f414 | ||
![]() |
e0152319f5 | ||
![]() |
a44cc7a3d1 | ||
![]() |
37760541bd | ||
![]() |
8a90e61c1a | ||
![]() |
105b6374ae | ||
![]() |
88b9733253 | ||
![]() |
52c243cf05 | ||
![]() |
5fa1fa1e6f | ||
![]() |
c1f762ca56 | ||
![]() |
b1cdf772eb | ||
![]() |
ac7a175a3c | ||
![]() |
df2e5aad6f | ||
![]() |
ecdc22b06c | ||
![]() |
c7f6fb6e17 | ||
![]() |
c17d98f55c | ||
![]() |
5c2c78e2dd | ||
![]() |
e444e59963 | ||
![]() |
73653de5ff | ||
![]() |
f257ccf22e | ||
![]() |
277f478572 | ||
![]() |
3b73d3f140 | ||
![]() |
3c86da8000 | ||
![]() |
55785a96eb | ||
![]() |
751ad3c618 | ||
![]() |
487b19b4fa | ||
![]() |
f77dc3bacc | ||
![]() |
e01382739d | ||
![]() |
c051115e03 | ||
![]() |
57966a619f | ||
![]() |
ce132cf652 | ||
![]() |
70d7a02cae | ||
![]() |
a926a6afc2 | ||
![]() |
a2206180d6 | ||
![]() |
d4e1592609 | ||
![]() |
1827a48964 | ||
![]() |
617693e691 | ||
![]() |
e9d73d2ee0 | ||
![]() |
97ac77513f | ||
![]() |
84badc97b3 | ||
![]() |
ef603c6fe1 | ||
![]() |
914aa8a5d3 | ||
![]() |
2874914bcb | ||
![]() |
3db2ac4e00 | ||
![]() |
e3330fb98f |
67 changed files with 2858 additions and 397 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
*.o
|
*.o
|
||||||
*.d
|
*.d
|
||||||
.*.swp
|
.*.swp
|
||||||
|
*.gch
|
||||||
/.cproject
|
/.cproject
|
||||||
/.project
|
/.project
|
||||||
/.settings
|
/.settings
|
||||||
|
@ -27,3 +28,5 @@
|
||||||
/yosys-win32-vcxsrc-*
|
/yosys-win32-vcxsrc-*
|
||||||
/yosysjs-*
|
/yosysjs-*
|
||||||
/libyosys.so
|
/libyosys.so
|
||||||
|
/tests/unit/bintest/
|
||||||
|
/tests/unit/objtest/
|
||||||
|
|
69
CodingReadme
69
CodingReadme
|
@ -411,3 +411,72 @@ Updating the website:
|
||||||
git commit -am update
|
git commit -am update
|
||||||
make push
|
make push
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
79
Makefile
79
Makefile
|
@ -18,6 +18,7 @@ ENABLE_LIBYOSYS := 0
|
||||||
# other configuration flags
|
# other configuration flags
|
||||||
ENABLE_GPROF := 0
|
ENABLE_GPROF := 0
|
||||||
ENABLE_NDEBUG := 0
|
ENABLE_NDEBUG := 0
|
||||||
|
LINK_CURSES := 0
|
||||||
|
|
||||||
# clang sanitizers
|
# clang sanitizers
|
||||||
SANITIZER =
|
SANITIZER =
|
||||||
|
@ -44,6 +45,9 @@ TARGETS = yosys$(EXE) yosys-config
|
||||||
PRETTY = 1
|
PRETTY = 1
|
||||||
SMALL = 0
|
SMALL = 0
|
||||||
|
|
||||||
|
# Unit test
|
||||||
|
UNITESTPATH := tests/unit
|
||||||
|
|
||||||
all: top-all
|
all: top-all
|
||||||
|
|
||||||
YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST)))
|
YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST)))
|
||||||
|
@ -53,26 +57,42 @@ CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PRE
|
||||||
LDFLAGS += -L$(LIBDIR)
|
LDFLAGS += -L$(LIBDIR)
|
||||||
LDLIBS = -lstdc++ -lm
|
LDLIBS = -lstdc++ -lm
|
||||||
|
|
||||||
PKG_CONFIG = pkg-config
|
PKG_CONFIG ?= pkg-config
|
||||||
SED = sed
|
SED ?= sed
|
||||||
BISON = bison
|
BISON ?= bison
|
||||||
|
|
||||||
ifeq (Darwin,$(findstring Darwin,$(shell uname)))
|
ifeq (Darwin,$(findstring Darwin,$(shell uname)))
|
||||||
# add macports/homebrew include and library path to search directories, don't use '-rdynamic' and '-lrt':
|
|
||||||
CXXFLAGS += -I/opt/local/include -I/usr/local/opt/readline/include
|
# homebrew search paths
|
||||||
LDFLAGS += -L/opt/local/lib -L/usr/local/opt/readline/lib
|
ifneq ($(shell which brew),)
|
||||||
# add homebrew's libffi include and library path
|
BREW_PREFIX := $(shell brew --prefix)/opt
|
||||||
CXXFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --cflags libffi)
|
|
||||||
LDFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --libs libffi)
|
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
|
||||||
# use bison installed by homebrew if available
|
LDFLAGS += -L$(BREW_PREFIX)/readline/lib
|
||||||
BISON = $(shell (brew list bison | grep -m1 "bin/bison") || echo bison)
|
|
||||||
SED = sed
|
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
|
||||||
else
|
PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
|
||||||
LDFLAGS += -rdynamic
|
|
||||||
LDLIBS += -lrt
|
export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
|
||||||
|
|
||||||
|
# macports search paths
|
||||||
|
else ifneq ($(shell which port),)
|
||||||
|
PORT_PREFIX := $(patsubst %/bin/port,%,$(shell which port))
|
||||||
|
|
||||||
|
CXXFLAGS += -I$(PORT_PREFIX)/include
|
||||||
|
LDFLAGS += -L$(PORT_PREFIX)/lib
|
||||||
|
|
||||||
|
PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH)
|
||||||
|
|
||||||
|
export PATH := $(PORT_PREFIX)/bin:$(PATH)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
YOSYS_VER := 0.7
|
else
|
||||||
|
LDFLAGS += -rdynamic
|
||||||
|
LDLIBS += -lrt
|
||||||
|
endif
|
||||||
|
|
||||||
|
YOSYS_VER := 0.7+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 61f6811.. | wc -l; })
|
||||||
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
||||||
OBJS = kernel/version_$(GIT_REV).o
|
OBJS = kernel/version_$(GIT_REV).o
|
||||||
|
|
||||||
|
@ -82,7 +102,7 @@ OBJS = kernel/version_$(GIT_REV).o
|
||||||
# is just a symlink to your actual ABC working directory, as 'make mrproper'
|
# is just a symlink to your actual ABC working directory, as 'make mrproper'
|
||||||
# will remove the 'abc' directory and you do not want to accidentally
|
# will remove the 'abc' directory and you do not want to accidentally
|
||||||
# delete your work on ABC..
|
# delete your work on ABC..
|
||||||
ABCREV = eb6eca6807cc
|
ABCREV = f8cadfe3861f
|
||||||
ABCPULL = 1
|
ABCPULL = 1
|
||||||
ABCURL ?= https://bitbucket.org/alanmi/abc
|
ABCURL ?= https://bitbucket.org/alanmi/abc
|
||||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)"
|
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)"
|
||||||
|
@ -170,7 +190,7 @@ CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE
|
||||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||||
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
||||||
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
||||||
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
|
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)"
|
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)"
|
||||||
EXE = .exe
|
EXE = .exe
|
||||||
|
|
||||||
|
@ -181,7 +201,7 @@ CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||||
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
||||||
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
||||||
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
|
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="$(CXX)" CXX="$(CXX)"
|
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="$(CXX)" CXX="$(CXX)"
|
||||||
EXE = .exe
|
EXE = .exe
|
||||||
|
|
||||||
|
@ -196,21 +216,26 @@ endif
|
||||||
ifeq ($(ENABLE_READLINE),1)
|
ifeq ($(ENABLE_READLINE),1)
|
||||||
CXXFLAGS += -DYOSYS_ENABLE_READLINE
|
CXXFLAGS += -DYOSYS_ENABLE_READLINE
|
||||||
LDLIBS += -lreadline
|
LDLIBS += -lreadline
|
||||||
|
ifeq ($(LINK_CURSES),1)
|
||||||
|
LDLIBS += -lcurses
|
||||||
|
ABCMKARGS += "ABC_READLINE_LIBRARIES=-lcurses -lreadline"
|
||||||
|
endif
|
||||||
ifeq ($(CONFIG),mxe)
|
ifeq ($(CONFIG),mxe)
|
||||||
LDLIBS += -lpdcurses
|
LDLIBS += -lpdcurses
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_PLUGINS),1)
|
ifeq ($(ENABLE_PLUGINS),1)
|
||||||
CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell $(PKG_CONFIG) --silence-errors --cflags libffi)
|
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS
|
||||||
LDLIBS += $(shell $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl
|
LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_TCL),1)
|
ifeq ($(ENABLE_TCL),1)
|
||||||
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
|
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
|
||||||
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
|
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
|
||||||
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
|
|
||||||
LDLIBS += -l$(TCL_VERSION)
|
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
|
||||||
|
LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_GPROF),1)
|
ifeq ($(ENABLE_GPROF),1)
|
||||||
|
@ -442,6 +467,14 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
@echo " Passed \"make vloghtb\"."
|
@echo " Passed \"make vloghtb\"."
|
||||||
@echo ""
|
@echo ""
|
||||||
|
|
||||||
|
# Unit test
|
||||||
|
unit-test: libyosys.so
|
||||||
|
@$(MAKE) -C $(UNITESTPATH) CXX="$(CXX)" CPPFLAGS="$(CPPFLAGS)" \
|
||||||
|
CXXFLAGS="$(CXXFLAGS)" LDLIBS="$(LDLIBS)" ROOTPATH="$(CURDIR)"
|
||||||
|
|
||||||
|
clean-unit-test:
|
||||||
|
@$(MAKE) -C $(UNITESTPATH) clean
|
||||||
|
|
||||||
install: $(TARGETS) $(EXTRA_TARGETS)
|
install: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
|
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
|
||||||
$(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(BINDIR)
|
$(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(BINDIR)
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
|
```
|
||||||
/-----------------------------------------------------------------------------\
|
|
||||||
| |
|
|
||||||
| yosys -- Yosys Open SYnthesis Suite |
|
|
||||||
| |
|
|
||||||
| Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> |
|
|
||||||
| |
|
|
||||||
| 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
|
||||||
|
|
||||||
|
Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at>
|
||||||
|
|
||||||
|
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
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
This is a framework for RTL synthesis tools. It currently has
|
This is a framework for RTL synthesis tools. It currently has
|
||||||
|
@ -41,17 +38,16 @@ Web Site
|
||||||
========
|
========
|
||||||
|
|
||||||
More information and documentation can be found on the Yosys web site:
|
More information and documentation can be found on the Yosys web site:
|
||||||
|
http://www.clifford.at/yosys/
|
||||||
|
|
||||||
http://www.clifford.at/yosys/
|
Setup
|
||||||
|
======
|
||||||
|
|
||||||
Getting Started
|
|
||||||
===============
|
|
||||||
|
|
||||||
You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
|
You need a C++ compiler with C++11 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).
|
||||||
Xdot (graphviz) is used by the "show" command in yosys to display schematics.
|
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
|
||||||
|
|
||||||
For example on Ubuntu Linux 16.04 LTS the following commands will install all
|
For example on Ubuntu Linux 16.04 LTS the following commands will install all
|
||||||
prerequisites for building yosys:
|
prerequisites for building yosys:
|
||||||
|
|
||||||
|
@ -59,11 +55,16 @@ prerequisites for building yosys:
|
||||||
libreadline-dev gawk tcl-dev libffi-dev git mercurial \
|
libreadline-dev gawk tcl-dev libffi-dev git mercurial \
|
||||||
graphviz xdot pkg-config python3
|
graphviz xdot pkg-config python3
|
||||||
|
|
||||||
|
Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
|
||||||
|
|
||||||
|
$ brew install bison flex gawk libffi \
|
||||||
|
git mercurial graphviz pkg-config python3
|
||||||
|
$ sudo port install bison flex readline gawk libffi \
|
||||||
|
git mercurial graphviz pkgconfig python36
|
||||||
|
|
||||||
There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
|
There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
|
||||||
as a source distribution for Visual Studio. Visit the Yosys download page for
|
as a source distribution for Visual Studio. Visit the Yosys download page for
|
||||||
more information:
|
more information: http://www.clifford.at/yosys/download.html
|
||||||
|
|
||||||
http://www.clifford.at/yosys/download.html
|
|
||||||
|
|
||||||
To configure the build system to use a specific compiler, use one of
|
To configure the build system to use a specific compiler, use one of
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ For other compilers and build configurations it might be
|
||||||
necessary to make some changes to the config section of the
|
necessary to make some changes to the config section of the
|
||||||
Makefile.
|
Makefile.
|
||||||
|
|
||||||
$ vi Makefile ..or..
|
$ vi Makefile # ..or..
|
||||||
$ vi Makefile.conf
|
$ vi Makefile.conf
|
||||||
|
|
||||||
To build Yosys simply type 'make' in this directory.
|
To build Yosys simply type 'make' in this directory.
|
||||||
|
@ -86,6 +87,9 @@ To build Yosys simply type 'make' in this directory.
|
||||||
Note that this also downloads, builds and installs ABC (using yosys-abc
|
Note that this also downloads, builds and installs ABC (using yosys-abc
|
||||||
as executable name).
|
as executable name).
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
Yosys can be used with the interactive command shell, with
|
Yosys can be used with the interactive command shell, with
|
||||||
synthesis scripts or with command line arguments. Let's perform
|
synthesis scripts or with command line arguments. Let's perform
|
||||||
a simple synthesis job using the interactive command shell:
|
a simple synthesis job using the interactive command shell:
|
||||||
|
@ -93,8 +97,8 @@ a simple synthesis job using the interactive command shell:
|
||||||
$ ./yosys
|
$ ./yosys
|
||||||
yosys>
|
yosys>
|
||||||
|
|
||||||
the command "help" can be used to print a list of all available
|
the command ``help`` can be used to print a list of all available
|
||||||
commands and "help <command>" to print details on the specified command:
|
commands and ``help <command>`` to print details on the specified command:
|
||||||
|
|
||||||
yosys> help help
|
yosys> help help
|
||||||
|
|
||||||
|
@ -110,16 +114,16 @@ elaborate design hierarchy:
|
||||||
|
|
||||||
yosys> hierarchy
|
yosys> hierarchy
|
||||||
|
|
||||||
convert processes ("always" blocks) to netlist elements and perform
|
convert processes (``always`` blocks) to netlist elements and perform
|
||||||
some simple optimizations:
|
some simple optimizations:
|
||||||
|
|
||||||
yosys> proc; opt
|
yosys> proc; opt
|
||||||
|
|
||||||
display design netlist using xdot:
|
display design netlist using ``xdot``:
|
||||||
|
|
||||||
yosys> show
|
yosys> show
|
||||||
|
|
||||||
the same thing using 'gv' as postscript viewer:
|
the same thing using ``gv`` as postscript viewer:
|
||||||
|
|
||||||
yosys> show -format ps -viewer gv
|
yosys> show -format ps -viewer gv
|
||||||
|
|
||||||
|
@ -171,8 +175,8 @@ The following very basic synthesis script should work well with all designs:
|
||||||
techmap; opt
|
techmap; opt
|
||||||
|
|
||||||
If ABC is enabled in the Yosys build configuration and a cell library is given
|
If ABC is enabled in the Yosys build configuration and a cell library is given
|
||||||
in the liberty file mycells.lib, the following synthesis script will synthesize
|
in the liberty file ``mycells.lib``, the following synthesis script will
|
||||||
for the given cell library:
|
synthesize for the given cell library:
|
||||||
|
|
||||||
# the high-level stuff
|
# the high-level stuff
|
||||||
hierarchy; proc; fsm; opt; memory; opt
|
hierarchy; proc; fsm; opt; memory; opt
|
||||||
|
@ -190,16 +194,17 @@ for the given cell library:
|
||||||
clean
|
clean
|
||||||
|
|
||||||
If you do not have a liberty file but want to test this synthesis script,
|
If you do not have a liberty file but want to test this synthesis script,
|
||||||
you can use the file examples/cmos/cmos_cells.lib from the yosys sources.
|
you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources.
|
||||||
|
|
||||||
Liberty file downloads for and information about free and open ASIC standard
|
Liberty file downloads for and information about free and open ASIC standard
|
||||||
cell libraries can be found here:
|
cell libraries can be found here:
|
||||||
|
|
||||||
http://www.vlsitechnology.org/html/libraries.html
|
- http://www.vlsitechnology.org/html/libraries.html
|
||||||
http://www.vlsitechnology.org/synopsys/vsclib013.lib
|
- http://www.vlsitechnology.org/synopsys/vsclib013.lib
|
||||||
|
|
||||||
The command "synth" provides a good default synthesis script (see "help synth").
|
The command ``synth`` provides a good default synthesis script (see
|
||||||
If possible a synthesis script should borrow from "synth". For example:
|
``help synth``). If possible a synthesis script should borrow from ``synth``.
|
||||||
|
For example:
|
||||||
|
|
||||||
# the high-level stuff
|
# the high-level stuff
|
||||||
hierarchy
|
hierarchy
|
||||||
|
@ -224,11 +229,11 @@ for them:
|
||||||
- Non-synthesizable language features as defined in
|
- Non-synthesizable language features as defined in
|
||||||
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
|
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
|
||||||
|
|
||||||
- The "tri", "triand", "trior", "wand" and "wor" net types
|
- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
|
||||||
|
|
||||||
- The "config" keyword and library map files
|
- The ``config`` keyword and library map files
|
||||||
|
|
||||||
- The "disable", "primitive" and "specify" statements
|
- The ``disable``, ``primitive`` and ``specify`` statements
|
||||||
|
|
||||||
- Latched logic (is synthesized as logic with feedback loops)
|
- Latched logic (is synthesized as logic with feedback loops)
|
||||||
|
|
||||||
|
@ -236,83 +241,83 @@ for them:
|
||||||
Verilog Attributes and non-standard features
|
Verilog Attributes and non-standard features
|
||||||
============================================
|
============================================
|
||||||
|
|
||||||
- The 'full_case' attribute on case statements is supported
|
- The ``full_case`` attribute on case statements is supported
|
||||||
(also the non-standard "// synopsys full_case" directive)
|
(also the non-standard ``// synopsys full_case`` directive)
|
||||||
|
|
||||||
- The 'parallel_case' attribute on case statements is supported
|
- The ``parallel_case`` attribute on case statements is supported
|
||||||
(also the non-standard "// synopsys parallel_case" directive)
|
(also the non-standard ``// synopsys parallel_case`` directive)
|
||||||
|
|
||||||
- The "// synopsys translate_off" and "// synopsys translate_on"
|
- The ``// synopsys translate_off`` and ``// synopsys translate_on``
|
||||||
directives are also supported (but the use of `ifdef .. `endif
|
directives are also supported (but the use of ``` `ifdef .. `endif ```
|
||||||
is strongly recommended instead).
|
is strongly recommended instead).
|
||||||
|
|
||||||
- The "nomem2reg" attribute on modules or arrays prohibits the
|
- The ``nomem2reg`` attribute on modules or arrays prohibits the
|
||||||
automatic early conversion of arrays to separate registers. This
|
automatic early conversion of arrays to separate registers. This
|
||||||
is potentially dangerous. Usually the front-end has good reasons
|
is potentially dangerous. Usually the front-end has good reasons
|
||||||
for converting an array to a list of registers. Prohibiting this
|
for converting an array to a list of registers. Prohibiting this
|
||||||
step will likely result in incorrect synthesis results.
|
step will likely result in incorrect synthesis results.
|
||||||
|
|
||||||
- The "mem2reg" attribute on modules or arrays forces the early
|
- The ``mem2reg`` attribute on modules or arrays forces the early
|
||||||
conversion of arrays to separate registers.
|
conversion of arrays to separate registers.
|
||||||
|
|
||||||
- The "nomeminit" attribute on modules or arrays prohibits the
|
- The ``nomeminit`` attribute on modules or arrays prohibits the
|
||||||
creation of initialized memories. This effectively puts "mem2reg"
|
creation of initialized memories. This effectively puts ``mem2reg``
|
||||||
on all memories that are written to in an "initial" block and
|
on all memories that are written to in an ``initial`` block and
|
||||||
are not ROMs.
|
are not ROMs.
|
||||||
|
|
||||||
- The "nolatches" attribute on modules or always-blocks
|
- The ``nolatches`` attribute on modules or always-blocks
|
||||||
prohibits the generation of logic-loops for latches. Instead
|
prohibits the generation of logic-loops for latches. Instead
|
||||||
all not explicitly assigned values default to x-bits. This does
|
all not explicitly assigned values default to x-bits. This does
|
||||||
not affect clocked storage elements such as flip-flops.
|
not affect clocked storage elements such as flip-flops.
|
||||||
|
|
||||||
- The "nosync" attribute on registers prohibits the generation of a
|
- The ``nosync`` attribute on registers prohibits the generation of a
|
||||||
storage element. The register itself will always have all bits set
|
storage element. The register itself will always have all bits set
|
||||||
to 'x' (undefined). The variable may only be used as blocking assigned
|
to 'x' (undefined). The variable may only be used as blocking assigned
|
||||||
temporary variable within an always block. This is mostly used internally
|
temporary variable within an always block. This is mostly used internally
|
||||||
by yosys to synthesize Verilog functions and access arrays.
|
by yosys to synthesize Verilog functions and access arrays.
|
||||||
|
|
||||||
- The "onehot" attribute on wires mark them as onehot state register. This
|
- The ``onehot`` attribute on wires mark them as onehot state register. This
|
||||||
is used for example for memory port sharing and set by the fsm_map pass.
|
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
|
- 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
|
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
|
on the internal configuration. This modules are only used by the synthesis
|
||||||
passes to identify input and output ports of cells. The Verilog backend
|
passes to identify input and output ports of cells. The Verilog backend
|
||||||
also does not output blackbox modules on default.
|
also does not output blackbox modules on default.
|
||||||
|
|
||||||
- The "keep" attribute on cells and wires is used to mark objects that should
|
- 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
|
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.
|
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
|
Setting the ``keep`` attribute on a module has the same effect as setting it
|
||||||
on all instances of the module.
|
on all instances of the module.
|
||||||
|
|
||||||
- The "keep_hierarchy" attribute on cells and modules keeps the "flatten"
|
- The ``keep_hierarchy`` attribute on cells and modules keeps the ``flatten``
|
||||||
command from flattening the indicated cells and modules.
|
command from flattening the indicated cells and modules.
|
||||||
|
|
||||||
- The "init" attribute on wires is set by the frontend when a register is
|
- 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
|
initialized "FPGA-style" with ``reg foo = val``. It can be used during
|
||||||
to add the necessary reset logic.
|
synthesis to add the necessary reset logic.
|
||||||
|
|
||||||
- The "top" attribute on a module marks this module as the top of the
|
- The ``top`` attribute on a module marks this module as the top of the
|
||||||
design hierarchy. The "hierarchy" command sets this attribute when called
|
design hierarchy. The ``hierarchy`` command sets this attribute when called
|
||||||
with "-top". Other commands, such as "flatten" and various backends
|
with ``-top``. Other commands, such as ``flatten`` and various backends
|
||||||
use this attribute to determine the top module.
|
use this attribute to determine the top module.
|
||||||
|
|
||||||
- The "src" attribute is set on cells and wires created by to the string
|
- 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
|
``<hdl-file-name>:<line-number>`` by the HDL front-end and is then carried
|
||||||
through the synthesis. When entities are combined, a new |-separated
|
through the synthesis. When entities are combined, a new |-separated
|
||||||
string is created that contains all the string from the original entities.
|
string is created that contains all the string from the original entities.
|
||||||
|
|
||||||
- In addition to the (* ... *) attribute syntax, yosys supports
|
- In addition to the ``(* ... *)`` attribute syntax, yosys supports
|
||||||
the non-standard {* ... *} attribute syntax to set default attributes
|
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
||||||
for everything that comes after the {* ... *} statement. (Reset
|
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||||
by adding an empty {* *} statement.)
|
by adding an empty ``{* *}`` statement.)
|
||||||
|
|
||||||
- In module parameter and port declarations, and cell port and parameter
|
- In module parameter and port declarations, and cell port and parameter
|
||||||
lists, a trailing comma is ignored. This simplifies writing verilog code
|
lists, a trailing comma is ignored. This simplifies writing verilog code
|
||||||
generators a bit in some cases.
|
generators a bit in some cases.
|
||||||
|
|
||||||
- Modules can be declared with "module mod_name(...);" (with three dots
|
- Modules can be declared with ``module mod_name(...);`` (with three dots
|
||||||
instead of a list of module ports). With this syntax it is sufficient
|
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
|
to simply declare a module port as 'input' or 'output' in the module
|
||||||
body.
|
body.
|
||||||
|
@ -326,7 +331,7 @@ Verilog Attributes and non-standard features
|
||||||
assign b = 42;
|
assign b = 42;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
- The attribute "via_celltype" can be used to implement a Verilog task or
|
- 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
|
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
|
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.
|
be specified by appending it to the cell type separated by a whitespace.
|
||||||
|
@ -354,9 +359,9 @@ Verilog Attributes and non-standard features
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
- A limited subset of DPI-C functions is supported. The plugin mechanism
|
- A limited subset of DPI-C functions is supported. The plugin mechanism
|
||||||
(see "help plugin") can be used to load .so files with implementations
|
(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
|
of DPI-C routines. As a non-standard extension it is possible to specify
|
||||||
a plugin alias using the "<alias>:" syntax. for example:
|
a plugin alias using the ``<alias>:`` syntax. For example:
|
||||||
|
|
||||||
module dpitest;
|
module dpitest;
|
||||||
import "DPI-C" function foo:round = real my_round (real);
|
import "DPI-C" function foo:round = real my_round (real);
|
||||||
|
@ -365,11 +370,11 @@ Verilog Attributes and non-standard features
|
||||||
|
|
||||||
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
|
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
|
||||||
|
|
||||||
- Sized constants (the syntax <size>'s?[bodh]<value>) support constant
|
- Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant
|
||||||
expressions as <size>. If the expression is not a simple identifier, it
|
expressions as <size>. If the expression is not a simple identifier, it
|
||||||
must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010
|
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
|
||||||
|
|
||||||
- The system tasks $finish and $display are supported in initial blocks
|
- The system tasks ``$finish`` and ``$display`` are supported in initial blocks
|
||||||
in an unconditional context (only if/case statements on parameters
|
in an unconditional context (only if/case statements on parameters
|
||||||
and constant values). The intended use for this is synthesis-time DRC.
|
and constant values). The intended use for this is synthesis-time DRC.
|
||||||
|
|
||||||
|
@ -377,42 +382,42 @@ Verilog Attributes and non-standard features
|
||||||
Non-standard or SystemVerilog features for formal verification
|
Non-standard or SystemVerilog features for formal verification
|
||||||
==============================================================
|
==============================================================
|
||||||
|
|
||||||
- Support for "assert", "assume", and "restrict" is enabled when
|
- Support for ``assert``, ``assume``, and ``restrict`` is enabled when
|
||||||
read_verilog is called with -formal.
|
``read_verilog`` is called with ``-formal``.
|
||||||
|
|
||||||
- The system task $initstate evaluates to 1 in the initial state and
|
- The system task ``$initstate`` evaluates to 1 in the initial state and
|
||||||
to 0 otherwise.
|
to 0 otherwise.
|
||||||
|
|
||||||
- The system task $anyconst evaluates to any constant value.
|
- The system task ``$anyconst`` evaluates to any constant value.
|
||||||
|
|
||||||
- The system task $anyseq evaluates to any value, possibly a different
|
- The system task ``$anyseq`` evaluates to any value, possibly a different
|
||||||
value in each cycle.
|
value in each cycle.
|
||||||
|
|
||||||
- The SystemVerilog tasks $past, $stable, $rose and $fell are supported
|
- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
|
||||||
in any clocked block.
|
supported in any clocked block.
|
||||||
|
|
||||||
- The syntax @($global_clock) can be used to create FFs that have no
|
- The syntax ``@($global_clock)`` can be used to create FFs that have no
|
||||||
explicit clock input ($ff cells).
|
explicit clock input ($ff cells).
|
||||||
|
|
||||||
|
|
||||||
Supported features from SystemVerilog
|
Supported features from SystemVerilog
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
When read_verilog is called with -sv, it accepts some language features
|
When ``read_verilog`` is called with ``-sv``, it accepts some language features
|
||||||
from SystemVerilog:
|
from SystemVerilog:
|
||||||
|
|
||||||
- The "assert" statement from SystemVerilog is supported in its most basic
|
- The ``assert`` statement from SystemVerilog is supported in its most basic
|
||||||
form. In module context: "assert property (<expression>);" and within an
|
form. In module context: ``assert property (<expression>);`` and within an
|
||||||
always block: "assert(<expression>);". It is transformed to a $assert cell.
|
always block: ``assert(<expression>);``. It is transformed to a $assert cell.
|
||||||
|
|
||||||
- The "assume" and "restrict" statements from SystemVerilog are also
|
- The ``assume`` and ``restrict`` statements from SystemVerilog are also
|
||||||
supported. The same limitations as with the "assert" statement apply.
|
supported. The same limitations as with the ``assert`` statement apply.
|
||||||
|
|
||||||
- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
|
- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic``
|
||||||
"bit" are supported.
|
and ``bit`` are supported.
|
||||||
|
|
||||||
- SystemVerilog packages are supported. Once a SystemVerilog file is read
|
- SystemVerilog packages are supported. Once a SystemVerilog file is read
|
||||||
into a design with "read_verilog", all its packages are available to
|
into a design with ``read_verilog``, all its packages are available to
|
||||||
SystemVerilog files being read into the same design afterwards.
|
SystemVerilog files being read into the same design afterwards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -448,4 +453,3 @@ Notes:
|
||||||
- To run `make manual` you need to have installed yosys with `make install`,
|
- To run `make manual` you need to have installed yosys with `make install`,
|
||||||
otherwise it will fail on finding `kernel/yosys.h` while building
|
otherwise it will fail on finding `kernel/yosys.h` while building
|
||||||
`PRESENTATION_Prog`.
|
`PRESENTATION_Prog`.
|
||||||
|
|
3
backends/aiger/Makefile.inc
Normal file
3
backends/aiger/Makefile.inc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
OBJS += backends/aiger/aiger.o
|
||||||
|
|
552
backends/aiger/aiger.cc
Normal file
552
backends/aiger/aiger.cc
Normal file
|
@ -0,0 +1,552 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* 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/sigtools.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
void aiger_encode(std::ostream &f, int x)
|
||||||
|
{
|
||||||
|
log_assert(x >= 0);
|
||||||
|
|
||||||
|
while (x & ~0x7f) {
|
||||||
|
f.put((x & 0x7f) | 0x80);
|
||||||
|
x = x >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.put(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AigerWriter
|
||||||
|
{
|
||||||
|
Module *module;
|
||||||
|
bool zinit_mode;
|
||||||
|
SigMap sigmap;
|
||||||
|
|
||||||
|
dict<SigBit, bool> init_map;
|
||||||
|
pool<SigBit> input_bits, output_bits;
|
||||||
|
dict<SigBit, SigBit> not_map, ff_map;
|
||||||
|
dict<SigBit, pair<SigBit, SigBit>> and_map;
|
||||||
|
vector<pair<SigBit, SigBit>> asserts, assumes;
|
||||||
|
pool<SigBit> initstate_bits;
|
||||||
|
|
||||||
|
vector<pair<int, int>> aig_gates;
|
||||||
|
vector<int> aig_latchin, aig_latchinit, aig_outputs;
|
||||||
|
int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0, aig_b = 0, aig_c = 0;
|
||||||
|
|
||||||
|
dict<SigBit, int> aig_map;
|
||||||
|
dict<SigBit, int> ordered_outputs;
|
||||||
|
dict<SigBit, int> ordered_latches;
|
||||||
|
|
||||||
|
dict<SigBit, int> init_inputs;
|
||||||
|
int initstate_ff = 0;
|
||||||
|
|
||||||
|
int mkgate(int a0, int a1)
|
||||||
|
{
|
||||||
|
aig_m++, aig_a++;
|
||||||
|
aig_gates.push_back(a0 > a1 ? make_pair(a0, a1) : make_pair(a1, a0));
|
||||||
|
return 2*aig_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bit2aig(SigBit bit)
|
||||||
|
{
|
||||||
|
if (aig_map.count(bit) == 0)
|
||||||
|
{
|
||||||
|
aig_map[bit] = -1;
|
||||||
|
|
||||||
|
if (initstate_bits.count(bit)) {
|
||||||
|
log_assert(initstate_ff > 0);
|
||||||
|
aig_map[bit] = initstate_ff;
|
||||||
|
} else
|
||||||
|
if (not_map.count(bit)) {
|
||||||
|
int a = bit2aig(not_map.at(bit)) ^ 1;
|
||||||
|
aig_map[bit] = a;
|
||||||
|
} else
|
||||||
|
if (and_map.count(bit)) {
|
||||||
|
auto args = and_map.at(bit);
|
||||||
|
int a0 = bit2aig(args.first);
|
||||||
|
int a1 = bit2aig(args.second);
|
||||||
|
aig_map[bit] = mkgate(a0, a1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert(aig_map.at(bit) >= 0);
|
||||||
|
return aig_map.at(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
AigerWriter(Module *module, bool zinit_mode) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
||||||
|
{
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
{
|
||||||
|
if (wire->attributes.count("\\init")) {
|
||||||
|
SigSpec initsig = sigmap(wire);
|
||||||
|
Const initval = wire->attributes.at("\\init");
|
||||||
|
for (int i = 0; i < GetSize(wire) && i < GetSize(initval); i++)
|
||||||
|
if (initval[i] == State::S0 || initval[i] == State::S1)
|
||||||
|
init_map[initsig[i]] = initval[i] == State::S1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wire->port_input)
|
||||||
|
for (auto bit : sigmap(wire))
|
||||||
|
input_bits.insert(bit);
|
||||||
|
|
||||||
|
if (wire->port_output)
|
||||||
|
for (auto bit : sigmap(wire))
|
||||||
|
output_bits.insert(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (cell->type == "$_NOT_")
|
||||||
|
{
|
||||||
|
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||||
|
SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
|
||||||
|
not_map[Y] = A;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_"))
|
||||||
|
{
|
||||||
|
SigBit D = sigmap(cell->getPort("\\D").as_bit());
|
||||||
|
SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
|
||||||
|
ff_map[Q] = D;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type == "$_AND_")
|
||||||
|
{
|
||||||
|
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||||
|
SigBit B = sigmap(cell->getPort("\\B").as_bit());
|
||||||
|
SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
|
||||||
|
and_map[Y] = make_pair(A, B);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type == "$initstate")
|
||||||
|
{
|
||||||
|
SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
|
||||||
|
initstate_bits.insert(Y);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type == "$assert")
|
||||||
|
{
|
||||||
|
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||||
|
SigBit EN = sigmap(cell->getPort("\\EN").as_bit());
|
||||||
|
asserts.push_back(make_pair(A, EN));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type == "$assume")
|
||||||
|
{
|
||||||
|
SigBit A = sigmap(cell->getPort("\\A").as_bit());
|
||||||
|
SigBit EN = sigmap(cell->getPort("\\EN").as_bit());
|
||||||
|
assumes.push_back(make_pair(A, EN));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type == "$anyconst")
|
||||||
|
{
|
||||||
|
for (auto bit : sigmap(cell->getPort("\\Y")))
|
||||||
|
ff_map[bit] = bit;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
init_map.sort();
|
||||||
|
input_bits.sort();
|
||||||
|
output_bits.sort();
|
||||||
|
not_map.sort();
|
||||||
|
ff_map.sort();
|
||||||
|
and_map.sort();
|
||||||
|
|
||||||
|
aig_map[State::S0] = 0;
|
||||||
|
aig_map[State::S1] = 1;
|
||||||
|
|
||||||
|
for (auto bit : input_bits) {
|
||||||
|
aig_m++, aig_i++;
|
||||||
|
aig_map[bit] = 2*aig_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zinit_mode)
|
||||||
|
{
|
||||||
|
for (auto it : ff_map) {
|
||||||
|
if (init_map.count(it.first))
|
||||||
|
continue;
|
||||||
|
aig_m++, aig_i++;
|
||||||
|
init_inputs[it.first] = 2*aig_m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it : ff_map) {
|
||||||
|
aig_m++, aig_l++;
|
||||||
|
aig_map[it.first] = 2*aig_m;
|
||||||
|
ordered_latches[it.first] = aig_l-1;
|
||||||
|
if (init_map.count(it.first) == 0)
|
||||||
|
aig_latchinit.push_back(2);
|
||||||
|
else
|
||||||
|
aig_latchinit.push_back(init_map.at(it.first) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initstate_bits.empty() || !init_inputs.empty()) {
|
||||||
|
aig_m++, aig_l++;
|
||||||
|
initstate_ff = 2*aig_m+1;
|
||||||
|
aig_latchinit.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zinit_mode)
|
||||||
|
{
|
||||||
|
for (auto it : ff_map)
|
||||||
|
{
|
||||||
|
int l = ordered_latches[it.first];
|
||||||
|
|
||||||
|
if (aig_latchinit.at(l) == 1)
|
||||||
|
aig_map[it.first] ^= 1;
|
||||||
|
|
||||||
|
if (aig_latchinit.at(l) == 2)
|
||||||
|
{
|
||||||
|
int gated_ffout = mkgate(aig_map[it.first], initstate_ff^1);
|
||||||
|
int gated_initin = mkgate(init_inputs[it.first], initstate_ff);
|
||||||
|
aig_map[it.first] = mkgate(gated_ffout^1, gated_initin^1)^1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it : ff_map) {
|
||||||
|
int a = bit2aig(it.second);
|
||||||
|
int l = ordered_latches[it.first];
|
||||||
|
if (zinit_mode && aig_latchinit.at(l) == 1)
|
||||||
|
aig_latchin.push_back(a ^ 1);
|
||||||
|
else
|
||||||
|
aig_latchin.push_back(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initstate_bits.empty() || !init_inputs.empty())
|
||||||
|
aig_latchin.push_back(1);
|
||||||
|
|
||||||
|
for (auto bit : output_bits) {
|
||||||
|
aig_o++;
|
||||||
|
ordered_outputs[bit] = aig_o-1;
|
||||||
|
aig_outputs.push_back(bit2aig(bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it : asserts) {
|
||||||
|
aig_b++;
|
||||||
|
int bit_a = bit2aig(it.first);
|
||||||
|
int bit_en = bit2aig(it.second);
|
||||||
|
aig_outputs.push_back(mkgate(bit_a^1, bit_en));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it : assumes) {
|
||||||
|
aig_c++;
|
||||||
|
int bit_a = bit2aig(it.first);
|
||||||
|
int bit_en = bit2aig(it.second);
|
||||||
|
aig_outputs.push_back(mkgate(bit_a^1, bit_en)^1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_aiger(std::ostream &f, bool ascii_mode, bool miter_mode, bool symbols_mode)
|
||||||
|
{
|
||||||
|
log_assert(aig_m == aig_i + aig_l + aig_a);
|
||||||
|
log_assert(aig_l == GetSize(aig_latchin));
|
||||||
|
log_assert(aig_l == GetSize(aig_latchinit));
|
||||||
|
log_assert((aig_o + aig_b + aig_c) == GetSize(aig_outputs));
|
||||||
|
|
||||||
|
if (miter_mode) {
|
||||||
|
if (aig_b || aig_c)
|
||||||
|
log_error("Running AIGER back-end in -miter mode, but design contains $assert and/or $assume cells!\n");
|
||||||
|
f << stringf("%s %d %d %d 0 %d %d\n", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_a, aig_o);
|
||||||
|
} else {
|
||||||
|
f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a);
|
||||||
|
if (aig_b || aig_c)
|
||||||
|
f << stringf(" %d %d", aig_b, aig_c);
|
||||||
|
f << stringf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ascii_mode)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < aig_i; i++)
|
||||||
|
f << stringf("%d\n", 2*i+2);
|
||||||
|
|
||||||
|
for (int i = 0; i < aig_l; i++) {
|
||||||
|
if (zinit_mode || aig_latchinit.at(i) == 0)
|
||||||
|
f << stringf("%d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i));
|
||||||
|
else if (aig_latchinit.at(i) == 1)
|
||||||
|
f << stringf("%d %d 1\n", 2*(aig_i+i)+2, aig_latchin.at(i));
|
||||||
|
else if (aig_latchinit.at(i) == 2)
|
||||||
|
f << stringf("%d %d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i), 2*(aig_i+i)+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < aig_o + aig_b + aig_c; i++)
|
||||||
|
f << stringf("%d\n", aig_outputs.at(i));
|
||||||
|
|
||||||
|
for (int i = 0; i < aig_a; i++)
|
||||||
|
f << stringf("%d %d %d\n", 2*(aig_i+aig_l+i)+2, aig_gates.at(i).first, aig_gates.at(i).second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < aig_l; i++) {
|
||||||
|
if (zinit_mode || aig_latchinit.at(i) == 0)
|
||||||
|
f << stringf("%d\n", aig_latchin.at(i));
|
||||||
|
else if (aig_latchinit.at(i) == 1)
|
||||||
|
f << stringf("%d 1\n", aig_latchin.at(i));
|
||||||
|
else if (aig_latchinit.at(i) == 2)
|
||||||
|
f << stringf("%d %d\n", aig_latchin.at(i), 2*(aig_i+i)+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < aig_o + aig_b + aig_c; i++)
|
||||||
|
f << stringf("%d\n", aig_outputs.at(i));
|
||||||
|
|
||||||
|
for (int i = 0; i < aig_a; i++) {
|
||||||
|
int lhs = 2*(aig_i+aig_l+i)+2;
|
||||||
|
int rhs0 = aig_gates.at(i).first;
|
||||||
|
int rhs1 = aig_gates.at(i).second;
|
||||||
|
int delta0 = lhs - rhs0;
|
||||||
|
int delta1 = rhs0 - rhs1;
|
||||||
|
aiger_encode(f, delta0);
|
||||||
|
aiger_encode(f, delta1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbols_mode)
|
||||||
|
{
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
{
|
||||||
|
if (wire->name[0] == '$')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec sig = sigmap(wire);
|
||||||
|
|
||||||
|
for (int i = 0; i < GetSize(wire); i++)
|
||||||
|
{
|
||||||
|
if (wire->port_input) {
|
||||||
|
int a = aig_map.at(sig[i]);
|
||||||
|
log_assert((a & 1) == 0);
|
||||||
|
if (GetSize(wire) != 1)
|
||||||
|
f << stringf("i%d %s[%d]\n", (a >> 1)-1, log_id(wire), i);
|
||||||
|
else
|
||||||
|
f << stringf("i%d %s\n", (a >> 1)-1, log_id(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wire->port_output) {
|
||||||
|
int o = ordered_outputs.at(sig[i]);
|
||||||
|
if (GetSize(wire) != 1)
|
||||||
|
f << stringf("%c%d %s[%d]\n", miter_mode ? 'b' : 'o', o, log_id(wire), i);
|
||||||
|
else
|
||||||
|
f << stringf("%c%d %s\n", miter_mode ? 'b' : 'o', o, log_id(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_inputs.count(sig[i])) {
|
||||||
|
int a = init_inputs.at(sig[i]);
|
||||||
|
log_assert((a & 1) == 0);
|
||||||
|
if (GetSize(wire) != 1)
|
||||||
|
f << stringf("i%d init:%s[%d]\n", (a >> 1)-1, log_id(wire), i);
|
||||||
|
else
|
||||||
|
f << stringf("i%d init:%s\n", (a >> 1)-1, log_id(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ordered_latches.count(sig[i])) {
|
||||||
|
int l = ordered_latches.at(sig[i]);
|
||||||
|
const char *p = (zinit_mode && (aig_latchinit.at(l) == 1)) ? "!" : "";
|
||||||
|
if (GetSize(wire) != 1)
|
||||||
|
f << stringf("l%d %s%s[%d]\n", l, p, log_id(wire), i);
|
||||||
|
else
|
||||||
|
f << stringf("l%d %s%s\n", l, p, log_id(wire));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f << stringf("c\nGenerated by %s\n", yosys_version_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_map(std::ostream &f, bool verbose_map)
|
||||||
|
{
|
||||||
|
dict<int, string> input_lines;
|
||||||
|
dict<int, string> init_lines;
|
||||||
|
dict<int, string> output_lines;
|
||||||
|
dict<int, string> latch_lines;
|
||||||
|
dict<int, string> wire_lines;
|
||||||
|
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
{
|
||||||
|
if (!verbose_map && wire->name[0] == '$')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec sig = sigmap(wire);
|
||||||
|
|
||||||
|
for (int i = 0; i < GetSize(wire); i++)
|
||||||
|
{
|
||||||
|
if (aig_map.count(sig[i]) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int a = aig_map.at(sig[i]);
|
||||||
|
|
||||||
|
if (verbose_map)
|
||||||
|
wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire));
|
||||||
|
|
||||||
|
if (wire->port_input) {
|
||||||
|
log_assert((a & 1) == 0);
|
||||||
|
input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wire->port_output) {
|
||||||
|
int o = ordered_outputs.at(sig[i]);
|
||||||
|
output_lines[o] += stringf("output %d %d %s\n", o, i, log_id(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_inputs.count(sig[i])) {
|
||||||
|
int a = init_inputs.at(sig[i]);
|
||||||
|
log_assert((a & 1) == 0);
|
||||||
|
init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ordered_latches.count(sig[i])) {
|
||||||
|
int l = ordered_latches.at(sig[i]);
|
||||||
|
if (zinit_mode && (aig_latchinit.at(l) == 1))
|
||||||
|
latch_lines[l] += stringf("invlatch %d %d %s\n", l, i, log_id(wire));
|
||||||
|
else
|
||||||
|
latch_lines[l] += stringf("latch %d %d %s\n", l, i, log_id(wire));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input_lines.sort();
|
||||||
|
for (auto &it : input_lines)
|
||||||
|
f << it.second;
|
||||||
|
|
||||||
|
init_lines.sort();
|
||||||
|
for (auto &it : init_lines)
|
||||||
|
f << it.second;
|
||||||
|
|
||||||
|
output_lines.sort();
|
||||||
|
for (auto &it : output_lines)
|
||||||
|
f << it.second;
|
||||||
|
|
||||||
|
latch_lines.sort();
|
||||||
|
for (auto &it : latch_lines)
|
||||||
|
f << it.second;
|
||||||
|
|
||||||
|
wire_lines.sort();
|
||||||
|
for (auto &it : wire_lines)
|
||||||
|
f << it.second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AigerBackend : public Backend {
|
||||||
|
AigerBackend() : Backend("aiger", "write design to AIGER file") { }
|
||||||
|
virtual void help()
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" write_aiger [options] [filename]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Write the current design to an AIGER file. The design must be flattened and\n");
|
||||||
|
log("must not contain any cell types except $_AND_, $_NOT_, simple FF types,\n");
|
||||||
|
log("$assert and $assume cells, and $initstate cells.\n");
|
||||||
|
log("\n");
|
||||||
|
log("$assert and $assume cells are converted to AIGER bad state properties and\n");
|
||||||
|
log("invariant constraints.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -ascii\n");
|
||||||
|
log(" write ASCII version of AGIER format\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -zinit\n");
|
||||||
|
log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");
|
||||||
|
log(" uninitialized FFs.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -miter\n");
|
||||||
|
log(" design outputs are AIGER bad state properties\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -symbols\n");
|
||||||
|
log(" include a symbol table in the generated AIGER file\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -map <filename>\n");
|
||||||
|
log(" write an extra file with port and latch symbols\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -vmap <filename>\n");
|
||||||
|
log(" like -map, but more verbose\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||||
|
{
|
||||||
|
bool ascii_mode = false;
|
||||||
|
bool zinit_mode = false;
|
||||||
|
bool miter_mode = false;
|
||||||
|
bool symbols_mode = false;
|
||||||
|
bool verbose_map = false;
|
||||||
|
std::string map_filename;
|
||||||
|
|
||||||
|
log_header(design, "Executing AIGER backend.\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-ascii") {
|
||||||
|
ascii_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-zinit") {
|
||||||
|
zinit_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-miter") {
|
||||||
|
miter_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-symbols") {
|
||||||
|
symbols_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
|
||||||
|
map_filename = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) {
|
||||||
|
map_filename = args[++argidx];
|
||||||
|
verbose_map = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
||||||
|
Module *top_module = design->top_module();
|
||||||
|
|
||||||
|
if (top_module == nullptr)
|
||||||
|
log_error("Can't find top module in current design!\n");
|
||||||
|
|
||||||
|
AigerWriter writer(top_module, zinit_mode);
|
||||||
|
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
||||||
|
|
||||||
|
if (!map_filename.empty()) {
|
||||||
|
std::ofstream mapf;
|
||||||
|
mapf.open(map_filename.c_str(), std::ofstream::trunc);
|
||||||
|
if (mapf.fail())
|
||||||
|
log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno));
|
||||||
|
writer.write_map(mapf, verbose_map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} AigerBackend;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -112,7 +112,7 @@ struct BlifDumper
|
||||||
str[i] = '?';
|
str[i] = '?';
|
||||||
|
|
||||||
if (sig.wire->width != 1)
|
if (sig.wire->width != 1)
|
||||||
str += stringf("[%d]", sig.offset);
|
str += stringf("[%d]", sig.wire->upto ? sig.wire->start_offset+sig.wire->width-sig.offset-1 : sig.wire->start_offset+sig.offset);
|
||||||
|
|
||||||
cstr_buf.push_back(str);
|
cstr_buf.push_back(str);
|
||||||
return cstr_buf.back().c_str();
|
return cstr_buf.back().c_str();
|
||||||
|
|
2
backends/firrtl/.gitignore
vendored
Normal file
2
backends/firrtl/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
test.fir
|
||||||
|
test_out.v
|
3
backends/firrtl/Makefile.inc
Normal file
3
backends/firrtl/Makefile.inc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
OBJS += backends/firrtl/firrtl.o
|
||||||
|
|
470
backends/firrtl/firrtl.cc
Normal file
470
backends/firrtl/firrtl.cc
Normal file
|
@ -0,0 +1,470 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* 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/rtlil.h"
|
||||||
|
#include "kernel/register.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "kernel/celltypes.h"
|
||||||
|
#include "kernel/cellaigs.h"
|
||||||
|
#include "kernel/log.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
pool<string> used_names;
|
||||||
|
dict<IdString, string> namecache;
|
||||||
|
int autoid_counter;
|
||||||
|
|
||||||
|
string next_id()
|
||||||
|
{
|
||||||
|
string new_id;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
new_id = stringf("_%d", autoid_counter++);
|
||||||
|
if (used_names.count(new_id) == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
used_names.insert(new_id);
|
||||||
|
return new_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *make_id(IdString id)
|
||||||
|
{
|
||||||
|
if (namecache.count(id) != 0)
|
||||||
|
return namecache.at(id).c_str();
|
||||||
|
|
||||||
|
string new_id = log_id(id);
|
||||||
|
|
||||||
|
for (int i = 0; i < GetSize(new_id); i++)
|
||||||
|
{
|
||||||
|
char &ch = new_id[i];
|
||||||
|
if ('a' <= ch && ch <= 'z') continue;
|
||||||
|
if ('A' <= ch && ch <= 'Z') continue;
|
||||||
|
if ('0' <= ch && ch <= '9' && i != 0) continue;
|
||||||
|
if ('_' == ch) continue;
|
||||||
|
ch = '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
while (used_names.count(new_id) != 0)
|
||||||
|
new_id += '_';
|
||||||
|
|
||||||
|
namecache[id] = new_id;
|
||||||
|
used_names.insert(new_id);
|
||||||
|
return namecache.at(id).c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FirrtlWorker
|
||||||
|
{
|
||||||
|
Module *module;
|
||||||
|
std::ostream &f;
|
||||||
|
|
||||||
|
dict<SigBit, pair<string, int>> reverse_wire_map;
|
||||||
|
string unconn_id;
|
||||||
|
|
||||||
|
void register_reverse_wire_map(string id, SigSpec sig)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < GetSize(sig); i++)
|
||||||
|
reverse_wire_map[sig[i]] = make_pair(id, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
FirrtlWorker(Module *module, std::ostream &f) : module(module), f(f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
string make_expr(SigSpec sig)
|
||||||
|
{
|
||||||
|
string expr;
|
||||||
|
|
||||||
|
for (auto chunk : sig.chunks())
|
||||||
|
{
|
||||||
|
string new_expr;
|
||||||
|
|
||||||
|
if (chunk.wire == nullptr)
|
||||||
|
{
|
||||||
|
std::vector<RTLIL::State> bits = chunk.data;
|
||||||
|
new_expr = stringf("UInt<%d>(\"h", GetSize(bits));
|
||||||
|
|
||||||
|
while (GetSize(bits) % 4 != 0)
|
||||||
|
bits.push_back(State::S0);
|
||||||
|
|
||||||
|
for (int i = GetSize(bits)-4; i >= 0; i -= 4)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
if (bits[i+0] == State::S1) val += 1;
|
||||||
|
if (bits[i+1] == State::S1) val += 2;
|
||||||
|
if (bits[i+2] == State::S1) val += 4;
|
||||||
|
if (bits[i+3] == State::S1) val += 8;
|
||||||
|
new_expr.push_back(val < 10 ? '0' + val : 'a' + val - 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_expr += "\")";
|
||||||
|
}
|
||||||
|
else if (chunk.offset == 0 && chunk.width == chunk.wire->width)
|
||||||
|
{
|
||||||
|
new_expr = make_id(chunk.wire->name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string wire_id = make_id(chunk.wire->name);
|
||||||
|
new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr.empty())
|
||||||
|
expr = new_expr;
|
||||||
|
else
|
||||||
|
expr = "cat(" + new_expr + ", " + expr + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
f << stringf(" module %s:\n", make_id(module->name));
|
||||||
|
vector<string> port_decls, wire_decls, cell_exprs, wire_exprs;
|
||||||
|
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
{
|
||||||
|
if (wire->port_id)
|
||||||
|
{
|
||||||
|
if (wire->port_input && wire->port_output)
|
||||||
|
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
|
||||||
|
port_decls.push_back(stringf(" %s %s: UInt<%d>\n", wire->port_input ? "input" : "output",
|
||||||
|
make_id(wire->name), wire->width));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", make_id(wire->name), wire->width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (cell->type.in("$add", "$sub", "$xor"))
|
||||||
|
{
|
||||||
|
string y_id = make_id(cell->name);
|
||||||
|
bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
|
||||||
|
int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
|
||||||
|
string a_expr = make_expr(cell->getPort("\\A"));
|
||||||
|
string b_expr = make_expr(cell->getPort("\\B"));
|
||||||
|
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||||
|
|
||||||
|
if (is_signed) {
|
||||||
|
a_expr = "asSInt(" + a_expr + ")";
|
||||||
|
b_expr = "asSInt(" + b_expr + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||||
|
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
|
||||||
|
|
||||||
|
string primop;
|
||||||
|
if (cell->type == "$add") primop = "add";
|
||||||
|
if (cell->type == "$sub") primop = "sub";
|
||||||
|
if (cell->type == "$xor") primop = "xor";
|
||||||
|
|
||||||
|
string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
|
||||||
|
|
||||||
|
if ((is_signed && !cell->type.in("$xor")) || cell->type.in("$sub"))
|
||||||
|
expr = stringf("asUInt(%s)", expr.c_str());
|
||||||
|
|
||||||
|
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
|
||||||
|
register_reverse_wire_map(y_id, cell->getPort("\\Y"));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type.in("$mux"))
|
||||||
|
{
|
||||||
|
string y_id = make_id(cell->name);
|
||||||
|
int width = cell->parameters.at("\\WIDTH").as_int();
|
||||||
|
string a_expr = make_expr(cell->getPort("\\A"));
|
||||||
|
string b_expr = make_expr(cell->getPort("\\B"));
|
||||||
|
string s_expr = make_expr(cell->getPort("\\S"));
|
||||||
|
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), width));
|
||||||
|
|
||||||
|
string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
|
||||||
|
|
||||||
|
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
|
||||||
|
register_reverse_wire_map(y_id, cell->getPort("\\Y"));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type.in("$mem"))
|
||||||
|
{
|
||||||
|
string mem_id = make_id(cell->name);
|
||||||
|
int abits = cell->parameters.at("\\ABITS").as_int();
|
||||||
|
int width = cell->parameters.at("\\WIDTH").as_int();
|
||||||
|
int size = cell->parameters.at("\\SIZE").as_int();
|
||||||
|
int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
|
||||||
|
int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
|
||||||
|
|
||||||
|
Const initdata = cell->parameters.at("\\INIT");
|
||||||
|
for (State bit : initdata.bits)
|
||||||
|
if (bit != State::Sx)
|
||||||
|
log_error("Memory with initialization data: %s.%s\n", log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
Const rd_clk_enable = cell->parameters.at("\\RD_CLK_ENABLE");
|
||||||
|
Const wr_clk_enable = cell->parameters.at("\\WR_CLK_ENABLE");
|
||||||
|
Const wr_clk_polarity = cell->parameters.at("\\WR_CLK_POLARITY");
|
||||||
|
|
||||||
|
int offset = cell->parameters.at("\\OFFSET").as_int();
|
||||||
|
if (offset != 0)
|
||||||
|
log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
cell_exprs.push_back(stringf(" mem %s:\n", mem_id.c_str()));
|
||||||
|
cell_exprs.push_back(stringf(" data-type => UInt<%d>\n", width));
|
||||||
|
cell_exprs.push_back(stringf(" depth => %d\n", size));
|
||||||
|
|
||||||
|
for (int i = 0; i < rd_ports; i++)
|
||||||
|
cell_exprs.push_back(stringf(" reader => r%d\n", i));
|
||||||
|
|
||||||
|
for (int i = 0; i < wr_ports; i++)
|
||||||
|
cell_exprs.push_back(stringf(" writer => w%d\n", i));
|
||||||
|
|
||||||
|
cell_exprs.push_back(stringf(" read-latency => 0\n"));
|
||||||
|
cell_exprs.push_back(stringf(" write-latency => 1\n"));
|
||||||
|
cell_exprs.push_back(stringf(" read-under-write => undefined\n"));
|
||||||
|
|
||||||
|
for (int i = 0; i < rd_ports; i++)
|
||||||
|
{
|
||||||
|
if (rd_clk_enable[i] != State::S0)
|
||||||
|
log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width);
|
||||||
|
string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits));
|
||||||
|
|
||||||
|
cell_exprs.push_back(stringf(" %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
|
||||||
|
cell_exprs.push_back(stringf(" %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i));
|
||||||
|
cell_exprs.push_back(stringf(" %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i));
|
||||||
|
|
||||||
|
register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < wr_ports; i++)
|
||||||
|
{
|
||||||
|
if (wr_clk_enable[i] != State::S1)
|
||||||
|
log_error("Unclocked write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
if (wr_clk_polarity[i] != State::S1)
|
||||||
|
log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits));
|
||||||
|
string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width));
|
||||||
|
string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i));
|
||||||
|
|
||||||
|
SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width);
|
||||||
|
string wen_expr = make_expr(wen_sig[0]);
|
||||||
|
|
||||||
|
for (int i = 1; i < GetSize(wen_sig); i++)
|
||||||
|
if (wen_sig[0] != wen_sig[i])
|
||||||
|
log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
cell_exprs.push_back(stringf(" %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
|
||||||
|
cell_exprs.push_back(stringf(" %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str()));
|
||||||
|
cell_exprs.push_back(stringf(" %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str()));
|
||||||
|
cell_exprs.push_back(stringf(" %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i));
|
||||||
|
cell_exprs.push_back(stringf(" %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell->type.in("$dff"))
|
||||||
|
{
|
||||||
|
bool clkpol = cell->parameters.at("\\CLK_POLARITY").as_bool();
|
||||||
|
if (clkpol == false)
|
||||||
|
log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
string q_id = make_id(cell->name);
|
||||||
|
int width = cell->parameters.at("\\WIDTH").as_int();
|
||||||
|
string expr = make_expr(cell->getPort("\\D"));
|
||||||
|
string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")";
|
||||||
|
|
||||||
|
wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str()));
|
||||||
|
|
||||||
|
cell_exprs.push_back(stringf(" %s <= %s\n", q_id.c_str(), expr.c_str()));
|
||||||
|
register_reverse_wire_map(q_id, cell->getPort("\\Q"));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto conn : module->connections())
|
||||||
|
{
|
||||||
|
string y_id = next_id();
|
||||||
|
int y_width = GetSize(conn.first);
|
||||||
|
string expr = make_expr(conn.second);
|
||||||
|
|
||||||
|
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||||
|
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
|
||||||
|
register_reverse_wire_map(y_id, conn.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
{
|
||||||
|
string expr;
|
||||||
|
|
||||||
|
if (wire->port_input)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int cursor = 0;
|
||||||
|
bool is_valid = false;
|
||||||
|
bool make_unconn_id = false;
|
||||||
|
|
||||||
|
while (cursor < wire->width)
|
||||||
|
{
|
||||||
|
int chunk_width = 1;
|
||||||
|
string new_expr;
|
||||||
|
|
||||||
|
SigBit start_bit(wire, cursor);
|
||||||
|
|
||||||
|
if (reverse_wire_map.count(start_bit))
|
||||||
|
{
|
||||||
|
pair<string, int> start_map = reverse_wire_map.at(start_bit);
|
||||||
|
|
||||||
|
while (cursor+chunk_width < wire->width)
|
||||||
|
{
|
||||||
|
SigBit stop_bit(wire, cursor+chunk_width);
|
||||||
|
|
||||||
|
if (reverse_wire_map.count(stop_bit) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pair<string, int> stop_map = reverse_wire_map.at(stop_bit);
|
||||||
|
stop_map.second -= chunk_width;
|
||||||
|
|
||||||
|
if (start_map != stop_map)
|
||||||
|
break;
|
||||||
|
|
||||||
|
chunk_width++;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_expr = stringf("bits(%s, %d, %d)", start_map.first.c_str(),
|
||||||
|
start_map.second + chunk_width - 1, start_map.second);
|
||||||
|
is_valid = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unconn_id.empty()) {
|
||||||
|
unconn_id = next_id();
|
||||||
|
make_unconn_id = true;
|
||||||
|
}
|
||||||
|
new_expr = unconn_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr.empty())
|
||||||
|
expr = new_expr;
|
||||||
|
else
|
||||||
|
expr = "cat(" + new_expr + ", " + expr + ")";
|
||||||
|
|
||||||
|
cursor += chunk_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_valid) {
|
||||||
|
if (make_unconn_id) {
|
||||||
|
wire_decls.push_back(stringf(" wire %s: UInt<1>\n", unconn_id.c_str()));
|
||||||
|
cell_exprs.push_back(stringf(" %s is invalid\n", unconn_id.c_str()));
|
||||||
|
}
|
||||||
|
wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str()));
|
||||||
|
} else {
|
||||||
|
if (make_unconn_id) {
|
||||||
|
unconn_id.clear();
|
||||||
|
}
|
||||||
|
wire_exprs.push_back(stringf(" %s is invalid\n", make_id(wire->name)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto str : port_decls)
|
||||||
|
f << str;
|
||||||
|
|
||||||
|
f << stringf("\n");
|
||||||
|
|
||||||
|
for (auto str : wire_decls)
|
||||||
|
f << str;
|
||||||
|
|
||||||
|
f << stringf("\n");
|
||||||
|
|
||||||
|
for (auto str : cell_exprs)
|
||||||
|
f << str;
|
||||||
|
|
||||||
|
f << stringf("\n");
|
||||||
|
|
||||||
|
for (auto str : wire_exprs)
|
||||||
|
f << str;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FirrtlBackend : public Backend {
|
||||||
|
FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { }
|
||||||
|
virtual void help()
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" write_firrtl [options] [filename]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Write a FIRRTL netlist of the current design.\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||||
|
{
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
// if (args[argidx] == "-aig") {
|
||||||
|
// aig_mode = true;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
||||||
|
log_header(design, "Executing FIRRTL backend.\n");
|
||||||
|
|
||||||
|
Module *top = design->top_module();
|
||||||
|
|
||||||
|
if (top == nullptr)
|
||||||
|
log_error("No top module found!\n");
|
||||||
|
|
||||||
|
namecache.clear();
|
||||||
|
autoid_counter = 0;
|
||||||
|
|
||||||
|
for (auto module : design->modules()) {
|
||||||
|
make_id(module->name);
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->port_id)
|
||||||
|
make_id(wire->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
*f << stringf("circuit %s:\n", make_id(top->name));
|
||||||
|
|
||||||
|
for (auto module : design->modules())
|
||||||
|
{
|
||||||
|
FirrtlWorker worker(module, *f);
|
||||||
|
worker.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
namecache.clear();
|
||||||
|
autoid_counter = 0;
|
||||||
|
}
|
||||||
|
} FirrtlBackend;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
22
backends/firrtl/test.sh
Normal file
22
backends/firrtl/test.sh
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
../../yosys -p 'prep -nordff; write_firrtl test.fir' test.v
|
||||||
|
|
||||||
|
firrtl -i test.fir -o test_out.v
|
||||||
|
|
||||||
|
../../yosys -p '
|
||||||
|
read_verilog test.v
|
||||||
|
rename test gold
|
||||||
|
|
||||||
|
read_verilog test_out.v
|
||||||
|
rename test gate
|
||||||
|
|
||||||
|
prep
|
||||||
|
memory_map
|
||||||
|
miter -equiv -flatten gold gate miter
|
||||||
|
hierarchy -top miter
|
||||||
|
|
||||||
|
sat -verify -prove trigger 0 -set-init-zero -seq 10 miter
|
||||||
|
'
|
||||||
|
|
24
backends/firrtl/test.v
Normal file
24
backends/firrtl/test.v
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
module test(
|
||||||
|
input clk, wen,
|
||||||
|
input [4:0] waddr, raddr,
|
||||||
|
input [31:0] wdata,
|
||||||
|
output reg [31:0] rdata,
|
||||||
|
signed input [7:0] a, b, x,
|
||||||
|
output [15:0] s, d, y, z, u, q
|
||||||
|
);
|
||||||
|
reg [31:0] memory [0:31];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
rdata <= memory[raddr];
|
||||||
|
if (wen) memory[waddr] <= wdata;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign s = a+{b[6:2], 2'b1};
|
||||||
|
assign d = a-b;
|
||||||
|
assign y = x;
|
||||||
|
assign z[7:0] = s+d;
|
||||||
|
assign z[15:8] = s-d;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
q <= s ^ d ^ x;
|
||||||
|
endmodule
|
|
@ -333,6 +333,10 @@ struct JsonBackend : public Backend {
|
||||||
log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
|
log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
|
||||||
log("a number.\n");
|
log("a number.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("Numeric parameter and attribute values up to 32 bits are written as decimal\n");
|
||||||
|
log("values. Numbers larger than that are written as string holding the binary\n");
|
||||||
|
log("representation of the value.\n");
|
||||||
|
log("\n");
|
||||||
log("For example the following Verilog code:\n");
|
log("For example the following Verilog code:\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" module test(input x, y);\n");
|
log(" module test(input x, y);\n");
|
||||||
|
|
|
@ -639,12 +639,24 @@ struct Smt2Worker
|
||||||
if (wire->attributes.count("\\init")) {
|
if (wire->attributes.count("\\init")) {
|
||||||
RTLIL::SigSpec sig = sigmap(wire);
|
RTLIL::SigSpec sig = sigmap(wire);
|
||||||
Const val = wire->attributes.at("\\init");
|
Const val = wire->attributes.at("\\init");
|
||||||
val.bits.resize(GetSize(sig));
|
val.bits.resize(GetSize(sig), State::Sx);
|
||||||
if (bvmode && GetSize(sig) > 1) {
|
if (bvmode && GetSize(sig) > 1) {
|
||||||
init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_id(wire)));
|
Const mask(State::S1, GetSize(sig));
|
||||||
|
bool use_mask = false;
|
||||||
|
for (int i = 0; i < GetSize(sig); i++)
|
||||||
|
if (val[i] != State::S0 && val[i] != State::S1) {
|
||||||
|
val[i] = State::S0;
|
||||||
|
mask[i] = State::S0;
|
||||||
|
use_mask = true;
|
||||||
|
}
|
||||||
|
if (use_mask)
|
||||||
|
init_list.push_back(stringf("(= (bvand %s #b%s) #b%s) ; %s", get_bv(sig).c_str(), mask.as_string().c_str(), val.as_string().c_str(), get_id(wire)));
|
||||||
|
else
|
||||||
|
init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_id(wire)));
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < GetSize(sig); i++)
|
for (int i = 0; i < GetSize(sig); i++)
|
||||||
init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", get_id(wire)));
|
if (val[i] == State::S0 || val[i] == State::S1)
|
||||||
|
init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val[i] == State::S1 ? "true" : "false", get_id(wire)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,6 +761,10 @@ struct Smt2Worker
|
||||||
|
|
||||||
if (verbose) log("=> export logic driving hierarchical cells\n");
|
if (verbose) log("=> export logic driving hierarchical cells\n");
|
||||||
|
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
if (module->design->module(cell->type) != nullptr)
|
||||||
|
export_cell(cell);
|
||||||
|
|
||||||
while (!hiercells_queue.empty())
|
while (!hiercells_queue.empty())
|
||||||
{
|
{
|
||||||
std::set<RTLIL::Cell*> queue;
|
std::set<RTLIL::Cell*> queue;
|
||||||
|
|
|
@ -22,11 +22,16 @@ import os, sys, getopt, re
|
||||||
from smtio import SmtIo, SmtOpts, MkVcd
|
from smtio import SmtIo, SmtOpts, MkVcd
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
got_topt = False
|
||||||
skip_steps = 0
|
skip_steps = 0
|
||||||
step_size = 1
|
step_size = 1
|
||||||
num_steps = 20
|
num_steps = 20
|
||||||
|
append_steps = 0
|
||||||
vcdfile = None
|
vcdfile = None
|
||||||
cexfile = None
|
cexfile = None
|
||||||
|
aimfile = None
|
||||||
|
aiwfile = None
|
||||||
|
aigheader = True
|
||||||
vlogtbfile = None
|
vlogtbfile = None
|
||||||
inconstr = list()
|
inconstr = list()
|
||||||
outconstr = None
|
outconstr = None
|
||||||
|
@ -65,6 +70,19 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
||||||
--cex <cex_filename>
|
--cex <cex_filename>
|
||||||
read cex file as written by ABC's "write_cex -n"
|
read cex file as written by ABC's "write_cex -n"
|
||||||
|
|
||||||
|
--aig <prefix>
|
||||||
|
read AIGER map file (as written by Yosys' "write_aiger -map")
|
||||||
|
and AIGER witness file. The file names are <prefix>.aim for
|
||||||
|
the map file and <prefix>.aiw for the witness file.
|
||||||
|
|
||||||
|
--aig <aim_filename>:<aiw_filename>
|
||||||
|
like above, but for map files and witness files that do not
|
||||||
|
share a filename prefix (or use differen file extensions).
|
||||||
|
|
||||||
|
--aig-noheader
|
||||||
|
the AIGER witness file does not include the status and
|
||||||
|
properties lines.
|
||||||
|
|
||||||
--noinfo
|
--noinfo
|
||||||
only run the core proof, do not collect and print any
|
only run the core proof, do not collect and print any
|
||||||
additional information (e.g. which assert failed)
|
additional information (e.g. which assert failed)
|
||||||
|
@ -92,18 +110,25 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
||||||
when using -g or -i, create a dump file for each
|
when using -g or -i, create a dump file for each
|
||||||
step. The character '%' is replaces in all dump
|
step. The character '%' is replaces in all dump
|
||||||
filenames with the step number.
|
filenames with the step number.
|
||||||
|
|
||||||
|
--append <num_steps>
|
||||||
|
add <num_steps> time steps at the end of the trace
|
||||||
|
when creating a counter example (this additional time
|
||||||
|
steps will still be constrained by assumtions)
|
||||||
""" + so.helpmsg())
|
""" + so.helpmsg())
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igm:", so.longopts +
|
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igm:", so.longopts +
|
||||||
["final-only", "assume-skipped=", "smtc=", "cex=", "dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo"])
|
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader",
|
||||||
|
"dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo", "append="])
|
||||||
except:
|
except:
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
for o, a in opts:
|
for o, a in opts:
|
||||||
if o == "-t":
|
if o == "-t":
|
||||||
|
got_topt = True
|
||||||
a = a.split(":")
|
a = a.split(":")
|
||||||
if len(a) == 1:
|
if len(a) == 1:
|
||||||
num_steps = int(a[0])
|
num_steps = int(a[0])
|
||||||
|
@ -115,7 +140,7 @@ for o, a in opts:
|
||||||
step_size = int(a[1])
|
step_size = int(a[1])
|
||||||
num_steps = int(a[2])
|
num_steps = int(a[2])
|
||||||
else:
|
else:
|
||||||
assert 0
|
assert False
|
||||||
elif o == "--assume-skipped":
|
elif o == "--assume-skipped":
|
||||||
assume_skipped = int(a)
|
assume_skipped = int(a)
|
||||||
elif o == "--final-only":
|
elif o == "--final-only":
|
||||||
|
@ -124,6 +149,14 @@ for o, a in opts:
|
||||||
inconstr.append(a)
|
inconstr.append(a)
|
||||||
elif o == "--cex":
|
elif o == "--cex":
|
||||||
cexfile = a
|
cexfile = a
|
||||||
|
elif o == "--aig":
|
||||||
|
if ":" in a:
|
||||||
|
aimfile, aiwfile = a.split(":")
|
||||||
|
else:
|
||||||
|
aimfile = a + ".aim"
|
||||||
|
aiwfile = a + ".aiw"
|
||||||
|
elif o == "--aig-noheader":
|
||||||
|
aigheader = False
|
||||||
elif o == "--dump-vcd":
|
elif o == "--dump-vcd":
|
||||||
vcdfile = a
|
vcdfile = a
|
||||||
elif o == "--dump-vlogtb":
|
elif o == "--dump-vlogtb":
|
||||||
|
@ -134,6 +167,8 @@ for o, a in opts:
|
||||||
dumpall = True
|
dumpall = True
|
||||||
elif o == "--noinfo":
|
elif o == "--noinfo":
|
||||||
noinfo = True
|
noinfo = True
|
||||||
|
elif o == "--append":
|
||||||
|
append_steps = int(a)
|
||||||
elif o == "-i":
|
elif o == "-i":
|
||||||
tempind = True
|
tempind = True
|
||||||
elif o == "-g":
|
elif o == "-g":
|
||||||
|
@ -182,12 +217,11 @@ for fn in inconstr:
|
||||||
current_states = set(["final-%d" % i for i in range(0, num_steps+1)])
|
current_states = set(["final-%d" % i for i in range(0, num_steps+1)])
|
||||||
constr_final_start = 0
|
constr_final_start = 0
|
||||||
elif len(tokens) == 2:
|
elif len(tokens) == 2:
|
||||||
i = int(tokens[1])
|
arg = abs(int(tokens[1]))
|
||||||
assert i < 0
|
current_states = set(["final-%d" % i for i in range(arg, num_steps+1)])
|
||||||
current_states = set(["final-%d" % i for i in range(-i, num_steps+1)])
|
constr_final_start = arg if constr_final_start is None else min(constr_final_start, arg)
|
||||||
constr_final_start = -i if constr_final_start is None else min(constr_final_start, -i)
|
|
||||||
else:
|
else:
|
||||||
assert 0
|
assert False
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if tokens[0] == "state":
|
if tokens[0] == "state":
|
||||||
|
@ -206,18 +240,17 @@ for fn in inconstr:
|
||||||
for i in range(lower, upper+1):
|
for i in range(lower, upper+1):
|
||||||
current_states.add(i)
|
current_states.add(i)
|
||||||
else:
|
else:
|
||||||
assert 0
|
assert False
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if tokens[0] == "always":
|
if tokens[0] == "always":
|
||||||
if len(tokens) == 1:
|
if len(tokens) == 1:
|
||||||
current_states = set(range(0, num_steps+1))
|
current_states = set(range(0, num_steps+1))
|
||||||
elif len(tokens) == 2:
|
elif len(tokens) == 2:
|
||||||
i = int(tokens[1])
|
arg = abs(int(tokens[1]))
|
||||||
assert i < 0
|
current_states = set(range(arg, num_steps+1))
|
||||||
current_states = set(range(-i, num_steps+1))
|
|
||||||
else:
|
else:
|
||||||
assert 0
|
assert False
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if tokens[0] == "assert":
|
if tokens[0] == "assert":
|
||||||
|
@ -244,7 +277,7 @@ for fn in inconstr:
|
||||||
so.logic = " ".join(tokens[1:])
|
so.logic = " ".join(tokens[1:])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert 0
|
assert False
|
||||||
|
|
||||||
|
|
||||||
def get_constr_expr(db, state, final=False, getvalues=False):
|
def get_constr_expr(db, state, final=False, getvalues=False):
|
||||||
|
@ -318,6 +351,11 @@ assert topmod is not None
|
||||||
assert topmod in smt.modinfo
|
assert topmod in smt.modinfo
|
||||||
|
|
||||||
if cexfile is not None:
|
if cexfile is not None:
|
||||||
|
if not got_topt:
|
||||||
|
assume_skipped = 0
|
||||||
|
skip_steps = 0
|
||||||
|
num_steps = 0
|
||||||
|
|
||||||
with open(cexfile, "r") as f:
|
with open(cexfile, "r") as f:
|
||||||
cex_regex = re.compile(r'([^\[@=]+)(\[\d+\])?([^@=]*)(@\d+)=([01])')
|
cex_regex = re.compile(r'([^\[@=]+)(\[\d+\])?([^@=]*)(@\d+)=([01])')
|
||||||
for entry in f.read().split():
|
for entry in f.read().split():
|
||||||
|
@ -349,6 +387,144 @@ if cexfile is not None:
|
||||||
# print("cex@%d: %s" % (step, smtexpr))
|
# print("cex@%d: %s" % (step, smtexpr))
|
||||||
constr_assumes[step].append((cexfile, smtexpr))
|
constr_assumes[step].append((cexfile, smtexpr))
|
||||||
|
|
||||||
|
if not got_topt:
|
||||||
|
skip_steps = max(skip_steps, step)
|
||||||
|
num_steps = max(num_steps, step+1)
|
||||||
|
|
||||||
|
if aimfile is not None:
|
||||||
|
input_map = dict()
|
||||||
|
init_map = dict()
|
||||||
|
latch_map = dict()
|
||||||
|
|
||||||
|
if not got_topt:
|
||||||
|
assume_skipped = 0
|
||||||
|
skip_steps = 0
|
||||||
|
num_steps = 0
|
||||||
|
|
||||||
|
with open(aimfile, "r") as f:
|
||||||
|
for entry in f.read().splitlines():
|
||||||
|
entry = entry.split()
|
||||||
|
|
||||||
|
if entry[0] == "input":
|
||||||
|
input_map[int(entry[1])] = (entry[3], int(entry[2]))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if entry[0] == "init":
|
||||||
|
init_map[int(entry[1])] = (entry[3], int(entry[2]))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if entry[0] in ["latch", "invlatch"]:
|
||||||
|
latch_map[int(entry[1])] = (entry[3], int(entry[2]), entry[0] == "invlatch")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if entry[0] in ["output", "wire"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
assert False
|
||||||
|
|
||||||
|
with open(aiwfile, "r") as f:
|
||||||
|
got_state = False
|
||||||
|
got_ffinit = False
|
||||||
|
step = 0
|
||||||
|
|
||||||
|
if not aigheader:
|
||||||
|
got_state = True
|
||||||
|
|
||||||
|
for entry in f.read().splitlines():
|
||||||
|
if len(entry) == 0 or entry[0] in "bcjfu.":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not got_state:
|
||||||
|
got_state = True
|
||||||
|
assert entry == "1"
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not got_ffinit:
|
||||||
|
got_ffinit = True
|
||||||
|
if len(init_map) == 0:
|
||||||
|
for i in range(len(entry)):
|
||||||
|
if entry[i] == "x":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if i in latch_map:
|
||||||
|
value = int(entry[i])
|
||||||
|
name = latch_map[i][0]
|
||||||
|
bitidx = latch_map[i][1]
|
||||||
|
invert = latch_map[i][2]
|
||||||
|
|
||||||
|
if invert:
|
||||||
|
value = 1 - value
|
||||||
|
|
||||||
|
path = smt.get_path(topmod, name)
|
||||||
|
width = smt.net_width(topmod, path)
|
||||||
|
|
||||||
|
if width == 1:
|
||||||
|
assert bitidx == 0
|
||||||
|
smtexpr = "(= [%s] %s)" % (name, "true" if value else "false")
|
||||||
|
else:
|
||||||
|
smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx, bitidx, name, value)
|
||||||
|
|
||||||
|
constr_assumes[0].append((cexfile, smtexpr))
|
||||||
|
continue
|
||||||
|
|
||||||
|
for i in range(len(entry)):
|
||||||
|
if entry[i] == "x":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (step == 0) and (i in init_map):
|
||||||
|
value = int(entry[i])
|
||||||
|
name = init_map[i][0]
|
||||||
|
bitidx = init_map[i][1]
|
||||||
|
|
||||||
|
path = smt.get_path(topmod, name)
|
||||||
|
|
||||||
|
if not smt.net_exists(topmod, path):
|
||||||
|
match = re.match(r"(.*)\[(\d+)\]$", path[-1])
|
||||||
|
if match:
|
||||||
|
path[-1] = match.group(1)
|
||||||
|
addr = int(match.group(2))
|
||||||
|
|
||||||
|
if not match or not smt.mem_exists(topmod, path):
|
||||||
|
print_msg("Ignoring init value for unknown net: %s" % (name))
|
||||||
|
continue
|
||||||
|
|
||||||
|
meminfo = smt.mem_info(topmod, path)
|
||||||
|
smtexpr = "(select [%s] #b%s)" % (".".join(path), bin(addr)[2:].zfill(meminfo[0]))
|
||||||
|
width = meminfo[1]
|
||||||
|
|
||||||
|
else:
|
||||||
|
smtexpr = "[%s]" % name
|
||||||
|
width = smt.net_width(topmod, path)
|
||||||
|
|
||||||
|
if width == 1:
|
||||||
|
assert bitidx == 0
|
||||||
|
smtexpr = "(= %s %s)" % (smtexpr, "true" if value else "false")
|
||||||
|
else:
|
||||||
|
smtexpr = "(= ((_ extract %d %d) %s) #b%d)" % (bitidx, bitidx, smtexpr, value)
|
||||||
|
|
||||||
|
constr_assumes[0].append((cexfile, smtexpr))
|
||||||
|
|
||||||
|
if i in input_map:
|
||||||
|
value = int(entry[i])
|
||||||
|
name = input_map[i][0]
|
||||||
|
bitidx = input_map[i][1]
|
||||||
|
|
||||||
|
path = smt.get_path(topmod, name)
|
||||||
|
width = smt.net_width(topmod, path)
|
||||||
|
|
||||||
|
if width == 1:
|
||||||
|
assert bitidx == 0
|
||||||
|
smtexpr = "(= [%s] %s)" % (name, "true" if value else "false")
|
||||||
|
else:
|
||||||
|
smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx, bitidx, name, value)
|
||||||
|
|
||||||
|
constr_assumes[step].append((cexfile, smtexpr))
|
||||||
|
|
||||||
|
if not got_topt:
|
||||||
|
skip_steps = max(skip_steps, step)
|
||||||
|
num_steps = max(num_steps, step+1)
|
||||||
|
step += 1
|
||||||
|
|
||||||
def write_vcd_trace(steps_start, steps_stop, index):
|
def write_vcd_trace(steps_start, steps_stop, index):
|
||||||
filename = vcdfile.replace("%", index)
|
filename = vcdfile.replace("%", index)
|
||||||
print_msg("Writing trace to VCD file: %s" % (filename))
|
print_msg("Writing trace to VCD file: %s" % (filename))
|
||||||
|
@ -429,7 +605,7 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
|
||||||
|
|
||||||
mems = sorted(smt.hiermems(topmod))
|
mems = sorted(smt.hiermems(topmod))
|
||||||
for mempath in mems:
|
for mempath in mems:
|
||||||
abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
|
abits, width, ports = smt.mem_info(topmod, mempath)
|
||||||
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
||||||
|
|
||||||
addr_expr_list = list()
|
addr_expr_list = list()
|
||||||
|
@ -490,7 +666,7 @@ def write_constr_trace(steps_start, steps_stop, index):
|
||||||
|
|
||||||
mems = sorted(smt.hiermems(topmod))
|
mems = sorted(smt.hiermems(topmod))
|
||||||
for mempath in mems:
|
for mempath in mems:
|
||||||
abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
|
abits, width, ports = smt.mem_info(topmod, mempath)
|
||||||
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
||||||
|
|
||||||
addr_expr_list = list()
|
addr_expr_list = list()
|
||||||
|
@ -649,6 +825,7 @@ else: # not tempind
|
||||||
for i in range(1, step_size):
|
for i in range(1, step_size):
|
||||||
if step+i < num_steps:
|
if step+i < num_steps:
|
||||||
smt.write("(declare-fun s%d () |%s_s|)" % (step+i, topmod))
|
smt.write("(declare-fun s%d () |%s_s|)" % (step+i, topmod))
|
||||||
|
smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step+i))
|
||||||
smt.write("(assert (|%s_u| s%d))" % (topmod, step+i))
|
smt.write("(assert (|%s_u| s%d))" % (topmod, step+i))
|
||||||
smt.write("(assert (|%s_h| s%d))" % (topmod, step+i))
|
smt.write("(assert (|%s_h| s%d))" % (topmod, step+i))
|
||||||
smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step+i-1, step+i))
|
smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step+i-1, step+i))
|
||||||
|
@ -668,10 +845,21 @@ else: # not tempind
|
||||||
|
|
||||||
if smt.check_sat() == "sat":
|
if smt.check_sat() == "sat":
|
||||||
print("%s BMC failed!" % smt.timestamp())
|
print("%s BMC failed!" % smt.timestamp())
|
||||||
|
if append_steps > 0:
|
||||||
|
for i in range(last_check_step+1, last_check_step+1+append_steps):
|
||||||
|
print_msg("Appending additional step %d." % i)
|
||||||
|
smt.write("(declare-fun s%d () |%s_s|)" % (i, topmod))
|
||||||
|
smt.write("(assert (not (|%s_is| s%d)))" % (topmod, i))
|
||||||
|
smt.write("(assert (|%s_u| s%d))" % (topmod, i))
|
||||||
|
smt.write("(assert (|%s_h| s%d))" % (topmod, i))
|
||||||
|
smt.write("(assert (|%s_t| s%d s%d))" % (topmod, i-1, i))
|
||||||
|
smt.write("(assert %s)" % get_constr_expr(constr_assumes, i))
|
||||||
|
print_msg("Re-solving with appended steps..")
|
||||||
|
assert smt.check_sat() == "sat"
|
||||||
print_anyconsts(step)
|
print_anyconsts(step)
|
||||||
for i in range(step, last_check_step+1):
|
for i in range(step, last_check_step+1):
|
||||||
print_failed_asserts(i)
|
print_failed_asserts(i)
|
||||||
write_trace(0, last_check_step+1, '%')
|
write_trace(0, last_check_step+1+append_steps, '%')
|
||||||
retstatus = False
|
retstatus = False
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
#
|
#
|
||||||
# yosys -- Yosys Open SYnthesis Suite
|
# yosys -- Yosys Open SYnthesis Suite
|
||||||
#
|
#
|
||||||
|
@ -17,7 +16,7 @@
|
||||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
import sys, subprocess, re
|
import sys, subprocess, re, os
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from select import select
|
from select import select
|
||||||
from time import time
|
from time import time
|
||||||
|
@ -74,7 +73,7 @@ class SmtIo:
|
||||||
self.debug_print = False
|
self.debug_print = False
|
||||||
self.debug_file = None
|
self.debug_file = None
|
||||||
self.dummy_file = None
|
self.dummy_file = None
|
||||||
self.timeinfo = True
|
self.timeinfo = os.name != "nt"
|
||||||
self.unroll = False
|
self.unroll = False
|
||||||
self.noincr = False
|
self.noincr = False
|
||||||
self.info_stmts = list()
|
self.info_stmts = list()
|
||||||
|
@ -568,6 +567,26 @@ class SmtIo:
|
||||||
assert net_path[-1] in self.modinfo[mod].wsize
|
assert net_path[-1] in self.modinfo[mod].wsize
|
||||||
return self.modinfo[mod].wsize[net_path[-1]]
|
return self.modinfo[mod].wsize[net_path[-1]]
|
||||||
|
|
||||||
|
def net_exists(self, mod, net_path):
|
||||||
|
for i in range(len(net_path)-1):
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if net_path[i] not in self.modinfo[mod].cells: return False
|
||||||
|
mod = self.modinfo[mod].cells[net_path[i]]
|
||||||
|
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if net_path[-1] not in self.modinfo[mod].wsize: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def mem_exists(self, mod, mem_path):
|
||||||
|
for i in range(len(mem_path)-1):
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if mem_path[i] not in self.modinfo[mod].cells: return False
|
||||||
|
mod = self.modinfo[mod].cells[mem_path[i]]
|
||||||
|
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if mem_path[-1] not in self.modinfo[mod].memories: return False
|
||||||
|
return True
|
||||||
|
|
||||||
def mem_expr(self, mod, base, path, portidx=None, infomode=False):
|
def mem_expr(self, mod, base, path, portidx=None, infomode=False):
|
||||||
if len(path) == 1:
|
if len(path) == 1:
|
||||||
assert mod in self.modinfo
|
assert mod in self.modinfo
|
||||||
|
@ -583,8 +602,8 @@ class SmtIo:
|
||||||
nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
|
nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
|
||||||
return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode)
|
return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode)
|
||||||
|
|
||||||
def mem_info(self, mod, base, path):
|
def mem_info(self, mod, path):
|
||||||
return self.mem_expr(mod, base, path, infomode=True)
|
return self.mem_expr(mod, "", path, infomode=True)
|
||||||
|
|
||||||
def get_net(self, mod_name, net_path, state_name):
|
def get_net(self, mod_name, net_path, state_name):
|
||||||
return self.get(self.net_expr(mod_name, state_name, net_path))
|
return self.get(self.net_expr(mod_name, state_name, net_path))
|
||||||
|
@ -619,7 +638,7 @@ class SmtOpts:
|
||||||
self.dummy_file = None
|
self.dummy_file = None
|
||||||
self.unroll = False
|
self.unroll = False
|
||||||
self.noincr = False
|
self.noincr = False
|
||||||
self.timeinfo = True
|
self.timeinfo = os.name != "nt"
|
||||||
self.logic = None
|
self.logic = None
|
||||||
self.info_stmts = list()
|
self.info_stmts = list()
|
||||||
self.nocomments = False
|
self.nocomments = False
|
||||||
|
@ -634,7 +653,7 @@ class SmtOpts:
|
||||||
elif o == "--noincr":
|
elif o == "--noincr":
|
||||||
self.noincr = True
|
self.noincr = True
|
||||||
elif o == "--noprogress":
|
elif o == "--noprogress":
|
||||||
self.timeinfo = True
|
self.timeinfo = False
|
||||||
elif o == "--dump-smt2":
|
elif o == "--dump-smt2":
|
||||||
self.debug_file = open(a, "w")
|
self.debug_file = open(a, "w")
|
||||||
elif o == "--logic":
|
elif o == "--logic":
|
||||||
|
@ -674,6 +693,7 @@ class SmtOpts:
|
||||||
|
|
||||||
--noprogress
|
--noprogress
|
||||||
disable timer display during solving
|
disable timer display during solving
|
||||||
|
(this option is set implicitly on Windows)
|
||||||
|
|
||||||
--dump-smt2 <filename>
|
--dump-smt2 <filename>
|
||||||
write smt2 statements to file
|
write smt2 statements to file
|
||||||
|
|
|
@ -33,13 +33,15 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nostr, defparam;
|
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam;
|
||||||
int auto_name_counter, auto_name_offset, auto_name_digits;
|
int auto_name_counter, auto_name_offset, auto_name_digits;
|
||||||
std::map<RTLIL::IdString, int> auto_name_map;
|
std::map<RTLIL::IdString, int> auto_name_map;
|
||||||
std::set<RTLIL::IdString> reg_wires, reg_ct;
|
std::set<RTLIL::IdString> reg_wires, reg_ct;
|
||||||
std::string auto_prefix;
|
std::string auto_prefix;
|
||||||
|
|
||||||
RTLIL::Module *active_module;
|
RTLIL::Module *active_module;
|
||||||
|
dict<RTLIL::SigBit, RTLIL::State> active_initdata;
|
||||||
|
SigMap active_sigmap;
|
||||||
|
|
||||||
void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
|
void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
|
||||||
{
|
{
|
||||||
|
@ -159,14 +161,14 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
||||||
if (width < 0)
|
if (width < 0)
|
||||||
width = data.bits.size() - offset;
|
width = data.bits.size() - offset;
|
||||||
if (nostr)
|
if (nostr)
|
||||||
goto dump_bits;
|
goto dump_hex;
|
||||||
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
|
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
|
||||||
if (width == 32 && !no_decimal && !nodec) {
|
if (width == 32 && !no_decimal && !nodec) {
|
||||||
int32_t val = 0;
|
int32_t val = 0;
|
||||||
for (int i = offset+width-1; i >= offset; i--) {
|
for (int i = offset+width-1; i >= offset; i--) {
|
||||||
log_assert(i < (int)data.bits.size());
|
log_assert(i < (int)data.bits.size());
|
||||||
if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
|
if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
|
||||||
goto dump_bits;
|
goto dump_hex;
|
||||||
if (data.bits[i] == RTLIL::S1)
|
if (data.bits[i] == RTLIL::S1)
|
||||||
val |= 1 << (i - offset);
|
val |= 1 << (i - offset);
|
||||||
}
|
}
|
||||||
|
@ -175,7 +177,55 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
||||||
else
|
else
|
||||||
f << stringf("32'%sd%u", set_signed ? "s" : "", val);
|
f << stringf("32'%sd%u", set_signed ? "s" : "", val);
|
||||||
} else {
|
} else {
|
||||||
dump_bits:
|
dump_hex:
|
||||||
|
if (nohex)
|
||||||
|
goto dump_bin;
|
||||||
|
vector<char> bin_digits, hex_digits;
|
||||||
|
for (int i = offset; i < offset+width; i++) {
|
||||||
|
log_assert(i < (int)data.bits.size());
|
||||||
|
switch (data.bits[i]) {
|
||||||
|
case RTLIL::S0: bin_digits.push_back('0'); break;
|
||||||
|
case RTLIL::S1: bin_digits.push_back('1'); break;
|
||||||
|
case RTLIL::Sx: bin_digits.push_back('x'); break;
|
||||||
|
case RTLIL::Sz: bin_digits.push_back('z'); break;
|
||||||
|
case RTLIL::Sa: bin_digits.push_back('z'); break;
|
||||||
|
case RTLIL::Sm: log_error("Found marker state in final netlist.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GetSize(bin_digits) == 0)
|
||||||
|
goto dump_bin;
|
||||||
|
while (GetSize(bin_digits) % 4 != 0)
|
||||||
|
if (bin_digits.back() == '1')
|
||||||
|
bin_digits.push_back('0');
|
||||||
|
else
|
||||||
|
bin_digits.push_back(bin_digits.back());
|
||||||
|
for (int i = 0; i < GetSize(bin_digits); i += 4)
|
||||||
|
{
|
||||||
|
char bit_3 = bin_digits[i+3];
|
||||||
|
char bit_2 = bin_digits[i+2];
|
||||||
|
char bit_1 = bin_digits[i+1];
|
||||||
|
char bit_0 = bin_digits[i+0];
|
||||||
|
if (bit_3 == 'x' || bit_2 == 'x' || bit_1 == 'x' || bit_0 == 'x') {
|
||||||
|
if (bit_3 != 'x' || bit_2 != 'x' || bit_1 != 'x' || bit_0 != 'x')
|
||||||
|
goto dump_bin;
|
||||||
|
hex_digits.push_back('x');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (bit_3 == 'z' || bit_2 == 'z' || bit_1 == 'z' || bit_0 == 'z') {
|
||||||
|
if (bit_3 != 'z' || bit_2 != 'z' || bit_1 != 'z' || bit_0 != 'z')
|
||||||
|
goto dump_bin;
|
||||||
|
hex_digits.push_back('z');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int val = 8*(bit_3 - '0') + 4*(bit_2 - '0') + 2*(bit_1 - '0') + (bit_0 - '0');
|
||||||
|
hex_digits.push_back(val < 10 ? '0' + val : 'a' + val - 10);
|
||||||
|
}
|
||||||
|
f << stringf("%d'%sh", width, set_signed ? "s" : "");
|
||||||
|
for (int i = GetSize(hex_digits)-1; i >= 0; i--)
|
||||||
|
f << hex_digits[i];
|
||||||
|
}
|
||||||
|
if (0) {
|
||||||
|
dump_bin:
|
||||||
f << stringf("%d'%sb", width, set_signed ? "s" : "");
|
f << stringf("%d'%sb", width, set_signed ? "s" : "");
|
||||||
if (width == 0)
|
if (width == 0)
|
||||||
f << stringf("0");
|
f << stringf("0");
|
||||||
|
@ -214,6 +264,26 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_reg_init(std::ostream &f, SigSpec sig)
|
||||||
|
{
|
||||||
|
Const initval;
|
||||||
|
bool gotinit = false;
|
||||||
|
|
||||||
|
for (auto bit : active_sigmap(sig)) {
|
||||||
|
if (active_initdata.count(bit)) {
|
||||||
|
initval.bits.push_back(active_initdata.at(bit));
|
||||||
|
gotinit = true;
|
||||||
|
} else {
|
||||||
|
initval.bits.push_back(State::Sx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gotinit) {
|
||||||
|
f << " = ";
|
||||||
|
dump_const(f, initval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
|
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
|
||||||
{
|
{
|
||||||
if (chunk.wire == NULL) {
|
if (chunk.wire == NULL) {
|
||||||
|
@ -302,12 +372,12 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
|
||||||
if (wire->port_input && wire->port_output)
|
if (wire->port_input && wire->port_output)
|
||||||
f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
||||||
if (reg_wires.count(wire->name)) {
|
if (reg_wires.count(wire->name)) {
|
||||||
f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
f << stringf("%s" "reg%s %s", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
||||||
if (wire->attributes.count("\\init")) {
|
if (wire->attributes.count("\\init")) {
|
||||||
f << stringf("%s" "initial %s = ", indent.c_str(), id(wire->name).c_str());
|
f << stringf(" = ");
|
||||||
dump_const(f, wire->attributes.at("\\init"));
|
dump_const(f, wire->attributes.at("\\init"));
|
||||||
f << stringf(";\n");
|
|
||||||
}
|
}
|
||||||
|
f << stringf(";\n");
|
||||||
} else if (!wire->port_input && !wire->port_output)
|
} else if (!wire->port_input && !wire->port_output)
|
||||||
f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
||||||
#endif
|
#endif
|
||||||
|
@ -474,8 +544,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
std::string reg_name = cellname(cell);
|
std::string reg_name = cellname(cell);
|
||||||
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
|
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
|
||||||
|
|
||||||
if (!out_is_reg_wire)
|
if (!out_is_reg_wire) {
|
||||||
f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
|
f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
|
||||||
|
dump_reg_init(f, cell->getPort("\\Q"));
|
||||||
|
f << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
dump_attributes(f, indent, cell->attributes);
|
dump_attributes(f, indent, cell->attributes);
|
||||||
f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
|
f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
|
||||||
|
@ -514,8 +587,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
std::string reg_name = cellname(cell);
|
std::string reg_name = cellname(cell);
|
||||||
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
|
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
|
||||||
|
|
||||||
if (!out_is_reg_wire)
|
if (!out_is_reg_wire) {
|
||||||
f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
|
f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
|
||||||
|
dump_reg_init(f, cell->getPort("\\Q"));
|
||||||
|
f << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
dump_attributes(f, indent, cell->attributes);
|
dump_attributes(f, indent, cell->attributes);
|
||||||
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
|
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
|
||||||
|
@ -698,8 +774,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
std::string reg_name = cellname(cell);
|
std::string reg_name = cellname(cell);
|
||||||
bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
|
bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
|
||||||
|
|
||||||
if (!out_is_reg_wire)
|
if (!out_is_reg_wire) {
|
||||||
f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
|
f << stringf("%s" "reg [%d:0] %s", indent.c_str(), width-1, reg_name.c_str());
|
||||||
|
dump_reg_init(f, sig_q);
|
||||||
|
f << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < width; i++) {
|
for (int i = 0; i < width; i++) {
|
||||||
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
|
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
|
||||||
|
@ -754,8 +833,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
std::string reg_name = cellname(cell);
|
std::string reg_name = cellname(cell);
|
||||||
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
|
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
|
||||||
|
|
||||||
if (!out_is_reg_wire)
|
if (!out_is_reg_wire) {
|
||||||
f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
|
f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
|
||||||
|
dump_reg_init(f, cell->getPort("\\Q"));
|
||||||
|
f << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
|
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
|
||||||
dump_sigspec(f, sig_clk);
|
dump_sigspec(f, sig_clk);
|
||||||
|
@ -806,7 +888,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
// for memory block make something like:
|
// for memory block make something like:
|
||||||
// reg [7:0] memid [3:0];
|
// reg [7:0] memid [3:0];
|
||||||
// initial begin
|
// initial begin
|
||||||
// memid[0] <= ...
|
// memid[0] = ...
|
||||||
// end
|
// end
|
||||||
f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
|
f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
|
||||||
if (use_init)
|
if (use_init)
|
||||||
|
@ -814,7 +896,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
f << stringf("%s" "initial begin\n", indent.c_str());
|
f << stringf("%s" "initial begin\n", indent.c_str());
|
||||||
for (int i=0; i<size; i++)
|
for (int i=0; i<size; i++)
|
||||||
{
|
{
|
||||||
f << stringf("%s" " %s[%d] <= ", indent.c_str(), mem_id.c_str(), i);
|
f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i);
|
||||||
dump_const(f, cell->parameters["\\INIT"].extract(i*width, width));
|
dump_const(f, cell->parameters["\\INIT"].extract(i*width, width));
|
||||||
f << stringf(";\n");
|
f << stringf(";\n");
|
||||||
}
|
}
|
||||||
|
@ -912,7 +994,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
|
int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
|
||||||
RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
|
RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
|
||||||
bool wr_clk_posedge;
|
bool wr_clk_posedge;
|
||||||
SigMap sigmap(active_module);
|
|
||||||
// write ports
|
// write ports
|
||||||
for (int i=0; i < nwrite_ports; i++)
|
for (int i=0; i < nwrite_ports; i++)
|
||||||
{
|
{
|
||||||
|
@ -937,7 +1019,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
int start_i = i, width = 1;
|
int start_i = i, width = 1;
|
||||||
SigBit wen_bit = sig_wr_en[i];
|
SigBit wen_bit = sig_wr_en[i];
|
||||||
|
|
||||||
while (i+1 < GetSize(sig_wr_en) && sigmap(sig_wr_en[i+1]) == sigmap(wen_bit))
|
while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit))
|
||||||
i++, width++;
|
i++, width++;
|
||||||
|
|
||||||
if (wen_bit == State::S0)
|
if (wen_bit == State::S0)
|
||||||
|
@ -1251,6 +1333,16 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
||||||
reg_wires.clear();
|
reg_wires.clear();
|
||||||
reset_auto_counter(module);
|
reset_auto_counter(module);
|
||||||
active_module = module;
|
active_module = module;
|
||||||
|
active_sigmap.set(module);
|
||||||
|
active_initdata.clear();
|
||||||
|
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->attributes.count("\\init")) {
|
||||||
|
SigSpec sig = active_sigmap(wire);
|
||||||
|
Const val = wire->attributes.at("\\init");
|
||||||
|
for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
|
||||||
|
active_initdata[sig[i]] = val.bits.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
if (!module->processes.empty())
|
if (!module->processes.empty())
|
||||||
log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
|
log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
|
||||||
|
@ -1327,6 +1419,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
||||||
|
|
||||||
f << stringf("%s" "endmodule\n", indent.c_str());
|
f << stringf("%s" "endmodule\n", indent.c_str());
|
||||||
active_module = NULL;
|
active_module = NULL;
|
||||||
|
active_sigmap.clear();
|
||||||
|
active_initdata.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VerilogBackend : public Backend {
|
struct VerilogBackend : public Backend {
|
||||||
|
@ -1362,6 +1456,11 @@ struct VerilogBackend : public Backend {
|
||||||
log(" not bit pattern. This option decativates this feature and instead\n");
|
log(" not bit pattern. This option decativates this feature and instead\n");
|
||||||
log(" will write out all constants in binary.\n");
|
log(" will write out all constants in binary.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -nohex\n");
|
||||||
|
log(" constant values that are compatible with hex output are usually\n");
|
||||||
|
log(" dumped as hex values. This option decativates this feature and\n");
|
||||||
|
log(" instead will write out all constants in binary.\n");
|
||||||
|
log("\n");
|
||||||
log(" -nostr\n");
|
log(" -nostr\n");
|
||||||
log(" Parameters and attributes that are specified as strings in the\n");
|
log(" Parameters and attributes that are specified as strings in the\n");
|
||||||
log(" original input will be output as strings by this back-end. This\n");
|
log(" original input will be output as strings by this back-end. This\n");
|
||||||
|
@ -1401,6 +1500,7 @@ struct VerilogBackend : public Backend {
|
||||||
attr2comment = false;
|
attr2comment = false;
|
||||||
noexpr = false;
|
noexpr = false;
|
||||||
nodec = false;
|
nodec = false;
|
||||||
|
nohex = false;
|
||||||
nostr = false;
|
nostr = false;
|
||||||
defparam = false;
|
defparam = false;
|
||||||
auto_prefix = "";
|
auto_prefix = "";
|
||||||
|
@ -1461,6 +1561,10 @@ struct VerilogBackend : public Backend {
|
||||||
nodec = true;
|
nodec = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-nohex") {
|
||||||
|
nohex = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-nostr") {
|
if (arg == "-nostr") {
|
||||||
nostr = true;
|
nostr = true;
|
||||||
continue;
|
continue;
|
||||||
|
|
5
examples/aiger/.gitignore
vendored
Normal file
5
examples/aiger/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
demo.aig
|
||||||
|
demo.aim
|
||||||
|
demo.aiw
|
||||||
|
demo.smt2
|
||||||
|
demo.vcd
|
22
examples/aiger/README
Normal file
22
examples/aiger/README
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
AIGER is a format for And-Inverter Graphs (AIGs).
|
||||||
|
See http://fmv.jku.at/aiger/ for details.
|
||||||
|
|
||||||
|
AIGER is used in the Hardware Model Checking Competition (HWMCC),
|
||||||
|
therefore all solvers competing in the competition have to support
|
||||||
|
the format.
|
||||||
|
|
||||||
|
The example in this directory is using super_prove as solver. Check
|
||||||
|
http://downloads.bvsrc.org/super_prove/ for the lates release. (See
|
||||||
|
https://bitbucket.org/sterin/super_prove_build for sources.)
|
||||||
|
|
||||||
|
The "demo.sh" script in this directory expects a "super_prove" executable
|
||||||
|
in the PATH. E.g. extract the release to /usr/local/libexec/super_prove
|
||||||
|
and then create a /usr/local/bin/super_prove file with the following
|
||||||
|
contents (and "chmod +x" that file):
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
exec /usr/local/libexec/super_prove/bin/super_prove.sh "$@"
|
||||||
|
|
||||||
|
The "demo.sh" script also expects the "z3" SMT2 solver in the PATH for
|
||||||
|
converting the witness file generated by super_prove to VCD using
|
||||||
|
yosys-smtbmc. See https://github.com/Z3Prover/z3 for install notes.
|
14
examples/aiger/demo.sh
Normal file
14
examples/aiger/demo.sh
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
yosys -p '
|
||||||
|
read_verilog -formal demo.v
|
||||||
|
prep -flatten -nordff -top demo
|
||||||
|
write_smt2 -wires demo.smt2
|
||||||
|
flatten demo; delete -output
|
||||||
|
memory_map; opt -full
|
||||||
|
techmap; opt -fast
|
||||||
|
abc -fast -g AND; opt_clean
|
||||||
|
write_aiger -map demo.aim demo.aig
|
||||||
|
'
|
||||||
|
super_prove demo.aig > demo.aiw
|
||||||
|
yosys-smtbmc --dump-vcd demo.vcd --aig demo demo.smt2
|
12
examples/aiger/demo.v
Normal file
12
examples/aiger/demo.v
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module demo(input clk, reset, ctrl);
|
||||||
|
localparam NBITS = 10;
|
||||||
|
reg [NBITS-1:0] counter;
|
||||||
|
initial counter[NBITS-2] = 0;
|
||||||
|
initial counter[0] = 1;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
counter <= reset ? 1 : ctrl ? counter + 1 : counter - 1;
|
||||||
|
assume(counter != 0);
|
||||||
|
assume(counter != 1 << (NBITS-1));
|
||||||
|
assert(counter != (1 << NBITS)-1);
|
||||||
|
end
|
||||||
|
endmodule
|
8
examples/gowin/.gitignore
vendored
Normal file
8
examples/gowin/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
demo.bit
|
||||||
|
demo.out
|
||||||
|
demo.rpt
|
||||||
|
demo_syn.v
|
||||||
|
demo_out.v
|
||||||
|
demo_tr.html
|
||||||
|
testbench
|
||||||
|
testbench.vcd
|
17
examples/gowin/README
Normal file
17
examples/gowin/README
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Simple test project for Gowinsemi GW2A-55K Eval Board Mini.
|
||||||
|
|
||||||
|
Follow the install instructions for the Gowinsemi tools below,
|
||||||
|
then run "bash run.sh" in this directory.
|
||||||
|
|
||||||
|
|
||||||
|
Install instructions for gowinTool_linux
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
1.) extract gowinTool_linux.zip
|
||||||
|
|
||||||
|
2.) set GOWIN_HOME env variable to the full path to the
|
||||||
|
gowinTool_linux directory
|
||||||
|
|
||||||
|
3.) edit gowinTool_linux/bin/gwlicense.ini. Set lic="..." to
|
||||||
|
the full path to the license file.
|
||||||
|
|
41
examples/gowin/demo.cst
Normal file
41
examples/gowin/demo.cst
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// 50 MHz Clock
|
||||||
|
IO_LOC "clk" D11;
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
IO_LOC "leds[0]" D22;
|
||||||
|
IO_LOC "leds[1]" E22;
|
||||||
|
IO_LOC "leds[2]" G22;
|
||||||
|
IO_LOC "leds[3]" J22;
|
||||||
|
IO_LOC "leds[4]" L22;
|
||||||
|
IO_LOC "leds[5]" L19;
|
||||||
|
IO_LOC "leds[6]" L20;
|
||||||
|
IO_LOC "leds[7]" M21;
|
||||||
|
IO_LOC "leds[8]" N19;
|
||||||
|
IO_LOC "leds[9]" R19;
|
||||||
|
IO_LOC "leds[10]" T18;
|
||||||
|
IO_LOC "leds[11]" AA22;
|
||||||
|
IO_LOC "leds[12]" U18;
|
||||||
|
IO_LOC "leds[13]" V20;
|
||||||
|
IO_LOC "leds[14]" AA21;
|
||||||
|
IO_LOC "leds[15]" AB21;
|
||||||
|
|
||||||
|
|
||||||
|
// 7-Segment Display
|
||||||
|
IO_LOC "seg7dig[0]" E20;
|
||||||
|
IO_LOC "seg7dig[1]" G18;
|
||||||
|
IO_LOC "seg7dig[2]" G20;
|
||||||
|
IO_LOC "seg7dig[3]" F21;
|
||||||
|
IO_LOC "seg7dig[4]" J20;
|
||||||
|
IO_LOC "seg7dig[5]" H21;
|
||||||
|
IO_LOC "seg7dig[6]" H18;
|
||||||
|
IO_LOC "seg7dig[7]" D20;
|
||||||
|
IO_LOC "seg7sel[0]" C19;
|
||||||
|
IO_LOC "seg7sel[1]" B22;
|
||||||
|
IO_LOC "seg7sel[2]" C20;
|
||||||
|
IO_LOC "seg7sel[3]" C21;
|
||||||
|
|
||||||
|
// Switches
|
||||||
|
IO_LOC "sw[0]" AB20;
|
||||||
|
IO_LOC "sw[1]" AB19;
|
||||||
|
IO_LOC "sw[2]" AB18;
|
||||||
|
IO_LOC "sw[3]" AB17;
|
1
examples/gowin/demo.sdc
Normal file
1
examples/gowin/demo.sdc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
create_clock -name clk -period 20 -waveform {0 10} [get_ports {clk}]
|
12
examples/gowin/demo.v
Normal file
12
examples/gowin/demo.v
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module demo (
|
||||||
|
input clk,
|
||||||
|
input [3:0] sw,
|
||||||
|
output [15:0] leds,
|
||||||
|
output [7:0] seg7dig,
|
||||||
|
output [3:0] seg7sel
|
||||||
|
);
|
||||||
|
localparam PRESCALE = 20;
|
||||||
|
reg [PRESCALE+3:0] counter = 0;
|
||||||
|
always @(posedge clk) counter <= counter + 1;
|
||||||
|
assign leds = 1 << counter[PRESCALE +: 4];
|
||||||
|
endmodule
|
12
examples/gowin/run.sh
Normal file
12
examples/gowin/run.sh
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
yosys -p "synth_gowin -top demo -vout demo_syn.v" demo.v
|
||||||
|
$GOWIN_HOME/bin/gowin -d demo_syn.v -cst demo.cst -sdc demo.sdc -p GW2A55-PBGA484-6 \
|
||||||
|
-warning_all -out demo_out.v -rpt demo.rpt -tr demo_tr.html -bit demo.bit
|
||||||
|
|
||||||
|
# post place&route simulation (icarus verilog)
|
||||||
|
if false; then
|
||||||
|
iverilog -D POST_IMPL -o testbench -s testbench testbench.v \
|
||||||
|
demo_out.v $(yosys-config --datdir/gowin/cells_sim.v)
|
||||||
|
vvp -N testbench
|
||||||
|
fi
|
40
examples/gowin/testbench.v
Normal file
40
examples/gowin/testbench.v
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
module testbench;
|
||||||
|
reg clk;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#5 clk = 0;
|
||||||
|
forever #5 clk = ~clk;
|
||||||
|
end
|
||||||
|
|
||||||
|
wire [15:0] leds;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// $dumpfile("testbench.vcd");
|
||||||
|
// $dumpvars(0, testbench);
|
||||||
|
$monitor("%b", leds);
|
||||||
|
end
|
||||||
|
|
||||||
|
demo uut (
|
||||||
|
.clk (clk ),
|
||||||
|
`ifdef POST_IMPL
|
||||||
|
.\leds[0] (leds[0]),
|
||||||
|
.\leds[1] (leds[1]),
|
||||||
|
.\leds[2] (leds[2]),
|
||||||
|
.\leds[3] (leds[3]),
|
||||||
|
.\leds[4] (leds[4]),
|
||||||
|
.\leds[5] (leds[5]),
|
||||||
|
.\leds[6] (leds[6]),
|
||||||
|
.\leds[7] (leds[7]),
|
||||||
|
.\leds[8] (leds[8]),
|
||||||
|
.\leds[9] (leds[9]),
|
||||||
|
.\leds[10] (leds[10]),
|
||||||
|
.\leds[11] (leds[11]),
|
||||||
|
.\leds[12] (leds[12]),
|
||||||
|
.\leds[13] (leds[13]),
|
||||||
|
.\leds[14] (leds[14]),
|
||||||
|
.\leds[15] (leds[15])
|
||||||
|
`else
|
||||||
|
.leds(leds)
|
||||||
|
`endif
|
||||||
|
);
|
||||||
|
endmodule
|
|
@ -1016,14 +1016,12 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
|
||||||
flag_icells = icells;
|
flag_icells = icells;
|
||||||
flag_autowire = autowire;
|
flag_autowire = autowire;
|
||||||
|
|
||||||
std::vector<AstNode*> global_decls;
|
|
||||||
|
|
||||||
log_assert(current_ast->type == AST_DESIGN);
|
log_assert(current_ast->type == AST_DESIGN);
|
||||||
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
|
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
|
||||||
{
|
{
|
||||||
if ((*it)->type == AST_MODULE)
|
if ((*it)->type == AST_MODULE)
|
||||||
{
|
{
|
||||||
for (auto n : global_decls)
|
for (auto n : design->verilog_globals)
|
||||||
(*it)->children.push_back(n->clone());
|
(*it)->children.push_back(n->clone());
|
||||||
|
|
||||||
for (auto n : design->verilog_packages){
|
for (auto n : design->verilog_packages){
|
||||||
|
@ -1054,7 +1052,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
|
||||||
else if ((*it)->type == AST_PACKAGE)
|
else if ((*it)->type == AST_PACKAGE)
|
||||||
design->verilog_packages.push_back((*it)->clone());
|
design->verilog_packages.push_back((*it)->clone());
|
||||||
else
|
else
|
||||||
global_decls.push_back(*it);
|
design->verilog_globals.push_back((*it)->clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1115,8 +1113,13 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
|
||||||
goto rewrite_parameter;
|
goto rewrite_parameter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parameters.size() > 0)
|
|
||||||
log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), stripped_name.c_str());
|
for (auto param : parameters) {
|
||||||
|
AstNode *defparam = new AstNode(AST_DEFPARAM, new AstNode(AST_IDENTIFIER));
|
||||||
|
defparam->children[0]->str = param.first.str();
|
||||||
|
defparam->children.push_back(AstNode::mkconst_bits(param.second.bits, (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0));
|
||||||
|
new_ast->children.push_back(defparam);
|
||||||
|
}
|
||||||
|
|
||||||
std::string modname;
|
std::string modname;
|
||||||
|
|
||||||
|
|
|
@ -685,19 +685,40 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
current_scope.clear();
|
current_scope.clear();
|
||||||
|
|
||||||
// convert defparam nodes to cell parameters
|
// convert defparam nodes to cell parameters
|
||||||
if (type == AST_DEFPARAM && !str.empty()) {
|
if (type == AST_DEFPARAM && !children.empty())
|
||||||
size_t pos = str.rfind('.');
|
{
|
||||||
|
if (children[0]->type != AST_IDENTIFIER)
|
||||||
|
log_error("Module name in defparam at %s:%d contains non-constant expressions!\n", filename.c_str(), linenum);
|
||||||
|
|
||||||
|
string modname, paramname = children[0]->str;
|
||||||
|
|
||||||
|
size_t pos = paramname.rfind('.');
|
||||||
|
|
||||||
|
while (pos != 0 && pos != std::string::npos)
|
||||||
|
{
|
||||||
|
modname = paramname.substr(0, pos);
|
||||||
|
|
||||||
|
if (current_scope.count(modname))
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos = paramname.rfind('.', pos - 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
log_error("Defparam `%s' does not contain a dot (module/parameter separator) at %s:%d!\n",
|
log_error("Can't find object for defparam `%s` at %s:%d!\n", RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum);
|
||||||
RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
|
|
||||||
std::string modname = str.substr(0, pos), paraname = "\\" + str.substr(pos+1);
|
paramname = "\\" + paramname.substr(pos+1);
|
||||||
if (current_scope.count(modname) == 0 || current_scope.at(modname)->type != AST_CELL)
|
|
||||||
log_error("Can't find cell for defparam `%s . %s` at %s:%d!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paraname).c_str(), filename.c_str(), linenum);
|
if (current_scope.at(modname)->type != AST_CELL)
|
||||||
AstNode *cell = current_scope.at(modname), *paraset = clone();
|
log_error("Defparam argument `%s . %s` does not match a cell at %s:%d!\n",
|
||||||
|
RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum);
|
||||||
|
|
||||||
|
AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL);
|
||||||
|
paraset->str = paramname;
|
||||||
|
|
||||||
|
AstNode *cell = current_scope.at(modname);
|
||||||
cell->children.insert(cell->children.begin() + 1, paraset);
|
cell->children.insert(cell->children.begin() + 1, paraset);
|
||||||
paraset->type = AST_PARASET;
|
delete_children();
|
||||||
paraset->str = paraname;
|
|
||||||
str.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve constant prefixes
|
// resolve constant prefixes
|
||||||
|
@ -1062,6 +1083,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
did_something = true;
|
did_something = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for local objects in unnamed block
|
||||||
|
if (type == AST_BLOCK && str.empty())
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < children.size(); i++)
|
||||||
|
if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM)
|
||||||
|
log_error("Local declaration in unnamed block at %s:%d is an unsupported SystemVerilog feature!\n",
|
||||||
|
children[i]->filename.c_str(), children[i]->linenum);
|
||||||
|
}
|
||||||
|
|
||||||
// transform block with name
|
// transform block with name
|
||||||
if (type == AST_BLOCK && !str.empty())
|
if (type == AST_BLOCK && !str.empty())
|
||||||
{
|
{
|
||||||
|
@ -1070,7 +1100,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
|
|
||||||
std::vector<AstNode*> new_children;
|
std::vector<AstNode*> new_children;
|
||||||
for (size_t i = 0; i < children.size(); i++)
|
for (size_t i = 0; i < children.size(); i++)
|
||||||
if (children[i]->type == AST_WIRE || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
|
if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
|
||||||
children[i]->simplify(false, false, false, stage, -1, false, false);
|
children[i]->simplify(false, false, false, stage, -1, false, false);
|
||||||
current_ast_mod->children.push_back(children[i]);
|
current_ast_mod->children.push_back(children[i]);
|
||||||
current_scope[children[i]->str] = children[i];
|
current_scope[children[i]->str] = children[i];
|
||||||
|
@ -1843,7 +1873,8 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
if (str == "\\$ln" || str == "\\$log10" || str == "\\$exp" || str == "\\$sqrt" || str == "\\$pow" ||
|
if (str == "\\$ln" || str == "\\$log10" || str == "\\$exp" || str == "\\$sqrt" || str == "\\$pow" ||
|
||||||
str == "\\$floor" || str == "\\$ceil" || str == "\\$sin" || str == "\\$cos" || str == "\\$tan" ||
|
str == "\\$floor" || str == "\\$ceil" || str == "\\$sin" || str == "\\$cos" || str == "\\$tan" ||
|
||||||
str == "\\$asin" || str == "\\$acos" || str == "\\$atan" || str == "\\$atan2" || str == "\\$hypot" ||
|
str == "\\$asin" || str == "\\$acos" || str == "\\$atan" || str == "\\$atan2" || str == "\\$hypot" ||
|
||||||
str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh")
|
str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh" ||
|
||||||
|
str == "\\$rtoi" || str == "\\$itor")
|
||||||
{
|
{
|
||||||
bool func_with_two_arguments = str == "\\$pow" || str == "\\$atan2" || str == "\\$hypot";
|
bool func_with_two_arguments = str == "\\$pow" || str == "\\$atan2" || str == "\\$hypot";
|
||||||
double x = 0, y = 0;
|
double x = 0, y = 0;
|
||||||
|
@ -1880,29 +1911,34 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
y = children[1]->asReal(child_sign_hint);
|
y = children[1]->asReal(child_sign_hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
newNode = new AstNode(AST_REALVALUE);
|
if (str == "\\$rtoi") {
|
||||||
if (str == "\\$ln") newNode->realvalue = ::log(x);
|
newNode = AstNode::mkconst_int(x, true);
|
||||||
else if (str == "\\$log10") newNode->realvalue = ::log10(x);
|
} else {
|
||||||
else if (str == "\\$exp") newNode->realvalue = ::exp(x);
|
newNode = new AstNode(AST_REALVALUE);
|
||||||
else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x);
|
if (str == "\\$ln") newNode->realvalue = ::log(x);
|
||||||
else if (str == "\\$pow") newNode->realvalue = ::pow(x, y);
|
else if (str == "\\$log10") newNode->realvalue = ::log10(x);
|
||||||
else if (str == "\\$floor") newNode->realvalue = ::floor(x);
|
else if (str == "\\$exp") newNode->realvalue = ::exp(x);
|
||||||
else if (str == "\\$ceil") newNode->realvalue = ::ceil(x);
|
else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x);
|
||||||
else if (str == "\\$sin") newNode->realvalue = ::sin(x);
|
else if (str == "\\$pow") newNode->realvalue = ::pow(x, y);
|
||||||
else if (str == "\\$cos") newNode->realvalue = ::cos(x);
|
else if (str == "\\$floor") newNode->realvalue = ::floor(x);
|
||||||
else if (str == "\\$tan") newNode->realvalue = ::tan(x);
|
else if (str == "\\$ceil") newNode->realvalue = ::ceil(x);
|
||||||
else if (str == "\\$asin") newNode->realvalue = ::asin(x);
|
else if (str == "\\$sin") newNode->realvalue = ::sin(x);
|
||||||
else if (str == "\\$acos") newNode->realvalue = ::acos(x);
|
else if (str == "\\$cos") newNode->realvalue = ::cos(x);
|
||||||
else if (str == "\\$atan") newNode->realvalue = ::atan(x);
|
else if (str == "\\$tan") newNode->realvalue = ::tan(x);
|
||||||
else if (str == "\\$atan2") newNode->realvalue = ::atan2(x, y);
|
else if (str == "\\$asin") newNode->realvalue = ::asin(x);
|
||||||
else if (str == "\\$hypot") newNode->realvalue = ::hypot(x, y);
|
else if (str == "\\$acos") newNode->realvalue = ::acos(x);
|
||||||
else if (str == "\\$sinh") newNode->realvalue = ::sinh(x);
|
else if (str == "\\$atan") newNode->realvalue = ::atan(x);
|
||||||
else if (str == "\\$cosh") newNode->realvalue = ::cosh(x);
|
else if (str == "\\$atan2") newNode->realvalue = ::atan2(x, y);
|
||||||
else if (str == "\\$tanh") newNode->realvalue = ::tanh(x);
|
else if (str == "\\$hypot") newNode->realvalue = ::hypot(x, y);
|
||||||
else if (str == "\\$asinh") newNode->realvalue = ::asinh(x);
|
else if (str == "\\$sinh") newNode->realvalue = ::sinh(x);
|
||||||
else if (str == "\\$acosh") newNode->realvalue = ::acosh(x);
|
else if (str == "\\$cosh") newNode->realvalue = ::cosh(x);
|
||||||
else if (str == "\\$atanh") newNode->realvalue = ::atanh(x);
|
else if (str == "\\$tanh") newNode->realvalue = ::tanh(x);
|
||||||
else log_abort();
|
else if (str == "\\$asinh") newNode->realvalue = ::asinh(x);
|
||||||
|
else if (str == "\\$acosh") newNode->realvalue = ::acosh(x);
|
||||||
|
else if (str == "\\$atanh") newNode->realvalue = ::atanh(x);
|
||||||
|
else if (str == "\\$itor") newNode->realvalue = x;
|
||||||
|
else log_abort();
|
||||||
|
}
|
||||||
goto apply_newNode;
|
goto apply_newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2137,7 +2173,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto child : decl->children)
|
for (auto child : decl->children)
|
||||||
if (child->type == AST_WIRE || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
|
if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
|
||||||
{
|
{
|
||||||
AstNode *wire = nullptr;
|
AstNode *wire = nullptr;
|
||||||
|
|
||||||
|
@ -2197,7 +2233,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto child : decl->children)
|
for (auto child : decl->children)
|
||||||
if (child->type != AST_WIRE && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)
|
if (child->type != AST_WIRE && child->type != AST_MEMORY && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)
|
||||||
{
|
{
|
||||||
AstNode *stmt = child->clone();
|
AstNode *stmt = child->clone();
|
||||||
stmt->replace_ids(prefix, replace_rules);
|
stmt->replace_ids(prefix, replace_rules);
|
||||||
|
@ -2660,7 +2696,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
|
||||||
std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
|
std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
|
||||||
size_t pos = child->str.rfind('.');
|
size_t pos = child->str.rfind('.');
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
pos = child->str[0] == '\\' ? 1 : 0;
|
pos = child->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0;
|
||||||
else
|
else
|
||||||
pos = pos + 1;
|
pos = pos + 1;
|
||||||
new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos);
|
new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos);
|
||||||
|
@ -3043,6 +3079,8 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
|
||||||
|
|
||||||
if (bit_part_sel)
|
if (bit_part_sel)
|
||||||
children.push_back(bit_part_sel);
|
children.push_back(bit_part_sel);
|
||||||
|
|
||||||
|
did_something = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
|
log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
|
||||||
|
|
|
@ -210,7 +210,8 @@ static void input_file(std::istream &f, std::string filename)
|
||||||
input_buffer.insert(it, "\n`file_pop\n");
|
input_buffer.insert(it, "\n`file_pop\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
|
std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map,
|
||||||
|
dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs)
|
||||||
{
|
{
|
||||||
std::set<std::string> defines_with_args;
|
std::set<std::string> defines_with_args;
|
||||||
std::map<std::string, std::string> defines_map(pre_defines_map);
|
std::map<std::string, std::string> defines_map(pre_defines_map);
|
||||||
|
@ -222,9 +223,19 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
|
||||||
input_buffer_charp = 0;
|
input_buffer_charp = 0;
|
||||||
|
|
||||||
input_file(f, filename);
|
input_file(f, filename);
|
||||||
|
|
||||||
defines_map["YOSYS"] = "1";
|
defines_map["YOSYS"] = "1";
|
||||||
defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1";
|
defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1";
|
||||||
|
|
||||||
|
for (auto &it : pre_defines_map)
|
||||||
|
defines_map[it.first] = it.second;
|
||||||
|
|
||||||
|
for (auto &it : global_defines_cache) {
|
||||||
|
if (it.second.second)
|
||||||
|
defines_with_args.insert(it.first);
|
||||||
|
defines_map[it.first] = it.second.first;
|
||||||
|
}
|
||||||
|
|
||||||
while (!input_buffer.empty())
|
while (!input_buffer.empty())
|
||||||
{
|
{
|
||||||
std::string tok = next_token();
|
std::string tok = next_token();
|
||||||
|
@ -281,6 +292,8 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
|
||||||
if (tok == "`include") {
|
if (tok == "`include") {
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
std::string fn = next_token(true);
|
std::string fn = next_token(true);
|
||||||
|
while (fn.size() > 1 && fn[0] == '`' && defines_map.count(fn.substr(1)) > 0)
|
||||||
|
fn = defines_map.at(fn.substr(1));
|
||||||
while (1) {
|
while (1) {
|
||||||
size_t pos = fn.find('"');
|
size_t pos = fn.find('"');
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
|
@ -379,6 +392,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
|
||||||
defines_with_args.insert(name);
|
defines_with_args.insert(name);
|
||||||
else
|
else
|
||||||
defines_with_args.erase(name);
|
defines_with_args.erase(name);
|
||||||
|
global_defines_cache[name] = std::pair<std::string, bool>(value, state == 2);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,6 +403,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
|
||||||
// printf("undef: >>%s<<\n", name.c_str());
|
// printf("undef: >>%s<<\n", name.c_str());
|
||||||
defines_map.erase(name);
|
defines_map.erase(name);
|
||||||
defines_with_args.erase(name);
|
defines_with_args.erase(name);
|
||||||
|
global_defines_cache.erase(name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,10 +303,10 @@ struct VerilogFrontend : public Frontend {
|
||||||
}
|
}
|
||||||
if (arg == "-D" && argidx+1 < args.size()) {
|
if (arg == "-D" && argidx+1 < args.size()) {
|
||||||
std::string name = args[++argidx], value;
|
std::string name = args[++argidx], value;
|
||||||
size_t equal = name.find('=', 2);
|
size_t equal = name.find('=');
|
||||||
if (equal != std::string::npos) {
|
if (equal != std::string::npos) {
|
||||||
value = arg.substr(equal+1);
|
value = name.substr(equal+1);
|
||||||
name = arg.substr(0, equal);
|
name = name.substr(0, equal);
|
||||||
}
|
}
|
||||||
defines_map[name] = value;
|
defines_map[name] = value;
|
||||||
continue;
|
continue;
|
||||||
|
@ -345,7 +345,7 @@ struct VerilogFrontend : public Frontend {
|
||||||
std::string code_after_preproc;
|
std::string code_after_preproc;
|
||||||
|
|
||||||
if (!flag_nopp) {
|
if (!flag_nopp) {
|
||||||
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, include_dirs);
|
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, design->verilog_defines, include_dirs);
|
||||||
if (flag_ppdump)
|
if (flag_ppdump)
|
||||||
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
|
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
|
||||||
lexin = new std::istringstream(code_after_preproc);
|
lexin = new std::istringstream(code_after_preproc);
|
||||||
|
@ -436,6 +436,66 @@ struct VerilogDefaults : public Pass {
|
||||||
}
|
}
|
||||||
} VerilogDefaults;
|
} VerilogDefaults;
|
||||||
|
|
||||||
|
struct VerilogDefines : public Pass {
|
||||||
|
VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { }
|
||||||
|
virtual void help()
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" verilog_defines [options]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Define and undefine verilog preprocessor macros.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -Dname[=definition]\n");
|
||||||
|
log(" define the preprocessor symbol 'name' and set its optional value\n");
|
||||||
|
log(" 'definition'\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -Uname[=definition]\n");
|
||||||
|
log(" undefine the preprocessor symbol 'name'\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
|
{
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
std::string arg = args[argidx];
|
||||||
|
if (arg == "-D" && argidx+1 < args.size()) {
|
||||||
|
std::string name = args[++argidx], value;
|
||||||
|
size_t equal = name.find('=');
|
||||||
|
if (equal != std::string::npos) {
|
||||||
|
value = name.substr(equal+1);
|
||||||
|
name = name.substr(0, equal);
|
||||||
|
}
|
||||||
|
design->verilog_defines[name] = std::pair<std::string, bool>(value, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg.compare(0, 2, "-D") == 0) {
|
||||||
|
size_t equal = arg.find('=', 2);
|
||||||
|
std::string name = arg.substr(2, equal-2);
|
||||||
|
std::string value;
|
||||||
|
if (equal != std::string::npos)
|
||||||
|
value = arg.substr(equal+1);
|
||||||
|
design->verilog_defines[name] = std::pair<std::string, bool>(value, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-U" && argidx+1 < args.size()) {
|
||||||
|
std::string name = args[++argidx];
|
||||||
|
design->verilog_defines.erase(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg.compare(0, 2, "-U") == 0) {
|
||||||
|
std::string name = arg.substr(2);
|
||||||
|
design->verilog_defines.erase(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.size() != argidx)
|
||||||
|
cmd_error(args, argidx, "Extra argument.");
|
||||||
|
}
|
||||||
|
} VerilogDefines;
|
||||||
|
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
// the yyerror function used by bison to report parser errors
|
// the yyerror function used by bison to report parser errors
|
||||||
|
|
|
@ -68,7 +68,8 @@ namespace VERILOG_FRONTEND
|
||||||
}
|
}
|
||||||
|
|
||||||
// the pre-processor
|
// the pre-processor
|
||||||
std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs);
|
std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map,
|
||||||
|
dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs);
|
||||||
|
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,9 @@ YOSYS_NAMESPACE_END
|
||||||
"genvar" { return TOK_GENVAR; }
|
"genvar" { return TOK_GENVAR; }
|
||||||
"real" { return TOK_REAL; }
|
"real" { return TOK_REAL; }
|
||||||
|
|
||||||
|
"enum" { SV_KEYWORD(TOK_ENUM); }
|
||||||
|
"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
|
||||||
|
|
||||||
[0-9][0-9_]* {
|
[0-9][0-9_]* {
|
||||||
frontend_verilog_yylval.string = new std::string(yytext);
|
frontend_verilog_yylval.string = new std::string(yytext);
|
||||||
return TOK_CONST;
|
return TOK_CONST;
|
||||||
|
|
|
@ -114,7 +114,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
||||||
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||||
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
||||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
|
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
|
||||||
%token TOK_RESTRICT TOK_PROPERTY
|
%token TOK_RESTRICT TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
||||||
|
|
||||||
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
||||||
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
||||||
|
@ -666,14 +666,13 @@ defparam_decl_list:
|
||||||
single_defparam_decl | defparam_decl_list ',' single_defparam_decl;
|
single_defparam_decl | defparam_decl_list ',' single_defparam_decl;
|
||||||
|
|
||||||
single_defparam_decl:
|
single_defparam_decl:
|
||||||
range hierarchical_id '=' expr {
|
range rvalue '=' expr {
|
||||||
AstNode *node = new AstNode(AST_DEFPARAM);
|
AstNode *node = new AstNode(AST_DEFPARAM);
|
||||||
node->str = *$2;
|
node->children.push_back($2);
|
||||||
node->children.push_back($4);
|
node->children.push_back($4);
|
||||||
if ($1 != NULL)
|
if ($1 != NULL)
|
||||||
node->children.push_back($1);
|
node->children.push_back($1);
|
||||||
ast_stack.back()->children.push_back(node);
|
ast_stack.back()->children.push_back(node);
|
||||||
delete $2;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
wire_decl:
|
wire_decl:
|
||||||
|
|
|
@ -218,6 +218,9 @@ int main(int argc, char **argv)
|
||||||
printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n");
|
printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n");
|
||||||
printf(" Use 'ALL' as <header_id> to dump at every header.\n");
|
printf(" Use 'ALL' as <header_id> to dump at every header.\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
printf(" -W regex\n");
|
||||||
|
printf(" print a warning for all log messages matching the regex \n");
|
||||||
|
printf("\n");
|
||||||
printf(" -V\n");
|
printf(" -V\n");
|
||||||
printf(" print version information and exit\n");
|
printf(" print version information and exit\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -238,7 +241,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:D:")) != -1)
|
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:D:")) != -1)
|
||||||
{
|
{
|
||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
|
@ -320,6 +323,12 @@ int main(int argc, char **argv)
|
||||||
scriptfile = optarg;
|
scriptfile = optarg;
|
||||||
scriptfile_tcl = true;
|
scriptfile_tcl = true;
|
||||||
break;
|
break;
|
||||||
|
case 'W':
|
||||||
|
log_warn_regexes.push_back(std::regex(optarg,
|
||||||
|
std::regex_constants::nosubs |
|
||||||
|
std::regex_constants::optimize |
|
||||||
|
std::regex_constants::egrep));
|
||||||
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
{
|
{
|
||||||
auto args = split_tokens(optarg, ":");
|
auto args = split_tokens(optarg, ":");
|
||||||
|
|
|
@ -41,6 +41,7 @@ YOSYS_NAMESPACE_BEGIN
|
||||||
std::vector<FILE*> log_files;
|
std::vector<FILE*> log_files;
|
||||||
std::vector<std::ostream*> log_streams;
|
std::vector<std::ostream*> log_streams;
|
||||||
std::map<std::string, std::set<std::string>> log_hdump;
|
std::map<std::string, std::set<std::string>> log_hdump;
|
||||||
|
std::vector<std::regex> log_warn_regexes;
|
||||||
bool log_hdump_all = false;
|
bool log_hdump_all = false;
|
||||||
FILE *log_errfile = NULL;
|
FILE *log_errfile = NULL;
|
||||||
SHA1 *log_hasher = NULL;
|
SHA1 *log_hasher = NULL;
|
||||||
|
@ -136,6 +137,32 @@ void logv(const char *format, va_list ap)
|
||||||
|
|
||||||
for (auto f : log_streams)
|
for (auto f : log_streams)
|
||||||
*f << str;
|
*f << str;
|
||||||
|
|
||||||
|
static std::string linebuffer;
|
||||||
|
static bool log_warn_regex_recusion_guard = false;
|
||||||
|
|
||||||
|
if (!log_warn_regex_recusion_guard)
|
||||||
|
{
|
||||||
|
log_warn_regex_recusion_guard = true;
|
||||||
|
|
||||||
|
if (log_warn_regexes.empty())
|
||||||
|
{
|
||||||
|
linebuffer.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
linebuffer += str;
|
||||||
|
|
||||||
|
if (!linebuffer.empty() && linebuffer.back() == '\n') {
|
||||||
|
for (auto &re : log_warn_regexes)
|
||||||
|
if (std::regex_search(linebuffer, re))
|
||||||
|
log_warning("Found log message matching -W regex:\n%s", str.c_str());
|
||||||
|
linebuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn_regex_recusion_guard = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void logv_header(RTLIL::Design *design, const char *format, va_list ap)
|
void logv_header(RTLIL::Design *design, const char *format, va_list ap)
|
||||||
|
@ -262,8 +289,8 @@ void log_cmd_error(const char *format, ...)
|
||||||
|
|
||||||
void log_spacer()
|
void log_spacer()
|
||||||
{
|
{
|
||||||
while (log_newline_count < 2)
|
if (log_newline_count < 2) log("\n");
|
||||||
log("\n");
|
if (log_newline_count < 2) log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_push()
|
void log_push()
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define LOG_H
|
#define LOG_H
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
|
@ -48,6 +49,7 @@ struct log_cmd_error_exception { };
|
||||||
extern std::vector<FILE*> log_files;
|
extern std::vector<FILE*> log_files;
|
||||||
extern std::vector<std::ostream*> log_streams;
|
extern std::vector<std::ostream*> log_streams;
|
||||||
extern std::map<std::string, std::set<std::string>> log_hdump;
|
extern std::map<std::string, std::set<std::string>> log_hdump;
|
||||||
|
extern std::vector<std::regex> log_warn_regexes;
|
||||||
extern bool log_hdump_all;
|
extern bool log_hdump_all;
|
||||||
extern FILE *log_errfile;
|
extern FILE *log_errfile;
|
||||||
extern SHA1 *log_hasher;
|
extern SHA1 *log_hasher;
|
||||||
|
|
|
@ -173,7 +173,7 @@ void Pass::call(RTLIL::Design *design, std::string command)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!tok.empty()) {
|
while (!tok.empty()) {
|
||||||
if (tok == "#") {
|
if (tok[0] == '#') {
|
||||||
int stop;
|
int stop;
|
||||||
for (stop = 0; stop < GetSize(cmd_buf); stop++)
|
for (stop = 0; stop < GetSize(cmd_buf); stop++)
|
||||||
if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n')
|
if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n')
|
||||||
|
|
|
@ -306,6 +306,8 @@ RTLIL::Design::~Design()
|
||||||
delete it->second;
|
delete it->second;
|
||||||
for (auto n : verilog_packages)
|
for (auto n : verilog_packages)
|
||||||
delete n;
|
delete n;
|
||||||
|
for (auto n : verilog_globals)
|
||||||
|
delete n;
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
|
RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
|
||||||
|
@ -2048,6 +2050,7 @@ RTLIL::Memory::Memory()
|
||||||
hashidx_ = hashidx_count;
|
hashidx_ = hashidx_count;
|
||||||
|
|
||||||
width = 1;
|
width = 1;
|
||||||
|
start_offset = 0;
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2764,10 +2767,11 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe
|
||||||
other->unpack();
|
other->unpack();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = GetSize(bits_) - 1; i >= 0; i--) {
|
for (int i = GetSize(bits_) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
if (bits_[i].wire == NULL) continue;
|
if (bits_[i].wire == NULL) continue;
|
||||||
|
|
||||||
for (auto &pattern_chunk : pattern.chunks()) {
|
for (auto &pattern_chunk : pattern.chunks())
|
||||||
if (bits_[i].wire == pattern_chunk.wire &&
|
if (bits_[i].wire == pattern_chunk.wire &&
|
||||||
bits_[i].offset >= pattern_chunk.offset &&
|
bits_[i].offset >= pattern_chunk.offset &&
|
||||||
bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) {
|
bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) {
|
||||||
|
@ -2777,8 +2781,8 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe
|
||||||
other->bits_.erase(other->bits_.begin() + i);
|
other->bits_.erase(other->bits_.begin() + i);
|
||||||
other->width_--;
|
other->width_--;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check();
|
check();
|
||||||
|
|
|
@ -793,7 +793,8 @@ struct RTLIL::Design
|
||||||
|
|
||||||
int refcount_modules_;
|
int refcount_modules_;
|
||||||
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
dict<RTLIL::IdString, RTLIL::Module*> modules_;
|
||||||
std::vector<AST::AstNode*> verilog_packages;
|
std::vector<AST::AstNode*> verilog_packages, verilog_globals;
|
||||||
|
dict<std::string, std::pair<std::string, bool>> verilog_defines;
|
||||||
|
|
||||||
std::vector<RTLIL::Selection> selection_stack;
|
std::vector<RTLIL::Selection> selection_stack;
|
||||||
dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
|
dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
|
||||||
|
|
|
@ -903,6 +903,8 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig
|
||||||
command = "verilog";
|
command = "verilog";
|
||||||
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
|
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
|
||||||
command = "ilang";
|
command = "ilang";
|
||||||
|
else if (filename.size() > 4 && filename.substr(filename.size()-4) == ".aig")
|
||||||
|
command = "aiger";
|
||||||
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
|
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
|
||||||
command = "blif";
|
command = "blif";
|
||||||
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif")
|
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif")
|
||||||
|
|
|
@ -44,6 +44,9 @@ struct CheckPass : public Pass {
|
||||||
log("When called with -noinit then this command also checks for wires which have\n");
|
log("When called with -noinit then this command also checks for wires which have\n");
|
||||||
log("the 'init' attribute set.\n");
|
log("the 'init' attribute set.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("When called with -initdrv then this command also checks for wires which have\n");
|
||||||
|
log("the 'init' attribute set and aren't driven by a FF cell type.\n");
|
||||||
|
log("\n");
|
||||||
log("When called with -assert then the command will produce an error if any\n");
|
log("When called with -assert then the command will produce an error if any\n");
|
||||||
log("problems are found in the current design.\n");
|
log("problems are found in the current design.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -52,6 +55,7 @@ struct CheckPass : public Pass {
|
||||||
{
|
{
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
bool noinit = false;
|
bool noinit = false;
|
||||||
|
bool initdrv = false;
|
||||||
bool assert_mode = false;
|
bool assert_mode = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
|
@ -60,6 +64,10 @@ struct CheckPass : public Pass {
|
||||||
noinit = true;
|
noinit = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-initdrv") {
|
||||||
|
initdrv = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-assert") {
|
if (args[argidx] == "-assert") {
|
||||||
assert_mode = true;
|
assert_mode = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -70,6 +78,49 @@ struct CheckPass : public Pass {
|
||||||
|
|
||||||
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
|
log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
|
||||||
|
|
||||||
|
pool<IdString> fftypes;
|
||||||
|
fftypes.insert("$sr");
|
||||||
|
fftypes.insert("$ff");
|
||||||
|
fftypes.insert("$dff");
|
||||||
|
fftypes.insert("$dffe");
|
||||||
|
fftypes.insert("$dffsr");
|
||||||
|
fftypes.insert("$adff");
|
||||||
|
fftypes.insert("$dlatch");
|
||||||
|
fftypes.insert("$dlatchsr");
|
||||||
|
fftypes.insert("$_DFFE_NN_");
|
||||||
|
fftypes.insert("$_DFFE_NP_");
|
||||||
|
fftypes.insert("$_DFFE_PN_");
|
||||||
|
fftypes.insert("$_DFFE_PP_");
|
||||||
|
fftypes.insert("$_DFFSR_NNN_");
|
||||||
|
fftypes.insert("$_DFFSR_NNP_");
|
||||||
|
fftypes.insert("$_DFFSR_NPN_");
|
||||||
|
fftypes.insert("$_DFFSR_NPP_");
|
||||||
|
fftypes.insert("$_DFFSR_PNN_");
|
||||||
|
fftypes.insert("$_DFFSR_PNP_");
|
||||||
|
fftypes.insert("$_DFFSR_PPN_");
|
||||||
|
fftypes.insert("$_DFFSR_PPP_");
|
||||||
|
fftypes.insert("$_DFF_NN0_");
|
||||||
|
fftypes.insert("$_DFF_NN1_");
|
||||||
|
fftypes.insert("$_DFF_NP0_");
|
||||||
|
fftypes.insert("$_DFF_NP1_");
|
||||||
|
fftypes.insert("$_DFF_N_");
|
||||||
|
fftypes.insert("$_DFF_PN0_");
|
||||||
|
fftypes.insert("$_DFF_PN1_");
|
||||||
|
fftypes.insert("$_DFF_PP0_");
|
||||||
|
fftypes.insert("$_DFF_PP1_");
|
||||||
|
fftypes.insert("$_DFF_P_");
|
||||||
|
fftypes.insert("$_DLATCHSR_NNN_");
|
||||||
|
fftypes.insert("$_DLATCHSR_NNP_");
|
||||||
|
fftypes.insert("$_DLATCHSR_NPN_");
|
||||||
|
fftypes.insert("$_DLATCHSR_NPP_");
|
||||||
|
fftypes.insert("$_DLATCHSR_PNN_");
|
||||||
|
fftypes.insert("$_DLATCHSR_PNP_");
|
||||||
|
fftypes.insert("$_DLATCHSR_PPN_");
|
||||||
|
fftypes.insert("$_DLATCHSR_PPP_");
|
||||||
|
fftypes.insert("$_DLATCH_N_");
|
||||||
|
fftypes.insert("$_DLATCH_P_");
|
||||||
|
fftypes.insert("$_FF_");
|
||||||
|
|
||||||
for (auto module : design->selected_whole_modules_warn())
|
for (auto module : design->selected_whole_modules_warn())
|
||||||
{
|
{
|
||||||
if (module->has_processes_warn())
|
if (module->has_processes_warn())
|
||||||
|
@ -109,6 +160,8 @@ struct CheckPass : public Pass {
|
||||||
if (bit.wire) wire_drivers_count[bit]++;
|
if (bit.wire) wire_drivers_count[bit]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool<SigBit> init_bits;
|
||||||
|
|
||||||
for (auto wire : module->wires()) {
|
for (auto wire : module->wires()) {
|
||||||
if (wire->port_input) {
|
if (wire->port_input) {
|
||||||
SigSpec sig = sigmap(wire);
|
SigSpec sig = sigmap(wire);
|
||||||
|
@ -121,9 +174,15 @@ struct CheckPass : public Pass {
|
||||||
if (wire->port_input && !wire->port_output)
|
if (wire->port_input && !wire->port_output)
|
||||||
for (auto bit : sigmap(wire))
|
for (auto bit : sigmap(wire))
|
||||||
if (bit.wire) wire_drivers_count[bit]++;
|
if (bit.wire) wire_drivers_count[bit]++;
|
||||||
if (noinit && wire->attributes.count("\\init")) {
|
if (wire->attributes.count("\\init")) {
|
||||||
log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
|
Const initval = wire->attributes.at("\\init");
|
||||||
counter++;
|
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
|
||||||
|
if (initval[i] == State::S0 || initval[i] == State::S1)
|
||||||
|
init_bits.insert(sigmap(SigBit(wire, i)));
|
||||||
|
if (noinit) {
|
||||||
|
log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +209,26 @@ struct CheckPass : public Pass {
|
||||||
log_warning("%s", message.c_str());
|
log_warning("%s", message.c_str());
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initdrv)
|
||||||
|
{
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (fftypes.count(cell->type) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto bit : sigmap(cell->getPort("\\Q")))
|
||||||
|
init_bits.erase(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec init_sig(init_bits);
|
||||||
|
init_sig.sort_and_unify();
|
||||||
|
|
||||||
|
for (auto chunk : init_sig.chunks()) {
|
||||||
|
log_warning("Wire %s.%s has 'init' attribute and is not driven by an FF cell.\n", log_id(module), log_signal(chunk));
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log("found and reported %d problems.\n", counter);
|
log("found and reported %d problems.\n", counter);
|
||||||
|
|
|
@ -17,10 +17,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kernel/register.h"
|
#include "kernel/yosys.h"
|
||||||
#include "kernel/celltypes.h"
|
#include "frontends/ast/ast.h"
|
||||||
#include "kernel/rtlil.h"
|
|
||||||
#include "kernel/log.h"
|
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
@ -82,11 +80,18 @@ struct DesignPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Copy modules from the current design into the specified one.\n");
|
log("Copy modules from the current design into the specified one.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("\n");
|
||||||
|
log(" design -reset-vlog\n");
|
||||||
|
log("\n");
|
||||||
|
log("The Verilog front-end remembers defined macros and top-level declarations\n");
|
||||||
|
log("between calls to 'read_verilog'. This command resets this memory.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
bool got_mode = false;
|
bool got_mode = false;
|
||||||
bool reset_mode = false;
|
bool reset_mode = false;
|
||||||
|
bool reset_vlog_mode = false;
|
||||||
bool push_mode = false;
|
bool push_mode = false;
|
||||||
bool pop_mode = false;
|
bool pop_mode = false;
|
||||||
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
|
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
|
||||||
|
@ -102,6 +107,11 @@ struct DesignPass : public Pass {
|
||||||
reset_mode = true;
|
reset_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!got_mode && args[argidx] == "-reset-vlog") {
|
||||||
|
got_mode = true;
|
||||||
|
reset_vlog_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!got_mode && args[argidx] == "-push") {
|
if (!got_mode && args[argidx] == "-push") {
|
||||||
got_mode = true;
|
got_mode = true;
|
||||||
push_mode = true;
|
push_mode = true;
|
||||||
|
@ -235,19 +245,34 @@ struct DesignPass : public Pass {
|
||||||
design->selection_stack.push_back(RTLIL::Selection());
|
design->selection_stack.push_back(RTLIL::Selection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)
|
||||||
|
{
|
||||||
|
for (auto node : design->verilog_packages)
|
||||||
|
delete node;
|
||||||
|
design->verilog_packages.clear();
|
||||||
|
|
||||||
|
for (auto node : design->verilog_globals)
|
||||||
|
delete node;
|
||||||
|
design->verilog_globals.clear();
|
||||||
|
|
||||||
|
design->verilog_defines.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (!load_name.empty() || pop_mode)
|
if (!load_name.empty() || pop_mode)
|
||||||
{
|
{
|
||||||
RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name);
|
RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name);
|
||||||
|
|
||||||
if (pop_mode)
|
|
||||||
pushed_designs.pop_back();
|
|
||||||
|
|
||||||
for (auto &it : saved_design->modules_)
|
for (auto &it : saved_design->modules_)
|
||||||
design->add(it.second->clone());
|
design->add(it.second->clone());
|
||||||
|
|
||||||
design->selection_stack = saved_design->selection_stack;
|
design->selection_stack = saved_design->selection_stack;
|
||||||
design->selection_vars = saved_design->selection_vars;
|
design->selection_vars = saved_design->selection_vars;
|
||||||
design->selected_active_module = saved_design->selected_active_module;
|
design->selected_active_module = saved_design->selected_active_module;
|
||||||
|
|
||||||
|
if (pop_mode) {
|
||||||
|
delete saved_design;
|
||||||
|
pushed_designs.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} DesignPass;
|
} DesignPass;
|
||||||
|
|
|
@ -163,16 +163,8 @@ struct SccWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto cell : workQueue)
|
for (auto cell : workQueue)
|
||||||
cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
|
|
||||||
|
|
||||||
labelCounter = 0;
|
|
||||||
cellLabels.clear();
|
|
||||||
|
|
||||||
while (workQueue.size() > 0)
|
|
||||||
{
|
{
|
||||||
RTLIL::Cell *cell = *workQueue.begin();
|
cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);
|
||||||
log_assert(cellStack.size() == 0);
|
|
||||||
cellDepth.clear();
|
|
||||||
|
|
||||||
if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
|
if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
|
||||||
log("Found an SCC:");
|
log("Found an SCC:");
|
||||||
|
@ -183,6 +175,16 @@ struct SccWorker
|
||||||
sccList.push_back(scc);
|
sccList.push_back(scc);
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
labelCounter = 0;
|
||||||
|
cellLabels.clear();
|
||||||
|
|
||||||
|
while (!workQueue.empty())
|
||||||
|
{
|
||||||
|
RTLIL::Cell *cell = *workQueue.begin();
|
||||||
|
log_assert(cellStack.size() == 0);
|
||||||
|
cellDepth.clear();
|
||||||
|
|
||||||
run(cell, 0, maxDepth);
|
run(cell, 0, maxDepth);
|
||||||
}
|
}
|
||||||
|
@ -244,11 +246,9 @@ struct SccPass : public Pass {
|
||||||
log(" are assumed to be bidirectional 'inout' ports.\n");
|
log(" are assumed to be bidirectional 'inout' ports.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -set_attr <name> <value>\n");
|
log(" -set_attr <name> <value>\n");
|
||||||
log(" -set_cell_attr <name> <value>\n");
|
log(" set the specified attribute on all cells that are part of a logic\n");
|
||||||
log(" -set_wire_attr <name> <value>\n");
|
log(" loop. the special token {} in the value is replaced with a unique\n");
|
||||||
log(" set the specified attribute on all cells and/or wires that are part of\n");
|
log(" identifier for the logic loop.\n");
|
||||||
log(" a logic loop. the special token {} in the value is replaced with a\n");
|
|
||||||
log(" unique identifier for the logic loop.\n");
|
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -select\n");
|
log(" -select\n");
|
||||||
log(" replace the current selection with a selection of all cells and wires\n");
|
log(" replace the current selection with a selection of all cells and wires\n");
|
||||||
|
@ -257,7 +257,7 @@ struct SccPass : public Pass {
|
||||||
}
|
}
|
||||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> setCellAttr, setWireAttr;
|
std::map<std::string, std::string> setAttr;
|
||||||
bool allCellTypes = false;
|
bool allCellTypes = false;
|
||||||
bool selectMode = false;
|
bool selectMode = false;
|
||||||
bool nofeedbackMode = false;
|
bool nofeedbackMode = false;
|
||||||
|
@ -285,18 +285,7 @@ struct SccPass : public Pass {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
|
if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
|
||||||
setCellAttr[args[argidx+1]] = args[argidx+2];
|
setAttr[args[argidx+1]] = args[argidx+2];
|
||||||
setWireAttr[args[argidx+1]] = args[argidx+2];
|
|
||||||
argidx += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (args[argidx] == "-set_cell_attr" && argidx+2 < args.size()) {
|
|
||||||
setCellAttr[args[argidx+1]] = args[argidx+2];
|
|
||||||
argidx += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (args[argidx] == "-set_wire_attr" && argidx+2 < args.size()) {
|
|
||||||
setWireAttr[args[argidx+1]] = args[argidx+2];
|
|
||||||
argidx += 2;
|
argidx += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -309,9 +298,6 @@ struct SccPass : public Pass {
|
||||||
int origSelectPos = design->selection_stack.size() - 1;
|
int origSelectPos = design->selection_stack.size() - 1;
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
if (setCellAttr.size() > 0 || setWireAttr.size() > 0)
|
|
||||||
log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
|
|
||||||
|
|
||||||
RTLIL::Selection newSelection(false);
|
RTLIL::Selection newSelection(false);
|
||||||
int scc_counter = 0;
|
int scc_counter = 0;
|
||||||
|
|
||||||
|
@ -319,7 +305,33 @@ struct SccPass : public Pass {
|
||||||
if (design->selected(mod_it.second))
|
if (design->selected(mod_it.second))
|
||||||
{
|
{
|
||||||
SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);
|
SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);
|
||||||
scc_counter += GetSize(worker.sccList);
|
|
||||||
|
if (!setAttr.empty())
|
||||||
|
{
|
||||||
|
for (const auto &cells : worker.sccList)
|
||||||
|
{
|
||||||
|
for (auto attr : setAttr)
|
||||||
|
{
|
||||||
|
IdString attr_name(RTLIL::escape_id(attr.first));
|
||||||
|
string attr_valstr = attr.second;
|
||||||
|
string index = stringf("%d", scc_counter);
|
||||||
|
|
||||||
|
for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
|
||||||
|
attr_valstr.replace(pos, 2, index);
|
||||||
|
|
||||||
|
Const attr_value(attr_valstr);
|
||||||
|
|
||||||
|
for (auto cell : cells)
|
||||||
|
cell->attributes[attr_name] = attr_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scc_counter += GetSize(worker.sccList);
|
||||||
|
}
|
||||||
|
|
||||||
if (selectMode)
|
if (selectMode)
|
||||||
worker.select(newSelection);
|
worker.select(newSelection);
|
||||||
|
|
|
@ -90,6 +90,8 @@ struct SetundefPass : public Pass {
|
||||||
bool init_mode = false;
|
bool init_mode = false;
|
||||||
SetundefWorker worker;
|
SetundefWorker worker;
|
||||||
|
|
||||||
|
log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n");
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
{
|
{
|
||||||
|
@ -137,8 +139,11 @@ struct SetundefPass : public Pass {
|
||||||
SigPool undriven_signals;
|
SigPool undriven_signals;
|
||||||
|
|
||||||
for (auto &it : module->wires_)
|
for (auto &it : module->wires_)
|
||||||
if (!it.second->port_input)
|
undriven_signals.add(sigmap(it.second));
|
||||||
undriven_signals.add(sigmap(it.second));
|
|
||||||
|
for (auto &it : module->wires_)
|
||||||
|
if (it.second->port_input)
|
||||||
|
undriven_signals.del(sigmap(it.second));
|
||||||
|
|
||||||
CellTypes ct(design);
|
CellTypes ct(design);
|
||||||
for (auto &it : module->cells_)
|
for (auto &it : module->cells_)
|
||||||
|
|
|
@ -37,14 +37,20 @@ struct SplitnetsWorker
|
||||||
new_wire_name += format.substr(0, 1);
|
new_wire_name += format.substr(0, 1);
|
||||||
|
|
||||||
if (width > 1) {
|
if (width > 1) {
|
||||||
new_wire_name += stringf("%d", offset+width-1);
|
if (wire->upto)
|
||||||
|
new_wire_name += stringf("%d", wire->start_offset+wire->width-(offset+width)-1);
|
||||||
|
else
|
||||||
|
new_wire_name += stringf("%d", wire->start_offset+offset+width-1);
|
||||||
if (format.size() > 2)
|
if (format.size() > 2)
|
||||||
new_wire_name += format.substr(2, 1);
|
new_wire_name += format.substr(2, 1);
|
||||||
else
|
else
|
||||||
new_wire_name += ":";
|
new_wire_name += ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
new_wire_name += stringf("%d", offset);
|
if (wire->upto)
|
||||||
|
new_wire_name += stringf("%d", wire->start_offset+wire->width-offset-1);
|
||||||
|
else
|
||||||
|
new_wire_name += stringf("%d", wire->start_offset+offset);
|
||||||
|
|
||||||
if (format.size() > 1)
|
if (format.size() > 1)
|
||||||
new_wire_name += format.substr(1, 1);
|
new_wire_name += format.substr(1, 1);
|
||||||
|
|
|
@ -80,7 +80,7 @@ struct EquivPurgeWorker
|
||||||
Wire *wire = module->addWire(name, GetSize(sig));
|
Wire *wire = module->addWire(name, GetSize(sig));
|
||||||
wire->port_input = true;
|
wire->port_input = true;
|
||||||
module->connect(sig, wire);
|
module->connect(sig, wire);
|
||||||
log(" Module input: %s\n", log_signal(wire));
|
log(" Module input: %s (%s)\n", log_signal(wire), log_signal(sig));
|
||||||
return module->addWire(NEW_ID, GetSize(sig));
|
return module->addWire(NEW_ID, GetSize(sig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct EquivSimpleWorker
|
||||||
for (auto &conn : cell->connections())
|
for (auto &conn : cell->connections())
|
||||||
if (yosys_celltypes.cell_input(cell->type, conn.first))
|
if (yosys_celltypes.cell_input(cell->type, conn.first))
|
||||||
for (auto bit : sigmap(conn.second)) {
|
for (auto bit : sigmap(conn.second)) {
|
||||||
if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_")) {
|
if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_")) {
|
||||||
if (!conn.first.in("\\CLK", "\\C"))
|
if (!conn.first.in("\\CLK", "\\C"))
|
||||||
next_seed.insert(bit);
|
next_seed.insert(bit);
|
||||||
} else
|
} else
|
||||||
|
@ -329,7 +329,7 @@ struct EquivSimplePass : public Pass {
|
||||||
unproven_cells_counter, GetSize(unproven_equiv_cells), log_id(module));
|
unproven_cells_counter, GetSize(unproven_equiv_cells), log_id(module));
|
||||||
|
|
||||||
for (auto cell : module->cells()) {
|
for (auto cell : module->cells()) {
|
||||||
if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_"))
|
if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_"))
|
||||||
continue;
|
continue;
|
||||||
for (auto &conn : cell->connections())
|
for (auto &conn : cell->connections())
|
||||||
if (yosys_celltypes.cell_output(cell->type, conn.first))
|
if (yosys_celltypes.cell_output(cell->type, conn.first))
|
||||||
|
|
|
@ -54,13 +54,27 @@ struct FsmExpand
|
||||||
if (cell->getPort("\\A").size() < 2)
|
if (cell->getPort("\\A").size() < 2)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
int in_bits = 0;
|
||||||
RTLIL::SigSpec new_signals;
|
RTLIL::SigSpec new_signals;
|
||||||
if (cell->hasPort("\\A"))
|
|
||||||
|
if (cell->hasPort("\\A")) {
|
||||||
|
in_bits += GetSize(cell->getPort("\\A"));
|
||||||
new_signals.append(assign_map(cell->getPort("\\A")));
|
new_signals.append(assign_map(cell->getPort("\\A")));
|
||||||
if (cell->hasPort("\\B"))
|
}
|
||||||
|
|
||||||
|
if (cell->hasPort("\\B")) {
|
||||||
|
in_bits += GetSize(cell->getPort("\\B"));
|
||||||
new_signals.append(assign_map(cell->getPort("\\B")));
|
new_signals.append(assign_map(cell->getPort("\\B")));
|
||||||
if (cell->hasPort("\\S"))
|
}
|
||||||
|
|
||||||
|
if (cell->hasPort("\\S")) {
|
||||||
|
in_bits += GetSize(cell->getPort("\\S"));
|
||||||
new_signals.append(assign_map(cell->getPort("\\S")));
|
new_signals.append(assign_map(cell->getPort("\\S")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_bits > 8)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (cell->hasPort("\\Y"))
|
if (cell->hasPort("\\Y"))
|
||||||
new_signals.append(assign_map(cell->getPort("\\Y")));
|
new_signals.append(assign_map(cell->getPort("\\Y")));
|
||||||
|
|
||||||
|
@ -173,6 +187,16 @@ struct FsmExpand
|
||||||
new_ctrl_out.append(output_sig);
|
new_ctrl_out.append(output_sig);
|
||||||
fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
|
fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
|
||||||
|
|
||||||
|
if (GetSize(input_sig) > 10)
|
||||||
|
log_warning("Cell %s.%s (%s) has %d input bits, merging into FSM %s.%s might be problematic.\n",
|
||||||
|
log_id(cell->module), log_id(cell), log_id(cell->type),
|
||||||
|
GetSize(input_sig), log_id(fsm_cell->module), log_id(fsm_cell));
|
||||||
|
|
||||||
|
if (GetSize(fsm_data.transition_table) > 10000)
|
||||||
|
log_warning("Transition table for FSM %s.%s already has %d rows, merging more cells "
|
||||||
|
"into this FSM might be problematic.\n", log_id(fsm_cell->module), log_id(fsm_cell),
|
||||||
|
GetSize(fsm_data.transition_table));
|
||||||
|
|
||||||
std::vector<FsmData::transition_t> new_transition_table;
|
std::vector<FsmData::transition_t> new_transition_table;
|
||||||
for (auto &tr : fsm_data.transition_table) {
|
for (auto &tr : fsm_data.transition_table) {
|
||||||
for (int i = 0; i < (1 << input_sig.size()); i++) {
|
for (int i = 0; i < (1 << input_sig.size()); i++) {
|
||||||
|
|
|
@ -175,16 +175,12 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
|
||||||
{
|
{
|
||||||
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
|
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
|
||||||
if (check_file_exists(filename)) {
|
if (check_file_exists(filename)) {
|
||||||
std::vector<std::string> args;
|
|
||||||
args.push_back(filename);
|
|
||||||
Frontend::frontend_call(design, NULL, filename, "verilog");
|
Frontend::frontend_call(design, NULL, filename, "verilog");
|
||||||
goto loaded_module;
|
goto loaded_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
|
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
|
||||||
if (check_file_exists(filename)) {
|
if (check_file_exists(filename)) {
|
||||||
std::vector<std::string> args;
|
|
||||||
args.push_back(filename);
|
|
||||||
Frontend::frontend_call(design, NULL, filename, "ilang");
|
Frontend::frontend_call(design, NULL, filename, "ilang");
|
||||||
goto loaded_module;
|
goto loaded_module;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +209,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
|
||||||
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
|
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
|
||||||
log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
|
log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
|
||||||
for (auto ¶m : cell->parameters)
|
for (auto ¶m : cell->parameters)
|
||||||
if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$')
|
if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL)
|
||||||
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
|
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
|
||||||
log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
|
log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
|
||||||
}
|
}
|
||||||
|
@ -367,6 +363,11 @@ struct HierarchyPass : public Pass {
|
||||||
log(" per default this pass also converts positional arguments in cells\n");
|
log(" per default this pass also converts positional arguments in cells\n");
|
||||||
log(" to arguments using port names. this option disables this behavior.\n");
|
log(" to arguments using port names. this option disables this behavior.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -keep_portwidths\n");
|
||||||
|
log(" per default this pass adjusts the port width on cells that are\n");
|
||||||
|
log(" module instances when the width does not match the module port. this\n");
|
||||||
|
log(" option disables this behavior.\n");
|
||||||
|
log("\n");
|
||||||
log(" -nokeep_asserts\n");
|
log(" -nokeep_asserts\n");
|
||||||
log(" per default this pass sets the \"keep\" attribute on all modules\n");
|
log(" per default this pass sets the \"keep\" attribute on all modules\n");
|
||||||
log(" that directly or indirectly contain one or more $assert cells. this\n");
|
log(" that directly or indirectly contain one or more $assert cells. this\n");
|
||||||
|
@ -412,6 +413,7 @@ struct HierarchyPass : public Pass {
|
||||||
bool auto_top_mode = false;
|
bool auto_top_mode = false;
|
||||||
bool generate_mode = false;
|
bool generate_mode = false;
|
||||||
bool keep_positionals = false;
|
bool keep_positionals = false;
|
||||||
|
bool keep_portwidths = false;
|
||||||
bool nokeep_asserts = false;
|
bool nokeep_asserts = false;
|
||||||
std::vector<std::string> generate_cells;
|
std::vector<std::string> generate_cells;
|
||||||
std::vector<generate_port_decl_t> generate_ports;
|
std::vector<generate_port_decl_t> generate_ports;
|
||||||
|
@ -470,6 +472,10 @@ struct HierarchyPass : public Pass {
|
||||||
keep_positionals = true;
|
keep_positionals = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-keep_portwidths") {
|
||||||
|
keep_portwidths = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-nokeep_asserts") {
|
if (args[argidx] == "-nokeep_asserts") {
|
||||||
nokeep_asserts = true;
|
nokeep_asserts = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -614,6 +620,52 @@ struct HierarchyPass : public Pass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!keep_portwidths)
|
||||||
|
{
|
||||||
|
for (auto module : design->modules())
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
Module *m = design->module(cell->type);
|
||||||
|
|
||||||
|
if (m == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
{
|
||||||
|
Wire *w = m->wire(conn.first);
|
||||||
|
|
||||||
|
if (w == nullptr || w->port_id == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (GetSize(w) == GetSize(conn.second))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec sig = conn.second;
|
||||||
|
|
||||||
|
if (GetSize(w) < GetSize(conn.second))
|
||||||
|
{
|
||||||
|
int n = GetSize(conn.second) - GetSize(w);
|
||||||
|
if (!w->port_input && w->port_output)
|
||||||
|
module->connect(sig.extract(GetSize(w), n), Const(0, n));
|
||||||
|
sig.remove(GetSize(w), n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int n = GetSize(w) - GetSize(conn.second);
|
||||||
|
if (w->port_input && !w->port_output)
|
||||||
|
sig.append(Const(0, n));
|
||||||
|
else
|
||||||
|
sig.append(module->addWire(NEW_ID, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conn.second.is_fully_const() || !w->port_input || w->port_output)
|
||||||
|
log_warning("Resizing cell port %s.%s.%s from %d bits to %d bits.\n", log_id(module), log_id(cell),
|
||||||
|
log_id(conn.first), GetSize(conn.second), GetSize(sig));
|
||||||
|
cell->setPort(conn.first, sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log_pop();
|
log_pop();
|
||||||
}
|
}
|
||||||
} HierarchyPass;
|
} HierarchyPass;
|
||||||
|
|
|
@ -169,6 +169,7 @@ struct SubmodWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
new_mod->fixup_ports();
|
new_mod->fixup_ports();
|
||||||
|
ct.setup_module(new_mod);
|
||||||
|
|
||||||
for (RTLIL::Cell *cell : submod.cells) {
|
for (RTLIL::Cell *cell : submod.cells) {
|
||||||
RTLIL::Cell *new_cell = new_mod->addCell(cell->name, cell);
|
RTLIL::Cell *new_cell = new_mod->addCell(cell->name, cell);
|
||||||
|
|
|
@ -41,9 +41,27 @@ void remove_init_attr(SigSpec sig)
|
||||||
|
|
||||||
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
|
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
|
||||||
{
|
{
|
||||||
SigSpec sig_e = dlatch->getPort("\\EN");
|
SigSpec sig_e;
|
||||||
|
State on_state, off_state;
|
||||||
|
|
||||||
if (sig_e == State::S0)
|
if (dlatch->type == "$dlatch") {
|
||||||
|
sig_e = assign_map(dlatch->getPort("\\EN"));
|
||||||
|
on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0;
|
||||||
|
off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1;
|
||||||
|
} else
|
||||||
|
if (dlatch->type == "$_DLATCH_P_") {
|
||||||
|
sig_e = assign_map(dlatch->getPort("\\E"));
|
||||||
|
on_state = State::S1;
|
||||||
|
off_state = State::S0;
|
||||||
|
} else
|
||||||
|
if (dlatch->type == "$_DLATCH_N_") {
|
||||||
|
sig_e = assign_map(dlatch->getPort("\\E"));
|
||||||
|
on_state = State::S0;
|
||||||
|
off_state = State::S1;
|
||||||
|
} else
|
||||||
|
log_abort();
|
||||||
|
|
||||||
|
if (sig_e == off_state)
|
||||||
{
|
{
|
||||||
RTLIL::Const val_init;
|
RTLIL::Const val_init;
|
||||||
for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
|
for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
|
||||||
|
@ -52,7 +70,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
|
||||||
goto delete_dlatch;
|
goto delete_dlatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sig_e == State::S1)
|
if (sig_e == on_state)
|
||||||
{
|
{
|
||||||
mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
|
mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
|
||||||
goto delete_dlatch;
|
goto delete_dlatch;
|
||||||
|
@ -268,7 +286,7 @@ struct OptRmdffPass : public Pass {
|
||||||
"$ff", "$dff", "$adff"))
|
"$ff", "$dff", "$adff"))
|
||||||
dff_list.push_back(cell->name);
|
dff_list.push_back(cell->name);
|
||||||
|
|
||||||
if (cell->type == "$dlatch")
|
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
|
||||||
dlatch_list.push_back(cell->name);
|
dlatch_list.push_back(cell->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,17 +29,17 @@
|
||||||
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
|
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
|
||||||
// http://en.wikipedia.org/wiki/Topological_sorting
|
// http://en.wikipedia.org/wiki/Topological_sorting
|
||||||
|
|
||||||
#define ABC_COMMAND_LIB "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}"
|
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; dch -f; map {D}"
|
||||||
#define ABC_COMMAND_CTR "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
||||||
#define ABC_COMMAND_LUT "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs"
|
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
|
||||||
#define ABC_COMMAND_SOP "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; cover {I} {P}"
|
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
|
||||||
#define ABC_COMMAND_DFL "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; map"
|
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; dch -f; map"
|
||||||
|
|
||||||
#define ABC_FAST_COMMAND_LIB "retime -o {D}; map {D}"
|
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
|
||||||
#define ABC_FAST_COMMAND_CTR "retime -o {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
||||||
#define ABC_FAST_COMMAND_LUT "retime -o; if"
|
#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
|
||||||
#define ABC_FAST_COMMAND_SOP "retime -o; cover -I {I} -P {P}"
|
#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
|
||||||
#define ABC_FAST_COMMAND_DFL "retime -o; map"
|
#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
|
||||||
|
|
||||||
#include "kernel/register.h"
|
#include "kernel/register.h"
|
||||||
#include "kernel/sigtools.h"
|
#include "kernel/sigtools.h"
|
||||||
|
@ -595,7 +595,7 @@ struct abc_output_filter
|
||||||
|
|
||||||
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
|
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
|
||||||
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
|
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
|
||||||
bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, bool fast_mode,
|
bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
|
||||||
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
|
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
|
||||||
{
|
{
|
||||||
module = current_module;
|
module = current_module;
|
||||||
|
@ -652,7 +652,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
all_luts_cost_same = false;
|
all_luts_cost_same = false;
|
||||||
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
|
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
|
||||||
if (all_luts_cost_same && !fast_mode)
|
if (all_luts_cost_same && !fast_mode)
|
||||||
abc_script += "; lutpack";
|
abc_script += "; lutpack {S}";
|
||||||
} else if (!liberty_file.empty())
|
} else if (!liberty_file.empty())
|
||||||
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
|
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
|
||||||
else if (sop_mode)
|
else if (sop_mode)
|
||||||
|
@ -660,6 +660,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
else
|
else
|
||||||
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
|
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
|
||||||
|
|
||||||
|
if (script_file.empty() && !delay_target.empty())
|
||||||
|
for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
|
||||||
|
abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
|
||||||
|
|
||||||
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
|
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
|
||||||
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
|
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
|
||||||
|
|
||||||
|
@ -669,6 +673,9 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
|
||||||
for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
|
for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
|
||||||
abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
|
abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
|
||||||
|
|
||||||
|
for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
|
||||||
|
abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
|
||||||
|
|
||||||
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
|
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
|
||||||
abc_script = add_echos_to_abc_cmd(abc_script);
|
abc_script = add_echos_to_abc_cmd(abc_script);
|
||||||
|
|
||||||
|
@ -1205,7 +1212,7 @@ struct AbcPass : public Pass {
|
||||||
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
|
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" for -lut/-luts (only one LUT size):\n");
|
log(" for -lut/-luts (only one LUT size):\n");
|
||||||
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack").c_str());
|
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack {S}").c_str());
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" for -lut/-luts (different LUT sizes):\n");
|
log(" for -lut/-luts (different LUT sizes):\n");
|
||||||
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
|
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
|
||||||
|
@ -1253,6 +1260,8 @@ struct AbcPass : public Pass {
|
||||||
log(" -D <picoseconds>\n");
|
log(" -D <picoseconds>\n");
|
||||||
log(" set delay target. the string {D} in the default scripts above is\n");
|
log(" set delay target. the string {D} in the default scripts above is\n");
|
||||||
log(" replaced by this option when used, and an empty string otherwise.\n");
|
log(" replaced by this option when used, and an empty string otherwise.\n");
|
||||||
|
log(" this also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
|
||||||
|
log(" default scripts above.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -I <num>\n");
|
log(" -I <num>\n");
|
||||||
log(" maximum number of SOP inputs.\n");
|
log(" maximum number of SOP inputs.\n");
|
||||||
|
@ -1262,6 +1271,10 @@ struct AbcPass : public Pass {
|
||||||
log(" maximum number of SOP products.\n");
|
log(" maximum number of SOP products.\n");
|
||||||
log(" (replaces {P} in the default scripts above)\n");
|
log(" (replaces {P} in the default scripts above)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -S <num>\n");
|
||||||
|
log(" maximum number of LUT inputs shared.\n");
|
||||||
|
log(" (replaces {S} in the default scripts above, default: -S 1)\n");
|
||||||
|
log("\n");
|
||||||
log(" -lut <width>\n");
|
log(" -lut <width>\n");
|
||||||
log(" generate netlist using luts of (max) the specified width.\n");
|
log(" generate netlist using luts of (max) the specified width.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -1333,7 +1346,7 @@ struct AbcPass : public Pass {
|
||||||
std::string exe_file = proc_self_dirname() + "yosys-abc";
|
std::string exe_file = proc_self_dirname() + "yosys-abc";
|
||||||
#endif
|
#endif
|
||||||
std::string script_file, liberty_file, constr_file, clk_str;
|
std::string script_file, liberty_file, constr_file, clk_str;
|
||||||
std::string delay_target, sop_inputs, sop_products;
|
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
|
||||||
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
|
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
|
||||||
bool show_tempdir = false, sop_mode = false;
|
bool show_tempdir = false, sop_mode = false;
|
||||||
vector<int> lut_costs;
|
vector<int> lut_costs;
|
||||||
|
@ -1393,6 +1406,10 @@ struct AbcPass : public Pass {
|
||||||
sop_products = "-P " + args[++argidx];
|
sop_products = "-P " + args[++argidx];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-S" && argidx+1 < args.size()) {
|
||||||
|
lutin_shared = "-S " + args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-lut" && argidx+1 < args.size()) {
|
if (arg == "-lut" && argidx+1 < args.size()) {
|
||||||
string arg = args[++argidx];
|
string arg = args[++argidx];
|
||||||
size_t pos = arg.find_first_of(':');
|
size_t pos = arg.find_first_of(':');
|
||||||
|
@ -1505,7 +1522,7 @@ struct AbcPass : public Pass {
|
||||||
log("Skipping module %s as it contains processes.\n", log_id(mod));
|
log("Skipping module %s as it contains processes.\n", log_id(mod));
|
||||||
else if (!dff_mode || !clk_str.empty())
|
else if (!dff_mode || !clk_str.empty())
|
||||||
abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
|
abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
|
||||||
delay_target, sop_inputs, sop_products, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
|
delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assign_map.set(mod);
|
assign_map.set(mod);
|
||||||
|
@ -1650,7 +1667,7 @@ struct AbcPass : public Pass {
|
||||||
en_polarity = std::get<2>(it.first);
|
en_polarity = std::get<2>(it.first);
|
||||||
en_sig = assign_map(std::get<3>(it.first));
|
en_sig = assign_map(std::get<3>(it.first));
|
||||||
abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
|
abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
|
||||||
keepff, delay_target, sop_inputs, sop_products, fast_mode, it.second, show_tempdir, sop_mode);
|
keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode);
|
||||||
assign_map.set(mod);
|
assign_map.set(mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,51 +1,59 @@
|
||||||
module LUT1(output F, input I0);
|
module LUT1(output F, input I0);
|
||||||
parameter [1:0] INIT = 0;
|
parameter [1:0] INIT = 0;
|
||||||
assign F = I0 ? INIT[1] : INIT[0];
|
assign F = I0 ? INIT[1] : INIT[0];
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module LUT2(output F, input I0, I1);
|
module LUT2(output F, input I0, I1);
|
||||||
parameter [3:0] INIT = 0;
|
parameter [3:0] INIT = 0;
|
||||||
wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
|
wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
|
||||||
assign F = I0 ? s1[1] : s1[0];
|
assign F = I0 ? s1[1] : s1[0];
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module LUT3(output F, input I0, I1, I2);
|
module LUT3(output F, input I0, I1, I2);
|
||||||
parameter [7:0] INIT = 0;
|
parameter [7:0] INIT = 0;
|
||||||
wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0];
|
wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0];
|
||||||
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
||||||
assign F = I0 ? s1[1] : s1[0];
|
assign F = I0 ? s1[1] : s1[0];
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module LUT4(output F, input I0, I1, I2, I3);
|
module LUT4(output F, input I0, I1, I2, I3);
|
||||||
parameter [15:0] INIT = 0;
|
parameter [15:0] INIT = 0;
|
||||||
wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
|
wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
|
||||||
wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
|
wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
|
||||||
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
|
||||||
assign F = I0 ? s1[1] : s1[0];
|
assign F = I0 ? s1[1] : s1[0];
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module DFF (output reg Q, input CLK, D);
|
module DFF (output reg Q, input CLK, D);
|
||||||
always @(posedge C)
|
parameter [0:0] INIT = 1'b0;
|
||||||
|
initial Q = INIT;
|
||||||
|
always @(posedge CLK)
|
||||||
Q <= D;
|
Q <= D;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module DFFN (output reg Q, input CLK, D);
|
module DFFN (output reg Q, input CLK, D);
|
||||||
always @(negedge C)
|
parameter [0:0] INIT = 1'b0;
|
||||||
|
initial Q = INIT;
|
||||||
|
always @(negedge CLK)
|
||||||
Q <= D;
|
Q <= D;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module VCC(output V);
|
module VCC(output V);
|
||||||
assign V = 1;
|
assign V = 1;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GND(output G);
|
module GND(output G);
|
||||||
assign G = 0;
|
assign G = 0;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module IBUF(output O, input I);
|
module IBUF(output O, input I);
|
||||||
assign O = I;
|
assign O = I;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module OBUF(output O, input I);
|
module OBUF(output O, input I);
|
||||||
assign O = I;
|
assign O = I;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GSR (input GSRI);
|
||||||
|
wire GSRO = GSRI;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -169,7 +169,7 @@ struct SynthGowinPass : public ScriptPass
|
||||||
if (check_label("vout"))
|
if (check_label("vout"))
|
||||||
{
|
{
|
||||||
if (!vout_file.empty() || help_mode)
|
if (!vout_file.empty() || help_mode)
|
||||||
run(stringf("write_verilog -attr2comment -defparam -renameprefix gen %s",
|
run(stringf("write_verilog -nodec -attr2comment -defparam -renameprefix gen %s",
|
||||||
help_mode ? "<file-name>" : vout_file.c_str()));
|
help_mode ? "<file-name>" : vout_file.c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ OBJS += techlibs/greenpak4/synth_greenpak4.o
|
||||||
OBJS += techlibs/greenpak4/greenpak4_counters.o
|
OBJS += techlibs/greenpak4/greenpak4_counters.o
|
||||||
OBJS += techlibs/greenpak4/greenpak4_dffinv.o
|
OBJS += techlibs/greenpak4/greenpak4_dffinv.o
|
||||||
|
|
||||||
|
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_latch.v))
|
||||||
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_map.v))
|
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_map.v))
|
||||||
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim.v))
|
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim.v))
|
||||||
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/gp_dff.lib))
|
$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/gp_dff.lib))
|
||||||
|
|
15
techlibs/greenpak4/cells_latch.v
Normal file
15
techlibs/greenpak4/cells_latch.v
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module $_DLATCH_P_(input E, input D, output Q);
|
||||||
|
GP_DLATCH _TECHMAP_REPLACE_ (
|
||||||
|
.D(D),
|
||||||
|
.nCLK(!E),
|
||||||
|
.Q(Q)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module $_DLATCH_N_(input E, input D, output Q);
|
||||||
|
GP_DLATCH _TECHMAP_REPLACE_ (
|
||||||
|
.D(D),
|
||||||
|
.nCLK(E),
|
||||||
|
.Q(Q)
|
||||||
|
);
|
||||||
|
endmodule
|
|
@ -50,6 +50,58 @@ module GP_DFFRI(input D, CLK, nRST, output reg nQ);
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHS(input D, nCLK, nSET, output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
GP_DLATCHSR #(
|
||||||
|
.INIT(INIT),
|
||||||
|
.SRMODE(1'b1),
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.D(D),
|
||||||
|
.nCLK(nCLK),
|
||||||
|
.nSR(nSET),
|
||||||
|
.Q(Q)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHR(input D, nCLK, nRST, output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
GP_DLATCHSR #(
|
||||||
|
.INIT(INIT),
|
||||||
|
.SRMODE(1'b0),
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.D(D),
|
||||||
|
.nCLK(nCLK),
|
||||||
|
.nSR(nRST),
|
||||||
|
.Q(Q)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHSI(input D, nCLK, nSET, output reg nQ);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
GP_DLATCHSRI #(
|
||||||
|
.INIT(INIT),
|
||||||
|
.SRMODE(1'b1),
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.D(D),
|
||||||
|
.nCLK(nCLK),
|
||||||
|
.nSR(nSET),
|
||||||
|
.nQ(nQ)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHRI(input D, nCLK, nRST, output reg nQ);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
GP_DLATCHSRI #(
|
||||||
|
.INIT(INIT),
|
||||||
|
.SRMODE(1'b0),
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.D(D),
|
||||||
|
.nCLK(nCLK),
|
||||||
|
.nSR(nRST),
|
||||||
|
.nQ(nQ)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
||||||
module GP_OBUFT(input IN, input OE, output OUT);
|
module GP_OBUFT(input IN, input OE, output OUT);
|
||||||
GP_IOBUF _TECHMAP_REPLACE_ (
|
GP_IOBUF _TECHMAP_REPLACE_ (
|
||||||
.IN(IN),
|
.IN(IN),
|
||||||
|
|
|
@ -16,11 +16,15 @@ module GP_4LUT(input IN0, IN1, IN2, IN3, output OUT);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_ABUF(input wire IN, output wire OUT);
|
module GP_ABUF(input wire IN, output wire OUT);
|
||||||
|
|
||||||
assign OUT = IN;
|
assign OUT = IN;
|
||||||
|
|
||||||
|
//must be 1, 5, 20, 50
|
||||||
|
//values >1 only available with Vdd > 2.7V
|
||||||
|
parameter BANDWIDTH_KHZ = 1;
|
||||||
|
|
||||||
//cannot simulate mixed signal IP
|
//cannot simulate mixed signal IP
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT);
|
module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT);
|
||||||
|
@ -29,9 +33,9 @@ module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT
|
||||||
parameter VIN_ATTEN = 1;
|
parameter VIN_ATTEN = 1;
|
||||||
parameter VIN_ISRC_EN = 0;
|
parameter VIN_ISRC_EN = 0;
|
||||||
parameter HYSTERESIS = 0;
|
parameter HYSTERESIS = 0;
|
||||||
|
|
||||||
initial OUT = 0;
|
initial OUT = 0;
|
||||||
|
|
||||||
//cannot simulate mixed signal IP
|
//cannot simulate mixed signal IP
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -40,37 +44,41 @@ module GP_BANDGAP(output reg OK);
|
||||||
parameter AUTO_PWRDN = 1;
|
parameter AUTO_PWRDN = 1;
|
||||||
parameter CHOPPER_EN = 1;
|
parameter CHOPPER_EN = 1;
|
||||||
parameter OUT_DELAY = 100;
|
parameter OUT_DELAY = 100;
|
||||||
|
|
||||||
//cannot simulate mixed signal IP
|
//cannot simulate mixed signal IP
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_CLKBUF(input wire IN, output wire OUT);
|
||||||
|
assign OUT = IN;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_COUNT8(input CLK, input wire RST, output reg OUT);
|
module GP_COUNT8(input CLK, input wire RST, output reg OUT);
|
||||||
|
|
||||||
parameter RESET_MODE = "RISING";
|
parameter RESET_MODE = "RISING";
|
||||||
|
|
||||||
parameter COUNT_TO = 8'h1;
|
parameter COUNT_TO = 8'h1;
|
||||||
parameter CLKIN_DIVIDE = 1;
|
parameter CLKIN_DIVIDE = 1;
|
||||||
|
|
||||||
//more complex hard IP blocks are not supported for simulation yet
|
//more complex hard IP blocks are not supported for simulation yet
|
||||||
|
|
||||||
reg[7:0] count = COUNT_TO;
|
reg[7:0] count = COUNT_TO;
|
||||||
|
|
||||||
//Combinatorially output whenever we wrap low
|
//Combinatorially output whenever we wrap low
|
||||||
always @(*) begin
|
always @(*) begin
|
||||||
OUT <= (count == 8'h0);
|
OUT <= (count == 8'h0);
|
||||||
end
|
end
|
||||||
|
|
||||||
//POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
|
//POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
|
||||||
//Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
|
//Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
|
||||||
//Datasheet seems to indicate that reset is asynchronous, but for now we model as sync due to Yosys issues...
|
//Datasheet seems to indicate that reset is asynchronous, but for now we model as sync due to Yosys issues...
|
||||||
always @(posedge CLK) begin
|
always @(posedge CLK) begin
|
||||||
|
|
||||||
count <= count - 1'd1;
|
count <= count - 1'd1;
|
||||||
|
|
||||||
if(count == 0)
|
if(count == 0)
|
||||||
count <= COUNT_TO;
|
count <= COUNT_TO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if((RESET_MODE == "RISING") && RST)
|
if((RESET_MODE == "RISING") && RST)
|
||||||
count <= 0;
|
count <= 0;
|
||||||
|
@ -78,18 +86,18 @@ module GP_COUNT8(input CLK, input wire RST, output reg OUT);
|
||||||
count <= 0;
|
count <= 0;
|
||||||
if((RESET_MODE == "BOTH") && RST)
|
if((RESET_MODE == "BOTH") && RST)
|
||||||
count <= 0;
|
count <= 0;
|
||||||
*/
|
*/
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_COUNT14(input CLK, input wire RST, output reg OUT);
|
module GP_COUNT14(input CLK, input wire RST, output reg OUT);
|
||||||
|
|
||||||
parameter RESET_MODE = "RISING";
|
parameter RESET_MODE = "RISING";
|
||||||
|
|
||||||
parameter COUNT_TO = 14'h1;
|
parameter COUNT_TO = 14'h1;
|
||||||
parameter CLKIN_DIVIDE = 1;
|
parameter CLKIN_DIVIDE = 1;
|
||||||
|
|
||||||
//more complex hard IP blocks are not supported for simulation yet
|
//more complex hard IP blocks are not supported for simulation yet
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -128,15 +136,70 @@ module GP_DAC(input[7:0] DIN, input wire VREF, output reg VOUT);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module GP_DCMP(input[7:0] INP, input[7:0] INN, input CLK, input PWRDN, output reg GREATER, output reg EQUAL);
|
||||||
|
parameter PWRDN_SYNC = 1'b0;
|
||||||
|
parameter CLK_EDGE = "RISING";
|
||||||
|
parameter GREATER_OR_EQUAL = 1'b0;
|
||||||
|
|
||||||
|
//TODO implement power-down mode
|
||||||
|
|
||||||
|
initial GREATER = 0;
|
||||||
|
initial EQUAL = 0;
|
||||||
|
|
||||||
|
wire clk_minv = (CLK_EDGE == "RISING") ? CLK : ~CLK;
|
||||||
|
always @(posedge clk_minv) begin
|
||||||
|
if(GREATER_OR_EQUAL)
|
||||||
|
GREATER <= (INP >= INN);
|
||||||
|
else
|
||||||
|
GREATER <= (INP > INN);
|
||||||
|
|
||||||
|
EQUAL <= (INP == INN);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DCMPREF(output reg[7:0]OUT);
|
||||||
|
parameter[7:0] REF_VAL = 8'h00;
|
||||||
|
initial OUT = REF_VAL;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DCMPMUX(input[1:0] SEL, input[7:0] IN0, input[7:0] IN1, input[7:0] IN2, input[7:0] IN3, output reg[7:0] OUTA, output reg[7:0] OUTB);
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
case(SEL)
|
||||||
|
2'd00: begin
|
||||||
|
OUTA <= IN0;
|
||||||
|
OUTB <= IN3;
|
||||||
|
end
|
||||||
|
|
||||||
|
2'd01: begin
|
||||||
|
OUTA <= IN1;
|
||||||
|
OUTB <= IN2;
|
||||||
|
end
|
||||||
|
|
||||||
|
2'd02: begin
|
||||||
|
OUTA <= IN2;
|
||||||
|
OUTB <= IN1;
|
||||||
|
end
|
||||||
|
|
||||||
|
2'd03: begin
|
||||||
|
OUTA <= IN3;
|
||||||
|
OUTB <= IN0;
|
||||||
|
end
|
||||||
|
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
module GP_DELAY(input IN, output reg OUT);
|
module GP_DELAY(input IN, output reg OUT);
|
||||||
|
|
||||||
parameter DELAY_STEPS = 1;
|
parameter DELAY_STEPS = 1;
|
||||||
parameter GLITCH_FILTER = 0;
|
parameter GLITCH_FILTER = 0;
|
||||||
|
|
||||||
initial OUT = 0;
|
initial OUT = 0;
|
||||||
|
|
||||||
generate
|
generate
|
||||||
|
|
||||||
//TODO: These delays are PTV dependent! For now, hard code 3v3 timing
|
//TODO: These delays are PTV dependent! For now, hard code 3v3 timing
|
||||||
//Change simulation-mode delay depending on global Vdd range (how to specify this?)
|
//Change simulation-mode delay depending on global Vdd range (how to specify this?)
|
||||||
always @(*) begin
|
always @(*) begin
|
||||||
|
@ -151,9 +214,9 @@ module GP_DELAY(input IN, output reg OUT);
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_DFF(input D, CLK, output reg Q);
|
module GP_DFF(input D, CLK, output reg Q);
|
||||||
|
@ -240,14 +303,100 @@ module GP_DFFSRI(input D, CLK, nSR, output reg nQ);
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCH(input D, input nCLK, output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
initial Q = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nCLK)
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHI(input D, input nCLK, output reg nQ);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
initial nQ = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nCLK)
|
||||||
|
nQ <= ~D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHR(input D, input nCLK, input nRST, output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
initial Q = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nRST)
|
||||||
|
Q <= 1'b0;
|
||||||
|
else if(!nCLK)
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHRI(input D, input nCLK, input nRST, output reg nQ);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
initial nQ = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nRST)
|
||||||
|
nQ <= 1'b1;
|
||||||
|
else if(!nCLK)
|
||||||
|
nQ <= ~D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHS(input D, input nCLK, input nSET, output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
initial Q = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nSET)
|
||||||
|
Q <= 1'b1;
|
||||||
|
else if(!nCLK)
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHSI(input D, input nCLK, input nSET, output reg nQ);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
initial nQ = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nSET)
|
||||||
|
nQ <= 1'b0;
|
||||||
|
else if(!nCLK)
|
||||||
|
nQ <= ~D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHSR(input D, input nCLK, input nSR, output reg Q);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
parameter[0:0] SRMODE = 1'bx;
|
||||||
|
initial Q = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nSR)
|
||||||
|
Q <= SRMODE;
|
||||||
|
else if(!nCLK)
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_DLATCHSRI(input D, input nCLK, input nSR, output reg nQ);
|
||||||
|
parameter [0:0] INIT = 1'bx;
|
||||||
|
parameter[0:0] SRMODE = 1'bx;
|
||||||
|
initial nQ = INIT;
|
||||||
|
always @(*) begin
|
||||||
|
if(!nSR)
|
||||||
|
nQ <= ~SRMODE;
|
||||||
|
else if(!nCLK)
|
||||||
|
nQ <= ~D;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
module GP_EDGEDET(input IN, output reg OUT);
|
module GP_EDGEDET(input IN, output reg OUT);
|
||||||
|
|
||||||
parameter EDGE_DIRECTION = "RISING";
|
parameter EDGE_DIRECTION = "RISING";
|
||||||
parameter DELAY_STEPS = 1;
|
parameter DELAY_STEPS = 1;
|
||||||
parameter GLITCH_FILTER = 0;
|
parameter GLITCH_FILTER = 0;
|
||||||
|
|
||||||
//not implemented for simulation
|
//not implemented for simulation
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_IBUF(input IN, output OUT);
|
module GP_IBUF(input IN, output OUT);
|
||||||
|
@ -264,16 +413,16 @@ module GP_INV(input IN, output OUT);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_LFOSC(input PWRDN, output reg CLKOUT);
|
module GP_LFOSC(input PWRDN, output reg CLKOUT);
|
||||||
|
|
||||||
parameter PWRDN_EN = 0;
|
parameter PWRDN_EN = 0;
|
||||||
parameter AUTO_PWRDN = 0;
|
parameter AUTO_PWRDN = 0;
|
||||||
parameter OUT_DIV = 1;
|
parameter OUT_DIV = 1;
|
||||||
|
|
||||||
initial CLKOUT = 0;
|
initial CLKOUT = 0;
|
||||||
|
|
||||||
//auto powerdown not implemented for simulation
|
//auto powerdown not implemented for simulation
|
||||||
//output dividers not implemented for simulation
|
//output dividers not implemented for simulation
|
||||||
|
|
||||||
always begin
|
always begin
|
||||||
if(PWRDN)
|
if(PWRDN)
|
||||||
CLKOUT = 0;
|
CLKOUT = 0;
|
||||||
|
@ -283,7 +432,7 @@ module GP_LFOSC(input PWRDN, output reg CLKOUT);
|
||||||
CLKOUT = ~CLKOUT;
|
CLKOUT = ~CLKOUT;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_OBUF(input IN, output OUT);
|
module GP_OBUF(input IN, output OUT);
|
||||||
|
@ -320,18 +469,22 @@ module GP_PGEN(input wire nRST, input wire CLK, output reg OUT);
|
||||||
OUT <= PATTERN_DATA[count];
|
OUT <= PATTERN_DATA[count];
|
||||||
|
|
||||||
if( (count + 1) == PATTERN_LEN)
|
if( (count + 1) == PATTERN_LEN)
|
||||||
count <= 0;
|
count <= 0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GP_PWRDET(output reg VDD_LOW);
|
||||||
|
initial VDD_LOW = 0;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_POR(output reg RST_DONE);
|
module GP_POR(output reg RST_DONE);
|
||||||
parameter POR_TIME = 500;
|
parameter POR_TIME = 500;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
RST_DONE = 0;
|
RST_DONE = 0;
|
||||||
|
|
||||||
if(POR_TIME == 4)
|
if(POR_TIME == 4)
|
||||||
#4000;
|
#4000;
|
||||||
else if(POR_TIME == 500)
|
else if(POR_TIME == 500)
|
||||||
|
@ -340,64 +493,64 @@ module GP_POR(output reg RST_DONE);
|
||||||
$display("ERROR: bad POR_TIME for GP_POR cell");
|
$display("ERROR: bad POR_TIME for GP_POR cell");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
||||||
RST_DONE = 1;
|
RST_DONE = 1;
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_RCOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
|
module GP_RCOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
|
||||||
|
|
||||||
parameter PWRDN_EN = 0;
|
parameter PWRDN_EN = 0;
|
||||||
parameter AUTO_PWRDN = 0;
|
parameter AUTO_PWRDN = 0;
|
||||||
parameter HARDIP_DIV = 1;
|
parameter HARDIP_DIV = 1;
|
||||||
parameter FABRIC_DIV = 1;
|
parameter FABRIC_DIV = 1;
|
||||||
parameter OSC_FREQ = "25k";
|
parameter OSC_FREQ = "25k";
|
||||||
|
|
||||||
initial CLKOUT_HARDIP = 0;
|
initial CLKOUT_HARDIP = 0;
|
||||||
initial CLKOUT_FABRIC = 0;
|
initial CLKOUT_FABRIC = 0;
|
||||||
|
|
||||||
//output dividers not implemented for simulation
|
//output dividers not implemented for simulation
|
||||||
//auto powerdown not implemented for simulation
|
//auto powerdown not implemented for simulation
|
||||||
|
|
||||||
always begin
|
always begin
|
||||||
if(PWRDN) begin
|
if(PWRDN) begin
|
||||||
CLKOUT_HARDIP = 0;
|
CLKOUT_HARDIP = 0;
|
||||||
CLKOUT_FABRIC = 0;
|
CLKOUT_FABRIC = 0;
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
|
|
||||||
if(OSC_FREQ == "25k") begin
|
if(OSC_FREQ == "25k") begin
|
||||||
//half period of 25 kHz
|
//half period of 25 kHz
|
||||||
#20000;
|
#20000;
|
||||||
end
|
end
|
||||||
|
|
||||||
else begin
|
else begin
|
||||||
//half period of 2 MHz
|
//half period of 2 MHz
|
||||||
#250;
|
#250;
|
||||||
end
|
end
|
||||||
|
|
||||||
CLKOUT_HARDIP = ~CLKOUT_HARDIP;
|
CLKOUT_HARDIP = ~CLKOUT_HARDIP;
|
||||||
CLKOUT_FABRIC = ~CLKOUT_FABRIC;
|
CLKOUT_FABRIC = ~CLKOUT_FABRIC;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
|
module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC);
|
||||||
|
|
||||||
parameter PWRDN_EN = 0;
|
parameter PWRDN_EN = 0;
|
||||||
parameter AUTO_PWRDN = 0;
|
parameter AUTO_PWRDN = 0;
|
||||||
parameter HARDIP_DIV = 1;
|
parameter HARDIP_DIV = 1;
|
||||||
parameter FABRIC_DIV = 1;
|
parameter FABRIC_DIV = 1;
|
||||||
|
|
||||||
initial CLKOUT_HARDIP = 0;
|
initial CLKOUT_HARDIP = 0;
|
||||||
initial CLKOUT_FABRIC = 0;
|
initial CLKOUT_FABRIC = 0;
|
||||||
|
|
||||||
//output dividers not implemented for simulation
|
//output dividers not implemented for simulation
|
||||||
//auto powerdown not implemented for simulation
|
//auto powerdown not implemented for simulation
|
||||||
|
|
||||||
always begin
|
always begin
|
||||||
if(PWRDN) begin
|
if(PWRDN) begin
|
||||||
CLKOUT_HARDIP = 0;
|
CLKOUT_HARDIP = 0;
|
||||||
|
@ -410,7 +563,7 @@ module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRI
|
||||||
CLKOUT_FABRIC = ~CLKOUT_FABRIC;
|
CLKOUT_FABRIC = ~CLKOUT_FABRIC;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB);
|
module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB);
|
||||||
|
@ -418,32 +571,58 @@ module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB);
|
||||||
parameter OUTA_TAP = 1;
|
parameter OUTA_TAP = 1;
|
||||||
parameter OUTA_INVERT = 0;
|
parameter OUTA_INVERT = 0;
|
||||||
parameter OUTB_TAP = 1;
|
parameter OUTB_TAP = 1;
|
||||||
|
|
||||||
reg[15:0] shreg = 0;
|
reg[15:0] shreg = 0;
|
||||||
|
|
||||||
always @(posedge CLK, negedge nRST) begin
|
always @(posedge CLK, negedge nRST) begin
|
||||||
|
|
||||||
if(!nRST)
|
if(!nRST)
|
||||||
shreg = 0;
|
shreg = 0;
|
||||||
|
|
||||||
else
|
else
|
||||||
shreg <= {shreg[14:0], IN};
|
shreg <= {shreg[14:0], IN};
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1];
|
assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1];
|
||||||
assign OUTB = shreg[OUTB_TAP - 1];
|
assign OUTB = shreg[OUTB_TAP - 1];
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module GP_SPI(
|
||||||
|
input SCK,
|
||||||
|
inout SDAT,
|
||||||
|
input CSN,
|
||||||
|
input[7:0] TXD_HIGH,
|
||||||
|
input[7:0] TXD_LOW,
|
||||||
|
output reg[7:0] RXD_HIGH,
|
||||||
|
output reg[7:0] RXD_LOW,
|
||||||
|
output reg INT);
|
||||||
|
|
||||||
|
initial DOUT_HIGH = 0;
|
||||||
|
initial DOUT_LOW = 0;
|
||||||
|
initial INT = 0;
|
||||||
|
|
||||||
|
parameter DATA_WIDTH = 8; //byte or word width
|
||||||
|
parameter SPI_CPHA = 0; //SPI clock phase
|
||||||
|
parameter SPI_CPOL = 0; //SPI clock polarity
|
||||||
|
parameter DIRECTION = "INPUT"; //SPI data direction (either input to chip or output to host)
|
||||||
|
//parallel output to fabric not yet implemented
|
||||||
|
|
||||||
|
//TODO: write sim model
|
||||||
|
//TODO: SPI SDIO control... can we use ADC output while SPI is input??
|
||||||
|
//TODO: clock sync
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
//keep constraint needed to prevent optimization since we have no outputs
|
//keep constraint needed to prevent optimization since we have no outputs
|
||||||
(* keep *)
|
(* keep *)
|
||||||
module GP_SYSRESET(input RST);
|
module GP_SYSRESET(input RST);
|
||||||
parameter RESET_MODE = "EDGE";
|
parameter RESET_MODE = "EDGE";
|
||||||
parameter EDGE_SPEED = 4;
|
parameter EDGE_SPEED = 4;
|
||||||
|
|
||||||
//cannot simulate whole system reset
|
//cannot simulate whole system reset
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module GP_VDD(output OUT);
|
module GP_VDD(output OUT);
|
||||||
|
|
|
@ -26,6 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
void invert_gp_dff(Cell *cell, bool invert_input)
|
void invert_gp_dff(Cell *cell, bool invert_input)
|
||||||
{
|
{
|
||||||
string cell_type = cell->type.str();
|
string cell_type = cell->type.str();
|
||||||
|
bool cell_type_latch = cell_type.find("LATCH") != string::npos;
|
||||||
bool cell_type_i = cell_type.find('I') != string::npos;
|
bool cell_type_i = cell_type.find('I') != string::npos;
|
||||||
bool cell_type_r = cell_type.find('R') != string::npos;
|
bool cell_type_r = cell_type.find('R') != string::npos;
|
||||||
bool cell_type_s = cell_type.find('S') != string::npos;
|
bool cell_type_s = cell_type.find('S') != string::npos;
|
||||||
|
@ -79,25 +80,28 @@ void invert_gp_dff(Cell *cell, bool invert_input)
|
||||||
cell_type_i = true;
|
cell_type_i = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell->type = stringf("\\GP_DFF%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
|
if(cell_type_latch)
|
||||||
|
cell->type = stringf("\\GP_DLATCH%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
|
||||||
|
else
|
||||||
|
cell->type = stringf("\\GP_DFF%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : "");
|
||||||
|
|
||||||
log("Merged %s inverter into cell %s.%s: %s -> %s\n", invert_input ? "input" : "output",
|
log("Merged %s inverter into cell %s.%s: %s -> %s\n", invert_input ? "input" : "output",
|
||||||
log_id(cell->module), log_id(cell), cell_type.c_str()+1, log_id(cell->type));
|
log_id(cell->module), log_id(cell), cell_type.c_str()+1, log_id(cell->type));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Greenpak4DffInvPass : public Pass {
|
struct Greenpak4DffInvPass : public Pass {
|
||||||
Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFFs") { }
|
Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFF/latches") { }
|
||||||
virtual void help()
|
virtual void help()
|
||||||
{
|
{
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" greenpak4_dffinv [options] [selection]\n");
|
log(" greenpak4_dffinv [options] [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Merge GP_INV cells with GP_DFF* cells.\n");
|
log("Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
log_header(design, "Executing GREENPAK4_DFFINV pass (merge synchronous set/reset into FF cells).\n");
|
log_header(design, "Executing GREENPAK4_DFFINV pass (merge input/output inverters into FF/latch cells).\n");
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
@ -120,6 +124,15 @@ struct Greenpak4DffInvPass : public Pass {
|
||||||
gp_dff_types.insert("\\GP_DFFSR");
|
gp_dff_types.insert("\\GP_DFFSR");
|
||||||
gp_dff_types.insert("\\GP_DFFSRI");
|
gp_dff_types.insert("\\GP_DFFSRI");
|
||||||
|
|
||||||
|
gp_dff_types.insert("\\GP_DLATCH");
|
||||||
|
gp_dff_types.insert("\\GP_DLATCHI");
|
||||||
|
gp_dff_types.insert("\\GP_DLATCHR");
|
||||||
|
gp_dff_types.insert("\\GP_DLATCHRI");
|
||||||
|
gp_dff_types.insert("\\GP_DLATCHS");
|
||||||
|
gp_dff_types.insert("\\GP_DLATCHSI");
|
||||||
|
gp_dff_types.insert("\\GP_DLATCHSR");
|
||||||
|
gp_dff_types.insert("\\GP_DLATCHSRI");
|
||||||
|
|
||||||
for (auto module : design->selected_modules())
|
for (auto module : design->selected_modules())
|
||||||
{
|
{
|
||||||
SigMap sigmap(module);
|
SigMap sigmap(module);
|
||||||
|
|
|
@ -36,6 +36,8 @@ struct SynthGreenPAK4Pass : public ScriptPass
|
||||||
log(" synth_greenpak4 [options]\n");
|
log(" synth_greenpak4 [options]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This command runs synthesis for GreenPAK4 FPGAs. This work is experimental.\n");
|
log("This command runs synthesis for GreenPAK4 FPGAs. This work is experimental.\n");
|
||||||
|
log("It is intended to be used with https://github.com/azonenberg/openfpga as the\n");
|
||||||
|
log("place-and-route.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -top <module>\n");
|
log(" -top <module>\n");
|
||||||
log(" use the specified module as top module (default='top')\n");
|
log(" use the specified module as top module (default='top')\n");
|
||||||
|
@ -159,6 +161,7 @@ struct SynthGreenPAK4Pass : public ScriptPass
|
||||||
run("memory_map");
|
run("memory_map");
|
||||||
run("opt -undriven -fine");
|
run("opt -undriven -fine");
|
||||||
run("techmap");
|
run("techmap");
|
||||||
|
run("techmap -map +/greenpak4/cells_latch.v");
|
||||||
run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib");
|
run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib");
|
||||||
run("opt -fast");
|
run("opt -fast");
|
||||||
if (retime || help_mode)
|
if (retime || help_mode)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
module array_test001(a, b, c, y);
|
module array_test001(a, b, c, y);
|
||||||
input a;
|
input a;
|
||||||
input [31:0] b, c;
|
input [31:0] b, c;
|
||||||
input [31:0] y;
|
output [31:0] y;
|
||||||
|
|
||||||
aoi12 p [31:0] (a, b, c, y);
|
aoi12 p [31:0] (a, b, c, y);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
23
tests/simple/hierdefparam.v
Normal file
23
tests/simple/hierdefparam.v
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
module hierdefparam_top(input [7:0] A, output [7:0] Y);
|
||||||
|
generate begin:foo
|
||||||
|
hierdefparam_a mod_a(.A(A), .Y(Y));
|
||||||
|
end endgenerate
|
||||||
|
defparam foo.mod_a.bar[0].mod_b.addvalue = 42;
|
||||||
|
defparam foo.mod_a.bar[1].mod_b.addvalue = 43;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module hierdefparam_a(input [7:0] A, output [7:0] Y);
|
||||||
|
genvar i;
|
||||||
|
generate
|
||||||
|
for (i = 0; i < 2; i=i+1) begin:bar
|
||||||
|
wire [7:0] a, y;
|
||||||
|
hierdefparam_b mod_b(.A(a), .Y(y));
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign bar[0].a = A, bar[1].a = bar[0].y, Y = bar[1].y;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module hierdefparam_b(input [7:0] A, output [7:0] Y);
|
||||||
|
parameter [7:0] addvalue = 44;
|
||||||
|
assign Y = A + addvalue;
|
||||||
|
endmodule
|
35
tests/unit/Makefile
Normal file
35
tests/unit/Makefile
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
GTESTFLAG := -lgtest -lgtest_main
|
||||||
|
RPATH := -Wl,-rpath
|
||||||
|
EXTRAFLAGS := -lyosys -pthreads
|
||||||
|
|
||||||
|
OBJTEST := objtest
|
||||||
|
BINTEST := bintest
|
||||||
|
|
||||||
|
ALLTESTFILE := $(shell find -name '*Test.cc' -printf '%P ')
|
||||||
|
TESTDIRS := $(sort $(dir $(ALLTESTFILE)))
|
||||||
|
TESTS := $(addprefix $(BINTEST)/, $(basename $(ALLTESTFILE:%Test.cc=%Test.o)))
|
||||||
|
|
||||||
|
# Prevent make from removing our .o files
|
||||||
|
.SECONDARY:
|
||||||
|
|
||||||
|
all: prepare $(TESTS) run-tests
|
||||||
|
|
||||||
|
$(BINTEST)/%: $(OBJTEST)/%.o
|
||||||
|
$(CXX) -L$(ROOTPATH) $(RPATH)=$(ROOTPATH) -o $@ $^ $(LDLIBS) \
|
||||||
|
$(GTESTFLAG) $(EXTRAFLAGS)
|
||||||
|
|
||||||
|
$(OBJTEST)/%.o: $(basename $(subst $(OBJTEST),.,%)).cc
|
||||||
|
$(CXX) -o $@ -c -I$(ROOTPATH) $(CPPFLAGS) $(CXXFLAGS) $^
|
||||||
|
|
||||||
|
.PHONY: prepare run-tests clean
|
||||||
|
|
||||||
|
run-tests: $(TESTS)
|
||||||
|
$(subst Test ,Test; ,$^)
|
||||||
|
|
||||||
|
prepare:
|
||||||
|
mkdir -p $(addprefix $(BINTEST)/,$(TESTDIRS))
|
||||||
|
mkdir -p $(addprefix $(OBJTEST)/,$(TESTDIRS))
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OBJTEST)
|
||||||
|
rm -rf $(BINTEST)
|
14
tests/unit/kernel/logTest.cc
Normal file
14
tests/unit/kernel/logTest.cc
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/log.h"
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
TEST(KernelLogTest, logvValidValues)
|
||||||
|
{
|
||||||
|
//TODO: Implement log test
|
||||||
|
EXPECT_EQ(7, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
14
tests/unit/kernel/rtlilTest.cc
Normal file
14
tests/unit/kernel/rtlilTest.cc
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/rtlil.h"
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
TEST(KernelRtlilTest, getReferenceValid)
|
||||||
|
{
|
||||||
|
//TODO: Implement rtlil test
|
||||||
|
EXPECT_EQ(33, 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
Loading…
Add table
Reference in a new issue