mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'origin/master' into feature/python_bindings
This commit is contained in:
commit
03d1606b42
|
@ -0,0 +1,7 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
|
@ -1,9 +1,20 @@
|
|||
## Steps to reproduce the issue
|
||||
|
||||
*Provide instructions for reproducing the issue. Make sure to include
|
||||
all neccessary source files. (You can simply drag&drop a .zip file into
|
||||
all necessary source files. (You can simply drag&drop a .zip file into
|
||||
the issue editor.)*
|
||||
|
||||
Also, make sure that the issue is actually reproducable in current git
|
||||
master of Yosys.
|
||||
|
||||
See https://stackoverflow.com/help/mcve for some information on how to
|
||||
create a Minimal, Complete, and Verifiable example (MCVE).
|
||||
|
||||
Please do not waste our time with issues that lack sufficient information
|
||||
to reproduce the issue easily. We will simply close those issues.
|
||||
|
||||
Contact https://www.symbioticeda.com/ if you need commercial support for Yosys.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
*Please describe the behavior you would have expected from the tool.*
|
||||
|
@ -11,6 +22,3 @@ the issue editor.)*
|
|||
## Actual behavior
|
||||
|
||||
*Please describe how the behavior you see differs from the expected behavior.*
|
||||
|
||||
**Important Note:** Nobody will be able to help you and/or fix the issue if you
|
||||
do not provide sufficient information for reproducing the problem.
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
*.d
|
||||
.*.swp
|
||||
*.gch
|
||||
*.gcda
|
||||
*.gcno
|
||||
/.cproject
|
||||
/.project
|
||||
/.settings
|
||||
|
@ -10,6 +12,8 @@
|
|||
/qtcreator.config
|
||||
/qtcreator.creator
|
||||
/qtcreator.creator.user
|
||||
/coverage.info
|
||||
/coverage_html
|
||||
/Makefile.conf
|
||||
/abc
|
||||
/viz.js
|
||||
|
@ -20,6 +24,8 @@
|
|||
/yosys-abc.exe
|
||||
/yosys-config
|
||||
/yosys-smtbmc
|
||||
/yosys-smtbmc.exe
|
||||
/yosys-smtbmc-script.py
|
||||
/yosys-filterlib
|
||||
/yosys-filterlib.exe
|
||||
/kernel/version_*.cc
|
||||
|
@ -30,3 +36,4 @@
|
|||
/libyosys.so
|
||||
/tests/unit/bintest/
|
||||
/tests/unit/objtest/
|
||||
/tests/ystests
|
||||
|
|
15
.travis.yml
15
.travis.yml
|
@ -28,7 +28,6 @@ matrix:
|
|||
- tcl-dev
|
||||
- libffi-dev
|
||||
- git
|
||||
- mercurial
|
||||
- graphviz
|
||||
- xdot
|
||||
- pkg-config
|
||||
|
@ -53,7 +52,6 @@ matrix:
|
|||
- tcl-dev
|
||||
- libffi-dev
|
||||
- git
|
||||
- mercurial
|
||||
- graphviz
|
||||
- xdot
|
||||
- pkg-config
|
||||
|
@ -78,7 +76,6 @@ matrix:
|
|||
- tcl-dev
|
||||
- libffi-dev
|
||||
- git
|
||||
- mercurial
|
||||
- graphviz
|
||||
- xdot
|
||||
- pkg-config
|
||||
|
@ -104,7 +101,6 @@ matrix:
|
|||
- tcl-dev
|
||||
- libffi-dev
|
||||
- git
|
||||
- mercurial
|
||||
- graphviz
|
||||
- xdot
|
||||
- pkg-config
|
||||
|
@ -129,7 +125,6 @@ matrix:
|
|||
- tcl-dev
|
||||
- libffi-dev
|
||||
- git
|
||||
- mercurial
|
||||
- graphviz
|
||||
- xdot
|
||||
- pkg-config
|
||||
|
@ -137,11 +132,11 @@ matrix:
|
|||
env:
|
||||
- MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
|
||||
|
||||
# Latest clang on Mac OS X
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
env:
|
||||
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
|
||||
# # Latest clang on Mac OS X
|
||||
# - os: osx
|
||||
# osx_image: xcode9.4
|
||||
# env:
|
||||
# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++"
|
||||
|
||||
before_install:
|
||||
- ./.travis/setup.sh
|
||||
|
|
|
@ -36,6 +36,8 @@ echo
|
|||
|
||||
##########################################################################
|
||||
|
||||
./yosys tests/simple/fiedler-cooley.v
|
||||
|
||||
echo
|
||||
echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r'
|
||||
echo
|
||||
|
|
|
@ -6,48 +6,15 @@ source .travis/common.sh
|
|||
|
||||
##########################################################################
|
||||
|
||||
# Fixing Travis's git clone
|
||||
echo
|
||||
echo 'Fixing git setup...' && echo -en 'travis_fold:start:before_install.git\\r'
|
||||
echo
|
||||
git fetch --unshallow && git fetch --tags
|
||||
|
||||
# For pull requests, we get more info about the git source.
|
||||
if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
|
||||
echo "- Fetching from pull request source"
|
||||
git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git
|
||||
git fetch source && git fetch --tags
|
||||
|
||||
echo "- Fetching the actual pull request"
|
||||
git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head
|
||||
git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge
|
||||
|
||||
git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge
|
||||
fi
|
||||
|
||||
# For building branches we need to fix the "detached head" state.
|
||||
if [ z"$TRAVIS_BRANCH" != z ]; then
|
||||
TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1)
|
||||
echo "- Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)"
|
||||
git remote -v
|
||||
git branch -v
|
||||
if [ x"$(git show-ref -s HEAD)" = x"$TRAVIS_COMMIT" ]; then
|
||||
echo "Checked out at $TRAVIS_COMMIT"
|
||||
else
|
||||
if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then
|
||||
git fetch source $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from source"
|
||||
fi
|
||||
git fetch origin $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from origin"
|
||||
fi
|
||||
git branch -D $TRAVIS_BRANCH || true
|
||||
git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH
|
||||
git branch -v
|
||||
fi
|
||||
|
||||
# Output status information.
|
||||
git status
|
||||
git describe --tags
|
||||
git log -n 5 --graph
|
||||
(
|
||||
set +e
|
||||
set -x
|
||||
git status
|
||||
git branch -v
|
||||
git log -n 5 --graph
|
||||
git log --format=oneline -n 20 --graph
|
||||
)
|
||||
echo
|
||||
echo -en 'travis_fold:end:before_install.git\\r'
|
||||
echo
|
||||
|
@ -64,7 +31,6 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
|||
brew tap Homebrew/bundle
|
||||
brew bundle
|
||||
brew install ccache
|
||||
brew install gcc
|
||||
echo
|
||||
echo -en 'travis_fold:end:before_install.brew\\r'
|
||||
echo
|
||||
|
|
1
Brewfile
1
Brewfile
|
@ -3,7 +3,6 @@ brew "flex"
|
|||
brew "gawk"
|
||||
brew "libffi"
|
||||
brew "git"
|
||||
brew "mercurial"
|
||||
brew "graphviz"
|
||||
brew "pkg-config"
|
||||
brew "python3"
|
||||
|
|
125
CHANGELOG
125
CHANGELOG
|
@ -3,9 +3,131 @@ List of major changes and improvements between releases
|
|||
=======================================================
|
||||
|
||||
|
||||
Yosys 0.7 .. Yosys ???
|
||||
Yosys 0.8 .. Yosys 0.8-dev
|
||||
--------------------------
|
||||
|
||||
* Various
|
||||
- Added $changed support to read_verilog
|
||||
- Added "write_edif -attrprop"
|
||||
- Added "ice40_unlut" pass
|
||||
- Added "opt_lut" pass
|
||||
- Added "synth_ice40 -relut"
|
||||
- Added "synth_ice40 -noabc"
|
||||
- Added "gate2lut.v" techmap rule
|
||||
- Added "rename -src"
|
||||
- Added "equiv_opt" pass
|
||||
|
||||
|
||||
Yosys 0.7 .. Yosys 0.8
|
||||
----------------------
|
||||
|
||||
* Various
|
||||
- Many bugfixes and small improvements
|
||||
- Strip debug symbols from installed binary
|
||||
- Replace -ignore_redef with -[no]overwrite in front-ends
|
||||
- Added write_verilog hex dump support, add -nohex option
|
||||
- Added "write_verilog -decimal"
|
||||
- Added "scc -set_attr"
|
||||
- Added "verilog_defines" command
|
||||
- Remeber defines from one read_verilog to next
|
||||
- Added support for hierarchical defparam
|
||||
- Added FIRRTL back-end
|
||||
- Improved ABC default scripts
|
||||
- Added "design -reset-vlog"
|
||||
- Added "yosys -W regex", "yosys -w regex", and "yosys -e regex"
|
||||
- Added Verilog $rtoi and $itor support
|
||||
- Added "check -initdrv"
|
||||
- Added "read_blif -wideports"
|
||||
- Added support for systemVerilog "++" and "--" operators
|
||||
- Added support for SystemVerilog unique, unique0, and priority case
|
||||
- Added "write_edif" options for edif "flavors"
|
||||
- Added support for resetall compiler directive
|
||||
- Added simple C beck-end (bitwise combinatorical only atm)
|
||||
- Added $_ANDNOT_ and $_ORNOT_ cell types
|
||||
- Added cell library aliases to "abc -g"
|
||||
- Added "setundef -anyseq"
|
||||
- Added "chtype" command
|
||||
- Added "design -import"
|
||||
- Added "write_table" command
|
||||
- Added "read_json" command
|
||||
- Added "sim" command
|
||||
- Added "extract_fa" and "extract_reduce" commands
|
||||
- Added "extract_counter" command
|
||||
- Added "opt_demorgan" command
|
||||
- Added support for $size and $bits SystemVerilog functions
|
||||
- Added "blackbox" command
|
||||
- Added "ltp" command
|
||||
- Added support for editline as replacement for readline
|
||||
- Added warnings for driver-driver conflicts between FFs (and other cells) and constants
|
||||
- Added "yosys -E" for creating Makefile dependencies files
|
||||
- Added "synth -noshare"
|
||||
- Added "memory_nordff"
|
||||
- Added "setundef -undef -expose -anyconst"
|
||||
- Added "expose -input"
|
||||
- Added specify/specparam parser support (simply ignore them)
|
||||
- Added "write_blif -inames -iattr"
|
||||
- Added "hierarchy -simcheck"
|
||||
- Added an option to statically link abc into yosys
|
||||
- Added protobuf back-end
|
||||
- Added BLIF parsing support for .conn and .cname
|
||||
- Added read_verilog error checking for reg/wire/logic misuse
|
||||
- Added "make coverage" and ENABLE_GCOV build option
|
||||
|
||||
* Changes in Yosys APIs
|
||||
- Added ConstEval defaultval feature
|
||||
- Added {get,set}_src_attribute() methods on RTLIL::AttrObject
|
||||
- Added SigSpec::is_fully_ones() and Const::is_fully_ones()
|
||||
- Added log_file_warning() and log_file_error() functions
|
||||
|
||||
* Formal Verification
|
||||
- Added "write_aiger"
|
||||
- Added "yosys-smtbmc --aig"
|
||||
- Added "always <positive_int>" to .smtc format
|
||||
- Added $cover cell type and support for cover properties
|
||||
- Added $fair/$live cell type and support for liveness properties
|
||||
- Added smtbmc support for memory vcd dumping
|
||||
- Added "chformal" command
|
||||
- Added "write_smt2 -stbv" and "write_smt2 -stdt"
|
||||
- Fix equiv_simple, old behavior now available with "equiv_simple -short"
|
||||
- Change to Yices2 as default SMT solver (it is GPL now)
|
||||
- Added "yosys-smtbmc --presat" (now default in SymbiYosys)
|
||||
- Added "yosys-smtbmc --smtc-init --smtc-top --noinit"
|
||||
- Added a brand new "write_btor" command for BTOR2
|
||||
- Added clk2fflogic memory support and other improvements
|
||||
- Added "async memory write" support to write_smt2
|
||||
- Simulate clock toggling in yosys-smtbmc VCD output
|
||||
- Added $allseq/$allconst cells for EA-solving
|
||||
- Make -nordff the default in "prep"
|
||||
- Added (* gclk *) attribute
|
||||
- Added "async2sync" pass for single-clock designs with async resets
|
||||
|
||||
* Verific support
|
||||
- Many improvements in Verific front-end
|
||||
- Added proper handling of concurent SVA properties
|
||||
- Map "const" and "rand const" to $anyseq/$anyconst
|
||||
- Added "verific -import -flatten" and "verific -import -extnets"
|
||||
- Added "verific -vlog-incdir -vlog-define -vlog-libdir"
|
||||
- Remove PSL support (because PSL has been removed in upstream Verific)
|
||||
- Improve integration with "hierarchy" command design elaboration
|
||||
- Added YOSYS_NOVERIFIC for running non-verific test cases with verific bin
|
||||
- Added simpilied "read" command that automatically uses verific if available
|
||||
- Added "verific -set-<severity> <msg_id>.."
|
||||
- Added "verific -work <libname>"
|
||||
|
||||
* New back-ends
|
||||
- Added initial Coolrunner-II support
|
||||
- Added initial eASIC support
|
||||
- Added initial ECP5 support
|
||||
|
||||
* GreenPAK Support
|
||||
- Added support for GP_DLATCH, GP_SPI, GP_DCMx, GP_COUNTx, etc.
|
||||
|
||||
* iCE40 Support
|
||||
- Add "synth_ice40 -vpr"
|
||||
- Add "synth_ice40 -nodffe"
|
||||
- Add "synth_ice40 -json"
|
||||
- Add Support for UltraPlus cells
|
||||
|
||||
* MAX10 and Cyclone IV Support
|
||||
- Added initial version of metacommand "synth_intel".
|
||||
- Improved write_verilog command to produce VQM netlist for Quartus Prime.
|
||||
|
@ -14,6 +136,7 @@ Yosys 0.7 .. Yosys ???
|
|||
- Added example of implementation for DE2i-150 board.
|
||||
- Added example of implementation for MAX10 development kit.
|
||||
- Added LFSR example from Asic World.
|
||||
- Added "dffinit -highlow" for mapping to Intel primitives
|
||||
|
||||
|
||||
Yosys 0.6 .. Yosys 0.7
|
||||
|
|
2
COPYING
2
COPYING
|
@ -1,4 +1,4 @@
|
|||
Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at>
|
||||
Copyright (C) 2012 - 2018 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
|
||||
|
|
|
@ -21,7 +21,7 @@ Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
|
|||
|
||||
struct HelloWorldPass : public Pass {
|
||||
HelloWorldPass() : Pass("hello_world") { }
|
||||
virtual void execute(vector<string>, Design*) {
|
||||
void execute(vector<string>, Design*) override {
|
||||
log("Hello World!\n");
|
||||
}
|
||||
} HelloWorldPass;
|
||||
|
@ -373,6 +373,7 @@ Finally run all tests with "make config-{clang,gcc,gcc-4.8}":
|
|||
cd ~yosys
|
||||
make clean
|
||||
make test
|
||||
make ystests
|
||||
make vloghtb
|
||||
make install
|
||||
|
||||
|
|
113
Makefile
113
Makefile
|
@ -5,10 +5,12 @@ CONFIG := clang
|
|||
# CONFIG := emcc
|
||||
# CONFIG := mxe
|
||||
# CONFIG := msys2
|
||||
# CONFIG := msys2-64
|
||||
|
||||
# features (the more the better)
|
||||
ENABLE_TCL := 1
|
||||
ENABLE_ABC := 1
|
||||
ENABLE_GLOB := 1
|
||||
ENABLE_PLUGINS := 1
|
||||
ENABLE_READLINE := 1
|
||||
ENABLE_EDITLINE := 0
|
||||
|
@ -23,6 +25,7 @@ PYTHON_VERSION := 3.5
|
|||
PYTHON_DESTDIR := /usr/local/lib/python$(PYTHON_VERSION)/dist-packages
|
||||
|
||||
# other configuration flags
|
||||
ENABLE_GCOV := 0
|
||||
ENABLE_GPROF := 0
|
||||
ENABLE_DEBUG := 0
|
||||
ENABLE_NDEBUG := 0
|
||||
|
@ -75,6 +78,7 @@ PKG_CONFIG ?= pkg-config
|
|||
SED ?= sed
|
||||
BISON ?= bison
|
||||
STRIP ?= strip
|
||||
AWK ?= awk
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
PLUGIN_LDFLAGS += -undefined dynamic_lookup
|
||||
|
@ -102,7 +106,7 @@ 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; })
|
||||
YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; })
|
||||
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
||||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
|
@ -112,7 +116,7 @@ OBJS = kernel/version_$(GIT_REV).o
|
|||
# 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
|
||||
# delete your work on ABC..
|
||||
ABCREV = 6df1396
|
||||
ABCREV = 2ddc57d
|
||||
ABCPULL = 1
|
||||
ABCURL ?= https://github.com/berkeley-abc/abc
|
||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
|
||||
|
@ -160,12 +164,30 @@ LD = gcc
|
|||
CXXFLAGS += -std=c++11 -Os
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),gcc-static)
|
||||
LD = $(CXX)
|
||||
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -static
|
||||
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
CXXFLAGS += -std=c++11 -Os
|
||||
ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(LD)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \
|
||||
ARCHFLAGS="-DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING=1 -Wno-unused-but-set-variable $(ARCHFLAGS)" ABC_USE_NO_READLINE=1
|
||||
ifeq ($(DISABLE_ABC_THREADS),1)
|
||||
ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
|
||||
endif
|
||||
|
||||
else ifeq ($(CONFIG),gcc-4.8)
|
||||
CXX = gcc-4.8
|
||||
LD = gcc-4.8
|
||||
CXXFLAGS += -std=c++11 -Os
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),cygwin)
|
||||
CXX = gcc
|
||||
LD = gcc
|
||||
CXXFLAGS += -std=gnu++11 -Os
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
||||
|
||||
else ifeq ($(CONFIG),emcc)
|
||||
CXX = emcc
|
||||
LD = emcc
|
||||
|
@ -204,14 +226,14 @@ yosys.html: misc/yosys.html
|
|||
|
||||
else ifeq ($(CONFIG),mxe)
|
||||
PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config
|
||||
CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
|
||||
LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
|
||||
CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++
|
||||
LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++
|
||||
CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
||||
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1
|
||||
ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
|
||||
EXE = .exe
|
||||
|
||||
else ifeq ($(CONFIG),msys2)
|
||||
|
@ -222,11 +244,22 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
|||
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
||||
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0
|
||||
ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)"
|
||||
EXE = .exe
|
||||
|
||||
else ifeq ($(CONFIG),msys2-64)
|
||||
CXX = x86_64-w64-mingw32-g++
|
||||
LD = x86_64-w64-mingw32-g++
|
||||
CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
|
||||
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
|
||||
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
|
||||
LDLIBS := $(filter-out -lrt,$(LDLIBS))
|
||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
|
||||
ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)"
|
||||
EXE = .exe
|
||||
|
||||
else ifneq ($(CONFIG),none)
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2)
|
||||
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2, msys2-64)
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_LIBYOSYS),1)
|
||||
|
@ -280,6 +313,10 @@ LDLIBS += -ldl
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_GLOB),1)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_GLOB
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_TCL),1)
|
||||
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
|
||||
ifeq ($(OS), FreeBSD)
|
||||
|
@ -290,7 +327,7 @@ endif
|
|||
|
||||
ifeq ($(CONFIG),mxe)
|
||||
CXXFLAGS += -DYOSYS_ENABLE_TCL
|
||||
LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32
|
||||
LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz
|
||||
else
|
||||
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
|
||||
ifeq ($(OS), FreeBSD)
|
||||
|
@ -302,6 +339,11 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_GCOV),1)
|
||||
CXXFLAGS += --coverage
|
||||
LDFLAGS += --coverage
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_GPROF),1)
|
||||
CXXFLAGS += -pg
|
||||
LDFLAGS += -pg
|
||||
|
@ -334,11 +376,15 @@ endif
|
|||
endif
|
||||
|
||||
ifeq ($(ENABLE_VERIFIC),1)
|
||||
VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
|
||||
VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf hier_tree
|
||||
VERIFIC_DIR ?= /usr/local/src/verific_lib
|
||||
VERIFIC_COMPONENTS ?= verilog vhdl database util containers hier_tree
|
||||
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
|
||||
ifeq ($(OS), Darwin)
|
||||
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-mac.a,$(VERIFIC_COMPONENTS)) -lz
|
||||
else
|
||||
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_PROTOBUF),1)
|
||||
LDLIBS += $(shell pkg-config --cflags --libs protobuf)
|
||||
|
@ -369,8 +415,8 @@ endef
|
|||
ifeq ($(PRETTY), 1)
|
||||
P_STATUS = 0
|
||||
P_OFFSET = 0
|
||||
P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
|
||||
P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
|
||||
P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
|
||||
P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
|
||||
P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
|
||||
Q = @
|
||||
S = -s
|
||||
|
@ -551,7 +597,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
|||
+cd tests/simple && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/hana && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/realmath && bash run-test.sh $(SEEDOPT)
|
||||
# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/share && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/techmap && bash run-test.sh
|
||||
|
@ -559,6 +605,9 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
|||
+cd tests/bram && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/various && bash run-test.sh
|
||||
+cd tests/sat && bash run-test.sh
|
||||
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
||||
+cd tests/opt && bash run-test.sh
|
||||
+cd tests/aiger && bash run-test.sh
|
||||
@echo ""
|
||||
@echo " Passed \"make test\"."
|
||||
@echo ""
|
||||
|
@ -577,6 +626,14 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS)
|
|||
@echo " Passed \"make vloghtb\"."
|
||||
@echo ""
|
||||
|
||||
ystests: $(TARGETS) $(EXTRA_TARGETS)
|
||||
rm -rf tests/ystests
|
||||
git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests
|
||||
+$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests
|
||||
@echo ""
|
||||
@echo " Finished \"make ystests\"."
|
||||
@echo ""
|
||||
|
||||
# Unit test
|
||||
unit-test: libyosys.so
|
||||
@$(MAKE) -C $(UNITESTPATH) CXX="$(CXX)" CPPFLAGS="$(CPPFLAGS)" \
|
||||
|
@ -644,6 +701,7 @@ clean:
|
|||
rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log
|
||||
rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp
|
||||
rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
|
||||
rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff
|
||||
rm -f tests/tools/cmp_tbdata
|
||||
|
||||
clean-abc:
|
||||
|
@ -653,6 +711,12 @@ clean-abc:
|
|||
mrproper: clean
|
||||
git clean -xdf
|
||||
|
||||
coverage:
|
||||
./yosys -qp 'help; help -all'
|
||||
rm -rf coverage.info coverage_html
|
||||
lcov --capture -d . --no-external -o coverage.info
|
||||
genhtml coverage.info --output-directory coverage_html
|
||||
|
||||
qtcreator:
|
||||
{ for file in $(basename $(OBJS)); do \
|
||||
for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \
|
||||
|
@ -692,6 +756,12 @@ config-clang: clean
|
|||
config-gcc: clean
|
||||
echo 'CONFIG := gcc' > Makefile.conf
|
||||
|
||||
config-gcc-static: clean
|
||||
echo 'CONFIG := gcc-static' > Makefile.conf
|
||||
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
|
||||
echo 'ENABLE_READLINE := 0' >> Makefile.conf
|
||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||
|
||||
config-gcc-4.8: clean
|
||||
echo 'CONFIG := gcc-4.8' > Makefile.conf
|
||||
|
||||
|
@ -709,6 +779,17 @@ config-mxe: clean
|
|||
config-msys2: clean
|
||||
echo 'CONFIG := msys2' > Makefile.conf
|
||||
|
||||
config-msys2-64: clean
|
||||
echo 'CONFIG := msys2-64' > Makefile.conf
|
||||
|
||||
config-cygwin: clean
|
||||
echo 'CONFIG := cygwin' > Makefile.conf
|
||||
|
||||
config-gcov: clean
|
||||
echo 'CONFIG := gcc' > Makefile.conf
|
||||
echo 'ENABLE_GCOV := 1' >> Makefile.conf
|
||||
echo 'ENABLE_DEBUG := 1' >> Makefile.conf
|
||||
|
||||
config-gprof: clean
|
||||
echo 'CONFIG := gcc' > Makefile.conf
|
||||
echo 'ENABLE_GPROF := 1' >> Makefile.conf
|
||||
|
@ -729,6 +810,6 @@ echo-git-rev:
|
|||
-include kernel/*.d
|
||||
-include techlibs/*/*.d
|
||||
|
||||
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator
|
||||
.PHONY: config-clean config-clang config-gcc config-gcc-4.8 config-gprof config-sudo
|
||||
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator coverage vcxsrc mxebin
|
||||
.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-gprof config-sudo
|
||||
|
||||
|
|
59
README.md
59
README.md
|
@ -1,7 +1,7 @@
|
|||
```
|
||||
yosys -- Yosys Open SYnthesis Suite
|
||||
|
||||
Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at>
|
||||
Copyright (C) 2012 - 2018 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
|
||||
|
@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license
|
|||
or the 2-clause BSD license).
|
||||
|
||||
|
||||
Web Site
|
||||
========
|
||||
Web Site and Other Resources
|
||||
============================
|
||||
|
||||
More information and documentation can be found on the Yosys web site:
|
||||
http://www.clifford.at/yosys/
|
||||
- http://www.clifford.at/yosys/
|
||||
|
||||
The "Documentation" page on the web site contains links to more resources,
|
||||
including a manual that even describes some of the Yosys internals:
|
||||
- http://www.clifford.at/yosys/documentation.html
|
||||
|
||||
The file `CodingReadme` in this directory contains additional information
|
||||
for people interested in using the Yosys C++ APIs.
|
||||
|
||||
Users interested in formal verification might want to use the formal verification
|
||||
front-end for Yosys, SymbiYosys:
|
||||
- https://symbiyosys.readthedocs.io/en/latest/
|
||||
- https://github.com/YosysHQ/SymbiYosys
|
||||
|
||||
|
||||
Setup
|
||||
======
|
||||
|
@ -69,6 +82,10 @@ On FreeBSD use the following command to install all prerequisites:
|
|||
On FreeBSD system use gmake instead of make. To run tests use:
|
||||
% MAKE=gmake CC=cc gmake test
|
||||
|
||||
For Cygwin use the following command to install all prerequisites, or select these additional packages:
|
||||
|
||||
setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel
|
||||
|
||||
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
|
||||
more information: http://www.clifford.at/yosys/download.html
|
||||
|
@ -88,12 +105,15 @@ Makefile.
|
|||
To build Yosys simply type 'make' in this directory.
|
||||
|
||||
$ make
|
||||
$ make test
|
||||
$ sudo make install
|
||||
|
||||
Note that this also downloads, builds and installs ABC (using yosys-abc
|
||||
as executable name).
|
||||
|
||||
Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
|
||||
|
||||
$ make test
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
|
@ -113,7 +133,7 @@ reading the design using the Verilog frontend:
|
|||
|
||||
yosys> read_verilog tests/simple/fiedler-cooley.v
|
||||
|
||||
writing the design to the console in yosys's internal format:
|
||||
writing the design to the console in Yosys's internal format:
|
||||
|
||||
yosys> write_ilang
|
||||
|
||||
|
@ -230,7 +250,7 @@ Unsupported Verilog-2005 Features
|
|||
=================================
|
||||
|
||||
The following Verilog-2005 features are not supported by
|
||||
yosys and there are currently no plans to add support
|
||||
Yosys and there are currently no plans to add support
|
||||
for them:
|
||||
|
||||
- Non-synthesizable language features as defined in
|
||||
|
@ -281,9 +301,9 @@ Verilog Attributes and non-standard features
|
|||
storage element. The register itself will always have all bits set
|
||||
to 'x' (undefined). The variable may only be used as blocking assigned
|
||||
temporary variable within an always block. This is mostly used internally
|
||||
by yosys to synthesize Verilog functions and access arrays.
|
||||
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 one-hot state register. This
|
||||
is used for example for memory port sharing and set by the fsm_map pass.
|
||||
|
||||
- The ``blackbox`` attribute on modules is used to mark empty stub modules
|
||||
|
@ -292,6 +312,12 @@ Verilog Attributes and non-standard features
|
|||
passes to identify input and output ports of cells. The Verilog backend
|
||||
also does not output blackbox modules on default.
|
||||
|
||||
- The ``dynports'' attribute is used by the Verilog front-end to mark modules
|
||||
that have ports with a width that depends on a parameter.
|
||||
|
||||
- The ``hdlname'' attribute is used by some passes to document the original
|
||||
(HDL) name of a module when renaming a module.
|
||||
|
||||
- The ``keep`` attribute on cells and wires is used to mark objects that should
|
||||
never be removed by the optimizer. This is used for example for cells that
|
||||
have hidden connections that are not part of the netlist, such as IO pads.
|
||||
|
@ -315,13 +341,13 @@ Verilog Attributes and non-standard features
|
|||
through the synthesis. When entities are combined, a new |-separated
|
||||
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
|
||||
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||
by adding an empty ``{* *}`` statement.)
|
||||
|
||||
- In module parameter and port declarations, and cell port and parameter
|
||||
lists, a trailing comma is ignored. This simplifies writing verilog code
|
||||
lists, a trailing comma is ignored. This simplifies writing Verilog code
|
||||
generators a bit in some cases.
|
||||
|
||||
- Modules can be declared with ``module mod_name(...);`` (with three dots
|
||||
|
@ -389,7 +415,7 @@ Verilog Attributes and non-standard features
|
|||
Non-standard or SystemVerilog features for formal verification
|
||||
==============================================================
|
||||
|
||||
- Support for ``assert``, ``assume``, ``restrict``, and ``cover'' is enabled
|
||||
- Support for ``assert``, ``assume``, ``restrict``, and ``cover`` is enabled
|
||||
when ``read_verilog`` is called with ``-formal``.
|
||||
|
||||
- The system task ``$initstate`` evaluates to 1 in the initial state and
|
||||
|
@ -406,11 +432,11 @@ Non-standard or SystemVerilog features for formal verification
|
|||
|
||||
- The system functions ``$allconst`` and ``$allseq`` can be used to construct
|
||||
formal exist-forall problems. Assumptions only hold if the trace satisfies
|
||||
the assumtion for all ``$allconst/$allseq`` values. For assertions and cover
|
||||
the assumption for all ``$allconst/$allseq`` values. For assertions and cover
|
||||
statements it is sufficient if just one ``$allconst/$allseq`` value triggers
|
||||
the property (similar to ``$anyconst/$anyseq``).
|
||||
|
||||
- Wires/registers decalred using the ``anyconst/anyseq/allconst/allseq`` attribute
|
||||
- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq`` attribute
|
||||
(for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven
|
||||
by a ``$anyconst/$anyseq/$allconst/$allseq`` function.
|
||||
|
||||
|
@ -448,6 +474,9 @@ from SystemVerilog:
|
|||
into a design with ``read_verilog``, all its packages are available to
|
||||
SystemVerilog files being read into the same design afterwards.
|
||||
|
||||
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
|
||||
ports are inputs or outputs are supported.
|
||||
|
||||
|
||||
Building the documentation
|
||||
==========================
|
||||
|
@ -478,6 +507,6 @@ Then execute, from the root of the repository:
|
|||
|
||||
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
|
||||
`PRESENTATION_Prog`.
|
||||
|
|
|
@ -100,7 +100,7 @@ struct AigerWriter
|
|||
return aig_map.at(bit);
|
||||
}
|
||||
|
||||
AigerWriter(Module *module, bool zinit_mode) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
||||
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
||||
{
|
||||
pool<SigBit> undriven_bits;
|
||||
pool<SigBit> unused_bits;
|
||||
|
@ -293,6 +293,10 @@ struct AigerWriter
|
|||
aig_map[bit] = 2*aig_m;
|
||||
}
|
||||
|
||||
if (imode && input_bits.empty()) {
|
||||
aig_m++, aig_i++;
|
||||
}
|
||||
|
||||
if (zinit_mode)
|
||||
{
|
||||
for (auto it : ff_map) {
|
||||
|
@ -371,6 +375,11 @@ struct AigerWriter
|
|||
aig_outputs.push_back(bit2aig(bit));
|
||||
}
|
||||
|
||||
if (omode && output_bits.empty()) {
|
||||
aig_o++;
|
||||
aig_outputs.push_back(0);
|
||||
}
|
||||
|
||||
for (auto it : asserts) {
|
||||
aig_b++;
|
||||
int bit_a = bit2aig(it.first);
|
||||
|
@ -378,6 +387,11 @@ struct AigerWriter
|
|||
aig_outputs.push_back(mkgate(bit_a^1, bit_en));
|
||||
}
|
||||
|
||||
if (bmode && asserts.empty()) {
|
||||
aig_b++;
|
||||
aig_outputs.push_back(0);
|
||||
}
|
||||
|
||||
for (auto it : assumes) {
|
||||
aig_c++;
|
||||
int bit_a = bit2aig(it.first);
|
||||
|
@ -657,7 +671,7 @@ struct AigerWriter
|
|||
|
||||
struct AigerBackend : public Backend {
|
||||
AigerBackend() : Backend("aiger", "write design to AIGER file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -689,14 +703,22 @@ struct AigerBackend : public Backend {
|
|||
log(" -vmap <filename>\n");
|
||||
log(" like -map, but more verbose\n");
|
||||
log("\n");
|
||||
log(" -I, -O, -B\n");
|
||||
log(" If the design contains no input/output/assert then create one\n");
|
||||
log(" dummy input/output/bad_state pin to make the tools reading the\n");
|
||||
log(" AIGER file happy.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool ascii_mode = false;
|
||||
bool zinit_mode = false;
|
||||
bool miter_mode = false;
|
||||
bool symbols_mode = false;
|
||||
bool verbose_map = false;
|
||||
bool imode = false;
|
||||
bool omode = false;
|
||||
bool bmode = false;
|
||||
std::string map_filename;
|
||||
|
||||
log_header(design, "Executing AIGER backend.\n");
|
||||
|
@ -729,6 +751,18 @@ struct AigerBackend : public Backend {
|
|||
verbose_map = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-I") {
|
||||
imode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-O") {
|
||||
omode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-B") {
|
||||
bmode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
@ -738,7 +772,7 @@ struct AigerBackend : public Backend {
|
|||
if (top_module == nullptr)
|
||||
log_error("Can't find top module in current design!\n");
|
||||
|
||||
AigerWriter writer(top_module, zinit_mode);
|
||||
AigerWriter writer(top_module, zinit_mode, imode, omode, bmode);
|
||||
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
||||
|
||||
if (!map_filename.empty()) {
|
||||
|
|
|
@ -464,7 +464,7 @@ struct BlifDumper
|
|||
|
||||
struct BlifBackend : public Backend {
|
||||
BlifBackend() : Backend("blif", "write design to BLIF file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -534,7 +534,7 @@ struct BlifBackend : public Backend {
|
|||
log(" do not write definitions for the $true, $false and $undef wires.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::string top_module_name;
|
||||
std::string buf_type, buf_in, buf_out;
|
||||
|
|
|
@ -133,12 +133,13 @@ struct BtorWorker
|
|||
cell_recursion_guard.insert(cell);
|
||||
btorf_push(log_id(cell));
|
||||
|
||||
if (cell->type.in("$add", "$sub", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
|
||||
"$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
|
||||
if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx",
|
||||
"$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
|
||||
{
|
||||
string btor_op;
|
||||
if (cell->type == "$add") btor_op = "add";
|
||||
if (cell->type == "$sub") btor_op = "sub";
|
||||
if (cell->type == "$mul") btor_op = "mul";
|
||||
if (cell->type.in("$shl", "$sshl")) btor_op = "sll";
|
||||
if (cell->type == "$shr") btor_op = "srl";
|
||||
if (cell->type == "$sshr") btor_op = "sra";
|
||||
|
@ -146,6 +147,7 @@ struct BtorWorker
|
|||
if (cell->type.in("$and", "$_AND_")) btor_op = "and";
|
||||
if (cell->type.in("$or", "$_OR_")) btor_op = "or";
|
||||
if (cell->type.in("$xor", "$_XOR_")) btor_op = "xor";
|
||||
if (cell->type == "$concat") btor_op = "concat";
|
||||
if (cell->type == "$_NAND_") btor_op = "nand";
|
||||
if (cell->type == "$_NOR_") btor_op = "nor";
|
||||
if (cell->type.in("$xnor", "$_XNOR_")) btor_op = "xnor";
|
||||
|
@ -214,6 +216,40 @@ struct BtorWorker
|
|||
goto okay;
|
||||
}
|
||||
|
||||
if (cell->type.in("$div", "$mod"))
|
||||
{
|
||||
string btor_op;
|
||||
if (cell->type == "$div") btor_op = "div";
|
||||
if (cell->type == "$mod") btor_op = "rem";
|
||||
log_assert(!btor_op.empty());
|
||||
|
||||
int width = GetSize(cell->getPort("\\Y"));
|
||||
width = std::max(width, GetSize(cell->getPort("\\A")));
|
||||
width = std::max(width, GetSize(cell->getPort("\\B")));
|
||||
|
||||
bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false;
|
||||
bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false;
|
||||
|
||||
int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed);
|
||||
int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed);
|
||||
|
||||
int sid = get_bv_sid(width);
|
||||
int nid = next_nid++;
|
||||
btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b);
|
||||
|
||||
SigSpec sig = sigmap(cell->getPort("\\Y"));
|
||||
|
||||
if (GetSize(sig) < width) {
|
||||
int sid = get_bv_sid(GetSize(sig));
|
||||
int nid2 = next_nid++;
|
||||
btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1);
|
||||
nid = nid2;
|
||||
}
|
||||
|
||||
add_nid_sig(nid, sig);
|
||||
goto okay;
|
||||
}
|
||||
|
||||
if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
|
||||
{
|
||||
int sid = get_bv_sid(1);
|
||||
|
@ -506,6 +542,18 @@ struct BtorWorker
|
|||
}
|
||||
}
|
||||
|
||||
Const initval;
|
||||
for (int i = 0; i < GetSize(sig_q); i++)
|
||||
if (initbits.count(sig_q[i]))
|
||||
initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
|
||||
else
|
||||
initval.bits.push_back(State::Sx);
|
||||
|
||||
int nid_init_val = -1;
|
||||
|
||||
if (!initval.is_fully_undef())
|
||||
nid_init_val = get_sig_nid(initval);
|
||||
|
||||
int sid = get_bv_sid(GetSize(sig_q));
|
||||
int nid = next_nid++;
|
||||
|
||||
|
@ -514,15 +562,7 @@ struct BtorWorker
|
|||
else
|
||||
btorf("%d state %d %s\n", nid, sid, log_id(symbol));
|
||||
|
||||
Const initval;
|
||||
for (int i = 0; i < GetSize(sig_q); i++)
|
||||
if (initbits.count(sig_q[i]))
|
||||
initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
|
||||
else
|
||||
initval.bits.push_back(State::Sx);
|
||||
|
||||
if (!initval.is_fully_undef()) {
|
||||
int nid_init_val = get_sig_nid(initval);
|
||||
if (nid_init_val >= 0) {
|
||||
int nid_init = next_nid++;
|
||||
if (verbose)
|
||||
btorf("; initval = %s\n", log_signal(initval));
|
||||
|
@ -575,6 +615,7 @@ struct BtorWorker
|
|||
{
|
||||
int abits = cell->getParam("\\ABITS").as_int();
|
||||
int width = cell->getParam("\\WIDTH").as_int();
|
||||
int nwords = cell->getParam("\\SIZE").as_int();
|
||||
int rdports = cell->getParam("\\RD_PORTS").as_int();
|
||||
int wrports = cell->getParam("\\WR_PORTS").as_int();
|
||||
|
||||
|
@ -601,6 +642,52 @@ struct BtorWorker
|
|||
int data_sid = get_bv_sid(width);
|
||||
int bool_sid = get_bv_sid(1);
|
||||
int sid = get_mem_sid(abits, width);
|
||||
|
||||
Const initdata = cell->getParam("\\INIT");
|
||||
initdata.exts(nwords*width);
|
||||
int nid_init_val = -1;
|
||||
|
||||
if (!initdata.is_fully_undef())
|
||||
{
|
||||
bool constword = true;
|
||||
Const firstword = initdata.extract(0, width);
|
||||
|
||||
for (int i = 1; i < nwords; i++) {
|
||||
Const thisword = initdata.extract(i*width, width);
|
||||
if (thisword != firstword) {
|
||||
constword = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (constword)
|
||||
{
|
||||
if (verbose)
|
||||
btorf("; initval = %s\n", log_signal(firstword));
|
||||
nid_init_val = get_sig_nid(firstword);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nid_init_val = next_nid++;
|
||||
btorf("%d state %d\n", nid_init_val, sid);
|
||||
|
||||
for (int i = 0; i < nwords; i++) {
|
||||
Const thisword = initdata.extract(i*width, width);
|
||||
if (thisword.is_fully_undef())
|
||||
continue;
|
||||
Const thisaddr(i, abits);
|
||||
int nid_thisword = get_sig_nid(thisword);
|
||||
int nid_thisaddr = get_sig_nid(thisaddr);
|
||||
int last_nid_init_val = nid_init_val;
|
||||
nid_init_val = next_nid++;
|
||||
if (verbose)
|
||||
btorf("; initval[%d] = %s\n", i, log_signal(thisword));
|
||||
btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int nid = next_nid++;
|
||||
int nid_head = nid;
|
||||
|
||||
|
@ -609,6 +696,12 @@ struct BtorWorker
|
|||
else
|
||||
btorf("%d state %d %s\n", nid, sid, log_id(cell));
|
||||
|
||||
if (nid_init_val >= 0)
|
||||
{
|
||||
int nid_init = next_nid++;
|
||||
btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val);
|
||||
}
|
||||
|
||||
if (asyncwr)
|
||||
{
|
||||
for (int port = 0; port < wrports; port++)
|
||||
|
@ -892,9 +985,8 @@ struct BtorWorker
|
|||
|
||||
btorf_push(stringf("output %s", log_id(wire)));
|
||||
|
||||
int sid = get_bv_sid(GetSize(wire));
|
||||
int nid = get_sig_nid(wire);
|
||||
btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire));
|
||||
btorf("%d output %d %s\n", next_nid++, nid, log_id(wire));
|
||||
|
||||
btorf_pop(stringf("output %s", log_id(wire)));
|
||||
}
|
||||
|
@ -1076,7 +1168,7 @@ struct BtorWorker
|
|||
|
||||
struct BtorBackend : public Backend {
|
||||
BtorBackend() : Backend("btor", "write design to BTOR file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -1091,7 +1183,7 @@ struct BtorBackend : public Backend {
|
|||
log(" Output only a single bad property for all asserts\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool verbose = false, single_bad = false;
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ struct EdifNames
|
|||
|
||||
struct EdifBackend : public Backend {
|
||||
EdifBackend() : Backend("edif", "write design to EDIF netlist file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -106,6 +106,13 @@ struct EdifBackend : public Backend {
|
|||
log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
|
||||
log(" constant drivers first)\n");
|
||||
log("\n");
|
||||
log(" -gndvccy\n");
|
||||
log(" create \"GND\" and \"VCC\" cells with \"Y\" outputs. (the default is \"G\"\n");
|
||||
log(" for \"GND\" and \"P\" for \"VCC\".)\n");
|
||||
log("\n");
|
||||
log(" -attrprop\n");
|
||||
log(" create EDIF properties for cell attributes\n");
|
||||
log("\n");
|
||||
log(" -pvector {par|bra|ang}\n");
|
||||
log(" sets the delimiting character for module port rename clauses to\n");
|
||||
log(" parentheses, square brackets, or angle brackets.\n");
|
||||
|
@ -116,13 +123,14 @@ struct EdifBackend : public Backend {
|
|||
log("is targeted.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing EDIF backend.\n");
|
||||
std::string top_module_name;
|
||||
bool port_rename = false;
|
||||
bool attr_properties = false;
|
||||
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
|
||||
bool nogndvcc = false;
|
||||
bool nogndvcc = false, gndvccy = false;
|
||||
CellTypes ct(design);
|
||||
EdifNames edif_names;
|
||||
|
||||
|
@ -137,6 +145,14 @@ struct EdifBackend : public Backend {
|
|||
nogndvcc = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-gndvccy") {
|
||||
gndvccy = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-attrprop") {
|
||||
attr_properties = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-pvector" && argidx+1 < args.size()) {
|
||||
std::string parray;
|
||||
port_rename = true;
|
||||
|
@ -203,7 +219,7 @@ struct EdifBackend : public Backend {
|
|||
*f << stringf(" (cellType GENERIC)\n");
|
||||
*f << stringf(" (view VIEW_NETLIST\n");
|
||||
*f << stringf(" (viewType NETLIST)\n");
|
||||
*f << stringf(" (interface (port G (direction OUTPUT)))\n");
|
||||
*f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'G');
|
||||
*f << stringf(" )\n");
|
||||
*f << stringf(" )\n");
|
||||
|
||||
|
@ -211,7 +227,7 @@ struct EdifBackend : public Backend {
|
|||
*f << stringf(" (cellType GENERIC)\n");
|
||||
*f << stringf(" (view VIEW_NETLIST\n");
|
||||
*f << stringf(" (viewType NETLIST)\n");
|
||||
*f << stringf(" (interface (port P (direction OUTPUT)))\n");
|
||||
*f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'P');
|
||||
*f << stringf(" )\n");
|
||||
*f << stringf(" )\n");
|
||||
}
|
||||
|
@ -332,24 +348,33 @@ struct EdifBackend : public Backend {
|
|||
*f << stringf(" (instance %s\n", EDIF_DEF(cell->name));
|
||||
*f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type),
|
||||
lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : "");
|
||||
for (auto &p : cell->parameters)
|
||||
if ((p.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
|
||||
*f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), p.second.decode_string().c_str());
|
||||
else if (p.second.bits.size() <= 32 && RTLIL::SigSpec(p.second).is_fully_def())
|
||||
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(p.first), p.second.as_int());
|
||||
|
||||
auto add_prop = [&](IdString name, Const val) {
|
||||
if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
|
||||
*f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str());
|
||||
else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
|
||||
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
|
||||
else {
|
||||
std::string hex_string = "";
|
||||
for (size_t i = 0; i < p.second.bits.size(); i += 4) {
|
||||
for (size_t i = 0; i < val.bits.size(); i += 4) {
|
||||
int digit_value = 0;
|
||||
if (i+0 < p.second.bits.size() && p.second.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
|
||||
if (i+1 < p.second.bits.size() && p.second.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
|
||||
if (i+2 < p.second.bits.size() && p.second.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
|
||||
if (i+3 < p.second.bits.size() && p.second.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
|
||||
if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
|
||||
if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
|
||||
if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
|
||||
if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
|
||||
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
|
||||
hex_string = std::string(digit_str) + hex_string;
|
||||
}
|
||||
*f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str());
|
||||
*f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &p : cell->parameters)
|
||||
add_prop(p.first, p.second);
|
||||
if (attr_properties)
|
||||
for (auto &p : cell->attributes)
|
||||
add_prop(p.first, p.second);
|
||||
|
||||
*f << stringf(")\n");
|
||||
for (auto &p : cell->connections()) {
|
||||
RTLIL::SigSpec sig = sigmap(p.second);
|
||||
|
@ -403,9 +428,9 @@ struct EdifBackend : public Backend {
|
|||
if (nogndvcc)
|
||||
log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
|
||||
if (sig == RTLIL::State::S0)
|
||||
*f << stringf(" (portRef G (instanceRef GND))\n");
|
||||
*f << stringf(" (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G');
|
||||
if (sig == RTLIL::State::S1)
|
||||
*f << stringf(" (portRef P (instanceRef VCC))\n");
|
||||
*f << stringf(" (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P');
|
||||
}
|
||||
*f << stringf(" ))\n");
|
||||
}
|
||||
|
|
|
@ -23,7 +23,11 @@
|
|||
#include "kernel/celltypes.h"
|
||||
#include "kernel/cellaigs.h"
|
||||
#include "kernel/log.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
@ -32,6 +36,28 @@ pool<string> used_names;
|
|||
dict<IdString, string> namecache;
|
||||
int autoid_counter;
|
||||
|
||||
typedef unsigned FDirection;
|
||||
static const FDirection FD_NODIRECTION = 0x0;
|
||||
static const FDirection FD_IN = 0x1;
|
||||
static const FDirection FD_OUT = 0x2;
|
||||
static const FDirection FD_INOUT = 0x3;
|
||||
static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
|
||||
|
||||
// Get a port direction with respect to a specific module.
|
||||
FDirection getPortFDirection(IdString id, Module *module)
|
||||
{
|
||||
Wire *wire = module->wires_.at(id);
|
||||
FDirection direction = FD_NODIRECTION;
|
||||
if (wire && wire->port_id)
|
||||
{
|
||||
if (wire->port_input)
|
||||
direction |= FD_IN;
|
||||
if (wire->port_output)
|
||||
direction |= FD_OUT;
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
string next_id()
|
||||
{
|
||||
string new_id;
|
||||
|
@ -77,6 +103,8 @@ struct FirrtlWorker
|
|||
|
||||
dict<SigBit, pair<string, int>> reverse_wire_map;
|
||||
string unconn_id;
|
||||
RTLIL::Design *design;
|
||||
std::string indent;
|
||||
|
||||
void register_reverse_wire_map(string id, SigSpec sig)
|
||||
{
|
||||
|
@ -84,11 +112,11 @@ struct FirrtlWorker
|
|||
reverse_wire_map[sig[i]] = make_pair(id, i);
|
||||
}
|
||||
|
||||
FirrtlWorker(Module *module, std::ostream &f) : module(module), f(f)
|
||||
FirrtlWorker(Module *module, std::ostream &f, RTLIL::Design *theDesign) : module(module), f(f), design(theDesign), indent(" ")
|
||||
{
|
||||
}
|
||||
|
||||
string make_expr(SigSpec sig)
|
||||
string make_expr(const SigSpec &sig)
|
||||
{
|
||||
string expr;
|
||||
|
||||
|
@ -135,6 +163,116 @@ struct FirrtlWorker
|
|||
return expr;
|
||||
}
|
||||
|
||||
std::string fid(RTLIL::IdString internal_id)
|
||||
{
|
||||
return make_id(internal_id);
|
||||
}
|
||||
|
||||
std::string cellname(RTLIL::Cell *cell)
|
||||
{
|
||||
return fid(cell->name).c_str();
|
||||
}
|
||||
|
||||
void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs)
|
||||
{
|
||||
std::string cell_type = fid(cell->type);
|
||||
std::string instanceOf;
|
||||
// If this is a parameterized module, its parent module is encoded in the cell type
|
||||
if (cell->type.substr(0, 8) == "$paramod")
|
||||
{
|
||||
std::string::iterator it;
|
||||
for (it = cell_type.begin(); it < cell_type.end(); it++)
|
||||
{
|
||||
switch (*it) {
|
||||
case '\\': /* FALL_THROUGH */
|
||||
case '=': /* FALL_THROUGH */
|
||||
case '\'': /* FALL_THROUGH */
|
||||
case '$': instanceOf.append("_"); break;
|
||||
default: instanceOf.append(1, *it); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
instanceOf = cell_type;
|
||||
}
|
||||
|
||||
std::string cell_name = cellname(cell);
|
||||
std::string cell_name_comment;
|
||||
if (cell_name != fid(cell->name))
|
||||
cell_name_comment = " /* " + fid(cell->name) + " */ ";
|
||||
else
|
||||
cell_name_comment = "";
|
||||
// Find the module corresponding to this instance.
|
||||
auto instModule = design->module(cell->type);
|
||||
// If there is no instance for this, just return.
|
||||
if (instModule == NULL)
|
||||
{
|
||||
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
|
||||
return;
|
||||
}
|
||||
wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
|
||||
|
||||
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
|
||||
if (it->second.size() > 0) {
|
||||
const SigSpec &secondSig = it->second;
|
||||
const std::string firstName = cell_name + "." + make_id(it->first);
|
||||
const std::string secondExpr = make_expr(secondSig);
|
||||
// Find the direction for this port.
|
||||
FDirection dir = getPortFDirection(it->first, instModule);
|
||||
std::string sourceExpr, sinkExpr;
|
||||
const SigSpec *sinkSig = nullptr;
|
||||
switch (dir) {
|
||||
case FD_INOUT:
|
||||
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
|
||||
case FD_OUT:
|
||||
sourceExpr = firstName;
|
||||
sinkExpr = secondExpr;
|
||||
sinkSig = &secondSig;
|
||||
break;
|
||||
case FD_NODIRECTION:
|
||||
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
|
||||
/* FALL_THROUGH */
|
||||
case FD_IN:
|
||||
sourceExpr = secondExpr;
|
||||
sinkExpr = firstName;
|
||||
break;
|
||||
default:
|
||||
log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
|
||||
break;
|
||||
}
|
||||
// Check for subfield assignment.
|
||||
std::string bitsString = "bits(";
|
||||
if (sinkExpr.substr(0, bitsString.length()) == bitsString ) {
|
||||
if (sinkSig == nullptr)
|
||||
log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
|
||||
// Don't generate the assignment here.
|
||||
// Add the source and sink to the "reverse_wire_map" and we'll output the assignment
|
||||
// as part of the coalesced subfield assignments for this wire.
|
||||
register_reverse_wire_map(sourceExpr, *sinkSig);
|
||||
} else {
|
||||
wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
wire_exprs.push_back(stringf("\n"));
|
||||
|
||||
}
|
||||
|
||||
// Given an expression for a shift amount, and a maximum width,
|
||||
// generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
|
||||
std::string gen_dshl(const string b_expr, const int b_padded_width)
|
||||
{
|
||||
string result = b_expr;
|
||||
if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
|
||||
int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
|
||||
string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
|
||||
// Deal with the difference in semantics between FIRRTL and verilog
|
||||
result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
f << stringf(" module %s:\n", make_id(module->name));
|
||||
|
@ -142,21 +280,35 @@ struct FirrtlWorker
|
|||
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
const auto wireName = make_id(wire->name);
|
||||
// If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
|
||||
if (wire->attributes.count("\\init")) {
|
||||
log_warning("Initial value (%s) for (%s.%s) not supported\n",
|
||||
wire->attributes.at("\\init").as_string().c_str(),
|
||||
log_id(module), log_id(wire));
|
||||
}
|
||||
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));
|
||||
wireName, wire->width));
|
||||
}
|
||||
else
|
||||
{
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", make_id(wire->name), wire->width));
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
bool extract_y_bits = false; // Assume no extraction of final bits will be required.
|
||||
// Is this cell is a module instance?
|
||||
if (cell->type[0] != '$')
|
||||
{
|
||||
process_instance(cell, wire_exprs);
|
||||
continue;
|
||||
}
|
||||
if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor"))
|
||||
{
|
||||
string y_id = make_id(cell->name);
|
||||
|
@ -169,26 +321,32 @@ struct FirrtlWorker
|
|||
a_expr = "asSInt(" + a_expr + ")";
|
||||
}
|
||||
|
||||
// Don't use the results of logical operations (a single bit) to control padding
|
||||
if (!(cell->type.in("$eq", "$eqx", "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$reduce_bool", "$logic_not") && y_width == 1) ) {
|
||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||
}
|
||||
|
||||
string primop;
|
||||
bool always_uint = false;
|
||||
if (cell->type == "$not") primop = "not";
|
||||
if (cell->type == "$neg") primop = "neg";
|
||||
if (cell->type == "$logic_not") {
|
||||
else if (cell->type == "$neg") primop = "neg";
|
||||
else if (cell->type == "$logic_not") {
|
||||
primop = "eq";
|
||||
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
|
||||
}
|
||||
if (cell->type == "$reduce_and") primop = "andr";
|
||||
if (cell->type == "$reduce_or") primop = "orr";
|
||||
if (cell->type == "$reduce_xor") primop = "xorr";
|
||||
if (cell->type == "$reduce_xnor") {
|
||||
else if (cell->type == "$reduce_and") primop = "andr";
|
||||
else if (cell->type == "$reduce_or") primop = "orr";
|
||||
else if (cell->type == "$reduce_xor") primop = "xorr";
|
||||
else if (cell->type == "$reduce_xnor") {
|
||||
primop = "not";
|
||||
a_expr = stringf("xorr(%s)", a_expr.c_str());
|
||||
}
|
||||
if (cell->type == "$reduce_bool") {
|
||||
else if (cell->type == "$reduce_bool") {
|
||||
primop = "neq";
|
||||
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
|
||||
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
|
||||
bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
|
||||
int a_width = cell->parameters.at("\\A_WIDTH").as_int();
|
||||
a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width);
|
||||
}
|
||||
|
||||
string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str());
|
||||
|
@ -210,20 +368,24 @@ struct FirrtlWorker
|
|||
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"));
|
||||
int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||
|
||||
if (cell->parameters.at("\\A_SIGNED").as_bool()) {
|
||||
a_expr = "asSInt(" + a_expr + ")";
|
||||
}
|
||||
if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type != "$shr")) {
|
||||
// Shift amount is always unsigned, and needn't be padded to result width.
|
||||
if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) {
|
||||
if (cell->parameters.at("\\B_SIGNED").as_bool()) {
|
||||
b_expr = "asSInt(" + b_expr + ")";
|
||||
}
|
||||
|
||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||
|
||||
if ((cell->type != "$shl") && (cell->type != "$sshl")) {
|
||||
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
|
||||
if (b_padded_width < y_width) {
|
||||
auto b_sig = cell->getPort("\\B");
|
||||
b_padded_width = y_width;
|
||||
}
|
||||
}
|
||||
|
||||
auto a_sig = cell->getPort("\\A");
|
||||
|
||||
if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) {
|
||||
a_expr = "asUInt(" + a_expr + ")";
|
||||
|
@ -232,55 +394,78 @@ struct FirrtlWorker
|
|||
string primop;
|
||||
bool always_uint = false;
|
||||
if (cell->type == "$add") primop = "add";
|
||||
if (cell->type == "$sub") primop = "sub";
|
||||
if (cell->type == "$mul") primop = "mul";
|
||||
if (cell->type == "$div") primop = "div";
|
||||
if (cell->type == "$mod") primop = "rem";
|
||||
if (cell->type == "$and") {
|
||||
else if (cell->type == "$sub") primop = "sub";
|
||||
else if (cell->type == "$mul") primop = "mul";
|
||||
else if (cell->type == "$div") primop = "div";
|
||||
else if (cell->type == "$mod") primop = "rem";
|
||||
else if (cell->type == "$and") {
|
||||
primop = "and";
|
||||
always_uint = true;
|
||||
}
|
||||
if (cell->type == "$or" ) {
|
||||
else if (cell->type == "$or" ) {
|
||||
primop = "or";
|
||||
always_uint = true;
|
||||
}
|
||||
if (cell->type == "$xor") {
|
||||
else if (cell->type == "$xor") {
|
||||
primop = "xor";
|
||||
always_uint = true;
|
||||
}
|
||||
if ((cell->type == "$eq") | (cell->type == "$eqx")) {
|
||||
else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
|
||||
primop = "eq";
|
||||
always_uint = true;
|
||||
}
|
||||
if ((cell->type == "$ne") | (cell->type == "$nex")) {
|
||||
else if ((cell->type == "$ne") | (cell->type == "$nex")) {
|
||||
primop = "neq";
|
||||
always_uint = true;
|
||||
}
|
||||
if (cell->type == "$gt") {
|
||||
else if (cell->type == "$gt") {
|
||||
primop = "gt";
|
||||
always_uint = true;
|
||||
}
|
||||
if (cell->type == "$ge") {
|
||||
else if (cell->type == "$ge") {
|
||||
primop = "geq";
|
||||
always_uint = true;
|
||||
}
|
||||
if (cell->type == "$lt") {
|
||||
else if (cell->type == "$lt") {
|
||||
primop = "lt";
|
||||
always_uint = true;
|
||||
}
|
||||
if (cell->type == "$le") {
|
||||
else if (cell->type == "$le") {
|
||||
primop = "leq";
|
||||
always_uint = true;
|
||||
}
|
||||
if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl";
|
||||
if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr";
|
||||
if ((cell->type == "$logic_and")) {
|
||||
else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
|
||||
// FIRRTL will widen the result (y) by the amount of the shift.
|
||||
// We'll need to offset this by extracting the un-widened portion as Verilog would do.
|
||||
extract_y_bits = true;
|
||||
// Is the shift amount constant?
|
||||
auto b_sig = cell->getPort("\\B");
|
||||
if (b_sig.is_fully_const()) {
|
||||
primop = "shl";
|
||||
} else {
|
||||
primop = "dshl";
|
||||
// Convert from FIRRTL left shift semantics.
|
||||
b_expr = gen_dshl(b_expr, b_padded_width);
|
||||
}
|
||||
}
|
||||
else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
|
||||
// We don't need to extract a specific range of bits.
|
||||
extract_y_bits = false;
|
||||
// Is the shift amount constant?
|
||||
auto b_sig = cell->getPort("\\B");
|
||||
if (b_sig.is_fully_const()) {
|
||||
primop = "shr";
|
||||
} else {
|
||||
primop = "dshr";
|
||||
}
|
||||
}
|
||||
else if ((cell->type == "$logic_and")) {
|
||||
primop = "and";
|
||||
a_expr = "neq(" + a_expr + ", UInt(0))";
|
||||
b_expr = "neq(" + b_expr + ", UInt(0))";
|
||||
always_uint = true;
|
||||
}
|
||||
if ((cell->type == "$logic_or")) {
|
||||
else if ((cell->type == "$logic_or")) {
|
||||
primop = "or";
|
||||
a_expr = "neq(" + a_expr + ", UInt(0))";
|
||||
b_expr = "neq(" + b_expr + ", UInt(0))";
|
||||
|
@ -293,6 +478,11 @@ struct FirrtlWorker
|
|||
|
||||
string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
|
||||
|
||||
// Deal with FIRRTL's "shift widens" semantics
|
||||
if (extract_y_bits) {
|
||||
expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
|
||||
}
|
||||
|
||||
if ((is_signed && !always_uint) || cell->type.in("$sub"))
|
||||
expr = stringf("asUInt(%s)", expr.c_str());
|
||||
|
||||
|
@ -418,7 +608,65 @@ struct FirrtlWorker
|
|||
continue;
|
||||
}
|
||||
|
||||
log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
|
||||
// This may be a parameterized module - paramod.
|
||||
if (cell->type.substr(0, 8) == "$paramod")
|
||||
{
|
||||
process_instance(cell, wire_exprs);
|
||||
continue;
|
||||
}
|
||||
if (cell->type == "$shiftx") {
|
||||
// assign y = a[b +: y_width];
|
||||
// We'll extract the correct bits as part of the primop.
|
||||
|
||||
string y_id = make_id(cell->name);
|
||||
int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
|
||||
string a_expr = make_expr(cell->getPort("\\A"));
|
||||
// Get the initial bit selector
|
||||
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 (cell->getParam("\\B_SIGNED").as_bool()) {
|
||||
// Use validif to constrain the selection (test the sign bit)
|
||||
auto b_string = b_expr.c_str();
|
||||
int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1;
|
||||
b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
|
||||
}
|
||||
string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_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 == "$shift") {
|
||||
// assign y = a >> b;
|
||||
// where b may be negative
|
||||
|
||||
string y_id = make_id(cell->name);
|
||||
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"));
|
||||
auto b_string = b_expr.c_str();
|
||||
int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
|
||||
string expr;
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||
|
||||
if (cell->getParam("\\B_SIGNED").as_bool()) {
|
||||
// We generate a left or right shift based on the sign of b.
|
||||
std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width);
|
||||
std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
|
||||
expr = stringf("mux(%s < 0, %s, %s)",
|
||||
b_string,
|
||||
dshl.c_str(),
|
||||
dshr.c_str()
|
||||
);
|
||||
} else {
|
||||
expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
|
||||
}
|
||||
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;
|
||||
}
|
||||
log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
|
||||
}
|
||||
|
||||
for (auto conn : module->connections())
|
||||
|
@ -494,14 +742,14 @@ struct FirrtlWorker
|
|||
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_decls.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)));
|
||||
wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -527,50 +775,65 @@ struct FirrtlWorker
|
|||
|
||||
struct FirrtlBackend : public Backend {
|
||||
FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---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("The following commands are executed by this command:\n");
|
||||
log(" pmuxtree\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
// if (args[argidx] == "-aig") {
|
||||
// aig_mode = true;
|
||||
// continue;
|
||||
// }
|
||||
break;
|
||||
size_t argidx = args.size(); // We aren't expecting any arguments.
|
||||
|
||||
// If we weren't explicitly passed a filename, use the last argument (if it isn't a flag).
|
||||
if (filename == "") {
|
||||
if (argidx > 0 && args[argidx - 1][0] != '-') {
|
||||
// extra_args and friends need to see this argument.
|
||||
argidx -= 1;
|
||||
filename = args[argidx];
|
||||
}
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
if (!design->full_selection())
|
||||
log_cmd_error("This command only operates on fully selected designs!\n");
|
||||
|
||||
log_header(design, "Executing FIRRTL backend.\n");
|
||||
log_push();
|
||||
|
||||
Module *top = design->top_module();
|
||||
|
||||
if (top == nullptr)
|
||||
log_error("No top module found!\n");
|
||||
Pass::call(design, stringf("pmuxtree"));
|
||||
|
||||
namecache.clear();
|
||||
autoid_counter = 0;
|
||||
|
||||
// Get the top module, or a reasonable facsimile - we need something for the circuit name.
|
||||
Module *top = design->top_module();
|
||||
Module *last = nullptr;
|
||||
// Generate module and wire names.
|
||||
for (auto module : design->modules()) {
|
||||
make_id(module->name);
|
||||
last = module;
|
||||
if (top == nullptr && module->get_bool_attribute("\\top")) {
|
||||
top = module;
|
||||
}
|
||||
for (auto wire : module->wires())
|
||||
if (wire->port_id)
|
||||
make_id(wire->name);
|
||||
}
|
||||
|
||||
if (top == nullptr)
|
||||
top = last;
|
||||
|
||||
*f << stringf("circuit %s:\n", make_id(top->name));
|
||||
|
||||
for (auto module : design->modules())
|
||||
{
|
||||
FirrtlWorker worker(module, *f);
|
||||
FirrtlWorker worker(module, *f, design);
|
||||
worker.run();
|
||||
}
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
|
|||
f << stringf("%s case ", indent.c_str());
|
||||
for (size_t i = 0; i < (*it)->compare.size(); i++) {
|
||||
if (i > 0)
|
||||
f << stringf(", ");
|
||||
f << stringf(" , ");
|
||||
dump_sigspec(f, (*it)->compare[i]);
|
||||
}
|
||||
f << stringf("\n");
|
||||
|
@ -382,7 +382,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct IlangBackend : public Backend {
|
||||
IlangBackend() : Backend("ilang", "write design to ilang file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -395,7 +395,7 @@ struct IlangBackend : public Backend {
|
|||
log(" only write selected parts of the design.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool selected = false;
|
||||
|
||||
|
@ -422,7 +422,7 @@ struct IlangBackend : public Backend {
|
|||
|
||||
struct DumpPass : public Pass {
|
||||
DumpPass() : Pass("dump", "print parts of the design in ilang format") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -445,7 +445,7 @@ struct DumpPass : public Pass {
|
|||
log(" like -outfile but append instead of overwrite\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::string filename;
|
||||
bool flag_m = false, flag_n = false, append = false;
|
||||
|
|
|
@ -46,7 +46,7 @@ static std::string netname(std::set<std::string> &conntypes_code, std::set<std::
|
|||
|
||||
struct IntersynthBackend : public Backend {
|
||||
IntersynthBackend() : Backend("intersynth", "write design to InterSynth netlist file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -71,7 +71,7 @@ struct IntersynthBackend : public Backend {
|
|||
log("http://www.clifford.at/intersynth/\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing INTERSYNTH backend.\n");
|
||||
log_push();
|
||||
|
|
|
@ -93,8 +93,10 @@ struct JsonWriter
|
|||
f << get_string(param.second.decode_string());
|
||||
else if (GetSize(param.second.bits) > 32)
|
||||
f << get_string(param.second.as_string());
|
||||
else
|
||||
else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
|
||||
f << stringf("%d", param.second.as_int());
|
||||
else
|
||||
f << stringf("%u", param.second.as_int());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
@ -250,7 +252,7 @@ struct JsonWriter
|
|||
|
||||
struct JsonBackend : public Backend {
|
||||
JsonBackend() : Backend("json", "write design to a JSON file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -458,7 +460,7 @@ struct JsonBackend : public Backend {
|
|||
log("format. A program processing this format must ignore all unknown fields.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool aig_mode = false;
|
||||
|
||||
|
@ -482,7 +484,7 @@ struct JsonBackend : public Backend {
|
|||
|
||||
struct JsonPass : public Pass {
|
||||
JsonPass() : Pass("json", "write design in JSON format") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -499,7 +501,7 @@ struct JsonPass : public Pass {
|
|||
log("See 'help write_json' for a description of the JSON format used.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::string filename;
|
||||
bool aig_mode = false;
|
||||
|
|
|
@ -231,7 +231,7 @@ struct ProtobufDesignSerializer
|
|||
|
||||
struct ProtobufBackend : public Backend {
|
||||
ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -249,7 +249,7 @@ struct ProtobufBackend : public Backend {
|
|||
log("Yosys source code distribution.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool aig_mode = false;
|
||||
bool text_mode = false;
|
||||
|
@ -286,7 +286,7 @@ struct ProtobufBackend : public Backend {
|
|||
|
||||
struct ProtobufPass : public Pass {
|
||||
ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -307,7 +307,7 @@ struct ProtobufPass : public Pass {
|
|||
log("Yosys source code distribution.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::string filename;
|
||||
bool aig_mode = false;
|
||||
|
|
|
@ -742,13 +742,13 @@ struct SimplecWorker
|
|||
|
||||
struct SimplecBackend : public Backend {
|
||||
SimplecBackend() : Backend("simplec", "convert design to simple C code") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" write_simplec [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Write simple C code for simulating the design. The C code writen can be used to\n");
|
||||
log("Write simple C code for simulating the design. The C code written can be used to\n");
|
||||
log("simulate the design in a C environment, but the purpose of this command is to\n");
|
||||
log("generate code that works well with C-based formal verification.\n");
|
||||
log("\n");
|
||||
|
@ -761,7 +761,7 @@ struct SimplecBackend : public Backend {
|
|||
log("THIS COMMAND IS UNDER CONSTRUCTION\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
reserved_cids.clear();
|
||||
id2cid.clear();
|
||||
|
|
|
@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
|
|||
|
||||
ifneq ($(CONFIG),mxe)
|
||||
ifneq ($(CONFIG),emcc)
|
||||
|
||||
# MSYS targets support yosys-smtbmc, but require a launcher script
|
||||
ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
|
||||
TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
|
||||
# Needed to find the Python interpreter for yosys-smtbmc scripts.
|
||||
# Override if necessary, it is only used for msys2 targets.
|
||||
PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
|
||||
|
||||
yosys-smtbmc-script.py: backends/smt2/smtbmc.py
|
||||
$(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
|
||||
-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
|
||||
|
||||
yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
|
||||
$(P) gcc -DGUI=0 -O -s -o $@ $<
|
||||
# Other targets
|
||||
else
|
||||
TARGETS += yosys-smtbmc
|
||||
|
||||
yosys-smtbmc: backends/smt2/smtbmc.py
|
||||
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(__file__) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
|
||||
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
|
||||
$(Q) chmod +x $@.new
|
||||
$(Q) mv $@.new $@
|
||||
endif
|
||||
|
||||
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -416,6 +416,7 @@ struct Smt2Worker
|
|||
for (char ch : expr) {
|
||||
if (ch == 'A') processed_expr += get_bv(sig_a);
|
||||
else if (ch == 'B') processed_expr += get_bv(sig_b);
|
||||
else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B"));
|
||||
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
|
||||
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
|
||||
else processed_expr += ch;
|
||||
|
@ -554,7 +555,9 @@ struct Smt2Worker
|
|||
|
||||
if (cell->type.in("$shift", "$shiftx")) {
|
||||
if (cell->getParam("\\B_SIGNED").as_bool()) {
|
||||
/* FIXME */
|
||||
return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
|
||||
"(bvlshr A B) (bvlshr A (bvneg B)))",
|
||||
GetSize(cell->getPort("\\B")), 0), 's');
|
||||
} else {
|
||||
return export_bvop(cell, "(bvlshr A B)", 's');
|
||||
}
|
||||
|
@ -885,8 +888,8 @@ struct Smt2Worker
|
|||
|
||||
string name_a = get_bool(cell->getPort("\\A"));
|
||||
string name_en = get_bool(cell->getPort("\\EN"));
|
||||
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id,
|
||||
cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
|
||||
string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell);
|
||||
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str()));
|
||||
|
||||
if (cell->type == "$cover")
|
||||
decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
|
||||
|
@ -1101,20 +1104,27 @@ struct Smt2Worker
|
|||
break;
|
||||
|
||||
Const initword = init_data.extract(i*width, width, State::Sx);
|
||||
Const initmask = initword;
|
||||
bool gen_init_constr = false;
|
||||
|
||||
for (auto bit : initword.bits)
|
||||
if (bit == State::S0 || bit == State::S1)
|
||||
for (int k = 0; k < GetSize(initword); k++) {
|
||||
if (initword[k] == State::S0 || initword[k] == State::S1) {
|
||||
gen_init_constr = true;
|
||||
initmask[k] = State::S1;
|
||||
} else {
|
||||
initmask[k] = State::S0;
|
||||
initword[k] = State::S0;
|
||||
}
|
||||
}
|
||||
|
||||
if (gen_init_constr)
|
||||
{
|
||||
if (statebv)
|
||||
/* FIXME */;
|
||||
else
|
||||
init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
|
||||
init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]",
|
||||
get_id(module), arrayid, Const(i, abits).as_string().c_str(),
|
||||
initword.as_string().c_str(), get_id(cell), i));
|
||||
initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1251,7 +1261,7 @@ struct Smt2Worker
|
|||
|
||||
struct Smt2Backend : public Backend {
|
||||
Smt2Backend() : Backend("smt2", "write design to SMT-LIBv2 file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -1407,7 +1417,7 @@ struct Smt2Backend : public Backend {
|
|||
log("from non-zero to zero in the test design.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::ifstream template_f;
|
||||
bool bvmode = true, memmode = true, wiresmode = false, verbose = false, statebv = false, statedt = false;
|
||||
|
|
|
@ -32,6 +32,7 @@ cexfile = None
|
|||
aimfile = None
|
||||
aiwfile = None
|
||||
aigheader = True
|
||||
btorwitfile = None
|
||||
vlogtbfile = None
|
||||
vlogtbtop = None
|
||||
inconstr = list()
|
||||
|
@ -86,12 +87,15 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
|||
|
||||
--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).
|
||||
share a filename prefix (or use different file extensions).
|
||||
|
||||
--aig-noheader
|
||||
the AIGER witness file does not include the status and
|
||||
properties lines.
|
||||
|
||||
--btorwit <btor_witness_filename>
|
||||
read a BTOR witness.
|
||||
|
||||
--noinfo
|
||||
only run the core proof, do not collect and print any
|
||||
additional information (e.g. which assert failed)
|
||||
|
@ -99,8 +103,8 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
|||
--presat
|
||||
check if the design with assumptions but without assertions
|
||||
is SAT before checking if assertions are UNSAT. This will
|
||||
detect if there are contradicting assumtions. In some cases
|
||||
this will also help to "warmup" the solver, potentially
|
||||
detect if there are contradicting assumptions. In some cases
|
||||
this will also help to "warm up" the solver, potentially
|
||||
yielding a speedup.
|
||||
|
||||
--final-only
|
||||
|
@ -145,14 +149,14 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
|||
--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)
|
||||
steps will still be constrained by assumptions)
|
||||
""" + so.helpmsg())
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
|
||||
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "presat",
|
||||
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat",
|
||||
"dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=",
|
||||
"smtc-init", "smtc-top=", "noinit"])
|
||||
except:
|
||||
|
@ -189,6 +193,8 @@ for o, a in opts:
|
|||
aiwfile = a + ".aiw"
|
||||
elif o == "--aig-noheader":
|
||||
aigheader = False
|
||||
elif o == "--btorwit":
|
||||
btorwitfile = a
|
||||
elif o == "--dump-vcd":
|
||||
vcdfile = a
|
||||
elif o == "--dump-vlogtb":
|
||||
|
@ -575,6 +581,103 @@ if aimfile is not None:
|
|||
num_steps = max(num_steps, step+1)
|
||||
step += 1
|
||||
|
||||
if btorwitfile is not None:
|
||||
with open(btorwitfile, "r") as f:
|
||||
step = None
|
||||
suffix = None
|
||||
altsuffix = None
|
||||
header_okay = False
|
||||
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
|
||||
if line == "sat":
|
||||
header_okay = True
|
||||
continue
|
||||
|
||||
if not header_okay:
|
||||
continue
|
||||
|
||||
if line == "" or line[0] == "b" or line[0] == "j":
|
||||
continue
|
||||
|
||||
if line == ".":
|
||||
break
|
||||
|
||||
if line[0] == '#' or line[0] == '@':
|
||||
step = int(line[1:])
|
||||
suffix = line
|
||||
altsuffix = suffix
|
||||
if suffix[0] == "@":
|
||||
altsuffix = "#" + suffix[1:]
|
||||
else:
|
||||
altsuffix = "@" + suffix[1:]
|
||||
continue
|
||||
|
||||
line = line.split()
|
||||
|
||||
if len(line) == 0:
|
||||
continue
|
||||
|
||||
if line[-1].endswith(suffix):
|
||||
line[-1] = line[-1][0:len(line[-1]) - len(suffix)]
|
||||
|
||||
if line[-1].endswith(altsuffix):
|
||||
line[-1] = line[-1][0:len(line[-1]) - len(altsuffix)]
|
||||
|
||||
if line[-1][0] == "$":
|
||||
continue
|
||||
|
||||
# BV assignments
|
||||
if len(line) == 3 and line[1][0] != "[":
|
||||
value = line[1]
|
||||
name = line[2]
|
||||
|
||||
path = smt.get_path(topmod, name)
|
||||
|
||||
if not smt.net_exists(topmod, path):
|
||||
continue
|
||||
|
||||
width = smt.net_width(topmod, path)
|
||||
|
||||
if width == 1:
|
||||
assert value in ["0", "1"]
|
||||
value = "true" if value == "1" else "false"
|
||||
else:
|
||||
value = "#b" + value
|
||||
|
||||
smtexpr = "(= [%s] %s)" % (name, value)
|
||||
constr_assumes[step].append((btorwitfile, smtexpr))
|
||||
|
||||
# Array assignments
|
||||
if len(line) == 4 and line[1][0] == "[":
|
||||
index = line[1]
|
||||
value = line[2]
|
||||
name = line[3]
|
||||
|
||||
path = smt.get_path(topmod, name)
|
||||
|
||||
if not smt.mem_exists(topmod, path):
|
||||
continue
|
||||
|
||||
meminfo = smt.mem_info(topmod, path)
|
||||
|
||||
if meminfo[1] == 1:
|
||||
assert value in ["0", "1"]
|
||||
value = "true" if value == "1" else "false"
|
||||
else:
|
||||
value = "#b" + value
|
||||
|
||||
assert index[0] == "["
|
||||
assert index[-1] == "]"
|
||||
index = "#b" + index[1:-1]
|
||||
|
||||
smtexpr = "(= (select [%s] %s) %s)" % (name, index, value)
|
||||
constr_assumes[step].append((btorwitfile, smtexpr))
|
||||
|
||||
skip_steps = step
|
||||
num_steps = step+1
|
||||
|
||||
def write_vcd_trace(steps_start, steps_stop, index):
|
||||
filename = vcdfile.replace("%", index)
|
||||
print_msg("Writing trace to VCD file: %s" % (filename))
|
||||
|
@ -1259,7 +1362,11 @@ elif covermode:
|
|||
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
|
||||
smt_assert_consequent(get_constr_expr(constr_assumes, i))
|
||||
print_msg("Re-solving with appended steps..")
|
||||
assert smt_check_sat() == "sat"
|
||||
if smt_check_sat() == "unsat":
|
||||
print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
|
||||
found_failed_assert = True
|
||||
retstatus = False
|
||||
break
|
||||
|
||||
reached_covers = smt.bv2bin(smt.get("(covers_%d s%d)" % (coveridx, step)))
|
||||
assert len(reached_covers) == len(cover_desc)
|
||||
|
@ -1377,7 +1484,11 @@ else: # not tempind, covermode
|
|||
smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
|
||||
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
|
||||
smt_assert_consequent(get_constr_expr(constr_assumes, i))
|
||||
assert smt_check_sat() == "sat"
|
||||
print_msg("Re-solving with appended steps..")
|
||||
if smt_check_sat() == "unsat":
|
||||
print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
|
||||
retstatus = False
|
||||
break
|
||||
print_anyconsts(step)
|
||||
for i in range(step, last_check_step+1):
|
||||
print_failed_asserts(i)
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#
|
||||
|
||||
import sys, re, os, signal
|
||||
import resource, subprocess
|
||||
import subprocess
|
||||
if os.name == "posix":
|
||||
import resource
|
||||
from copy import deepcopy
|
||||
from select import select
|
||||
from time import time
|
||||
|
@ -27,12 +29,21 @@ from threading import Thread
|
|||
|
||||
# This is needed so that the recursive SMT2 S-expression parser
|
||||
# does not run out of stack frames when parsing large expressions
|
||||
smtio_reclimit = 64 * 1024
|
||||
smtio_stacksize = 128 * 1024 * 1024
|
||||
if sys.getrecursionlimit() < smtio_reclimit:
|
||||
if os.name == "posix":
|
||||
smtio_reclimit = 64 * 1024
|
||||
if sys.getrecursionlimit() < smtio_reclimit:
|
||||
sys.setrecursionlimit(smtio_reclimit)
|
||||
if resource.getrlimit(resource.RLIMIT_STACK)[0] < smtio_stacksize:
|
||||
resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, -1))
|
||||
|
||||
current_rlimit_stack = resource.getrlimit(resource.RLIMIT_STACK)
|
||||
if current_rlimit_stack[0] != resource.RLIM_INFINITY:
|
||||
smtio_stacksize = 128 * 1024 * 1024
|
||||
if os.uname().sysname == "Darwin":
|
||||
# MacOS has rather conservative stack limits
|
||||
smtio_stacksize = 16 * 1024 * 1024
|
||||
if current_rlimit_stack[1] != resource.RLIM_INFINITY:
|
||||
smtio_stacksize = min(smtio_stacksize, current_rlimit_stack[1])
|
||||
if current_rlimit_stack[0] < smtio_stacksize:
|
||||
resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1]))
|
||||
|
||||
|
||||
# currently running solvers (so we can kill them)
|
||||
|
@ -51,8 +62,9 @@ def force_shutdown(signum, frame):
|
|||
os.kill(p.pid, signal.SIGTERM)
|
||||
sys.exit(1)
|
||||
|
||||
if os.name == "posix":
|
||||
signal.signal(signal.SIGHUP, force_shutdown)
|
||||
signal.signal(signal.SIGINT, force_shutdown)
|
||||
signal.signal(signal.SIGHUP, force_shutdown)
|
||||
signal.signal(signal.SIGTERM, force_shutdown)
|
||||
|
||||
def except_hook(exctype, value, traceback):
|
||||
|
@ -154,18 +166,27 @@ class SmtIo:
|
|||
self.unroll = False
|
||||
|
||||
if self.solver == "yices":
|
||||
if self.noincr:
|
||||
self.popen_vargs = ['yices-smt2'] + self.solver_opts
|
||||
else:
|
||||
self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
|
||||
|
||||
if self.solver == "z3":
|
||||
self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts
|
||||
|
||||
if self.solver == "cvc4":
|
||||
if self.noincr:
|
||||
self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
|
||||
else:
|
||||
self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
|
||||
|
||||
if self.solver == "mathsat":
|
||||
self.popen_vargs = ['mathsat'] + self.solver_opts
|
||||
|
||||
if self.solver == "boolector":
|
||||
if self.noincr:
|
||||
self.popen_vargs = ['boolector', '--smt2'] + self.solver_opts
|
||||
else:
|
||||
self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
|
||||
self.unroll = True
|
||||
|
||||
|
@ -763,7 +784,7 @@ class SmtIo:
|
|||
|
||||
def get_path(self, mod, path):
|
||||
assert mod in self.modinfo
|
||||
path = path.split(".")
|
||||
path = path.replace("\\", "/").split(".")
|
||||
|
||||
for i in range(len(path)-1):
|
||||
first = ".".join(path[0:i+1])
|
||||
|
@ -1053,4 +1074,3 @@ class MkVcd:
|
|||
print("b0 %s" % self.nets[path][0], file=self.f)
|
||||
else:
|
||||
print("b1 %s" % self.nets[path][0], file=self.f)
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ struct SmvWorker
|
|||
|
||||
pool<Wire*> partial_assignment_wires;
|
||||
dict<SigBit, std::pair<const char*, int>> partial_assignment_bits;
|
||||
vector<string> assignments, invarspecs;
|
||||
vector<string> inputvars, vars, definitions, assignments, invarspecs;
|
||||
|
||||
const char *cid()
|
||||
{
|
||||
|
@ -195,7 +195,7 @@ struct SmvWorker
|
|||
return rvalue(sig);
|
||||
|
||||
const char *temp_id = cid();
|
||||
f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig));
|
||||
// f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig));
|
||||
|
||||
int offset = 0;
|
||||
for (auto bit : sig) {
|
||||
|
@ -210,14 +210,14 @@ struct SmvWorker
|
|||
void run()
|
||||
{
|
||||
f << stringf("MODULE %s\n", cid(module->name));
|
||||
f << stringf(" VAR\n");
|
||||
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
if (SigSpec(wire) != sigmap(wire))
|
||||
partial_assignment_wires.insert(wire);
|
||||
|
||||
f << stringf(" %s : unsigned word[%d]; -- %s\n", cid(wire->name), wire->width, log_id(wire));
|
||||
if (wire->port_input)
|
||||
inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, log_id(wire)));
|
||||
|
||||
if (wire->attributes.count("\\init"))
|
||||
assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at("\\init"))));
|
||||
|
@ -275,8 +275,8 @@ struct SmvWorker
|
|||
const char *b_shr = rvalue_u(sig_b);
|
||||
const char *b_shl = cid();
|
||||
|
||||
f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
|
||||
assignments.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
|
||||
// f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
|
||||
definitions.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
|
||||
|
||||
string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a.c_str(), b_shl, shift_b_width-1, width_y);
|
||||
string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a.c_str(), b_shr, shift_b_width-1, width_y);
|
||||
|
@ -303,7 +303,7 @@ struct SmvWorker
|
|||
GetSize(sig_b)-shift_b_width, width_y, expr.c_str());
|
||||
}
|
||||
|
||||
assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
|
||||
definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -319,12 +319,12 @@ struct SmvWorker
|
|||
|
||||
if (cell->getParam("\\A_SIGNED").as_bool())
|
||||
{
|
||||
assignments.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")),
|
||||
op.c_str(), rvalue_s(cell->getPort("\\A"), width)));
|
||||
}
|
||||
else
|
||||
{
|
||||
assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")),
|
||||
op.c_str(), rvalue_u(cell->getPort("\\A"), width)));
|
||||
}
|
||||
|
||||
|
@ -346,12 +346,12 @@ struct SmvWorker
|
|||
|
||||
if (cell->getParam("\\A_SIGNED").as_bool())
|
||||
{
|
||||
assignments.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")),
|
||||
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width)));
|
||||
}
|
||||
else
|
||||
{
|
||||
assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
|
||||
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width)));
|
||||
}
|
||||
|
||||
|
@ -370,12 +370,12 @@ struct SmvWorker
|
|||
|
||||
if (cell->getParam("\\A_SIGNED").as_bool())
|
||||
{
|
||||
assignments.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
|
||||
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width), width_y));
|
||||
}
|
||||
else
|
||||
{
|
||||
assignments.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")),
|
||||
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width), width_y));
|
||||
}
|
||||
|
||||
|
@ -407,7 +407,7 @@ struct SmvWorker
|
|||
expr_b = stringf("resize(%s, %d)", rvalue(cell->getPort("\\B")), width);
|
||||
}
|
||||
|
||||
assignments.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
|
||||
expr_a.c_str(), op.c_str(), expr_b.c_str(), GetSize(cell->getPort("\\Y"))));
|
||||
|
||||
continue;
|
||||
|
@ -425,7 +425,7 @@ struct SmvWorker
|
|||
if (cell->type == "$reduce_or") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
|
||||
if (cell->type == "$reduce_bool") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
|
||||
|
||||
assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
|
||||
definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -444,7 +444,7 @@ struct SmvWorker
|
|||
if (cell->type == "$reduce_xnor")
|
||||
expr = "!(" + expr + ")";
|
||||
|
||||
assignments.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y));
|
||||
definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -462,7 +462,7 @@ struct SmvWorker
|
|||
if (cell->type == "$logic_and") expr = expr_a + " & " + expr_b;
|
||||
if (cell->type == "$logic_or") expr = expr_a + " | " + expr_b;
|
||||
|
||||
assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
|
||||
definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -474,7 +474,7 @@ struct SmvWorker
|
|||
string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a);
|
||||
const char *expr_y = lvalue(cell->getPort("\\Y"));
|
||||
|
||||
assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y));
|
||||
definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -490,12 +490,13 @@ struct SmvWorker
|
|||
expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width)));
|
||||
expr += rvalue(sig_a);
|
||||
|
||||
assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
|
||||
definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$dff")
|
||||
{
|
||||
vars.push_back(stringf("%s : unsigned word[%d]; -- %s", lvalue(cell->getPort("\\Q")), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
|
||||
assignments.push_back(stringf("next(%s) := %s;", lvalue(cell->getPort("\\Q")), rvalue(cell->getPort("\\D"))));
|
||||
continue;
|
||||
}
|
||||
|
@ -503,7 +504,7 @@ struct SmvWorker
|
|||
if (cell->type.in("$_BUF_", "$_NOT_"))
|
||||
{
|
||||
string op = cell->type == "$_NOT_" ? "!" : "";
|
||||
assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A"))));
|
||||
definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A"))));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -517,49 +518,49 @@ struct SmvWorker
|
|||
if (cell->type.in("$_XNOR_")) op = "xnor";
|
||||
|
||||
if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
|
||||
assignments.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
|
||||
else
|
||||
if (cell->type.in("$_NAND_", "$_NOR_"))
|
||||
assignments.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
|
||||
else
|
||||
assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$_MUX_")
|
||||
{
|
||||
assignments.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A"))));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$_AOI3_")
|
||||
{
|
||||
assignments.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$_OAI3_")
|
||||
{
|
||||
assignments.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$_AOI4_")
|
||||
{
|
||||
assignments.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type == "$_OAI4_")
|
||||
{
|
||||
assignments.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")),
|
||||
definitions.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")),
|
||||
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
|
||||
continue;
|
||||
}
|
||||
|
@ -567,13 +568,13 @@ struct SmvWorker
|
|||
if (cell->type[0] == '$')
|
||||
log_error("Found currently unsupported cell type %s (%s.%s).\n", log_id(cell->type), log_id(module), log_id(cell));
|
||||
|
||||
f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
|
||||
// f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
|
||||
|
||||
for (auto &conn : cell->connections())
|
||||
if (cell->output(conn.first))
|
||||
assignments.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first)));
|
||||
definitions.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first)));
|
||||
else
|
||||
assignments.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second)));
|
||||
definitions.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second)));
|
||||
}
|
||||
|
||||
for (Wire *wire : partial_assignment_wires)
|
||||
|
@ -657,7 +658,25 @@ struct SmvWorker
|
|||
}
|
||||
}
|
||||
|
||||
assignments.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str()));
|
||||
definitions.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str()));
|
||||
}
|
||||
|
||||
if (!inputvars.empty()) {
|
||||
f << stringf(" IVAR\n");
|
||||
for (const string &line : inputvars)
|
||||
f << stringf(" %s\n", line.c_str());
|
||||
}
|
||||
|
||||
if (!vars.empty()) {
|
||||
f << stringf(" VAR\n");
|
||||
for (const string &line : vars)
|
||||
f << stringf(" %s\n", line.c_str());
|
||||
}
|
||||
|
||||
if (!definitions.empty()) {
|
||||
f << stringf(" DEFINE\n");
|
||||
for (const string &line : definitions)
|
||||
f << stringf(" %s\n", line.c_str());
|
||||
}
|
||||
|
||||
if (!assignments.empty()) {
|
||||
|
@ -675,7 +694,7 @@ struct SmvWorker
|
|||
|
||||
struct SmvBackend : public Backend {
|
||||
SmvBackend() : Backend("smv", "write design to SMV file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -693,7 +712,7 @@ struct SmvBackend : public Backend {
|
|||
log("THIS COMMAND IS UNDER CONSTRUCTION\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::ifstream template_f;
|
||||
bool verbose = false;
|
||||
|
|
|
@ -132,7 +132,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
|
|||
|
||||
struct SpiceBackend : public Backend {
|
||||
SpiceBackend() : Backend("spice", "write design to SPICE netlist file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -161,7 +161,7 @@ struct SpiceBackend : public Backend {
|
|||
log(" set the specified module as design top module\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::string top_module_name;
|
||||
RTLIL::Module *top_module = NULL;
|
||||
|
|
|
@ -29,7 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct TableBackend : public Backend {
|
||||
TableBackend() : Backend("table", "write design as connectivity table") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -48,7 +48,7 @@ struct TableBackend : public Backend {
|
|||
log("module inputs and outputs are output using cell type and port '-' and with\n");
|
||||
log("'pi' (primary input) or 'po' (primary output) or 'pio' as direction.\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing TABLE backend.\n");
|
||||
|
||||
|
@ -109,7 +109,7 @@ struct TableBackend : public Backend {
|
|||
else if (cell->output(conn.first))
|
||||
*f << "out" << "\t";
|
||||
else
|
||||
*f << "unkown" << "\t";
|
||||
*f << "unknown" << "\t";
|
||||
|
||||
*f << log_signal(sigmap(conn.second)) << "\n";
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal;
|
||||
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit;
|
||||
int auto_name_counter, auto_name_offset, auto_name_digits;
|
||||
std::map<RTLIL::IdString, int> auto_name_map;
|
||||
std::set<RTLIL::IdString> reg_wires, reg_ct;
|
||||
|
@ -126,6 +126,33 @@ std::string id(RTLIL::IdString internal_id, bool may_rename = true)
|
|||
break;
|
||||
}
|
||||
|
||||
const pool<string> keywords = {
|
||||
// IEEE 1800-2017 Annex B
|
||||
"accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
|
||||
"begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
|
||||
"checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
|
||||
"cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
|
||||
"endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
|
||||
"endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
|
||||
"expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
|
||||
"generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
|
||||
"import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
|
||||
"intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
|
||||
"macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
|
||||
"noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
|
||||
"priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
|
||||
"pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
|
||||
"restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
|
||||
"s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
|
||||
"specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
|
||||
"sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
|
||||
"tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
|
||||
"untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
|
||||
"wildcard", "wire", "with", "within", "wor", "xnor", "xor",
|
||||
};
|
||||
if (keywords.count(str))
|
||||
do_escape = true;
|
||||
|
||||
if (do_escape)
|
||||
return "\\" + std::string(str) + " ";
|
||||
return std::string(str);
|
||||
|
@ -388,7 +415,7 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
|
|||
void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
|
||||
{
|
||||
dump_attributes(f, indent, memory->attributes);
|
||||
f << stringf("%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
|
||||
f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size+memory->start_offset-1, memory->start_offset);
|
||||
}
|
||||
|
||||
void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
|
||||
|
@ -678,13 +705,45 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
#undef HANDLE_UNIOP
|
||||
#undef HANDLE_BINOP
|
||||
|
||||
if (cell->type == "$shiftx")
|
||||
if (cell->type == "$shift")
|
||||
{
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort("\\Y"));
|
||||
f << stringf(" = ");
|
||||
if (cell->getParam("\\B_SIGNED").as_bool())
|
||||
{
|
||||
f << stringf("$signed(");
|
||||
dump_sigspec(f, cell->getPort("\\B"));
|
||||
f << stringf(")");
|
||||
f << stringf(" < 0 ? ");
|
||||
dump_sigspec(f, cell->getPort("\\A"));
|
||||
f << stringf("[");
|
||||
f << stringf(" << - ");
|
||||
dump_sigspec(f, cell->getPort("\\B"));
|
||||
f << stringf(" : ");
|
||||
dump_sigspec(f, cell->getPort("\\A"));
|
||||
f << stringf(" >> ");
|
||||
dump_sigspec(f, cell->getPort("\\B"));
|
||||
}
|
||||
else
|
||||
{
|
||||
dump_sigspec(f, cell->getPort("\\A"));
|
||||
f << stringf(" >> ");
|
||||
dump_sigspec(f, cell->getPort("\\B"));
|
||||
}
|
||||
f << stringf(";\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$shiftx")
|
||||
{
|
||||
std::string temp_id = next_auto_id();
|
||||
f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort("\\A"))-1, temp_id.c_str());
|
||||
dump_sigspec(f, cell->getPort("\\A"));
|
||||
f << stringf(";\n");
|
||||
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort("\\Y"));
|
||||
f << stringf(" = %s[", temp_id.c_str());
|
||||
if (cell->getParam("\\B_SIGNED").as_bool())
|
||||
f << stringf("$signed(");
|
||||
dump_sigspec(f, cell->getPort("\\B"));
|
||||
|
@ -757,6 +816,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$tribuf")
|
||||
{
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort("\\Y"));
|
||||
f << stringf(" = ");
|
||||
dump_sigspec(f, cell->getPort("\\EN"));
|
||||
f << stringf(" ? ");
|
||||
dump_sigspec(f, cell->getPort("\\A"));
|
||||
f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$slice")
|
||||
{
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
|
@ -779,6 +850,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$lut")
|
||||
{
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort("\\Y"));
|
||||
f << stringf(" = ");
|
||||
dump_const(f, cell->parameters.at("\\LUT"));
|
||||
f << stringf(" >> ");
|
||||
dump_attributes(f, "", cell->attributes, ' ');
|
||||
dump_sigspec(f, cell->getPort("\\A"));
|
||||
f << stringf(";\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == "$dffsr")
|
||||
{
|
||||
SigSpec sig_clk = cell->getPort("\\CLK");
|
||||
|
@ -939,6 +1023,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
|
||||
int abits = cell->parameters["\\ABITS"].as_int();
|
||||
int size = cell->parameters["\\SIZE"].as_int();
|
||||
int offset = cell->parameters["\\OFFSET"].as_int();
|
||||
int width = cell->parameters["\\WIDTH"].as_int();
|
||||
bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
|
||||
|
||||
|
@ -947,7 +1032,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
// initial begin
|
||||
// memid[0] = ...
|
||||
// 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+offset-1, offset);
|
||||
if (use_init)
|
||||
{
|
||||
f << stringf("%s" "initial begin\n", indent.c_str());
|
||||
|
@ -980,6 +1065,8 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
|
||||
rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
|
||||
rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
|
||||
if (use_rd_clk)
|
||||
{
|
||||
{
|
||||
std::ostringstream os;
|
||||
dump_sigspec(os, sig_rd_clk);
|
||||
|
@ -987,7 +1074,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
if( clk_to_lof_body.count(clk_domain_str) == 0 )
|
||||
clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
|
||||
}
|
||||
if (use_rd_clk && !rd_transparent)
|
||||
if (!rd_transparent)
|
||||
{
|
||||
// for clocked read ports make something like:
|
||||
// reg [..] temp_id;
|
||||
|
@ -1015,8 +1102,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
|
||||
clk_to_lof_body[""].push_back(line);
|
||||
}
|
||||
} else {
|
||||
if (rd_transparent) {
|
||||
}
|
||||
else
|
||||
{
|
||||
// for rd-transparent read-ports make something like:
|
||||
// reg [..] temp_id;
|
||||
// always @(posedge clk)
|
||||
|
@ -1036,6 +1124,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
|
||||
clk_to_lof_body[""].push_back(line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// for non-clocked read-ports make something like:
|
||||
// assign r_data = array_reg[r_addr];
|
||||
|
@ -1046,7 +1135,6 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
clk_to_lof_body[""].push_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
|
||||
RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
|
||||
|
@ -1222,6 +1310,15 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
}
|
||||
}
|
||||
|
||||
if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
|
||||
std::stringstream ss;
|
||||
dump_reg_init(ss, cell->getPort("\\Q"));
|
||||
if (!ss.str().empty()) {
|
||||
f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
|
||||
f << ss.str();
|
||||
f << ";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
|
||||
|
@ -1338,6 +1435,8 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
|
|||
|
||||
if (sync->type == RTLIL::STa) {
|
||||
f << stringf("%s" "always @* begin\n", indent.c_str());
|
||||
} else if (sync->type == RTLIL::STi) {
|
||||
f << stringf("%s" "initial begin\n", indent.c_str());
|
||||
} else {
|
||||
f << stringf("%s" "always @(", indent.c_str());
|
||||
if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
|
||||
|
@ -1402,10 +1501,10 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
}
|
||||
|
||||
if (!module->processes.empty())
|
||||
log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
|
||||
log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
|
||||
"can't always be mapped directly to Verilog always blocks. Unintended\n"
|
||||
"changes in simulation behavior are possible! Use \"proc\" to convert\n"
|
||||
"processes to logic networks and registers.", log_id(module));
|
||||
"processes to logic networks and registers.\n", log_id(module));
|
||||
|
||||
f << stringf("\n");
|
||||
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
||||
|
@ -1482,7 +1581,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
|
||||
struct VerilogBackend : public Backend {
|
||||
VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -1508,9 +1607,13 @@ struct VerilogBackend : public Backend {
|
|||
log(" without this option all internal cells are converted to Verilog\n");
|
||||
log(" expressions.\n");
|
||||
log("\n");
|
||||
log(" -siminit\n");
|
||||
log(" add initial statements with hierarchical refs to initialize FFs when\n");
|
||||
log(" in -noexpr mode.\n");
|
||||
log("\n");
|
||||
log(" -nodec\n");
|
||||
log(" 32-bit constant values are by default dumped as decimal numbers,\n");
|
||||
log(" not bit pattern. This option decativates this feature and instead\n");
|
||||
log(" not bit pattern. This option deactivates this feature and instead\n");
|
||||
log(" will write out all constants in binary.\n");
|
||||
log("\n");
|
||||
log(" -decimal\n");
|
||||
|
@ -1518,13 +1621,13 @@ struct VerilogBackend : public Backend {
|
|||
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(" dumped as hex values. This option deactivates this feature and\n");
|
||||
log(" instead will write out all constants in binary.\n");
|
||||
log("\n");
|
||||
log(" -nostr\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(" decativates this feature and instead will write string constants\n");
|
||||
log(" deactivates this feature and instead will write string constants\n");
|
||||
log(" as binary numbers.\n");
|
||||
log("\n");
|
||||
log(" -defparam\n");
|
||||
|
@ -1550,7 +1653,7 @@ struct VerilogBackend : public Backend {
|
|||
log("this command is called on a design with RTLIL processes.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing Verilog backend.\n");
|
||||
|
||||
|
@ -1564,11 +1667,14 @@ struct VerilogBackend : public Backend {
|
|||
nostr = false;
|
||||
defparam = false;
|
||||
decimal = false;
|
||||
siminit = false;
|
||||
auto_prefix = "";
|
||||
|
||||
bool blackboxes = false;
|
||||
bool selected = false;
|
||||
|
||||
auto_name_map.clear();
|
||||
reg_wires.clear();
|
||||
reg_ct.clear();
|
||||
|
||||
reg_ct.insert("$dff");
|
||||
|
@ -1640,6 +1746,10 @@ struct VerilogBackend : public Backend {
|
|||
decimal = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-siminit") {
|
||||
siminit = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-blackboxes") {
|
||||
blackboxes = true;
|
||||
continue;
|
||||
|
@ -1671,6 +1781,8 @@ struct VerilogBackend : public Backend {
|
|||
dump_module(*f, "", it->second);
|
||||
}
|
||||
|
||||
auto_name_map.clear();
|
||||
reg_wires.clear();
|
||||
reg_ct.clear();
|
||||
}
|
||||
} VerilogBackend;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
demo.bit
|
||||
demo_phy.area
|
||||
full.v
|
||||
*.log
|
||||
*.h
|
||||
*.tde
|
||||
*.svf
|
|
@ -0,0 +1,12 @@
|
|||
LED Blink project for Anlogic Lichee Tang board.
|
||||
|
||||
Follow the install instructions for the Tang Dynasty IDE from given link below.
|
||||
|
||||
https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/
|
||||
|
||||
|
||||
set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow.
|
||||
|
||||
export TD_HOME=<TD Install Directory>
|
||||
|
||||
then run "bash build.sh" in this directory.
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
yosys demo.ys
|
||||
$TD_HOME/bin/td build.tcl
|
|
@ -0,0 +1,11 @@
|
|||
import_device eagle_s20.db -package BG256
|
||||
read_verilog full.v -top demo
|
||||
read_adc demo.adc
|
||||
optimize_rtl
|
||||
map_macro
|
||||
map
|
||||
pack
|
||||
place
|
||||
route
|
||||
report_area -io_info -file demo_phy.area
|
||||
bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000
|
|
@ -0,0 +1,2 @@
|
|||
set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
|
||||
set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED
|
|
@ -0,0 +1,18 @@
|
|||
module demo (
|
||||
input wire CLK_IN,
|
||||
output wire R_LED
|
||||
);
|
||||
parameter time1 = 30'd12_000_000;
|
||||
reg led_state;
|
||||
reg [29:0] count;
|
||||
|
||||
always @(posedge CLK_IN)begin
|
||||
if(count == time1)begin
|
||||
count<= 30'd0;
|
||||
led_state <= ~led_state;
|
||||
end
|
||||
else
|
||||
count <= count + 1'b1;
|
||||
end
|
||||
assign R_LED = led_state;
|
||||
endmodule
|
|
@ -0,0 +1,3 @@
|
|||
read_verilog demo.v
|
||||
synth_anlogic -top demo
|
||||
write_verilog full.v
|
|
@ -19,3 +19,6 @@ set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN L1 } [get_ports {LD[15]}]
|
|||
|
||||
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports CLK]
|
||||
|
||||
set_property CONFIG_VOLTAGE 3.3 [current_design]
|
||||
set_property CFGBVS VCCO [current_design]
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
open_hw
|
||||
connect_hw_server
|
||||
open_hw_target [lindex [get_hw_targets] 0]
|
||||
set_property PROGRAM.FILE example.bit [lindex [get_hw_devices] 0]
|
||||
|
|
|
@ -22,7 +22,7 @@ struct EvalDemoPass : public Pass
|
|||
{
|
||||
EvalDemoPass() : Pass("evaldemo") { }
|
||||
|
||||
virtual void execute(vector<string>, Design *design)
|
||||
void execute(vector<string>, Design *design) YS_OVERRIDE
|
||||
{
|
||||
Module *module = design->top_module();
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/netlist.edn
|
||||
/netlist.vm
|
||||
/example.stp
|
||||
/proj
|
|
@ -0,0 +1,20 @@
|
|||
# Add placement constraints here
|
||||
|
||||
set_io clk -pinname H16 -fixed yes -DIRECTION INPUT
|
||||
|
||||
set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT
|
||||
set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT
|
||||
|
||||
set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT
|
||||
set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT
|
||||
set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT
|
||||
set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT
|
||||
|
||||
set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT
|
||||
set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT
|
||||
set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT
|
||||
set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT
|
||||
set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT
|
||||
set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT
|
||||
set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT
|
||||
set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT
|
|
@ -0,0 +1,2 @@
|
|||
# Add timing constraints here
|
||||
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]
|
|
@ -0,0 +1,64 @@
|
|||
module example (
|
||||
input clk,
|
||||
input SW1,
|
||||
input SW2,
|
||||
output LED1,
|
||||
output LED2,
|
||||
output LED3,
|
||||
output LED4,
|
||||
|
||||
output AA, AB, AC, AD,
|
||||
output AE, AF, AG, CA
|
||||
);
|
||||
|
||||
localparam BITS = 8;
|
||||
localparam LOG2DELAY = 22;
|
||||
|
||||
reg [BITS+LOG2DELAY-1:0] counter = 0;
|
||||
reg [BITS-1:0] outcnt;
|
||||
|
||||
always @(posedge clk) begin
|
||||
counter <= counter + SW1 + SW2 + 1;
|
||||
outcnt <= counter >> LOG2DELAY;
|
||||
end
|
||||
|
||||
assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1);
|
||||
|
||||
// assign CA = counter[10];
|
||||
// seg7enc seg7encinst (
|
||||
// .seg({AA, AB, AC, AD, AE, AF, AG}),
|
||||
// .dat(CA ? outcnt[3:0] : outcnt[7:4])
|
||||
// );
|
||||
|
||||
assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]);
|
||||
assign CA = outcnt[7];
|
||||
endmodule
|
||||
|
||||
module seg7enc (
|
||||
input [3:0] dat,
|
||||
output [6:0] seg
|
||||
);
|
||||
reg [6:0] seg_inv;
|
||||
always @* begin
|
||||
seg_inv = 0;
|
||||
case (dat)
|
||||
4'h0: seg_inv = 7'b 0111111;
|
||||
4'h1: seg_inv = 7'b 0000110;
|
||||
4'h2: seg_inv = 7'b 1011011;
|
||||
4'h3: seg_inv = 7'b 1001111;
|
||||
4'h4: seg_inv = 7'b 1100110;
|
||||
4'h5: seg_inv = 7'b 1101101;
|
||||
4'h6: seg_inv = 7'b 1111101;
|
||||
4'h7: seg_inv = 7'b 0000111;
|
||||
4'h8: seg_inv = 7'b 1111111;
|
||||
4'h9: seg_inv = 7'b 1101111;
|
||||
4'hA: seg_inv = 7'b 1110111;
|
||||
4'hB: seg_inv = 7'b 1111100;
|
||||
4'hC: seg_inv = 7'b 0111001;
|
||||
4'hD: seg_inv = 7'b 1011110;
|
||||
4'hE: seg_inv = 7'b 1111001;
|
||||
4'hF: seg_inv = 7'b 1110001;
|
||||
endcase
|
||||
end
|
||||
assign seg = ~seg_inv;
|
||||
endmodule
|
|
@ -0,0 +1,57 @@
|
|||
# Run with "libero SCRIPT:libero.tcl"
|
||||
|
||||
file delete -force proj
|
||||
|
||||
new_project \
|
||||
-name example \
|
||||
-location proj \
|
||||
-block_mode 0 \
|
||||
-hdl "VERILOG" \
|
||||
-family IGLOO2 \
|
||||
-die PA4MGL2500 \
|
||||
-package vf256 \
|
||||
-speed -1
|
||||
|
||||
import_files -hdl_source {netlist.vm}
|
||||
import_files -sdc {example.sdc}
|
||||
import_files -io_pdc {example.pdc}
|
||||
build_design_hierarchy
|
||||
set_option -synth 0
|
||||
|
||||
organize_tool_files -tool PLACEROUTE \
|
||||
-file {proj/constraint/example.sdc} \
|
||||
-file {proj/constraint/io/example.pdc} \
|
||||
-input_type constraint
|
||||
|
||||
organize_tool_files -tool VERIFYTIMING \
|
||||
-file {proj/constraint/example.sdc} \
|
||||
-input_type constraint
|
||||
|
||||
configure_tool -name PLACEROUTE \
|
||||
-params TDPR:true \
|
||||
-params PDPR:false \
|
||||
-params EFFORT_LEVEL:false \
|
||||
-params REPAIR_MIN_DELAY:false
|
||||
|
||||
puts ""
|
||||
puts "**> COMPILE"
|
||||
run_tool -name {COMPILE}
|
||||
puts "<** COMPILE"
|
||||
|
||||
puts ""
|
||||
puts "**> PLACEROUTE"
|
||||
run_tool -name {PLACEROUTE}
|
||||
puts "<** PLACEROUTE"
|
||||
|
||||
puts ""
|
||||
puts "**> VERIFYTIMING"
|
||||
run_tool -name {VERIFYTIMING}
|
||||
puts "<** VERIFYTIMING"
|
||||
|
||||
puts ""
|
||||
puts "**> BITSTREAM"
|
||||
export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
|
||||
puts "<** BITSTREAM"
|
||||
|
||||
puts ""
|
||||
exit 0
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
|
||||
export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost}
|
||||
/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl
|
||||
cp proj/designer/example/export/example.stp .
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
OBJS += frontends/aiger/aigerparse.o
|
||||
|
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* Eddie Hung <eddie@fpgeh.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012
|
||||
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
|
||||
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
#include <array>
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "aigerparse.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
#define log_debug log
|
||||
|
||||
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
|
||||
: design(design), f(f), clk_name(clk_name)
|
||||
{
|
||||
module = new RTLIL::Module;
|
||||
module->name = module_name;
|
||||
if (design->module(module->name))
|
||||
log_error("Duplicate definition of module %s!\n", log_id(module->name));
|
||||
}
|
||||
|
||||
void AigerReader::parse_aiger()
|
||||
{
|
||||
std::string header;
|
||||
f >> header;
|
||||
if (header != "aag" && header != "aig")
|
||||
log_error("Unsupported AIGER file!\n");
|
||||
|
||||
// Parse rest of header
|
||||
if (!(f >> M >> I >> L >> O >> A))
|
||||
log_error("Invalid AIGER header\n");
|
||||
|
||||
// Optional values
|
||||
B = C = J = F = 0;
|
||||
for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
|
||||
if (f.peek() != ' ') break;
|
||||
if (!(f >> i))
|
||||
log_error("Invalid AIGER header\n");
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::getline(f, line); // Ignore up to start of next line, as standard
|
||||
// says anything that follows could be used for
|
||||
// optional sections
|
||||
|
||||
log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
|
||||
|
||||
line_count = 1;
|
||||
|
||||
if (header == "aag")
|
||||
parse_aiger_ascii();
|
||||
else if (header == "aig")
|
||||
parse_aiger_binary();
|
||||
else
|
||||
log_abort();
|
||||
|
||||
// Parse footer (symbol table, comments, etc.)
|
||||
unsigned l1;
|
||||
std::string s;
|
||||
for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
|
||||
if (c == 'i' || c == 'l' || c == 'o') {
|
||||
f.ignore(1);
|
||||
if (!(f >> l1 >> s))
|
||||
log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
|
||||
|
||||
if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
|
||||
log_error("Line %u has invalid symbol position!\n", line_count);
|
||||
|
||||
RTLIL::Wire* wire;
|
||||
if (c == 'i') wire = inputs[l1];
|
||||
else if (c == 'l') wire = latches[l1];
|
||||
else if (c == 'o') wire = outputs[l1];
|
||||
else log_abort();
|
||||
|
||||
module->rename(wire, stringf("\\%s", s.c_str()));
|
||||
}
|
||||
else if (c == 'b' || c == 'j' || c == 'f') {
|
||||
// TODO
|
||||
}
|
||||
else if (c == 'c') {
|
||||
f.ignore(1);
|
||||
if (f.peek() == '\n')
|
||||
break;
|
||||
// Else constraint (TODO)
|
||||
}
|
||||
else
|
||||
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
}
|
||||
|
||||
module->fixup_ports();
|
||||
design->add(module);
|
||||
}
|
||||
|
||||
static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
|
||||
{
|
||||
const unsigned variable = literal >> 1;
|
||||
const bool invert = literal & 1;
|
||||
RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
|
||||
RTLIL::Wire *wire = module->wire(wire_name);
|
||||
if (wire) return wire;
|
||||
log_debug("Creating %s\n", wire_name.c_str());
|
||||
wire = module->addWire(wire_name);
|
||||
if (!invert) return wire;
|
||||
RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
|
||||
RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
|
||||
if (wire_inv) {
|
||||
if (module->cell(wire_inv_name)) return wire;
|
||||
}
|
||||
else {
|
||||
log_debug("Creating %s\n", wire_inv_name.c_str());
|
||||
wire_inv = module->addWire(wire_inv_name);
|
||||
}
|
||||
|
||||
log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
|
||||
module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
|
||||
|
||||
return wire;
|
||||
}
|
||||
|
||||
void AigerReader::parse_aiger_ascii()
|
||||
{
|
||||
std::string line;
|
||||
std::stringstream ss;
|
||||
|
||||
unsigned l1, l2, l3;
|
||||
|
||||
// Parse inputs
|
||||
for (unsigned i = 0; i < I; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an input!\n", line_count);
|
||||
log_debug("%d is an input\n", l1);
|
||||
log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_input = true;
|
||||
inputs.push_back(wire);
|
||||
}
|
||||
|
||||
// Parse latches
|
||||
RTLIL::Wire *clk_wire = nullptr;
|
||||
if (L > 0) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
log_assert(!clk_wire);
|
||||
log_debug("Creating %s\n", clk_name.c_str());
|
||||
clk_wire = module->addWire(clk_name);
|
||||
clk_wire->port_input = true;
|
||||
}
|
||||
for (unsigned i = 0; i < L; ++i, ++line_count) {
|
||||
if (!(f >> l1 >> l2))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
log_debug("%d %d is a latch\n", l1, l2);
|
||||
log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
|
||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||
|
||||
module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
|
||||
|
||||
// Reset logic is optional in AIGER 1.9
|
||||
if (f.peek() == ' ') {
|
||||
if (!(f >> l3))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
|
||||
if (l3 == 0 || l3 == 1)
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(l3);
|
||||
else if (l3 == l1) {
|
||||
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||
}
|
||||
else
|
||||
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||
}
|
||||
else {
|
||||
// AIGER latches are assumed to be initialized to zero
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(0);
|
||||
}
|
||||
latches.push_back(q_wire);
|
||||
}
|
||||
|
||||
// Parse outputs
|
||||
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||
|
||||
log_debug("%d is an output\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
outputs.push_back(wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse bad state properties
|
||||
for (unsigned i = 0; i < B; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse invariant constraints
|
||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse justice properties
|
||||
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse fairness constraints
|
||||
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// Parse AND
|
||||
for (unsigned i = 0; i < A; ++i) {
|
||||
if (!(f >> l1 >> l2 >> l3))
|
||||
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
|
||||
|
||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||
module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
}
|
||||
|
||||
static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
|
||||
{
|
||||
unsigned x = 0, i = 0;
|
||||
unsigned char ch;
|
||||
while ((ch = f.get()) & 0x80)
|
||||
x |= (ch & 0x7f) << (7 * i++);
|
||||
return ref - (x | (ch << (7 * i)));
|
||||
}
|
||||
|
||||
void AigerReader::parse_aiger_binary()
|
||||
{
|
||||
unsigned l1, l2, l3;
|
||||
std::string line;
|
||||
|
||||
// Parse inputs
|
||||
for (unsigned i = 1; i <= I; ++i) {
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
|
||||
wire->port_input = true;
|
||||
inputs.push_back(wire);
|
||||
}
|
||||
|
||||
// Parse latches
|
||||
RTLIL::Wire *clk_wire = nullptr;
|
||||
if (L > 0) {
|
||||
clk_wire = module->wire(clk_name);
|
||||
log_assert(!clk_wire);
|
||||
log_debug("Creating %s\n", clk_name.c_str());
|
||||
clk_wire = module->addWire(clk_name);
|
||||
clk_wire->port_input = true;
|
||||
}
|
||||
l1 = (I+1) * 2;
|
||||
for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
|
||||
if (!(f >> l2))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
log_debug("%d %d is a latch\n", l1, l2);
|
||||
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||
|
||||
module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
|
||||
|
||||
// Reset logic is optional in AIGER 1.9
|
||||
if (f.peek() == ' ') {
|
||||
if (!(f >> l3))
|
||||
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||
|
||||
if (l3 == 0 || l3 == 1)
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(l3);
|
||||
else if (l3 == l1) {
|
||||
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||
}
|
||||
else
|
||||
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||
}
|
||||
else {
|
||||
// AIGER latches are assumed to be initialized to zero
|
||||
q_wire->attributes["\\init"] = RTLIL::Const(0);
|
||||
}
|
||||
latches.push_back(q_wire);
|
||||
}
|
||||
|
||||
// Parse outputs
|
||||
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||
if (!(f >> l1))
|
||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||
|
||||
log_debug("%d is an output\n", l1);
|
||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||
wire->port_output = true;
|
||||
outputs.push_back(wire);
|
||||
}
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse bad state properties
|
||||
for (unsigned i = 0; i < B; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse invariant constraints
|
||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse justice properties
|
||||
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// TODO: Parse fairness constraints
|
||||
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||
std::getline(f, line); // Ignore up to start of next line
|
||||
|
||||
// Parse AND
|
||||
l1 = (I+L+1) << 1;
|
||||
for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
|
||||
l2 = parse_next_delta_literal(f, l1);
|
||||
l3 = parse_next_delta_literal(f, l2);
|
||||
|
||||
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||
|
||||
RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
|
||||
and_cell->setPort("\\A", i1_wire);
|
||||
and_cell->setPort("\\B", i2_wire);
|
||||
and_cell->setPort("\\Y", o_wire);
|
||||
}
|
||||
}
|
||||
|
||||
struct AigerFrontend : public Frontend {
|
||||
AigerFrontend() : Frontend("aiger", "read AIGER file") { }
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" read_aiger [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Load module from an AIGER file into the current design.\n");
|
||||
log("\n");
|
||||
log(" -module_name <module_name>\n");
|
||||
log(" Name of module to be created (default: <filename>)"
|
||||
#ifdef _WIN32
|
||||
"top" // FIXME
|
||||
#else
|
||||
"<filename>"
|
||||
#endif
|
||||
")\n");
|
||||
log("\n");
|
||||
log(" -clk_name <wire_name>\n");
|
||||
log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
|
||||
log(" this name (default: clk)\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing AIGER frontend.\n");
|
||||
|
||||
RTLIL::IdString clk_name = "\\clk";
|
||||
RTLIL::IdString module_name;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-module_name" && argidx+1 < args.size()) {
|
||||
module_name = RTLIL::escape_id(args[++argidx]);
|
||||
continue;
|
||||
}
|
||||
if (arg == "-clk_name" && argidx+1 < args.size()) {
|
||||
clk_name = RTLIL::escape_id(args[++argidx]);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
if (module_name.empty()) {
|
||||
#ifdef _WIN32
|
||||
module_name = "top"; // FIXME: basename equivalent on Win32?
|
||||
#else
|
||||
char* bn = strdup(filename.c_str());
|
||||
module_name = RTLIL::escape_id(bn);
|
||||
free(bn);
|
||||
#endif
|
||||
}
|
||||
|
||||
AigerReader reader(design, *f, module_name, clk_name);
|
||||
reader.parse_aiger();
|
||||
}
|
||||
} AigerFrontend;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* Eddie Hung <eddie@fpgeh.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ABC_AIGERPARSE
|
||||
#define ABC_AIGERPARSE
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct AigerReader
|
||||
{
|
||||
RTLIL::Design *design;
|
||||
std::istream &f;
|
||||
RTLIL::IdString clk_name;
|
||||
RTLIL::Module *module;
|
||||
|
||||
unsigned M, I, L, O, A;
|
||||
unsigned B, C, J, F; // Optional in AIGER 1.9
|
||||
unsigned line_count;
|
||||
|
||||
std::vector<RTLIL::Wire*> inputs;
|
||||
std::vector<RTLIL::Wire*> latches;
|
||||
std::vector<RTLIL::Wire*> outputs;
|
||||
|
||||
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
|
||||
void parse_aiger();
|
||||
void parse_aiger_ascii();
|
||||
void parse_aiger_binary();
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -2,6 +2,7 @@
|
|||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
* Copyright (C) 2018 Ruben Undheim <ruben.undheim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -35,16 +36,16 @@ YOSYS_NAMESPACE_BEGIN
|
|||
using namespace AST;
|
||||
using namespace AST_INTERNAL;
|
||||
|
||||
// instanciate global variables (public API)
|
||||
// instantiate global variables (public API)
|
||||
namespace AST {
|
||||
std::string current_filename;
|
||||
void (*set_line_num)(int) = NULL;
|
||||
int (*get_line_num)() = NULL;
|
||||
}
|
||||
|
||||
// instanciate global variables (private API)
|
||||
// instantiate global variables (private API)
|
||||
namespace AST_INTERNAL {
|
||||
bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
||||
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
||||
bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
||||
AstNode *current_ast, *current_ast_mod;
|
||||
std::map<std::string, AstNode*> current_scope;
|
||||
|
@ -171,8 +172,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
|
|||
|
||||
AstNode *attr = attributes.at(id);
|
||||
if (attr->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
id.c_str(), attr->filename.c_str(), attr->linenum);
|
||||
log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", id.c_str());
|
||||
|
||||
return attr->integer != 0;
|
||||
}
|
||||
|
@ -191,8 +191,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
|
|||
is_input = false;
|
||||
is_output = false;
|
||||
is_reg = false;
|
||||
is_logic = false;
|
||||
is_signed = false;
|
||||
is_string = false;
|
||||
was_checked = false;
|
||||
range_valid = false;
|
||||
range_swapped = false;
|
||||
port_id = 0;
|
||||
|
@ -265,10 +267,12 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
|
|||
std::string type_name = type2str(type);
|
||||
fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum);
|
||||
|
||||
if (!flag_no_dump_ptr) {
|
||||
if (id2ast)
|
||||
fprintf(f, " [%p -> %p]", this, id2ast);
|
||||
else
|
||||
fprintf(f, " [%p]", this);
|
||||
}
|
||||
|
||||
if (!str.empty())
|
||||
fprintf(f, " str='%s'", str.c_str());
|
||||
|
@ -285,7 +289,9 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
|
|||
fprintf(f, " input");
|
||||
if (is_output)
|
||||
fprintf(f, " output");
|
||||
if (is_reg)
|
||||
if (is_logic)
|
||||
fprintf(f, " logic");
|
||||
if (is_reg) // this is an AST dump, not Verilog - if we see "logic reg" that's fine.
|
||||
fprintf(f, " reg");
|
||||
if (is_signed)
|
||||
fprintf(f, " signed");
|
||||
|
@ -425,9 +431,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
break;
|
||||
|
||||
case AST_RANGE:
|
||||
if (range_valid)
|
||||
if (range_valid) {
|
||||
if (range_swapped)
|
||||
fprintf(f, "[%d:%d]", range_right, range_left);
|
||||
else
|
||||
fprintf(f, "[%d:%d]", range_left, range_right);
|
||||
else {
|
||||
} else {
|
||||
for (auto child : children) {
|
||||
fprintf(f, "%c", first ? '[' : ':');
|
||||
child->dumpVlog(f, "");
|
||||
|
@ -556,7 +565,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
|||
|
||||
case AST_CONCAT:
|
||||
fprintf(f, "{");
|
||||
for (auto child : children) {
|
||||
for (int i = GetSize(children)-1; i >= 0; i--) {
|
||||
auto child = children[i];
|
||||
if (!first)
|
||||
fprintf(f, ", ");
|
||||
child->dumpVlog(f, "");
|
||||
|
@ -652,6 +662,8 @@ bool AstNode::operator==(const AstNode &other) const
|
|||
return false;
|
||||
if (is_output != other.is_output)
|
||||
return false;
|
||||
if (is_logic != other.is_logic)
|
||||
return false;
|
||||
if (is_reg != other.is_reg)
|
||||
return false;
|
||||
if (is_signed != other.is_signed)
|
||||
|
@ -895,9 +907,9 @@ RTLIL::Const AstNode::realAsConst(int width)
|
|||
}
|
||||
|
||||
// create a new AstModule from an AST_MODULE AST node
|
||||
static AstModule* process_module(AstNode *ast, bool defer)
|
||||
static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL)
|
||||
{
|
||||
log_assert(ast->type == AST_MODULE);
|
||||
log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
|
||||
|
||||
if (defer)
|
||||
log("Storing AST representation for module `%s'.\n", ast->str.c_str());
|
||||
|
@ -908,28 +920,38 @@ static AstModule* process_module(AstNode *ast, bool defer)
|
|||
current_module->ast = NULL;
|
||||
current_module->name = ast->str;
|
||||
current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
|
||||
current_module->set_bool_attribute("\\cells_not_processed");
|
||||
|
||||
current_ast_mod = ast;
|
||||
AstNode *ast_before_simplify = ast->clone();
|
||||
AstNode *ast_before_simplify;
|
||||
if (original_ast != NULL)
|
||||
ast_before_simplify = original_ast;
|
||||
else
|
||||
ast_before_simplify = ast->clone();
|
||||
|
||||
if (flag_dump_ast1) {
|
||||
log("Dumping Verilog AST before simplification:\n");
|
||||
log("Dumping AST before simplification:\n");
|
||||
ast->dumpAst(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
if (flag_dump_vlog1) {
|
||||
log("Dumping Verilog AST before simplification:\n");
|
||||
ast->dumpVlog(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
if (!defer)
|
||||
{
|
||||
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
|
||||
|
||||
if (flag_dump_ast2) {
|
||||
log("Dumping Verilog AST after simplification:\n");
|
||||
log("Dumping AST after simplification:\n");
|
||||
ast->dumpAst(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
if (flag_dump_vlog) {
|
||||
log("Dumping Verilog AST (as requested by dump_vlog option):\n");
|
||||
if (flag_dump_vlog2) {
|
||||
log("Dumping Verilog AST after simplification:\n");
|
||||
ast->dumpVlog(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
@ -955,8 +977,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
|
|||
|
||||
for (auto &attr : ast->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), ast->filename.c_str(), ast->linenum);
|
||||
log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
current_module->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
|
@ -981,6 +1002,8 @@ static AstModule* process_module(AstNode *ast, bool defer)
|
|||
ignoreThisSignalsInInitial = RTLIL::SigSpec();
|
||||
}
|
||||
|
||||
if (ast->type == AST_INTERFACE)
|
||||
current_module->set_bool_attribute("\\is_interface");
|
||||
current_module->ast = ast_before_simplify;
|
||||
current_module->nolatches = flag_nolatches;
|
||||
current_module->nomeminit = flag_nomeminit;
|
||||
|
@ -1002,13 +1025,15 @@ static AstModule* process_module(AstNode *ast, bool defer)
|
|||
}
|
||||
|
||||
// create AstModule instances for all modules in the AST tree and add them to 'design'
|
||||
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil,
|
||||
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
|
||||
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
|
||||
{
|
||||
current_ast = ast;
|
||||
flag_dump_ast1 = dump_ast1;
|
||||
flag_dump_ast2 = dump_ast2;
|
||||
flag_dump_vlog = dump_vlog;
|
||||
flag_no_dump_ptr = no_dump_ptr;
|
||||
flag_dump_vlog1 = dump_vlog1;
|
||||
flag_dump_vlog2 = dump_vlog2;
|
||||
flag_dump_rtlil = dump_rtlil;
|
||||
flag_nolatches = nolatches;
|
||||
flag_nomeminit = nomeminit;
|
||||
|
@ -1022,7 +1047,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
|
|||
log_assert(current_ast->type == AST_DESIGN);
|
||||
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)
|
||||
{
|
||||
if ((*it)->type == AST_MODULE)
|
||||
if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE)
|
||||
{
|
||||
for (auto n : design->verilog_globals)
|
||||
(*it)->children.push_back(n->clone());
|
||||
|
@ -1044,8 +1069,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
|
|||
if (design->has((*it)->str)) {
|
||||
RTLIL::Module *existing_mod = design->module((*it)->str);
|
||||
if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
|
||||
log_error("Re-definition of module `%s' at %s:%d!\n",
|
||||
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
|
||||
log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str());
|
||||
} else if (nooverwrite) {
|
||||
log("Ignoring re-definition of module `%s' at %s:%d.\n",
|
||||
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
|
||||
|
@ -1074,8 +1098,264 @@ AstModule::~AstModule()
|
|||
delete ast;
|
||||
}
|
||||
|
||||
|
||||
// An interface port with modport is specified like this:
|
||||
// <interface_name>.<modport_name>
|
||||
// This function splits the interface_name from the modport_name, and fails if it is not a valid combination
|
||||
std::pair<std::string,std::string> AST::split_modport_from_type(std::string name_type)
|
||||
{
|
||||
std::string interface_type = "";
|
||||
std::string interface_modport = "";
|
||||
size_t ndots = std::count(name_type.begin(), name_type.end(), '.');
|
||||
// Separate the interface instance name from any modports:
|
||||
if (ndots == 0) { // Does not have modport
|
||||
interface_type = name_type;
|
||||
}
|
||||
else {
|
||||
std::stringstream name_type_stream(name_type);
|
||||
std::string segment;
|
||||
std::vector<std::string> seglist;
|
||||
while(std::getline(name_type_stream, segment, '.')) {
|
||||
seglist.push_back(segment);
|
||||
}
|
||||
if (ndots == 1) { // Has modport
|
||||
interface_type = seglist[0];
|
||||
interface_modport = seglist[1];
|
||||
}
|
||||
else { // Erroneous port type
|
||||
log_error("More than two '.' in signal port type (%s)\n", name_type.c_str());
|
||||
}
|
||||
}
|
||||
return std::pair<std::string,std::string>(interface_type, interface_modport);
|
||||
|
||||
}
|
||||
|
||||
AstNode * AST::find_modport(AstNode *intf, std::string name)
|
||||
{
|
||||
for (auto &ch : intf->children)
|
||||
if (ch->type == AST_MODPORT)
|
||||
if (ch->str == name) // Modport found
|
||||
return ch;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Iterate over all wires in an interface and add them as wires in the AST module:
|
||||
void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport)
|
||||
{
|
||||
for (auto &wire_it : intfmodule->wires_){
|
||||
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
|
||||
std::string origname = log_id(wire_it.first);
|
||||
std::string newname = intfname + "." + origname;
|
||||
wire->str = newname;
|
||||
if (modport != NULL) {
|
||||
bool found_in_modport = false;
|
||||
// Search for the current wire in the wire list for the current modport
|
||||
for (auto &ch : modport->children) {
|
||||
if (ch->type == AST_MODPORTMEMBER) {
|
||||
std::string compare_name = "\\" + origname;
|
||||
if (ch->str == compare_name) { // Found signal. The modport decides whether it is input or output
|
||||
found_in_modport = true;
|
||||
wire->is_input = ch->is_input;
|
||||
wire->is_output = ch->is_output;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found_in_modport) {
|
||||
module_ast->children.push_back(wire);
|
||||
}
|
||||
else { // If not found in modport, do not create port
|
||||
delete wire;
|
||||
}
|
||||
}
|
||||
else { // If no modport, set inout
|
||||
wire->is_input = true;
|
||||
wire->is_output = true;
|
||||
module_ast->children.push_back(wire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When an interface instance is found in a module, the whole RTLIL for the module will be rederived again
|
||||
// from AST. The interface members are copied into the AST module with the prefix of the interface.
|
||||
void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces)
|
||||
{
|
||||
bool is_top = false;
|
||||
AstNode *new_ast = ast->clone();
|
||||
for (auto &intf : local_interfaces) {
|
||||
std::string intfname = intf.first.str();
|
||||
RTLIL::Module *intfmodule = intf.second;
|
||||
for (auto &wire_it : intfmodule->wires_){
|
||||
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
|
||||
std::string newname = log_id(wire_it.first);
|
||||
newname = intfname + "." + newname;
|
||||
wire->str = newname;
|
||||
new_ast->children.push_back(wire);
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *ast_before_replacing_interface_ports = new_ast->clone();
|
||||
|
||||
// Explode all interface ports. Note this will only have an effect on 'top
|
||||
// level' modules. Other sub-modules will have their interface ports
|
||||
// exploded via the derive(..) function
|
||||
for (size_t i =0; i<new_ast->children.size(); i++)
|
||||
{
|
||||
AstNode *ch2 = new_ast->children[i];
|
||||
if (ch2->type == AST_INTERFACEPORT) { // Is an interface port
|
||||
std::string name_port = ch2->str; // Name of the interface port
|
||||
if (ch2->children.size() > 0) {
|
||||
for(size_t j=0; j<ch2->children.size();j++) {
|
||||
AstNode *ch = ch2->children[j];
|
||||
if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface
|
||||
std::pair<std::string,std::string> res = split_modport_from_type(ch->str);
|
||||
std::string interface_type = res.first;
|
||||
std::string interface_modport = res.second; // Is "", if no modport
|
||||
if (design->modules_.count(interface_type) > 0) {
|
||||
// Add a cell to the module corresponding to the interface port such that
|
||||
// it can further propagated down if needed:
|
||||
AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE);
|
||||
celltype_for_intf->str = interface_type;
|
||||
AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf);
|
||||
cell_for_intf->str = name_port + "_inst_from_top_dummy";
|
||||
new_ast->children.push_back(cell_for_intf);
|
||||
|
||||
// Get all members of this non-overridden dummy interface instance:
|
||||
RTLIL::Module *intfmodule = design->modules_[interface_type]; // All interfaces should at this point in time (assuming
|
||||
// reprocess_module is called from the hierarchy pass) be
|
||||
// present in design->modules_
|
||||
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
|
||||
std::string interface_modport_compare_str = "\\" + interface_modport;
|
||||
AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport
|
||||
// Iterate over all wires in the interface and add them to the module:
|
||||
explode_interface_port(new_ast, intfmodule, name_port, modport);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The old module will be deleted. Rename and mark for deletion:
|
||||
std::string original_name = this->name.str();
|
||||
std::string changed_name = original_name + "_before_replacing_local_interfaces";
|
||||
design->rename(this, changed_name);
|
||||
this->set_bool_attribute("\\to_delete");
|
||||
|
||||
// Check if the module was the top module. If it was, we need to remove the top attribute and put it on the
|
||||
// new module.
|
||||
if (this->get_bool_attribute("\\initial_top")) {
|
||||
this->attributes.erase("\\initial_top");
|
||||
is_top = true;
|
||||
}
|
||||
|
||||
// Generate RTLIL from AST for the new module and add to the design:
|
||||
AstModule *newmod = process_module(new_ast, false, ast_before_replacing_interface_ports);
|
||||
delete(new_ast);
|
||||
design->add(newmod);
|
||||
RTLIL::Module* mod = design->module(original_name);
|
||||
if (is_top)
|
||||
mod->set_bool_attribute("\\top");
|
||||
|
||||
// Set the attribute "interfaces_replaced_in_module" so that it does not happen again.
|
||||
mod->set_bool_attribute("\\interfaces_replaced_in_module");
|
||||
}
|
||||
|
||||
// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces
|
||||
// This method is used to explode the interface when the interface is a port of the module (not instantiated inside)
|
||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail)
|
||||
{
|
||||
AstNode *new_ast = NULL;
|
||||
std::string modname = derive_common(design, parameters, &new_ast, mayfail);
|
||||
|
||||
// Since interfaces themselves may be instantiated with different parameters,
|
||||
// "modname" must also take those into account, so that unique modules
|
||||
// are derived for any variant of interface connections:
|
||||
std::string interf_info = "";
|
||||
|
||||
bool has_interfaces = false;
|
||||
for(auto &intf : interfaces) {
|
||||
interf_info += log_id(intf.second->name);
|
||||
has_interfaces = true;
|
||||
}
|
||||
|
||||
if (has_interfaces)
|
||||
modname += "$interfaces$" + interf_info;
|
||||
|
||||
|
||||
if (!design->has(modname)) {
|
||||
new_ast->str = modname;
|
||||
|
||||
// Iterate over all interfaces which are ports in this module:
|
||||
for(auto &intf : interfaces) {
|
||||
RTLIL::Module * intfmodule = intf.second;
|
||||
std::string intfname = intf.first.str();
|
||||
// Check if a modport applies for the interface port:
|
||||
AstNode *modport = NULL;
|
||||
if (modports.count(intfname) > 0) {
|
||||
std::string interface_modport = modports.at(intfname).str();
|
||||
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
|
||||
AstNode *ast_node_of_interface = ast_module_of_interface->ast;
|
||||
modport = find_modport(ast_node_of_interface, interface_modport);
|
||||
}
|
||||
// Iterate over all wires in the interface and add them to the module:
|
||||
explode_interface_port(new_ast, intfmodule, intfname, modport);
|
||||
}
|
||||
|
||||
design->add(process_module(new_ast, false));
|
||||
design->module(modname)->check();
|
||||
|
||||
RTLIL::Module* mod = design->module(modname);
|
||||
|
||||
// Now that the interfaces have been exploded, we can delete the dummy port related to every interface.
|
||||
for(auto &intf : interfaces) {
|
||||
if(mod->wires_.count(intf.first)) {
|
||||
mod->wires_.erase(intf.first);
|
||||
mod->fixup_ports();
|
||||
// We copy the cell of the interface to the sub-module such that it can further be found if it is propagated
|
||||
// down to sub-sub-modules etc.
|
||||
RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name);
|
||||
new_subcell->set_bool_attribute("\\is_interface");
|
||||
}
|
||||
else {
|
||||
log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// If any interfaces were replaced, set the attribute 'interfaces_replaced_in_module':
|
||||
if (interfaces.size() > 0) {
|
||||
mod->set_bool_attribute("\\interfaces_replaced_in_module");
|
||||
}
|
||||
|
||||
} else {
|
||||
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
|
||||
}
|
||||
|
||||
delete new_ast;
|
||||
return modname;
|
||||
}
|
||||
|
||||
// create a new parametric module (when needed) and return the name of the generated module - without support for interfaces
|
||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail)
|
||||
{
|
||||
AstNode *new_ast = NULL;
|
||||
std::string modname = derive_common(design, parameters, &new_ast, mayfail);
|
||||
|
||||
if (!design->has(modname)) {
|
||||
new_ast->str = modname;
|
||||
design->add(process_module(new_ast, false));
|
||||
design->module(modname)->check();
|
||||
} else {
|
||||
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
|
||||
}
|
||||
|
||||
delete new_ast;
|
||||
return modname;
|
||||
}
|
||||
|
||||
// create a new parametric module (when needed) and return the name of the generated module
|
||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool)
|
||||
std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool)
|
||||
{
|
||||
std::string stripped_name = name.str();
|
||||
|
||||
|
@ -1087,7 +1367,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
|
|||
current_ast = NULL;
|
||||
flag_dump_ast1 = false;
|
||||
flag_dump_ast2 = false;
|
||||
flag_dump_vlog = false;
|
||||
flag_dump_vlog1 = false;
|
||||
flag_dump_vlog2 = false;
|
||||
flag_nolatches = nolatches;
|
||||
flag_nomeminit = nomeminit;
|
||||
flag_nomem2reg = nomem2reg;
|
||||
|
@ -1147,15 +1428,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
|
|||
else
|
||||
modname = "$paramod" + stripped_name + para_info;
|
||||
|
||||
if (!design->has(modname)) {
|
||||
new_ast->str = modname;
|
||||
design->add(process_module(new_ast, false));
|
||||
design->module(modname)->check();
|
||||
} else {
|
||||
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
|
||||
}
|
||||
|
||||
delete new_ast;
|
||||
(*new_ast_out) = new_ast;
|
||||
return modname;
|
||||
}
|
||||
|
||||
|
@ -1197,4 +1471,3 @@ void AST::use_internal_line_num()
|
|||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
|
@ -142,6 +142,11 @@ namespace AST
|
|||
AST_NEGEDGE,
|
||||
AST_EDGE,
|
||||
|
||||
AST_INTERFACE,
|
||||
AST_INTERFACEPORT,
|
||||
AST_INTERFACEPORTTYPE,
|
||||
AST_MODPORT,
|
||||
AST_MODPORTMEMBER,
|
||||
AST_PACKAGE
|
||||
};
|
||||
|
||||
|
@ -168,7 +173,7 @@ namespace AST
|
|||
// node content - most of it is unused in most node types
|
||||
std::string str;
|
||||
std::vector<RTLIL::State> bits;
|
||||
bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped;
|
||||
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked;
|
||||
int port_id, range_left, range_right;
|
||||
uint32_t integer;
|
||||
double realvalue;
|
||||
|
@ -209,6 +214,8 @@ namespace AST
|
|||
MEM2REG_FL_SET_ASYNC = 0x00000800,
|
||||
MEM2REG_FL_EQ2 = 0x00001000,
|
||||
MEM2REG_FL_CMPLX_LHS = 0x00002000,
|
||||
MEM2REG_FL_CONST_LHS = 0x00004000,
|
||||
MEM2REG_FL_VAR_LHS = 0x00008000,
|
||||
|
||||
/* proc flags */
|
||||
MEM2REG_FL_EQ1 = 0x01000000,
|
||||
|
@ -232,6 +239,7 @@ namespace AST
|
|||
bool has_const_only_constructs(bool &recommend_const_eval);
|
||||
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
|
||||
AstNode *eval_const_function(AstNode *fcall);
|
||||
bool is_simple_const_expr();
|
||||
|
||||
// create a human-readable text representation of the AST (for debugging)
|
||||
void dumpAst(FILE *f, std::string indent) const;
|
||||
|
@ -274,7 +282,7 @@ namespace AST
|
|||
};
|
||||
|
||||
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
|
||||
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
|
||||
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
|
||||
bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
|
||||
|
||||
// parametric modules are supported directly by the AST library
|
||||
|
@ -282,9 +290,12 @@ namespace AST
|
|||
struct AstModule : RTLIL::Module {
|
||||
AstNode *ast;
|
||||
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
|
||||
virtual ~AstModule();
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail);
|
||||
virtual RTLIL::Module *clone() const;
|
||||
~AstModule() YS_OVERRIDE;
|
||||
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
|
||||
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
|
||||
std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail);
|
||||
void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;
|
||||
RTLIL::Module *clone() const YS_OVERRIDE;
|
||||
};
|
||||
|
||||
// this must be set by the language frontend before parsing the sources
|
||||
|
@ -300,12 +311,17 @@ namespace AST
|
|||
|
||||
// call a DPI function
|
||||
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
|
||||
|
||||
// Helper functions related to handling SystemVerilog interfaces
|
||||
std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
|
||||
AstNode * find_modport(AstNode *intf, std::string name);
|
||||
void explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport);
|
||||
}
|
||||
|
||||
namespace AST_INTERNAL
|
||||
{
|
||||
// internal state variables
|
||||
extern bool flag_dump_ast1, flag_dump_ast2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
||||
extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
||||
extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
||||
extern AST::AstNode *current_ast, *current_ast_mod;
|
||||
extern std::map<std::string, AST::AstNode*> current_scope;
|
||||
|
|
|
@ -55,8 +55,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
|
|||
if (gen_attributes)
|
||||
for (auto &attr : that->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), that->filename.c_str(), that->linenum);
|
||||
log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
cell->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
|
@ -89,8 +88,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
|
|||
if (that != NULL)
|
||||
for (auto &attr : that->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), that->filename.c_str(), that->linenum);
|
||||
log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
cell->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
|
@ -117,8 +115,7 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi
|
|||
|
||||
for (auto &attr : that->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), that->filename.c_str(), that->linenum);
|
||||
log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
cell->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
|
@ -152,8 +149,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
|
|||
|
||||
for (auto &attr : that->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), that->filename.c_str(), that->linenum);
|
||||
log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
cell->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
|
@ -207,8 +203,8 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++);
|
||||
for (auto &attr : always->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), always->filename.c_str(), always->linenum);
|
||||
log_file_error(always->filename, always->linenum, "Attribute `%s' with non-constant value!\n",
|
||||
attr.first.c_str());
|
||||
proc->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
current_module->processes[proc->name] = proc;
|
||||
|
@ -238,7 +234,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
if (found_anyedge_syncs) {
|
||||
if (found_global_syncs)
|
||||
log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum);
|
||||
log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n");
|
||||
log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum);
|
||||
log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n");
|
||||
log("use of @* instead of @(...) for better match of synthesis and simulation.\n");
|
||||
|
@ -253,12 +249,12 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
continue;
|
||||
found_clocked_sync = true;
|
||||
if (found_global_syncs || found_anyedge_syncs)
|
||||
log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum);
|
||||
log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n");
|
||||
RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
|
||||
syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
|
||||
syncrule->signal = child->children[0]->genRTLIL();
|
||||
if (GetSize(syncrule->signal) != 1)
|
||||
log_error("Found posedge/negedge event on a signal that is not 1 bit wide at %s:%d!\n", always->filename.c_str(), always->linenum);
|
||||
log_file_error(always->filename, always->linenum, "Found posedge/negedge event on a signal that is not 1 bit wide!\n");
|
||||
addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
|
||||
proc->syncs.push_back(syncrule);
|
||||
}
|
||||
|
@ -480,8 +476,7 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
|
||||
for (auto &attr : ast->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), ast->filename.c_str(), ast->linenum);
|
||||
log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
sw->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
|
@ -530,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
}
|
||||
|
||||
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
|
||||
#if 0
|
||||
// this is a valid transformation, but as optimization it is premature.
|
||||
// better: add a default case that assigns 'x' to everything, and let later
|
||||
// optimizations take care of the rest
|
||||
last_generated_case->compare.clear();
|
||||
#else
|
||||
default_case = new RTLIL::CaseRule;
|
||||
addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
|
||||
sw->cases.push_back(default_case);
|
||||
#endif
|
||||
} else {
|
||||
if (default_case == NULL) {
|
||||
default_case = new RTLIL::CaseRule;
|
||||
|
@ -549,12 +553,16 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
break;
|
||||
|
||||
case AST_WIRE:
|
||||
log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
|
||||
log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n");
|
||||
break;
|
||||
|
||||
case AST_ASSIGN:
|
||||
log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n");
|
||||
break;
|
||||
|
||||
case AST_PARAMETER:
|
||||
case AST_LOCALPARAM:
|
||||
log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
|
||||
log_file_error(ast->filename, ast->linenum, "Found parameter declaration in block without label!\n");
|
||||
break;
|
||||
|
||||
case AST_NONE:
|
||||
|
@ -602,7 +610,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (id_ast == NULL && current_scope.count(str))
|
||||
id_ast = current_scope.at(str);
|
||||
if (!id_ast)
|
||||
log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str());
|
||||
if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) {
|
||||
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
|
||||
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
|
||||
|
@ -612,7 +620,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (id_ast->children[0]->type == AST_CONSTANT)
|
||||
this_width = id_ast->children[0]->bits.size();
|
||||
else
|
||||
log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Failed to detect width for parameter %s!\n", str.c_str());
|
||||
if (children.size() != 0)
|
||||
range = children[0];
|
||||
} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) {
|
||||
|
@ -624,7 +632,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
// log("---\n");
|
||||
// id_ast->dumpAst(NULL, "decl> ");
|
||||
// dumpAst(NULL, "ref> ");
|
||||
log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Failed to detect width of signal access `%s'!\n", str.c_str());
|
||||
}
|
||||
} else {
|
||||
this_width = id_ast->range_left - id_ast->range_right + 1;
|
||||
|
@ -635,10 +643,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
this_width = 32;
|
||||
} else if (id_ast->type == AST_MEMORY) {
|
||||
if (!id_ast->children[0]->range_valid)
|
||||
log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
|
||||
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
|
||||
} else
|
||||
log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
|
||||
if (range) {
|
||||
if (range->children.size() == 1)
|
||||
this_width = 1;
|
||||
|
@ -648,9 +656,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
|
||||
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
|
||||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
|
||||
log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
|
||||
this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
|
||||
delete left_at_zero_ast;
|
||||
delete right_at_zero_ast;
|
||||
} else
|
||||
|
@ -665,7 +672,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
case AST_TO_BITS:
|
||||
while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { }
|
||||
if (children[0]->type != AST_CONSTANT)
|
||||
log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Left operand of tobits expression is not constant!\n");
|
||||
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
|
||||
width_hint = max(width_hint, children[0]->bitsAsConst().as_int());
|
||||
break;
|
||||
|
@ -693,7 +700,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
case AST_REPLICATE:
|
||||
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
|
||||
if (children[0]->type != AST_CONSTANT)
|
||||
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n");
|
||||
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
|
||||
width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
|
||||
sign_hint = false;
|
||||
|
@ -767,7 +774,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (!id2ast->is_signed)
|
||||
sign_hint = false;
|
||||
if (!id2ast->children[0]->range_valid)
|
||||
log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
|
||||
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
|
||||
width_hint = max(width_hint, this_width);
|
||||
break;
|
||||
|
@ -777,8 +784,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (GetSize(children) == 1) {
|
||||
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
|
||||
if (children[0]->type != AST_CONSTANT)
|
||||
log_error("System function %s called with non-const argument at %s:%d!\n",
|
||||
RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
|
||||
RTLIL::unescape_id(str).c_str());
|
||||
width_hint = max(width_hint, int(children[0]->asInt(true)));
|
||||
}
|
||||
break;
|
||||
|
@ -798,9 +805,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
// everything should have been handled above -> print error if not.
|
||||
default:
|
||||
for (auto f : log_files)
|
||||
current_ast->dumpAst(f, "verilog-ast> ");
|
||||
log_error("Don't know how to detect sign and width for %s node at %s:%d!\n",
|
||||
type2str(type).c_str(), filename.c_str(), linenum);
|
||||
current_ast_mod->dumpAst(f, "verilog-ast> ");
|
||||
log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
|
||||
}
|
||||
|
||||
if (*found_real)
|
||||
|
@ -853,6 +859,35 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
case AST_GENIF:
|
||||
case AST_GENCASE:
|
||||
case AST_PACKAGE:
|
||||
case AST_MODPORT:
|
||||
case AST_MODPORTMEMBER:
|
||||
break;
|
||||
case AST_INTERFACEPORT: {
|
||||
// If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
|
||||
// This is used by the hierarchy pass to know when it can replace interface connection with the individual
|
||||
// signals.
|
||||
RTLIL::Wire *wire = current_module->addWire(str, 1);
|
||||
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
wire->start_offset = 0;
|
||||
wire->port_id = port_id;
|
||||
wire->port_input = true;
|
||||
wire->port_output = true;
|
||||
wire->set_bool_attribute("\\is_interface");
|
||||
if (children.size() > 0) {
|
||||
for(size_t i=0; i<children.size();i++) {
|
||||
if(children[i]->type == AST_INTERFACEPORTTYPE) {
|
||||
std::pair<std::string,std::string> res = AST::split_modport_from_type(children[i]->str);
|
||||
wire->attributes["\\interface_type"] = res.first;
|
||||
if (res.second != "")
|
||||
wire->attributes["\\interface_modport"] = res.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
wire->upto = 0;
|
||||
}
|
||||
break;
|
||||
case AST_INTERFACEPORTTYPE:
|
||||
break;
|
||||
|
||||
// remember the parameter, needed for example in techmap
|
||||
|
@ -863,11 +898,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
// create an RTLIL::Wire for an AST_WIRE node
|
||||
case AST_WIRE: {
|
||||
if (current_module->wires_.count(str) != 0)
|
||||
log_error("Re-definition of signal `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", str.c_str());
|
||||
if (!range_valid)
|
||||
log_error("Signal `%s' with non-constant width at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());
|
||||
|
||||
log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
|
||||
|
||||
|
@ -881,8 +914,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
for (auto &attr : attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
wire->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
}
|
||||
|
@ -891,16 +923,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
// create an RTLIL::Memory for an AST_MEMORY node
|
||||
case AST_MEMORY: {
|
||||
if (current_module->memories.count(str) != 0)
|
||||
log_error("Re-definition of memory `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", str.c_str());
|
||||
|
||||
log_assert(children.size() >= 2);
|
||||
log_assert(children[0]->type == AST_RANGE);
|
||||
log_assert(children[1]->type == AST_RANGE);
|
||||
|
||||
if (!children[0]->range_valid || !children[1]->range_valid)
|
||||
log_error("Memory `%s' with non-constant width or size at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", str.c_str());
|
||||
|
||||
RTLIL::Memory *memory = new RTLIL::Memory;
|
||||
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
|
@ -917,8 +947,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
for (auto &attr : attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
memory->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
}
|
||||
|
@ -926,19 +955,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
// simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
|
||||
case AST_CONSTANT:
|
||||
case AST_REALVALUE:
|
||||
{
|
||||
if (width_hint < 0)
|
||||
detectSignWidth(width_hint, sign_hint);
|
||||
|
||||
is_signed = sign_hint;
|
||||
return RTLIL::SigSpec(bitsAsConst());
|
||||
}
|
||||
|
||||
case AST_REALVALUE:
|
||||
{
|
||||
if (type == AST_CONSTANT)
|
||||
return RTLIL::SigSpec(bitsAsConst());
|
||||
|
||||
RTLIL::SigSpec sig = realAsConst(width_hint);
|
||||
log_warning("converting real value %e to binary %s at %s:%d.\n",
|
||||
realvalue, log_signal(sig), filename.c_str(), linenum);
|
||||
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
|
||||
return sig;
|
||||
}
|
||||
|
||||
|
@ -949,6 +976,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
{
|
||||
RTLIL::Wire *wire = NULL;
|
||||
RTLIL::SigChunk chunk;
|
||||
bool is_interface = false;
|
||||
|
||||
int add_undef_bits_msb = 0;
|
||||
int add_undef_bits_lsb = 0;
|
||||
|
@ -958,25 +986,48 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
wire->name = str;
|
||||
if (flag_autowire)
|
||||
log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_warning(filename, linenum, "Identifier `%s' is implicitly declared.\n", str.c_str());
|
||||
else
|
||||
log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
|
||||
}
|
||||
else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {
|
||||
if (id2ast->children[0]->type != AST_CONSTANT)
|
||||
log_error("Parameter %s does not evaluate to constant value at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str());
|
||||
chunk = RTLIL::Const(id2ast->children[0]->bits);
|
||||
goto use_const_chunk;
|
||||
}
|
||||
else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE &&
|
||||
id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0)
|
||||
log_error("Identifier `%s' doesn't map to any signal at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) {
|
||||
RTLIL::Wire *current_wire = current_module->wire(str);
|
||||
if (current_wire->get_bool_attribute("\\is_interface"))
|
||||
is_interface = true;
|
||||
// Ignore
|
||||
}
|
||||
// If an identifier is found that is not already known, assume that it is an interface:
|
||||
else if (1) { // FIXME: Check if sv_mode first?
|
||||
is_interface = true;
|
||||
}
|
||||
else {
|
||||
log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", str.c_str());
|
||||
}
|
||||
|
||||
if (id2ast->type == AST_MEMORY)
|
||||
log_error("Identifier `%s' does map to an unexpanded memory at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", str.c_str());
|
||||
|
||||
// If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface'
|
||||
// This makes it possible for the hierarchy pass to see what are interface connections and then replace them
|
||||
// with the individual signals:
|
||||
if (is_interface) {
|
||||
RTLIL::Wire *dummy_wire;
|
||||
std::string dummy_wire_name = "$dummywireforinterface" + str;
|
||||
if (current_module->wires_.count(dummy_wire_name))
|
||||
dummy_wire = current_module->wires_[dummy_wire_name];
|
||||
else {
|
||||
dummy_wire = current_module->addWire(dummy_wire_name);
|
||||
dummy_wire->set_bool_attribute("\\is_interface");
|
||||
}
|
||||
RTLIL::SigSpec tmp = RTLIL::SigSpec(dummy_wire);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
wire = current_module->wires_[str];
|
||||
chunk.wire = wire;
|
||||
|
@ -985,7 +1036,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
|
||||
use_const_chunk:
|
||||
if (children.size() != 0) {
|
||||
log_assert(children[0]->type == AST_RANGE);
|
||||
if (children[0]->type != AST_RANGE)
|
||||
log_file_error(filename, linenum, "Single range expected.\n");
|
||||
int source_width = id2ast->range_left - id2ast->range_right + 1;
|
||||
int source_offset = id2ast->range_right;
|
||||
if (!children[0]->range_valid) {
|
||||
|
@ -994,9 +1046,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
|
||||
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
|
||||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
|
||||
log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
|
||||
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
|
||||
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
|
||||
children[0]->children[1]->clone() : children[0]->children[0]->clone());
|
||||
fake_ast->children[0]->delete_children();
|
||||
|
@ -1023,11 +1074,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);
|
||||
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
|
||||
if (chunk.width == 1)
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
|
||||
str.c_str());
|
||||
else
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum, chunk.width);
|
||||
log_file_warning(filename, linenum, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
|
||||
children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
|
||||
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
|
||||
} else {
|
||||
if (chunk.width + chunk.offset > source_width) {
|
||||
|
@ -1040,11 +1091,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
chunk.offset += add_undef_bits_lsb;
|
||||
}
|
||||
if (add_undef_bits_lsb)
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
|
||||
log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
|
||||
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
|
||||
if (add_undef_bits_msb)
|
||||
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
|
||||
str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
|
||||
log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
|
||||
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1083,7 +1134,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
RTLIL::SigSpec left = children[0]->genRTLIL();
|
||||
RTLIL::SigSpec right = children[1]->genRTLIL();
|
||||
if (!left.is_fully_const())
|
||||
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n");
|
||||
int count = left.as_int();
|
||||
RTLIL::SigSpec sig;
|
||||
for (int i = 0; i < count; i++)
|
||||
|
@ -1300,6 +1351,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
|
||||
cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
|
||||
|
||||
if (!sign_hint)
|
||||
is_signed = false;
|
||||
|
||||
return RTLIL::SigSpec(wire);
|
||||
}
|
||||
|
||||
|
@ -1319,7 +1373,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
int num_words = 1;
|
||||
if (type == AST_MEMINIT) {
|
||||
if (children[2]->type != AST_CONSTANT)
|
||||
log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Memory init with non-constant word count!\n");
|
||||
num_words = int(children[2]->asInt(false));
|
||||
cell->parameters["\\WORDS"] = RTLIL::Const(num_words);
|
||||
}
|
||||
|
@ -1368,16 +1422,21 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
if (GetSize(en) != 1)
|
||||
en = current_module->ReduceBool(NEW_ID, en);
|
||||
|
||||
IdString cellname;
|
||||
if (str.empty()) {
|
||||
std::stringstream sstr;
|
||||
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||
cellname = sstr.str();
|
||||
} else {
|
||||
cellname = str;
|
||||
}
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype);
|
||||
RTLIL::Cell *cell = current_module->addCell(cellname, celltype);
|
||||
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
|
||||
for (auto &attr : attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
cell->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
|
||||
|
@ -1398,9 +1457,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
new_left.append(left[i]);
|
||||
new_right.append(right[i]);
|
||||
}
|
||||
log_warning("Ignoring assignment to constant bits at %s:%d:\n"
|
||||
log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n"
|
||||
" old assignment: %s = %s\n new assignment: %s = %s.\n",
|
||||
filename.c_str(), linenum, log_signal(left), log_signal(right),
|
||||
log_signal(left), log_signal(right),
|
||||
log_signal(new_left), log_signal(new_right));
|
||||
left = new_left;
|
||||
right = new_right;
|
||||
|
@ -1415,11 +1474,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
int port_counter = 0, para_counter = 0;
|
||||
|
||||
if (current_module->count_id(str) != 0)
|
||||
log_error("Re-definition of cell `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Re-definition of cell `%s'!\n", str.c_str());
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(str, "");
|
||||
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
// Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass
|
||||
cell->set_bool_attribute("\\module_not_derived");
|
||||
|
||||
for (auto it = children.begin(); it != children.end(); it++) {
|
||||
AstNode *child = *it;
|
||||
|
@ -1432,16 +1492,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
if (child->type == AST_PARASET) {
|
||||
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
|
||||
if (child->children[0]->type == AST_REALVALUE) {
|
||||
log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n",
|
||||
log_id(cell), log_id(paraname), child->children[0]->realvalue,
|
||||
filename.c_str(), linenum);
|
||||
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
|
||||
log_id(cell), log_id(paraname), child->children[0]->realvalue);
|
||||
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
|
||||
strnode->cloneInto(child->children[0]);
|
||||
delete strnode;
|
||||
}
|
||||
if (child->children[0]->type != AST_CONSTANT)
|
||||
log_error("Parameter %s.%s with non-constant value at %s:%d!\n",
|
||||
log_id(cell), log_id(paraname), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
|
||||
log_id(cell), log_id(paraname));
|
||||
cell->parameters[paraname] = child->children[0]->asParaConst();
|
||||
continue;
|
||||
}
|
||||
|
@ -1462,8 +1521,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
for (auto &attr : attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
|
||||
cell->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
}
|
||||
|
@ -1490,19 +1548,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
int width = width_hint;
|
||||
|
||||
if (GetSize(children) > 1)
|
||||
log_error("System function %s got %d arguments, expected 1 or 0 at %s:%d.\n",
|
||||
RTLIL::unescape_id(str).c_str(), GetSize(children), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n",
|
||||
RTLIL::unescape_id(str).c_str(), GetSize(children));
|
||||
|
||||
if (GetSize(children) == 1) {
|
||||
if (children[0]->type != AST_CONSTANT)
|
||||
log_error("System function %s called with non-const argument at %s:%d!\n",
|
||||
RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
|
||||
RTLIL::unescape_id(str).c_str());
|
||||
width = children[0]->asInt(true);
|
||||
}
|
||||
|
||||
if (width <= 0)
|
||||
log_error("Failed to detect width of %s at %s:%d!\n",
|
||||
RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Failed to detect width of %s!\n", RTLIL::unescape_id(str).c_str());
|
||||
|
||||
Cell *cell = current_module->addCell(myid, str.substr(1));
|
||||
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||
|
@ -1511,7 +1568,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
if (attributes.count("\\reg")) {
|
||||
auto &attr = attributes.at("\\reg");
|
||||
if (attr->type != AST_CONSTANT)
|
||||
log_error("Attribute `reg' with non-constant value at %s:%d!\n", filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Attribute `reg' with non-constant value!\n");
|
||||
cell->attributes["\\reg"] = attr->asAttrConst();
|
||||
}
|
||||
|
||||
|
@ -1527,10 +1584,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
// everything should have been handled above -> print error if not.
|
||||
default:
|
||||
for (auto f : log_files)
|
||||
current_ast->dumpAst(f, "verilog-ast> ");
|
||||
current_ast_mod->dumpAst(f, "verilog-ast> ");
|
||||
type_name = type2str(type);
|
||||
log_error("Don't know how to generate RTLIL code for %s node at %s:%d!\n",
|
||||
type_name.c_str(), filename.c_str(), linenum);
|
||||
log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str());
|
||||
}
|
||||
|
||||
return RTLIL::SigSpec();
|
||||
|
@ -1560,4 +1616,3 @@ RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL
|
|||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -83,7 +83,9 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
RTLIL::Module *module = nullptr;
|
||||
RTLIL::Const *lutptr = NULL;
|
||||
RTLIL::Cell *sopcell = NULL;
|
||||
RTLIL::Cell *lastcell = nullptr;
|
||||
RTLIL::State lut_default_state = RTLIL::State::Sx;
|
||||
std::string err_reason;
|
||||
int blif_maxnum = 0, sopmode = -1;
|
||||
|
||||
auto blif_wire = [&](const std::string &wire_name) -> Wire*
|
||||
|
@ -159,6 +161,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
if (module != nullptr)
|
||||
goto error;
|
||||
module = new RTLIL::Module;
|
||||
lastcell = nullptr;
|
||||
module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n"));
|
||||
obj_attributes = &module->attributes;
|
||||
obj_parameters = nullptr;
|
||||
|
@ -232,6 +235,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
}
|
||||
|
||||
module = nullptr;
|
||||
lastcell = nullptr;
|
||||
obj_attributes = nullptr;
|
||||
obj_parameters = nullptr;
|
||||
continue;
|
||||
|
@ -264,6 +268,22 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, ".cname"))
|
||||
{
|
||||
char *p = strtok(NULL, " \t\r\n");
|
||||
if (p == NULL)
|
||||
goto error;
|
||||
|
||||
if(lastcell == nullptr || module == nullptr)
|
||||
{
|
||||
err_reason = stringf("No primitive object to attach .cname %s.", p);
|
||||
goto error_with_reason;
|
||||
}
|
||||
|
||||
module->rename(lastcell, p);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) {
|
||||
char *n = strtok(NULL, " \t\r\n");
|
||||
char *v = strtok(NULL, "\r\n");
|
||||
|
@ -281,12 +301,16 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0;
|
||||
}
|
||||
if (!strcmp(cmd, ".attr")) {
|
||||
if (obj_attributes == nullptr)
|
||||
goto error;
|
||||
if (obj_attributes == nullptr) {
|
||||
err_reason = stringf("No object to attach .attr too.");
|
||||
goto error_with_reason;
|
||||
}
|
||||
(*obj_attributes)[id_n] = const_v;
|
||||
} else {
|
||||
if (obj_parameters == nullptr)
|
||||
goto error;
|
||||
if (obj_parameters == nullptr) {
|
||||
err_reason = stringf("No object to attach .param too.");
|
||||
goto error_with_reason;
|
||||
}
|
||||
(*obj_parameters)[id_n] = const_v;
|
||||
}
|
||||
continue;
|
||||
|
@ -331,6 +355,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
}
|
||||
}
|
||||
|
||||
lastcell = cell;
|
||||
obj_attributes = &cell->attributes;
|
||||
obj_parameters = &cell->parameters;
|
||||
continue;
|
||||
|
@ -383,6 +408,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
cell->setPort(it.first, sig);
|
||||
}
|
||||
|
||||
lastcell = cell;
|
||||
obj_attributes = &cell->attributes;
|
||||
obj_parameters = &cell->parameters;
|
||||
continue;
|
||||
|
@ -391,7 +417,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
obj_attributes = nullptr;
|
||||
obj_parameters = nullptr;
|
||||
|
||||
if (!strcmp(cmd, ".barbuf"))
|
||||
if (!strcmp(cmd, ".barbuf") || !strcmp(cmd, ".conn"))
|
||||
{
|
||||
char *p = strtok(NULL, " \t\r\n");
|
||||
if (p == NULL)
|
||||
|
@ -459,6 +485,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
sopcell->setPort("\\A", input_sig);
|
||||
sopcell->setPort("\\Y", output_sig);
|
||||
sopmode = -1;
|
||||
lastcell = sopcell;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -469,6 +496,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
cell->setPort("\\Y", output_sig);
|
||||
lutptr = &cell->parameters.at("\\LUT");
|
||||
lut_default_state = RTLIL::State::Sx;
|
||||
lastcell = cell;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -546,15 +574,17 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
|||
|
||||
error:
|
||||
log_error("Syntax error in line %d!\n", line_count);
|
||||
error_with_reason:
|
||||
log_error("Syntax error in line %d: %s\n", line_count, err_reason.c_str());
|
||||
}
|
||||
|
||||
struct BlifFrontend : public Frontend {
|
||||
BlifFrontend() : Frontend("blif", "read BLIF file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" read_blif [filename]\n");
|
||||
log(" read_blif [options] [filename]\n");
|
||||
log("\n");
|
||||
log("Load modules from a BLIF file into the current design.\n");
|
||||
log("\n");
|
||||
|
@ -566,7 +596,7 @@ struct BlifFrontend : public Frontend {
|
|||
log(" multi-bit port 'name'.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool sop_mode = false;
|
||||
bool wideports = false;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ilang_lexer.cc
|
||||
ilang_parser.output
|
||||
ilang_parser.tab.cc
|
||||
ilang_parser.tab.h
|
||||
ilang_parser.tab.hh
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
|
||||
GENFILES += frontends/ilang/ilang_parser.tab.cc
|
||||
GENFILES += frontends/ilang/ilang_parser.tab.h
|
||||
GENFILES += frontends/ilang/ilang_parser.tab.hh
|
||||
GENFILES += frontends/ilang/ilang_parser.output
|
||||
GENFILES += frontends/ilang/ilang_lexer.cc
|
||||
|
||||
frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
$(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser $<
|
||||
$(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
|
||||
$(P) $(BISON) -o $@ -d -r all -b frontends/ilang/ilang_parser $<
|
||||
|
||||
frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
|
||||
frontends/ilang/ilang_parser.tab.hh: frontends/ilang/ilang_parser.tab.cc
|
||||
|
||||
frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
|
|
|
@ -35,7 +35,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
struct IlangFrontend : public Frontend {
|
||||
IlangFrontend() : Frontend("ilang", "read modules from ilang file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -44,11 +44,39 @@ struct IlangFrontend : public Frontend {
|
|||
log("Load modules from an ilang file to the current design. (ilang is a text\n");
|
||||
log("representation of a design in yosys's internal format.)\n");
|
||||
log("\n");
|
||||
log(" -nooverwrite\n");
|
||||
log(" ignore re-definitions of modules. (the default behavior is to\n");
|
||||
log(" create an error message if the existing module is not a blackbox\n");
|
||||
log(" module, and overwrite the existing module if it is a blackbox module.)\n");
|
||||
log("\n");
|
||||
log(" -overwrite\n");
|
||||
log(" overwrite existing modules with the same name\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
ILANG_FRONTEND::flag_nooverwrite = false;
|
||||
ILANG_FRONTEND::flag_overwrite = false;
|
||||
|
||||
log_header(design, "Executing ILANG frontend.\n");
|
||||
extra_args(f, filename, args, 1);
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-nooverwrite") {
|
||||
ILANG_FRONTEND::flag_nooverwrite = true;
|
||||
ILANG_FRONTEND::flag_overwrite = false;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-overwrite") {
|
||||
ILANG_FRONTEND::flag_nooverwrite = false;
|
||||
ILANG_FRONTEND::flag_overwrite = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(f, filename, args, argidx);
|
||||
|
||||
log("Input filename: %s\n", filename.c_str());
|
||||
|
||||
ILANG_FRONTEND::lexin = f;
|
||||
|
|
|
@ -32,6 +32,8 @@ YOSYS_NAMESPACE_BEGIN
|
|||
namespace ILANG_FRONTEND {
|
||||
extern std::istream *lexin;
|
||||
extern RTLIL::Design *current_design;
|
||||
extern bool flag_nooverwrite;
|
||||
extern bool flag_overwrite;
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#endif
|
||||
|
||||
#include "frontends/ilang/ilang_frontend.h"
|
||||
#include "ilang_parser.tab.h"
|
||||
#include "ilang_parser.tab.hh"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ namespace ILANG_FRONTEND {
|
|||
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
|
||||
std::vector<RTLIL::CaseRule*> case_stack;
|
||||
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
|
||||
bool flag_nooverwrite, flag_overwrite;
|
||||
bool delete_current_module;
|
||||
}
|
||||
using namespace ILANG_FRONTEND;
|
||||
YOSYS_NAMESPACE_END
|
||||
|
@ -93,11 +95,26 @@ design:
|
|||
|
||||
module:
|
||||
TOK_MODULE TOK_ID EOL {
|
||||
if (current_design->has($2))
|
||||
delete_current_module = false;
|
||||
if (current_design->has($2)) {
|
||||
RTLIL::Module *existing_mod = current_design->module($2);
|
||||
if (!flag_overwrite && attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()) {
|
||||
log("Ignoring blackbox re-definition of module %s.\n", $2);
|
||||
delete_current_module = true;
|
||||
} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
|
||||
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
|
||||
} else if (flag_nooverwrite) {
|
||||
log("Ignoring re-definition of module %s.\n", $2);
|
||||
delete_current_module = true;
|
||||
} else {
|
||||
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2);
|
||||
current_design->remove(existing_mod);
|
||||
}
|
||||
}
|
||||
current_module = new RTLIL::Module;
|
||||
current_module->name = $2;
|
||||
current_module->attributes = attrbuf;
|
||||
if (!delete_current_module)
|
||||
current_design->add(current_module);
|
||||
attrbuf.clear();
|
||||
free($2);
|
||||
|
@ -105,6 +122,9 @@ module:
|
|||
if (attrbuf.size() != 0)
|
||||
rtlil_frontend_ilang_yyerror("dangling attribute");
|
||||
current_module->fixup_ports();
|
||||
if (delete_current_module)
|
||||
delete current_module;
|
||||
current_module = nullptr;
|
||||
} EOL;
|
||||
|
||||
module_body:
|
||||
|
@ -387,17 +407,13 @@ sigspec:
|
|||
$$ = new RTLIL::SigSpec(current_module->wires_[$1]);
|
||||
free($1);
|
||||
} |
|
||||
TOK_ID '[' TOK_INT ']' {
|
||||
if (current_module->wires_.count($1) == 0)
|
||||
rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
|
||||
$$ = new RTLIL::SigSpec(current_module->wires_[$1], $3);
|
||||
free($1);
|
||||
sigspec '[' TOK_INT ']' {
|
||||
$$ = new RTLIL::SigSpec($1->extract($3));
|
||||
delete $1;
|
||||
} |
|
||||
TOK_ID '[' TOK_INT ':' TOK_INT ']' {
|
||||
if (current_module->wires_.count($1) == 0)
|
||||
rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
|
||||
$$ = new RTLIL::SigSpec(current_module->wires_[$1], $5, $3 - $5 + 1);
|
||||
free($1);
|
||||
sigspec '[' TOK_INT ':' TOK_INT ']' {
|
||||
$$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1));
|
||||
delete $1;
|
||||
} |
|
||||
'{' sigspec_list '}' {
|
||||
$$ = $2;
|
||||
|
|
|
@ -494,7 +494,7 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
|||
|
||||
struct JsonFrontend : public Frontend {
|
||||
JsonFrontend() : Frontend("json", "read JSON file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -504,7 +504,7 @@ struct JsonFrontend : public Frontend {
|
|||
log("for a description of the file format.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log_header(design, "Executing JSON frontend.\n");
|
||||
|
||||
|
|
|
@ -36,7 +36,8 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&
|
|||
|
||||
int id_len = 0;
|
||||
while (('a' <= expr[id_len] && expr[id_len] <= 'z') || ('A' <= expr[id_len] && expr[id_len] <= 'Z') ||
|
||||
('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' || expr[id_len] == '_') id_len++;
|
||||
('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' ||
|
||||
expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++;
|
||||
|
||||
if (id_len == 0)
|
||||
log_error("Expected identifier at `%s'.\n", expr);
|
||||
|
@ -452,7 +453,7 @@ void parse_type_map(std::map<std::string, std::tuple<int, int, bool>> &type_map,
|
|||
|
||||
struct LibertyFrontend : public Frontend {
|
||||
LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -485,7 +486,7 @@ struct LibertyFrontend : public Frontend {
|
|||
log(" set the specified attribute (to the value 1) on all loaded modules\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool flag_lib = false;
|
||||
bool flag_nooverwrite = false;
|
||||
|
@ -615,7 +616,7 @@ struct LibertyFrontend : public Frontend {
|
|||
LibertyAst *bus_type_node = node->find("bus_type");
|
||||
|
||||
if (!bus_type_node || !type_map.count(bus_type_node->value))
|
||||
log_error("Unkown or unsupported type for bus interface %s on cell %s.\n",
|
||||
log_error("Unknown or unsupported type for bus interface %s on cell %s.\n",
|
||||
node->args.at(0).c_str(), log_id(cell_name));
|
||||
|
||||
int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
|
||||
|
@ -634,9 +635,12 @@ struct LibertyFrontend : public Frontend {
|
|||
}
|
||||
}
|
||||
|
||||
if (!flag_lib)
|
||||
{
|
||||
// some liberty files do not put ff/latch at the beginning of a cell
|
||||
// try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes
|
||||
for (auto node : cell->children)
|
||||
{
|
||||
if (!flag_lib) {
|
||||
if (node->id == "ff" && node->args.size() == 2)
|
||||
create_ff(module, node);
|
||||
if (node->id == "latch" && node->args.size() == 2)
|
||||
|
@ -645,7 +649,10 @@ struct LibertyFrontend : public Frontend {
|
|||
goto skip_cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto node : cell->children)
|
||||
{
|
||||
if (node->id == "pin" && node->args.size() == 1)
|
||||
{
|
||||
LibertyAst *dir = node->find("direction");
|
||||
|
|
|
@ -4,35 +4,6 @@ This directory contains Verific bindings for Yosys.
|
|||
See http://www.verific.com/ for details.
|
||||
|
||||
|
||||
Building Yosys with the 32 bit Verific eval library on amd64:
|
||||
=============================================================
|
||||
|
||||
1.) Use a Makefile.conf like the following one:
|
||||
|
||||
--snip--
|
||||
CONFIG := gcc
|
||||
ENABLE_TCL := 0
|
||||
ENABLE_PLUGINS := 0
|
||||
ENABLE_VERIFIC := 1
|
||||
CXXFLAGS += -m32
|
||||
LDFLAGS += -m32
|
||||
VERIFIC_DIR = /usr/local/src/verific_lib_eval
|
||||
--snap--
|
||||
|
||||
|
||||
2.) Install the necessary multilib packages
|
||||
|
||||
Hint: On debian/ubuntu the multilib packages have names such as
|
||||
libreadline-dev:i386 or lib32readline6-dev, depending on the
|
||||
exact version of debian/ubuntu you are working with.
|
||||
|
||||
|
||||
3.) Build and test
|
||||
|
||||
make -j8
|
||||
./yosys -p 'verific -sv frontends/verific/example.sv; verific -import top'
|
||||
|
||||
|
||||
Verific Features that should be enabled in your Verific library
|
||||
===============================================================
|
||||
|
||||
|
@ -50,7 +21,7 @@ Then run in the following command in this directory:
|
|||
|
||||
sby -f example.sby
|
||||
|
||||
This will generate approximately one page of text outpout. The last lines
|
||||
This will generate approximately one page of text output. The last lines
|
||||
should be something like this:
|
||||
|
||||
SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -78,6 +78,7 @@ struct VerificImporter
|
|||
|
||||
RTLIL::SigBit net_map_at(Verific::Net *net);
|
||||
|
||||
RTLIL::IdString new_verific_id(Verific::DesignObj *obj);
|
||||
void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj);
|
||||
|
||||
RTLIL::SigSpec operatorInput(Verific::Instance *inst);
|
||||
|
@ -101,6 +102,8 @@ void verific_import_sva_cover(VerificImporter *importer, Verific::Instance *inst
|
|||
void verific_import_sva_trigger(VerificImporter *importer, Verific::Instance *inst);
|
||||
bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net);
|
||||
|
||||
extern int verific_sva_fsm_limit;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -466,13 +466,14 @@ struct SvaFsm
|
|||
|
||||
dnode.ctrl.sort_and_unify();
|
||||
|
||||
if (GetSize(dnode.ctrl) > 16) {
|
||||
if (GetSize(dnode.ctrl) > verific_sva_fsm_limit) {
|
||||
if (verific_verbose >= 2) {
|
||||
log(" detected state explosion in DFSM generation:\n");
|
||||
dump();
|
||||
log(" ctrl signal: %s\n", log_signal(dnode.ctrl));
|
||||
}
|
||||
log_error("SVA DFSM state ctrl signal has %d (>16) bits. Stopping to prevent exponential design size explosion.\n", GetSize(dnode.ctrl));
|
||||
log_error("SVA DFSM state ctrl signal has %d (>%d) bits. Stopping to prevent exponential design size explosion.\n",
|
||||
GetSize(dnode.ctrl), verific_sva_fsm_limit);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (1 << GetSize(dnode.ctrl)); i++)
|
||||
|
@ -826,9 +827,9 @@ struct SvaFsm
|
|||
|
||||
for (auto &it : nodes[i].edges) {
|
||||
if (it.second != State::S1)
|
||||
log(" egde %s -> %d\n", log_signal(it.second), it.first);
|
||||
log(" edge %s -> %d\n", log_signal(it.second), it.first);
|
||||
else
|
||||
log(" egde -> %d\n", it.first);
|
||||
log(" edge -> %d\n", it.first);
|
||||
}
|
||||
|
||||
for (auto &it : nodes[i].links) {
|
||||
|
@ -855,9 +856,9 @@ struct SvaFsm
|
|||
|
||||
for (auto &it : unodes[i].edges) {
|
||||
if (!it.second.empty())
|
||||
log(" egde %s -> %d\n", log_signal(it.second), it.first);
|
||||
log(" edge %s -> %d\n", log_signal(it.second), it.first);
|
||||
else
|
||||
log(" egde -> %d\n", it.first);
|
||||
log(" edge -> %d\n", it.first);
|
||||
}
|
||||
|
||||
for (auto &ctrl : unodes[i].accept) {
|
||||
|
@ -980,7 +981,6 @@ struct VerificSvaImporter
|
|||
bool mode_assume = false;
|
||||
bool mode_cover = false;
|
||||
bool mode_trigger = false;
|
||||
bool eventually = false;
|
||||
|
||||
Instance *net_to_ast_driver(Net *n)
|
||||
{
|
||||
|
@ -1487,6 +1487,72 @@ struct VerificSvaImporter
|
|||
fsm.getFirstAcceptReject(accept_p, reject_p);
|
||||
}
|
||||
|
||||
bool eventually_property(Net *&net, SigBit &trig)
|
||||
{
|
||||
Instance *inst = net_to_ast_driver(net);
|
||||
|
||||
if (inst == nullptr)
|
||||
return false;
|
||||
|
||||
if (clocking.cond_net != nullptr)
|
||||
trig = importer->net_map_at(clocking.cond_net);
|
||||
else
|
||||
trig = State::S1;
|
||||
|
||||
if (inst->Type() == PRIM_SVA_S_EVENTUALLY || inst->Type() == PRIM_SVA_EVENTUALLY)
|
||||
{
|
||||
if (mode_cover || mode_trigger)
|
||||
parser_error(inst);
|
||||
|
||||
net = inst->GetInput();
|
||||
clocking.cond_net = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inst->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION ||
|
||||
inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION)
|
||||
{
|
||||
Net *antecedent_net = inst->GetInput1();
|
||||
Net *consequent_net = inst->GetInput2();
|
||||
|
||||
Instance *consequent_inst = net_to_ast_driver(consequent_net);
|
||||
|
||||
if (consequent_inst == nullptr)
|
||||
return false;
|
||||
|
||||
if (consequent_inst->Type() != PRIM_SVA_S_EVENTUALLY && consequent_inst->Type() != PRIM_SVA_EVENTUALLY)
|
||||
return false;
|
||||
|
||||
if (mode_cover || mode_trigger)
|
||||
parser_error(consequent_inst);
|
||||
|
||||
int node;
|
||||
|
||||
SvaFsm antecedent_fsm(clocking, trig);
|
||||
node = parse_sequence(antecedent_fsm, antecedent_fsm.createStartNode(), antecedent_net);
|
||||
if (inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) {
|
||||
int next_node = antecedent_fsm.createNode();
|
||||
antecedent_fsm.createEdge(node, next_node);
|
||||
node = next_node;
|
||||
}
|
||||
antecedent_fsm.createLink(node, antecedent_fsm.acceptNode);
|
||||
|
||||
trig = antecedent_fsm.getAccept();
|
||||
net = consequent_inst->GetInput();
|
||||
clocking.cond_net = nullptr;
|
||||
|
||||
if (verific_verbose) {
|
||||
log(" Eventually Antecedent FSM:\n");
|
||||
antecedent_fsm.dump();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void parse_property(Net *net, SigBit *accept_p, SigBit *reject_p)
|
||||
{
|
||||
Instance *inst = net_to_ast_driver(net);
|
||||
|
@ -1600,7 +1666,20 @@ struct VerificSvaImporter
|
|||
log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
|
||||
LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
|
||||
|
||||
RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
|
||||
bool is_user_declared = root->IsUserDeclared();
|
||||
|
||||
// FIXME
|
||||
if (!is_user_declared) {
|
||||
const char *name = root->Name();
|
||||
for (int i = 0; name[i]; i++) {
|
||||
if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) {
|
||||
is_user_declared = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID);
|
||||
|
||||
// parse SVA sequence into trigger signal
|
||||
|
||||
|
@ -1620,10 +1699,46 @@ struct VerificSvaImporter
|
|||
}
|
||||
else
|
||||
{
|
||||
if (mode_assert || mode_assume) {
|
||||
parse_property(clocking.body_net, nullptr, &reject_bit);
|
||||
Net *net = clocking.body_net;
|
||||
SigBit trig;
|
||||
|
||||
if (eventually_property(net, trig))
|
||||
{
|
||||
SigBit sig_a, sig_en = trig;
|
||||
parse_property(net, &sig_a, nullptr);
|
||||
|
||||
// add final FF stage
|
||||
|
||||
SigBit sig_a_q, sig_en_q;
|
||||
|
||||
if (clocking.body_net == nullptr) {
|
||||
sig_a_q = sig_a;
|
||||
sig_en_q = sig_en;
|
||||
} else {
|
||||
parse_property(clocking.body_net, &accept_bit, nullptr);
|
||||
sig_a_q = module->addWire(NEW_ID);
|
||||
sig_en_q = module->addWire(NEW_ID);
|
||||
clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0);
|
||||
clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0);
|
||||
}
|
||||
|
||||
// generate fair/live cell
|
||||
|
||||
RTLIL::Cell *c = nullptr;
|
||||
|
||||
if (mode_assert) c = module->addLive(root_name, sig_a_q, sig_en_q);
|
||||
if (mode_assume) c = module->addFair(root_name, sig_a_q, sig_en_q);
|
||||
|
||||
importer->import_attributes(c->attributes, root);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode_assert || mode_assume) {
|
||||
parse_property(net, nullptr, &reject_bit);
|
||||
} else {
|
||||
parse_property(net, &accept_bit, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
verilog_lexer.cc
|
||||
verilog_parser.output
|
||||
verilog_parser.tab.cc
|
||||
verilog_parser.tab.h
|
||||
verilog_parser.tab.hh
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
|
||||
GENFILES += frontends/verilog/verilog_parser.tab.cc
|
||||
GENFILES += frontends/verilog/verilog_parser.tab.h
|
||||
GENFILES += frontends/verilog/verilog_parser.tab.hh
|
||||
GENFILES += frontends/verilog/verilog_parser.output
|
||||
GENFILES += frontends/verilog/verilog_lexer.cc
|
||||
|
||||
frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
$(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $<
|
||||
$(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
|
||||
$(P) $(BISON) -o $@ -d -r all -b frontends/verilog/verilog_parser $<
|
||||
|
||||
frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
|
||||
frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc
|
||||
|
||||
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
|
|
|
@ -49,8 +49,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
|
|||
int carry = 0;
|
||||
for (size_t i = 0; i < digits.size(); i++) {
|
||||
if (digits[i] >= 10)
|
||||
log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n",
|
||||
current_filename.c_str(), get_line_num());
|
||||
log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
|
||||
digits[i] += carry * 10;
|
||||
carry = digits[i] % 2;
|
||||
digits[i] /= 2;
|
||||
|
@ -105,8 +104,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
|
|||
int bits_per_digit = my_ilog2(base-1);
|
||||
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
|
||||
if (*it > (base-1) && *it < 0xf0)
|
||||
log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n",
|
||||
base-1, base, current_filename.c_str(), get_line_num());
|
||||
log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n",
|
||||
base-1, base);
|
||||
for (int i = 0; i < bits_per_digit; i++) {
|
||||
int bitmask = 1 << i;
|
||||
if (*it == 0xf0)
|
||||
|
@ -238,4 +237,3 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
|
|||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -42,14 +42,14 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
|
|||
static void error_on_dpi_function(AST::AstNode *node)
|
||||
{
|
||||
if (node->type == AST::AST_DPI_FUNCTION)
|
||||
log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum);
|
||||
log_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str());
|
||||
for (auto child : node->children)
|
||||
error_on_dpi_function(child);
|
||||
}
|
||||
|
||||
struct VerilogFrontend : public Frontend {
|
||||
VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -66,19 +66,37 @@ struct VerilogFrontend : public Frontend {
|
|||
log(" enable support for SystemVerilog assertions and some Yosys extensions\n");
|
||||
log(" replace the implicit -D SYNTHESIS with -D FORMAL\n");
|
||||
log("\n");
|
||||
log(" -noassert\n");
|
||||
log(" ignore assert() statements\n");
|
||||
log("\n");
|
||||
log(" -noassume\n");
|
||||
log(" ignore assume() statements\n");
|
||||
log("\n");
|
||||
log(" -norestrict\n");
|
||||
log(" ignore restrict() assertions\n");
|
||||
log(" ignore restrict() statements\n");
|
||||
log("\n");
|
||||
log(" -assume-asserts\n");
|
||||
log(" treat all assert() statements like assume() statements\n");
|
||||
log("\n");
|
||||
log(" -assert-assumes\n");
|
||||
log(" treat all assume() statements like assert() statements\n");
|
||||
log("\n");
|
||||
log(" -debug\n");
|
||||
log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n");
|
||||
log("\n");
|
||||
log(" -dump_ast1\n");
|
||||
log(" dump abstract syntax tree (before simplification)\n");
|
||||
log("\n");
|
||||
log(" -dump_ast2\n");
|
||||
log(" dump abstract syntax tree (after simplification)\n");
|
||||
log("\n");
|
||||
log(" -dump_vlog\n");
|
||||
log(" -no_dump_ptr\n");
|
||||
log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
|
||||
log("\n");
|
||||
log(" -dump_vlog1\n");
|
||||
log(" dump ast as Verilog code (before simplification)\n");
|
||||
log("\n");
|
||||
log(" -dump_vlog2\n");
|
||||
log(" dump ast as Verilog code (after simplification)\n");
|
||||
log("\n");
|
||||
log(" -dump_rtlil\n");
|
||||
|
@ -180,11 +198,13 @@ struct VerilogFrontend : public Frontend {
|
|||
log("supported by the Yosys Verilog front-end.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
bool flag_dump_ast1 = false;
|
||||
bool flag_dump_ast2 = false;
|
||||
bool flag_dump_vlog = false;
|
||||
bool flag_no_dump_ptr = false;
|
||||
bool flag_dump_vlog1 = false;
|
||||
bool flag_dump_vlog2 = false;
|
||||
bool flag_dump_rtlil = false;
|
||||
bool flag_nolatches = false;
|
||||
bool flag_nomeminit = false;
|
||||
|
@ -225,6 +245,14 @@ struct VerilogFrontend : public Frontend {
|
|||
formal_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-noassert") {
|
||||
noassert_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-noassume") {
|
||||
noassume_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-norestrict") {
|
||||
norestrict_mode = true;
|
||||
continue;
|
||||
|
@ -233,6 +261,18 @@ struct VerilogFrontend : public Frontend {
|
|||
assume_asserts_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-assert-assumes") {
|
||||
assert_assumes_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-debug") {
|
||||
flag_dump_ast1 = true;
|
||||
flag_dump_ast2 = true;
|
||||
flag_dump_vlog1 = true;
|
||||
flag_dump_vlog2 = true;
|
||||
frontend_verilog_yydebug = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dump_ast1") {
|
||||
flag_dump_ast1 = true;
|
||||
continue;
|
||||
|
@ -241,8 +281,16 @@ struct VerilogFrontend : public Frontend {
|
|||
flag_dump_ast2 = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dump_vlog") {
|
||||
flag_dump_vlog = true;
|
||||
if (arg == "-no_dump_ptr") {
|
||||
flag_no_dump_ptr = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dump_vlog1") {
|
||||
flag_dump_vlog1 = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dump_vlog2") {
|
||||
flag_dump_vlog2 = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-dump_rtlil") {
|
||||
|
@ -381,7 +429,7 @@ struct VerilogFrontend : public Frontend {
|
|||
if (flag_nodpi)
|
||||
error_on_dpi_function(current_ast);
|
||||
|
||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
|
||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
|
||||
|
||||
if (!flag_nopp)
|
||||
delete lexin;
|
||||
|
@ -395,7 +443,7 @@ struct VerilogFrontend : public Frontend {
|
|||
|
||||
struct VerilogDefaults : public Pass {
|
||||
VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -416,7 +464,7 @@ struct VerilogDefaults : public Pass {
|
|||
log("not imply -clear.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design*)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
|
||||
{
|
||||
if (args.size() < 2)
|
||||
cmd_error(args, 1, "Missing argument.");
|
||||
|
@ -453,7 +501,7 @@ struct VerilogDefaults : public Pass {
|
|||
|
||||
struct VerilogDefines : public Pass {
|
||||
VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -469,7 +517,7 @@ struct VerilogDefines : public Pass {
|
|||
log(" undefine the preprocessor symbol 'name'\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
|
@ -519,13 +567,11 @@ void frontend_verilog_yyerror(char const *fmt, ...)
|
|||
va_list ap;
|
||||
char buffer[1024];
|
||||
char *p = buffer;
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
|
||||
YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
|
||||
va_start(ap, fmt);
|
||||
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
|
||||
va_end(ap);
|
||||
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
|
||||
YOSYS_NAMESPACE_PREFIX log_error("%s", buffer);
|
||||
YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(),
|
||||
"%s", buffer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,12 +54,21 @@ namespace VERILOG_FRONTEND
|
|||
// running in -formal mode
|
||||
extern bool formal_mode;
|
||||
|
||||
// running in -noassert mode
|
||||
extern bool noassert_mode;
|
||||
|
||||
// running in -noassume mode
|
||||
extern bool noassume_mode;
|
||||
|
||||
// running in -norestrict mode
|
||||
extern bool norestrict_mode;
|
||||
|
||||
// running in -assume-asserts mode
|
||||
extern bool assume_asserts_mode;
|
||||
|
||||
// running in -assert-assumes mode
|
||||
extern bool assert_assumes_mode;
|
||||
|
||||
// running in -lib mode
|
||||
extern bool lib_mode;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#include "kernel/log.h"
|
||||
#include "frontends/verilog/verilog_frontend.h"
|
||||
#include "frontends/ast/ast.h"
|
||||
#include "verilog_parser.tab.h"
|
||||
#include "verilog_parser.tab.hh"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
using namespace AST;
|
||||
|
@ -135,6 +135,9 @@ YOSYS_NAMESPACE_END
|
|||
frontend_verilog_yyerror("Unsupported default nettype: %s", p);
|
||||
}
|
||||
|
||||
"`protect"[^\n]* /* ignore `protect*/
|
||||
"`endprotect"[^\n]* /* ignore `endprotect*/
|
||||
|
||||
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
|
||||
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
|
||||
}
|
||||
|
@ -150,6 +153,9 @@ YOSYS_NAMESPACE_END
|
|||
"specparam" { return TOK_SPECPARAM; }
|
||||
"package" { SV_KEYWORD(TOK_PACKAGE); }
|
||||
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
|
||||
"interface" { SV_KEYWORD(TOK_INTERFACE); }
|
||||
"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
|
||||
"modport" { SV_KEYWORD(TOK_MODPORT); }
|
||||
"parameter" { return TOK_PARAMETER; }
|
||||
"localparam" { return TOK_LOCALPARAM; }
|
||||
"defparam" { return TOK_DEFPARAM; }
|
||||
|
@ -183,6 +189,14 @@ YOSYS_NAMESPACE_END
|
|||
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
|
||||
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
|
||||
|
||||
/* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
|
||||
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
|
||||
global state.. its a mess) */
|
||||
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
|
||||
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
|
||||
return TOK_SVA_LABEL;
|
||||
}
|
||||
|
||||
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
|
||||
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
|
||||
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
|
||||
|
@ -192,7 +206,7 @@ YOSYS_NAMESPACE_END
|
|||
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
||||
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
|
||||
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
|
||||
"logic" { SV_KEYWORD(TOK_REG); }
|
||||
"logic" { SV_KEYWORD(TOK_LOGIC); }
|
||||
"bit" { SV_KEYWORD(TOK_REG); }
|
||||
|
||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
|
@ -268,7 +282,7 @@ YOSYS_NAMESPACE_END
|
|||
yystr[j++] = yystr[i++];
|
||||
}
|
||||
yystr[j] = 0;
|
||||
frontend_verilog_yylval.string = new std::string(yystr);
|
||||
frontend_verilog_yylval.string = new std::string(yystr, j);
|
||||
free(yystr);
|
||||
return TOK_STRING;
|
||||
}
|
||||
|
@ -295,6 +309,11 @@ supply1 { return TOK_SUPPLY1; }
|
|||
return TOK_ID;
|
||||
}
|
||||
|
||||
[a-zA-Z_$][a-zA-Z0-9_$\.]* {
|
||||
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
|
||||
return TOK_ID;
|
||||
}
|
||||
|
||||
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
|
||||
static bool printed_warning = false;
|
||||
if (!printed_warning) {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
%{
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <string.h>
|
||||
#include "frontends/verilog/verilog_frontend.h"
|
||||
#include "kernel/log.h"
|
||||
|
@ -47,7 +48,8 @@ YOSYS_NAMESPACE_BEGIN
|
|||
namespace VERILOG_FRONTEND {
|
||||
int port_counter;
|
||||
std::map<std::string, int> port_stubs;
|
||||
std::map<std::string, AstNode*> attr_list, default_attr_list;
|
||||
std::map<std::string, AstNode*> *attr_list, default_attr_list;
|
||||
std::stack<std::map<std::string, AstNode*> *> attr_list_stack;
|
||||
std::map<std::string, AstNode*> *albuf;
|
||||
std::vector<AstNode*> ast_stack;
|
||||
struct AstNode *astbuf1, *astbuf2, *astbuf3;
|
||||
|
@ -58,8 +60,10 @@ namespace VERILOG_FRONTEND {
|
|||
bool do_not_require_port_stubs;
|
||||
bool default_nettype_wire;
|
||||
bool sv_mode, formal_mode, lib_mode;
|
||||
bool norestrict_mode, assume_asserts_mode;
|
||||
bool noassert_mode, noassume_mode, norestrict_mode;
|
||||
bool assume_asserts_mode, assert_assumes_mode;
|
||||
bool current_wire_rand, current_wire_const;
|
||||
bool current_modport_input, current_modport_output;
|
||||
std::istream *lexin;
|
||||
}
|
||||
YOSYS_NAMESPACE_END
|
||||
|
@ -101,11 +105,13 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
|||
bool boolean;
|
||||
}
|
||||
|
||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
|
||||
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
|
||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
||||
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG
|
||||
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT
|
||||
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
|
||||
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
|
||||
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
|
||||
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
|
||||
|
@ -114,15 +120,14 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
|||
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
|
||||
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
|
||||
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
||||
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
|
||||
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
|
||||
|
||||
%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 <string> opt_label tok_prim_wrapper hierarchical_id
|
||||
%type <boolean> opt_signed unique_case_attr
|
||||
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id
|
||||
%type <boolean> opt_signed opt_property unique_case_attr
|
||||
%type <al> attr case_attr
|
||||
|
||||
// operator precedence from low to high
|
||||
|
@ -167,19 +172,23 @@ design:
|
|||
param_decl design |
|
||||
localparam_decl design |
|
||||
package design |
|
||||
interface design |
|
||||
/* empty */;
|
||||
|
||||
attr:
|
||||
{
|
||||
for (auto &it : attr_list)
|
||||
delete it.second;
|
||||
attr_list.clear();
|
||||
if (attr_list != nullptr)
|
||||
attr_list_stack.push(attr_list);
|
||||
attr_list = new std::map<std::string, AstNode*>;
|
||||
for (auto &it : default_attr_list)
|
||||
attr_list[it.first] = it.second->clone();
|
||||
(*attr_list)[it.first] = it.second->clone();
|
||||
} attr_opt {
|
||||
std::map<std::string, AstNode*> *al = new std::map<std::string, AstNode*>;
|
||||
al->swap(attr_list);
|
||||
$$ = al;
|
||||
$$ = attr_list;
|
||||
if (!attr_list_stack.empty()) {
|
||||
attr_list = attr_list_stack.top();
|
||||
attr_list_stack.pop();
|
||||
} else
|
||||
attr_list = nullptr;
|
||||
};
|
||||
|
||||
attr_opt:
|
||||
|
@ -188,15 +197,20 @@ attr_opt:
|
|||
|
||||
defattr:
|
||||
DEFATTR_BEGIN {
|
||||
if (attr_list != nullptr)
|
||||
attr_list_stack.push(attr_list);
|
||||
attr_list = new std::map<std::string, AstNode*>;
|
||||
for (auto &it : default_attr_list)
|
||||
delete it.second;
|
||||
default_attr_list.clear();
|
||||
for (auto &it : attr_list)
|
||||
delete it.second;
|
||||
attr_list.clear();
|
||||
} opt_attr_list {
|
||||
default_attr_list = attr_list;
|
||||
attr_list.clear();
|
||||
attr_list->swap(default_attr_list);
|
||||
delete attr_list;
|
||||
if (!attr_list_stack.empty()) {
|
||||
attr_list = attr_list_stack.top();
|
||||
attr_list_stack.pop();
|
||||
} else
|
||||
attr_list = nullptr;
|
||||
} DEFATTR_END;
|
||||
|
||||
opt_attr_list:
|
||||
|
@ -208,15 +222,15 @@ attr_list:
|
|||
|
||||
attr_assign:
|
||||
hierarchical_id {
|
||||
if (attr_list.count(*$1) != 0)
|
||||
delete attr_list[*$1];
|
||||
attr_list[*$1] = AstNode::mkconst_int(1, false);
|
||||
if (attr_list->count(*$1) != 0)
|
||||
delete (*attr_list)[*$1];
|
||||
(*attr_list)[*$1] = AstNode::mkconst_int(1, false);
|
||||
delete $1;
|
||||
} |
|
||||
hierarchical_id '=' expr {
|
||||
if (attr_list.count(*$1) != 0)
|
||||
delete attr_list[*$1];
|
||||
attr_list[*$1] = $3;
|
||||
if (attr_list->count(*$1) != 0)
|
||||
delete (*attr_list)[*$1];
|
||||
(*attr_list)[*$1] = $3;
|
||||
delete $1;
|
||||
};
|
||||
|
||||
|
@ -301,7 +315,7 @@ module_arg_opt_assignment:
|
|||
else
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
|
||||
} else
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value.");
|
||||
} |
|
||||
/* empty */;
|
||||
|
||||
|
@ -319,6 +333,21 @@ module_arg:
|
|||
}
|
||||
delete $1;
|
||||
} module_arg_opt_assignment |
|
||||
TOK_ID {
|
||||
astbuf1 = new AstNode(AST_INTERFACEPORT);
|
||||
astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE));
|
||||
astbuf1->children[0]->str = *$1;
|
||||
delete $1;
|
||||
} TOK_ID { /* SV interfaces */
|
||||
if (!sv_mode)
|
||||
frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str());
|
||||
astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type.
|
||||
astbuf2->str = *$3;
|
||||
delete $3;
|
||||
astbuf2->port_id = ++port_counter;
|
||||
ast_stack.back()->children.push_back(astbuf2);
|
||||
delete astbuf1; // really only needed if multiple instances of same type.
|
||||
} module_arg_opt_assignment |
|
||||
attr wire_type range TOK_ID {
|
||||
AstNode *node = $2;
|
||||
node->str = *$4;
|
||||
|
@ -356,6 +385,33 @@ package_body:
|
|||
package_body_stmt:
|
||||
localparam_decl;
|
||||
|
||||
interface:
|
||||
TOK_INTERFACE TOK_ID {
|
||||
do_not_require_port_stubs = false;
|
||||
AstNode *intf = new AstNode(AST_INTERFACE);
|
||||
ast_stack.back()->children.push_back(intf);
|
||||
ast_stack.push_back(intf);
|
||||
current_ast_mod = intf;
|
||||
port_stubs.clear();
|
||||
port_counter = 0;
|
||||
intf->str = *$2;
|
||||
delete $2;
|
||||
} module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
|
||||
if (port_stubs.size() != 0)
|
||||
frontend_verilog_yyerror("Missing details for module port `%s'.",
|
||||
port_stubs.begin()->first.c_str());
|
||||
ast_stack.pop_back();
|
||||
log_assert(ast_stack.size() == 1);
|
||||
current_ast_mod = NULL;
|
||||
};
|
||||
|
||||
interface_body:
|
||||
interface_body interface_body_stmt |;
|
||||
|
||||
interface_body_stmt:
|
||||
param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
|
||||
modport_stmt;
|
||||
|
||||
non_opt_delay:
|
||||
'#' TOK_ID { delete $2; } |
|
||||
'#' TOK_CONSTVAL { delete $2; } |
|
||||
|
@ -376,9 +432,10 @@ wire_type:
|
|||
};
|
||||
|
||||
wire_type_token_list:
|
||||
wire_type_token | wire_type_token_list wire_type_token;
|
||||
wire_type_token | wire_type_token_list wire_type_token |
|
||||
wire_type_token_io ;
|
||||
|
||||
wire_type_token:
|
||||
wire_type_token_io:
|
||||
TOK_INPUT {
|
||||
astbuf3->is_input = true;
|
||||
} |
|
||||
|
@ -388,12 +445,17 @@ wire_type_token:
|
|||
TOK_INOUT {
|
||||
astbuf3->is_input = true;
|
||||
astbuf3->is_output = true;
|
||||
} |
|
||||
};
|
||||
|
||||
wire_type_token:
|
||||
TOK_WIRE {
|
||||
} |
|
||||
TOK_REG {
|
||||
astbuf3->is_reg = true;
|
||||
} |
|
||||
TOK_LOGIC {
|
||||
astbuf3->is_logic = true;
|
||||
} |
|
||||
TOK_INTEGER {
|
||||
astbuf3->is_reg = true;
|
||||
astbuf3->range_left = 31;
|
||||
|
@ -545,6 +607,7 @@ task_func_decl:
|
|||
AstNode *outreg = new AstNode(AST_WIRE);
|
||||
outreg->str = *$6;
|
||||
outreg->is_signed = $4;
|
||||
outreg->is_reg = true;
|
||||
if ($5 != NULL) {
|
||||
outreg->children.push_back($5);
|
||||
outreg->is_signed = $4 || $5->is_signed;
|
||||
|
@ -619,7 +682,7 @@ task_func_port:
|
|||
astbuf2 = $3;
|
||||
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
|
||||
if (astbuf2) {
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions (task/function arguments)");
|
||||
} else {
|
||||
astbuf2 = new AstNode(AST_RANGE);
|
||||
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
|
||||
|
@ -627,7 +690,7 @@ task_func_port:
|
|||
}
|
||||
}
|
||||
if (astbuf2 && astbuf2->children.size() != 2)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
|
||||
} wire_name | wire_name;
|
||||
|
||||
task_func_body:
|
||||
|
@ -647,7 +710,7 @@ specify_item:
|
|||
// | pulsestyle_declaration
|
||||
// | showcancelled_declaration
|
||||
| path_declaration
|
||||
// | system_timing_declaration
|
||||
| system_timing_declaration
|
||||
;
|
||||
|
||||
specparam_declaration:
|
||||
|
@ -675,22 +738,23 @@ showcancelled_declaration :
|
|||
*/
|
||||
|
||||
path_declaration :
|
||||
simple_path_declaration
|
||||
simple_path_declaration ';'
|
||||
// | edge_sensitive_path_declaration
|
||||
// | state_dependent_path_declaration
|
||||
;
|
||||
|
||||
simple_path_declaration :
|
||||
parallel_path_description '=' path_delay_value ';'
|
||||
// | full_path_description '=' path_delay_value ';'
|
||||
parallel_path_description '=' path_delay_value |
|
||||
full_path_description '=' path_delay_value
|
||||
;
|
||||
|
||||
path_delay_value :
|
||||
//list_of_path_delay_expressions
|
||||
'(' list_of_path_delay_expressions ')'
|
||||
'(' path_delay_expression list_of_path_delay_extra_expressions ')'
|
||||
| path_delay_expression
|
||||
| path_delay_expression list_of_path_delay_extra_expressions
|
||||
;
|
||||
|
||||
list_of_path_delay_expressions :
|
||||
list_of_path_delay_extra_expressions :
|
||||
/*
|
||||
t_path_delay_expression
|
||||
| trise_path_delay_expression ',' tfall_path_delay_expression
|
||||
|
@ -702,12 +766,11 @@ list_of_path_delay_expressions :
|
|||
t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ','
|
||||
tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression
|
||||
*/
|
||||
path_delay_expression
|
||||
| path_delay_expression ',' path_delay_expression
|
||||
| path_delay_expression ',' path_delay_expression ',' path_delay_expression
|
||||
| path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
|
||||
',' path_delay_expression
|
||||
| ',' path_delay_expression ',' path_delay_expression
|
||||
| ',' path_delay_expression ',' path_delay_expression ','
|
||||
path_delay_expression ',' path_delay_expression ',' path_delay_expression
|
||||
| path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
|
||||
| ',' path_delay_expression ',' path_delay_expression ','
|
||||
path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
|
||||
path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
|
||||
path_delay_expression ',' path_delay_expression ',' path_delay_expression
|
||||
|
@ -716,6 +779,22 @@ list_of_path_delay_expressions :
|
|||
parallel_path_description :
|
||||
'(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ;
|
||||
|
||||
full_path_description :
|
||||
'(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ;
|
||||
|
||||
// This was broken into 2 rules to solve shift/reduce conflicts
|
||||
list_of_path_inputs :
|
||||
specify_input_terminal_descriptor opt_polarity_operator |
|
||||
specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ;
|
||||
|
||||
more_path_inputs :
|
||||
',' specify_input_terminal_descriptor |
|
||||
more_path_inputs ',' specify_input_terminal_descriptor ;
|
||||
|
||||
list_of_path_outputs :
|
||||
specify_output_terminal_descriptor |
|
||||
list_of_path_outputs ',' specify_output_terminal_descriptor ;
|
||||
|
||||
opt_polarity_operator :
|
||||
'+'
|
||||
| '-'
|
||||
|
@ -729,10 +808,17 @@ specify_input_terminal_descriptor :
|
|||
specify_output_terminal_descriptor :
|
||||
TOK_ID ;
|
||||
|
||||
/*
|
||||
system_timing_declaration :
|
||||
;
|
||||
*/
|
||||
TOK_ID '(' system_timing_args ')' ';' ;
|
||||
|
||||
system_timing_arg :
|
||||
TOK_POSEDGE TOK_ID |
|
||||
TOK_NEGEDGE TOK_ID |
|
||||
expr ;
|
||||
|
||||
system_timing_args :
|
||||
system_timing_arg |
|
||||
system_timing_args ',' system_timing_arg ;
|
||||
|
||||
/*
|
||||
t_path_delay_expression :
|
||||
|
@ -785,7 +871,7 @@ tzx_path_delay_expression :
|
|||
*/
|
||||
|
||||
path_delay_expression :
|
||||
constant_mintypmax_expression;
|
||||
constant_expression;
|
||||
|
||||
constant_mintypmax_expression :
|
||||
constant_expression
|
||||
|
@ -795,7 +881,7 @@ constant_mintypmax_expression :
|
|||
// for the time being this is OK, but we may write our own expr here.
|
||||
// as I'm not sure it is legal to use a full expr here (probably not)
|
||||
// On the other hand, other rules requiring constant expressions also use 'expr'
|
||||
// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness
|
||||
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
|
||||
constant_expression:
|
||||
expr ;
|
||||
|
||||
|
@ -807,7 +893,7 @@ param_signed:
|
|||
param_integer:
|
||||
TOK_INTEGER {
|
||||
if (astbuf1->children.size() != 1)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("Internal error in param_integer - should not happen?");
|
||||
astbuf1->children.push_back(new AstNode(AST_RANGE));
|
||||
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true));
|
||||
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true));
|
||||
|
@ -817,7 +903,7 @@ param_integer:
|
|||
param_real:
|
||||
TOK_REAL {
|
||||
if (astbuf1->children.size() != 1)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real.");
|
||||
astbuf1->children.push_back(new AstNode(AST_REALVALUE));
|
||||
} | /* empty */;
|
||||
|
||||
|
@ -825,7 +911,7 @@ param_range:
|
|||
range {
|
||||
if ($1 != NULL) {
|
||||
if (astbuf1->children.size() != 1)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("integer/real parameters should not have a range.");
|
||||
astbuf1->children.push_back($1);
|
||||
}
|
||||
};
|
||||
|
@ -851,9 +937,15 @@ param_decl_list:
|
|||
|
||||
single_param_decl:
|
||||
TOK_ID '=' expr {
|
||||
if (astbuf1 == nullptr)
|
||||
frontend_verilog_yyerror("syntax error");
|
||||
AstNode *node = astbuf1->clone();
|
||||
AstNode *node;
|
||||
if (astbuf1 == nullptr) {
|
||||
if (!sv_mode)
|
||||
frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword");
|
||||
node = new AstNode(AST_PARAMETER);
|
||||
node->children.push_back(AstNode::mkconst_int(0, true));
|
||||
} else {
|
||||
node = astbuf1->clone();
|
||||
}
|
||||
node->str = *$1;
|
||||
delete node->children[0];
|
||||
node->children[0] = $3;
|
||||
|
@ -884,7 +976,7 @@ wire_decl:
|
|||
astbuf2 = $3;
|
||||
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
|
||||
if (astbuf2) {
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions.");
|
||||
} else {
|
||||
astbuf2 = new AstNode(AST_RANGE);
|
||||
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
|
||||
|
@ -892,7 +984,7 @@ wire_decl:
|
|||
}
|
||||
}
|
||||
if (astbuf2 && astbuf2->children.size() != 2)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
|
||||
} wire_name_list {
|
||||
delete astbuf1;
|
||||
if (astbuf2 != NULL)
|
||||
|
@ -986,7 +1078,7 @@ wire_name_and_opt_assign:
|
|||
wire_name:
|
||||
TOK_ID range_or_multirange {
|
||||
if (astbuf1 == nullptr)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node.");
|
||||
AstNode *node = astbuf1->clone();
|
||||
node->str = *$1;
|
||||
append_attr_clone(node, albuf);
|
||||
|
@ -994,7 +1086,7 @@ wire_name:
|
|||
node->children.push_back(astbuf2->clone());
|
||||
if ($2 != NULL) {
|
||||
if (node->is_input || node->is_output)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions.");
|
||||
if (!astbuf2) {
|
||||
AstNode *rng = new AstNode(AST_RANGE);
|
||||
rng->children.push_back(AstNode::mkconst_int(0, true));
|
||||
|
@ -1024,6 +1116,7 @@ wire_name:
|
|||
node->port_id = current_function_or_task_port_id++;
|
||||
}
|
||||
ast_stack.back()->children.push_back(node);
|
||||
|
||||
delete $1;
|
||||
};
|
||||
|
||||
|
@ -1236,74 +1329,216 @@ opt_label:
|
|||
$$ = NULL;
|
||||
};
|
||||
|
||||
opt_property:
|
||||
TOK_PROPERTY | /* empty */;
|
||||
opt_sva_label:
|
||||
TOK_SVA_LABEL ':' {
|
||||
$$ = $1;
|
||||
} |
|
||||
/* empty */ {
|
||||
$$ = NULL;
|
||||
};
|
||||
|
||||
opt_stmt_label:
|
||||
TOK_ID ':' | /* empty */;
|
||||
opt_property:
|
||||
TOK_PROPERTY {
|
||||
$$ = true;
|
||||
} |
|
||||
/* empty */ {
|
||||
$$ = false;
|
||||
};
|
||||
|
||||
modport_stmt:
|
||||
TOK_MODPORT TOK_ID {
|
||||
AstNode *modport = new AstNode(AST_MODPORT);
|
||||
ast_stack.back()->children.push_back(modport);
|
||||
ast_stack.push_back(modport);
|
||||
modport->str = *$2;
|
||||
delete $2;
|
||||
} modport_args_opt {
|
||||
ast_stack.pop_back();
|
||||
log_assert(ast_stack.size() == 2);
|
||||
} ';'
|
||||
|
||||
modport_args_opt:
|
||||
'(' ')' | '(' modport_args optional_comma ')';
|
||||
|
||||
modport_args:
|
||||
modport_arg | modport_args ',' modport_arg;
|
||||
|
||||
modport_arg:
|
||||
modport_type_token modport_member |
|
||||
modport_member
|
||||
|
||||
modport_member:
|
||||
TOK_ID {
|
||||
AstNode *modport_member = new AstNode(AST_MODPORTMEMBER);
|
||||
ast_stack.back()->children.push_back(modport_member);
|
||||
modport_member->str = *$1;
|
||||
modport_member->is_input = current_modport_input;
|
||||
modport_member->is_output = current_modport_output;
|
||||
delete $1;
|
||||
}
|
||||
|
||||
modport_type_token:
|
||||
TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
|
||||
|
||||
assert:
|
||||
opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
|
||||
} |
|
||||
opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
|
||||
} |
|
||||
opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
|
||||
} |
|
||||
opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
|
||||
} |
|
||||
opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
|
||||
} |
|
||||
opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
|
||||
} |
|
||||
opt_stmt_label TOK_COVER ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
|
||||
} |
|
||||
opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
|
||||
if (norestrict_mode)
|
||||
opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
|
||||
if (noassert_mode) {
|
||||
delete $5;
|
||||
else
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
|
||||
} else {
|
||||
AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
|
||||
if ($1 != nullptr)
|
||||
node->str = *$1;
|
||||
ast_stack.back()->children.push_back(node);
|
||||
}
|
||||
if ($1 != nullptr)
|
||||
delete $1;
|
||||
} |
|
||||
opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
if (norestrict_mode)
|
||||
opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
|
||||
if (noassume_mode) {
|
||||
delete $5;
|
||||
} else {
|
||||
AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
|
||||
if ($1 != nullptr)
|
||||
node->str = *$1;
|
||||
ast_stack.back()->children.push_back(node);
|
||||
}
|
||||
if ($1 != nullptr)
|
||||
delete $1;
|
||||
} |
|
||||
opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
if (noassert_mode) {
|
||||
delete $6;
|
||||
else
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
|
||||
} else {
|
||||
AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
|
||||
if ($1 != nullptr)
|
||||
node->str = *$1;
|
||||
ast_stack.back()->children.push_back(node);
|
||||
}
|
||||
if ($1 != nullptr)
|
||||
delete $1;
|
||||
} |
|
||||
opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
if (noassume_mode) {
|
||||
delete $6;
|
||||
} else {
|
||||
AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
|
||||
if ($1 != nullptr)
|
||||
node->str = *$1;
|
||||
ast_stack.back()->children.push_back(node);
|
||||
}
|
||||
if ($1 != nullptr)
|
||||
delete $1;
|
||||
} |
|
||||
opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
|
||||
AstNode *node = new AstNode(AST_COVER, $5);
|
||||
if ($1 != nullptr) {
|
||||
node->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
ast_stack.back()->children.push_back(node);
|
||||
} |
|
||||
opt_sva_label TOK_COVER opt_property '(' ')' ';' {
|
||||
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
|
||||
if ($1 != nullptr) {
|
||||
node->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
ast_stack.back()->children.push_back(node);
|
||||
} |
|
||||
opt_sva_label TOK_COVER ';' {
|
||||
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
|
||||
if ($1 != nullptr) {
|
||||
node->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
ast_stack.back()->children.push_back(node);
|
||||
} |
|
||||
opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
|
||||
if (norestrict_mode) {
|
||||
delete $5;
|
||||
} else {
|
||||
AstNode *node = new AstNode(AST_ASSUME, $5);
|
||||
if ($1 != nullptr)
|
||||
node->str = *$1;
|
||||
ast_stack.back()->children.push_back(node);
|
||||
}
|
||||
if (!$3)
|
||||
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
|
||||
if ($1 != nullptr)
|
||||
delete $1;
|
||||
} |
|
||||
opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
if (norestrict_mode) {
|
||||
delete $6;
|
||||
} else {
|
||||
AstNode *node = new AstNode(AST_FAIR, $6);
|
||||
if ($1 != nullptr)
|
||||
node->str = *$1;
|
||||
ast_stack.back()->children.push_back(node);
|
||||
}
|
||||
if (!$3)
|
||||
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
|
||||
if ($1 != nullptr)
|
||||
delete $1;
|
||||
};
|
||||
|
||||
assert_property:
|
||||
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
|
||||
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
|
||||
if ($1 != nullptr) {
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
} |
|
||||
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
|
||||
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
|
||||
if ($1 != nullptr) {
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
} |
|
||||
TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
|
||||
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
|
||||
if ($1 != nullptr) {
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
} |
|
||||
TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
|
||||
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
|
||||
if ($1 != nullptr) {
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
} |
|
||||
TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
|
||||
opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
|
||||
if ($1 != nullptr) {
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
} |
|
||||
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
|
||||
if (norestrict_mode)
|
||||
delete $4;
|
||||
else
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
|
||||
} |
|
||||
TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
if (norestrict_mode)
|
||||
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
|
||||
if (norestrict_mode) {
|
||||
delete $5;
|
||||
else
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
|
||||
} else {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
|
||||
if ($1 != nullptr) {
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
}
|
||||
} |
|
||||
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||
if (norestrict_mode) {
|
||||
delete $6;
|
||||
} else {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
|
||||
if ($1 != nullptr) {
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
simple_behavioral_stmt:
|
||||
|
@ -1348,7 +1583,7 @@ behavioral_stmt:
|
|||
node->str = *$3;
|
||||
} behavioral_stmt_list TOK_END opt_label {
|
||||
if ($3 != NULL && $7 != NULL && *$3 != *$7)
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
|
||||
if ($3 != NULL)
|
||||
delete $3;
|
||||
if ($7 != NULL)
|
||||
|
@ -1521,6 +1756,11 @@ case_expr_list:
|
|||
TOK_DEFAULT {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
|
||||
} |
|
||||
TOK_SVA_LABEL {
|
||||
ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||
ast_stack.back()->children.back()->str = *$1;
|
||||
delete $1;
|
||||
} |
|
||||
expr {
|
||||
ast_stack.back()->children.push_back($1);
|
||||
} |
|
||||
|
@ -1664,7 +1904,7 @@ basic_expr:
|
|||
} |
|
||||
'(' expr ')' TOK_CONSTVAL {
|
||||
if ($4->substr(0, 1) != "'")
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
|
||||
AstNode *bits = $2;
|
||||
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
|
||||
if (val == NULL)
|
||||
|
@ -1674,7 +1914,7 @@ basic_expr:
|
|||
} |
|
||||
hierarchical_id TOK_CONSTVAL {
|
||||
if ($2->substr(0, 1) != "'")
|
||||
frontend_verilog_yyerror("Syntax error.");
|
||||
frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
|
||||
AstNode *bits = new AstNode(AST_IDENTIFIER);
|
||||
bits->str = *$1;
|
||||
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
|
@ -38,7 +38,7 @@ struct FwdCellEdgesDatabase : AbstractCellEdgesDatabase
|
|||
dict<SigBit, pool<SigBit>> db;
|
||||
FwdCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }
|
||||
|
||||
virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {
|
||||
void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE {
|
||||
SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);
|
||||
SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);
|
||||
db[from_sigbit].insert(to_sigbit);
|
||||
|
@ -51,7 +51,7 @@ struct RevCellEdgesDatabase : AbstractCellEdgesDatabase
|
|||
dict<SigBit, pool<SigBit>> db;
|
||||
RevCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }
|
||||
|
||||
virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {
|
||||
void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE {
|
||||
SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);
|
||||
SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);
|
||||
db[to_sigbit].insert(from_sigbit);
|
||||
|
|
|
@ -81,6 +81,27 @@ struct CellTypes
|
|||
}
|
||||
|
||||
void setup_internals()
|
||||
{
|
||||
setup_internals_eval();
|
||||
|
||||
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
|
||||
|
||||
setup_type("$tribuf", {A, EN}, {Y}, true);
|
||||
|
||||
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$equiv", {A, B}, {Y}, true);
|
||||
}
|
||||
|
||||
void setup_internals_eval()
|
||||
{
|
||||
std::vector<RTLIL::IdString> unary_ops = {
|
||||
"$not", "$pos", "$neg",
|
||||
|
@ -111,20 +132,6 @@ struct CellTypes
|
|||
setup_type("$lcu", {P, G, CI}, {CO}, true);
|
||||
setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
|
||||
setup_type("$fa", {A, B, C}, {X, Y}, true);
|
||||
|
||||
setup_type("$tribuf", {A, EN}, {Y}, true);
|
||||
|
||||
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$equiv", {A, B}, {Y}, true);
|
||||
}
|
||||
|
||||
void setup_internals_mem()
|
||||
|
@ -153,11 +160,20 @@ struct CellTypes
|
|||
}
|
||||
|
||||
void setup_stdcells()
|
||||
{
|
||||
setup_stdcells_eval();
|
||||
|
||||
IdString A = "\\A", E = "\\E", Y = "\\Y";
|
||||
|
||||
setup_type("$_TBUF_", {A, E}, {Y}, true);
|
||||
}
|
||||
|
||||
void setup_stdcells_eval()
|
||||
{
|
||||
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
|
||||
IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
|
||||
IdString I = "\\I", J = "\\J", K = "\\K", L = "\\L";
|
||||
IdString M = "\\I", N = "\\N", O = "\\O", P = "\\P";
|
||||
IdString M = "\\M", N = "\\N", O = "\\O", P = "\\P";
|
||||
IdString S = "\\S", T = "\\T", U = "\\U", V = "\\V";
|
||||
IdString Y = "\\Y";
|
||||
|
||||
|
@ -179,7 +195,6 @@ struct CellTypes
|
|||
setup_type("$_OAI3_", {A, B, C}, {Y}, true);
|
||||
setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
|
||||
setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
|
||||
setup_type("$_TBUF_", {A, E}, {Y}, true);
|
||||
}
|
||||
|
||||
void setup_stdcells_mem()
|
||||
|
@ -257,7 +272,7 @@ struct CellTypes
|
|||
return v;
|
||||
}
|
||||
|
||||
static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||
static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)
|
||||
{
|
||||
if (type == "$sshr" && !signed1)
|
||||
type = "$shr";
|
||||
|
@ -329,10 +344,15 @@ struct CellTypes
|
|||
if (type == "$_ORNOT_")
|
||||
return const_or(arg1, eval_not(arg2), false, false, 1);
|
||||
|
||||
if (errp != nullptr) {
|
||||
*errp = true;
|
||||
return State::Sm;
|
||||
}
|
||||
|
||||
log_abort();
|
||||
}
|
||||
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2)
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)
|
||||
{
|
||||
if (cell->type == "$slice") {
|
||||
RTLIL::Const ret;
|
||||
|
@ -415,10 +435,10 @@ struct CellTypes
|
|||
bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
|
||||
bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
|
||||
int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
|
||||
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len);
|
||||
return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);
|
||||
}
|
||||
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
|
||||
{
|
||||
if (cell->type.in("$mux", "$pmux", "$_MUX_")) {
|
||||
RTLIL::Const ret = arg1;
|
||||
|
@ -436,10 +456,10 @@ struct CellTypes
|
|||
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1));
|
||||
|
||||
log_assert(arg3.bits.size() == 0);
|
||||
return eval(cell, arg1, arg2);
|
||||
return eval(cell, arg1, arg2, errp);
|
||||
}
|
||||
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4)
|
||||
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)
|
||||
{
|
||||
if (cell->type == "$_AOI4_")
|
||||
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
|
||||
|
@ -447,7 +467,7 @@ struct CellTypes
|
|||
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
|
||||
|
||||
log_assert(arg4.bits.size() == 0);
|
||||
return eval(cell, arg1, arg2, arg3);
|
||||
return eval(cell, arg1, arg2, arg3, errp);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -321,8 +321,13 @@ struct ConstEval
|
|||
if (sig_d.size() > 0 && !eval(sig_d, undef, cell))
|
||||
return false;
|
||||
|
||||
set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(),
|
||||
sig_c.as_const(), sig_d.as_const()));
|
||||
bool eval_err = false;
|
||||
RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);
|
||||
|
||||
if (eval_err)
|
||||
return false;
|
||||
|
||||
set(sig_y, eval_ret);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -183,6 +183,7 @@ int main(int argc, char **argv)
|
|||
{
|
||||
std::string frontend_command = "auto";
|
||||
std::string backend_command = "auto";
|
||||
std::vector<std::string> vlog_defines;
|
||||
std::vector<std::string> passes_commands;
|
||||
std::vector<std::string> plugin_filenames;
|
||||
std::string output_filename = "";
|
||||
|
@ -272,7 +273,10 @@ int main(int argc, char **argv)
|
|||
printf(" -A\n");
|
||||
printf(" will call abort() at the end of the script. for debugging\n");
|
||||
printf("\n");
|
||||
printf(" -D <header_id>[:<filename>]\n");
|
||||
printf(" -D <macro>[=<value>]\n");
|
||||
printf(" set the specified Verilog define (via \"read -define\")\n");
|
||||
printf("\n");
|
||||
printf(" -P <header_id>[:<filename>]\n");
|
||||
printf(" dump the design when printing the specified log header to a file.\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");
|
||||
|
@ -311,7 +315,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1)
|
||||
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
|
@ -412,6 +416,9 @@ int main(int argc, char **argv)
|
|||
std::regex_constants::egrep));
|
||||
break;
|
||||
case 'D':
|
||||
vlog_defines.push_back(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
{
|
||||
auto args = split_tokens(optarg, ":");
|
||||
if (!args.empty() && args[0] == "ALL") {
|
||||
|
@ -481,6 +488,13 @@ int main(int argc, char **argv)
|
|||
shell(yosys_design);
|
||||
}
|
||||
|
||||
if (!vlog_defines.empty()) {
|
||||
std::string vdef_cmd = "read -define";
|
||||
for (auto vdef : vlog_defines)
|
||||
vdef_cmd += " " + vdef;
|
||||
run_pass(vdef_cmd);
|
||||
}
|
||||
|
||||
while (optind < argc)
|
||||
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
|
||||
|
||||
|
|
|
@ -557,9 +557,11 @@ public:
|
|||
void clear() { hashtable.clear(); entries.clear(); }
|
||||
|
||||
iterator begin() { return iterator(this, int(entries.size())-1); }
|
||||
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
|
||||
iterator end() { return iterator(nullptr, -1); }
|
||||
|
||||
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
||||
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
|
||||
const_iterator end() const { return const_iterator(nullptr, -1); }
|
||||
};
|
||||
|
||||
|
@ -881,9 +883,11 @@ public:
|
|||
void clear() { hashtable.clear(); entries.clear(); }
|
||||
|
||||
iterator begin() { return iterator(this, int(entries.size())-1); }
|
||||
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
|
||||
iterator end() { return iterator(nullptr, -1); }
|
||||
|
||||
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
||||
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
|
||||
const_iterator end() const { return const_iterator(nullptr, -1); }
|
||||
};
|
||||
|
||||
|
@ -952,6 +956,7 @@ public:
|
|||
void clear() { database.clear(); }
|
||||
|
||||
const_iterator begin() const { return database.begin(); }
|
||||
const_iterator element(int n) const { return database.element(n); }
|
||||
const_iterator end() const { return database.end(); }
|
||||
};
|
||||
|
||||
|
@ -1051,6 +1056,7 @@ public:
|
|||
void clear() { database.clear(); parents.clear(); }
|
||||
|
||||
const_iterator begin() const { return database.begin(); }
|
||||
const_iterator element(int n) const { return database.element(n); }
|
||||
const_iterator end() const { return database.end(); }
|
||||
};
|
||||
|
||||
|
|
|
@ -196,14 +196,19 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
|
|||
if (log_hdump.count(header_id) && design != nullptr)
|
||||
for (auto &filename : log_hdump.at(header_id)) {
|
||||
log("Dumping current design to '%s'.\n", filename.c_str());
|
||||
if (yosys_xtrace)
|
||||
IdString::xtrace_db_dump();
|
||||
Pass::call(design, {"dump", "-o", filename});
|
||||
if (yosys_xtrace)
|
||||
log("#X# -- end of dump --\n");
|
||||
}
|
||||
|
||||
if (pop_errfile)
|
||||
log_files.pop_back();
|
||||
}
|
||||
|
||||
void logv_warning(const char *format, va_list ap)
|
||||
static void logv_warning_with_prefix(const char *prefix,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
std::string message = vstringf(format, ap);
|
||||
bool suppressed = false;
|
||||
|
@ -214,7 +219,7 @@ void logv_warning(const char *format, va_list ap)
|
|||
|
||||
if (suppressed)
|
||||
{
|
||||
log("Suppressed warning: %s", message.c_str());
|
||||
log("Suppressed %s%s", prefix, message.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -224,7 +229,7 @@ void logv_warning(const char *format, va_list ap)
|
|||
|
||||
if (log_warnings.count(message))
|
||||
{
|
||||
log("Warning: %s", message.c_str());
|
||||
log("%s%s", prefix, message.c_str());
|
||||
log_flush();
|
||||
}
|
||||
else
|
||||
|
@ -232,7 +237,7 @@ void logv_warning(const char *format, va_list ap)
|
|||
if (log_errfile != NULL && !log_quiet_warnings)
|
||||
log_files.push_back(log_errfile);
|
||||
|
||||
log("Warning: %s", message.c_str());
|
||||
log("%s%s", prefix, message.c_str());
|
||||
log_flush();
|
||||
|
||||
if (log_errfile != NULL && !log_quiet_warnings)
|
||||
|
@ -245,49 +250,30 @@ void logv_warning(const char *format, va_list ap)
|
|||
}
|
||||
}
|
||||
|
||||
void logv_warning(const char *format, va_list ap)
|
||||
{
|
||||
logv_warning_with_prefix("Warning: ", format, ap);
|
||||
}
|
||||
|
||||
void logv_warning_noprefix(const char *format, va_list ap)
|
||||
{
|
||||
std::string message = vstringf(format, ap);
|
||||
bool suppressed = false;
|
||||
|
||||
for (auto &re : log_nowarn_regexes)
|
||||
if (std::regex_search(message, re))
|
||||
suppressed = true;
|
||||
|
||||
if (suppressed)
|
||||
{
|
||||
log("%s", message.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &re : log_werror_regexes)
|
||||
if (std::regex_search(message, re))
|
||||
log_error("%s", message.c_str());
|
||||
|
||||
if (log_warnings.count(message))
|
||||
{
|
||||
log("%s", message.c_str());
|
||||
log_flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log_errfile != NULL && !log_quiet_warnings)
|
||||
log_files.push_back(log_errfile);
|
||||
|
||||
log("%s", message.c_str());
|
||||
log_flush();
|
||||
|
||||
if (log_errfile != NULL && !log_quiet_warnings)
|
||||
log_files.pop_back();
|
||||
|
||||
log_warnings.insert(message);
|
||||
}
|
||||
|
||||
log_warnings_count++;
|
||||
}
|
||||
logv_warning_with_prefix("", format, ap);
|
||||
}
|
||||
|
||||
void logv_error(const char *format, va_list ap)
|
||||
void log_file_warning(const std::string &filename, int lineno,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string prefix = stringf("%s:%d: Warning: ",
|
||||
filename.c_str(), lineno);
|
||||
logv_warning_with_prefix(prefix.c_str(), format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
YS_ATTRIBUTE(noreturn)
|
||||
static void logv_error_with_prefix(const char *prefix,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
#ifdef EMSCRIPTEN
|
||||
auto backup_log_files = log_files;
|
||||
|
@ -302,7 +288,7 @@ void logv_error(const char *format, va_list ap)
|
|||
f = stderr;
|
||||
|
||||
log_last_error = vstringf(format, ap);
|
||||
log("ERROR: %s", log_last_error.c_str());
|
||||
log("%s%s", prefix, log_last_error.c_str());
|
||||
log_flush();
|
||||
|
||||
if (log_error_atexit)
|
||||
|
@ -318,6 +304,21 @@ void logv_error(const char *format, va_list ap)
|
|||
#endif
|
||||
}
|
||||
|
||||
void logv_error(const char *format, va_list ap)
|
||||
{
|
||||
logv_error_with_prefix("ERROR: ", format, ap);
|
||||
}
|
||||
|
||||
void log_file_error(const string &filename, int lineno,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string prefix = stringf("%s:%d: ERROR: ",
|
||||
filename.c_str(), lineno);
|
||||
logv_error_with_prefix(prefix.c_str(), format, ap);
|
||||
}
|
||||
|
||||
void log(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -636,4 +637,3 @@ dict<std::string, std::pair<std::string, int>> get_coverage_data()
|
|||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
11
kernel/log.h
11
kernel/log.h
|
@ -73,8 +73,13 @@ YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noretur
|
|||
void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));
|
||||
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
|
||||
// Log with filename to report a problem in a source file.
|
||||
void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
|
||||
|
||||
void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
|
||||
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
|
||||
void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn);
|
||||
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
|
||||
|
||||
void log_spacer();
|
||||
|
@ -89,7 +94,9 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
|
|||
const char *log_const(const RTLIL::Const &value, bool autoint = true);
|
||||
const char *log_id(RTLIL::IdString id);
|
||||
|
||||
template<typename T> static inline const char *log_id(T *obj) {
|
||||
template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
|
||||
if (nullstr && obj == nullptr)
|
||||
return nullstr;
|
||||
return log_id(obj->name);
|
||||
}
|
||||
|
||||
|
@ -190,7 +197,7 @@ struct PerformanceTimer
|
|||
t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
|
||||
return t;
|
||||
# else
|
||||
# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
|
||||
# error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)."
|
||||
# endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
|
@ -158,7 +158,7 @@ struct ModIndex : public RTLIL::Monitor
|
|||
#endif
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
|
||||
void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == cell->module);
|
||||
|
||||
|
@ -169,7 +169,7 @@ struct ModIndex : public RTLIL::Monitor
|
|||
port_add(cell, port, sig);
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE
|
||||
void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == mod);
|
||||
|
||||
|
@ -214,13 +214,13 @@ struct ModIndex : public RTLIL::Monitor
|
|||
}
|
||||
}
|
||||
|
||||
virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE
|
||||
void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == mod);
|
||||
auto_reload_module = true;
|
||||
}
|
||||
|
||||
virtual void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE
|
||||
void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE
|
||||
{
|
||||
log_assert(module == mod);
|
||||
auto_reload_module = true;
|
||||
|
|
|
@ -86,6 +86,8 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
|
|||
|
||||
void Pass::post_execute(Pass::pre_post_exec_state_t state)
|
||||
{
|
||||
IdString::checkpoint();
|
||||
|
||||
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
|
||||
runtime_ns += time_ns;
|
||||
current_pass = state.parent_pass;
|
||||
|
@ -615,7 +617,7 @@ static struct CellHelpMessages {
|
|||
|
||||
struct HelpPass : public Pass {
|
||||
HelpPass() : Pass("help", "display help messages") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
log("\n");
|
||||
log(" help ................ list all commands\n");
|
||||
|
@ -684,7 +686,7 @@ struct HelpPass : public Pass {
|
|||
|
||||
fclose(f);
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design*)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
|
||||
{
|
||||
if (args.size() == 1) {
|
||||
log("\n");
|
||||
|
@ -768,7 +770,7 @@ struct HelpPass : public Pass {
|
|||
|
||||
struct EchoPass : public Pass {
|
||||
EchoPass() : Pass("echo", "turning echoing back of commands on and off") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
log("\n");
|
||||
log(" echo on\n");
|
||||
|
@ -781,7 +783,7 @@ struct EchoPass : public Pass {
|
|||
log("Do not print all commands to log before executing them. (default)\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design*)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
|
||||
{
|
||||
if (args.size() > 2)
|
||||
cmd_error(args, 2, "Unexpected argument.");
|
||||
|
@ -806,10 +808,9 @@ struct MinisatSatSolver : public SatSolver {
|
|||
MinisatSatSolver() : SatSolver("minisat") {
|
||||
yosys_satsolver = this;
|
||||
}
|
||||
virtual ezSAT *create() YS_OVERRIDE {
|
||||
ezSAT *create() YS_OVERRIDE {
|
||||
return new ezMiniSAT();
|
||||
}
|
||||
} MinisatSatSolver;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
|
@ -88,9 +88,9 @@ struct Frontend : Pass
|
|||
|
||||
std::string frontend_name;
|
||||
Frontend(std::string name, std::string short_help = "** document me **");
|
||||
virtual void run_register() YS_OVERRIDE;
|
||||
virtual ~Frontend();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
|
||||
void run_register() YS_OVERRIDE;
|
||||
~Frontend() YS_OVERRIDE;
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
|
||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
static std::vector<std::string> next_args;
|
||||
|
@ -104,9 +104,9 @@ struct Backend : Pass
|
|||
{
|
||||
std::string backend_name;
|
||||
Backend(std::string name, std::string short_help = "** document me **");
|
||||
virtual void run_register() YS_OVERRIDE;
|
||||
virtual ~Backend();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
|
||||
void run_register() YS_OVERRIDE;
|
||||
~Backend() YS_OVERRIDE;
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
|
||||
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
|
||||
|
|
|
@ -33,6 +33,8 @@ std::vector<int> RTLIL::IdString::global_refcount_storage_;
|
|||
std::vector<char*> RTLIL::IdString::global_id_storage_;
|
||||
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
|
||||
std::vector<int> RTLIL::IdString::global_free_idx_list_;
|
||||
int RTLIL::IdString::last_created_idx_[8];
|
||||
int RTLIL::IdString::last_created_idx_ptr_;
|
||||
|
||||
RTLIL::Const::Const()
|
||||
{
|
||||
|
@ -676,6 +678,11 @@ std::map<unsigned int, RTLIL::Module*> *RTLIL::Module::get_all_modules(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
|
||||
{
|
||||
log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name));
|
||||
}
|
||||
|
||||
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, bool mayfail)
|
||||
{
|
||||
if (mayfail)
|
||||
|
@ -683,6 +690,14 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLI
|
|||
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
|
||||
}
|
||||
|
||||
|
||||
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*>, dict<RTLIL::IdString, RTLIL::IdString>, bool mayfail)
|
||||
{
|
||||
if (mayfail)
|
||||
return RTLIL::IdString();
|
||||
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
|
||||
}
|
||||
|
||||
size_t RTLIL::Module::count_id(RTLIL::IdString id)
|
||||
{
|
||||
return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
|
||||
|
@ -782,7 +797,7 @@ namespace {
|
|||
|
||||
void check()
|
||||
{
|
||||
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
|
||||
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
|
||||
cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
|
||||
return;
|
||||
|
||||
|
@ -2423,7 +2438,7 @@ void RTLIL::Cell::check()
|
|||
|
||||
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
||||
{
|
||||
if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" ||
|
||||
if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
|
||||
type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
|
||||
return;
|
||||
|
||||
|
@ -2475,6 +2490,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
|||
if (connections_.count("\\Y"))
|
||||
parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
|
||||
|
||||
if (connections_.count("\\Q"))
|
||||
parameters["\\WIDTH"] = GetSize(connections_["\\Q"]);
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
|
@ -3305,7 +3323,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
|
|||
remove(width, width_ - width);
|
||||
|
||||
if (width_ < width) {
|
||||
RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0;
|
||||
RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx;
|
||||
if (!is_signed)
|
||||
padding = RTLIL::State::S0;
|
||||
while (width_ < width)
|
||||
|
@ -3866,6 +3884,11 @@ RTLIL::CaseRule::~CaseRule()
|
|||
delete *it;
|
||||
}
|
||||
|
||||
bool RTLIL::CaseRule::empty() const
|
||||
{
|
||||
return actions.empty() && switches.empty();
|
||||
}
|
||||
|
||||
RTLIL::CaseRule *RTLIL::CaseRule::clone() const
|
||||
{
|
||||
RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule;
|
||||
|
@ -3882,6 +3905,11 @@ RTLIL::SwitchRule::~SwitchRule()
|
|||
delete *it;
|
||||
}
|
||||
|
||||
bool RTLIL::SwitchRule::empty() const
|
||||
{
|
||||
return cases.empty();
|
||||
}
|
||||
|
||||
RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const
|
||||
{
|
||||
RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
|
@ -76,6 +76,9 @@ namespace RTLIL
|
|||
|
||||
struct IdString
|
||||
{
|
||||
#undef YOSYS_XTRACE_GET_PUT
|
||||
#undef YOSYS_SORT_ID_FREE_LIST
|
||||
|
||||
// the global id string cache
|
||||
|
||||
static struct destruct_guard_t {
|
||||
|
@ -89,9 +92,43 @@ namespace RTLIL
|
|||
static dict<char*, int, hash_cstr_ops> global_id_index_;
|
||||
static std::vector<int> global_free_idx_list_;
|
||||
|
||||
static int last_created_idx_ptr_;
|
||||
static int last_created_idx_[8];
|
||||
|
||||
static inline void xtrace_db_dump()
|
||||
{
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
|
||||
{
|
||||
if (global_id_storage_.at(idx) == nullptr)
|
||||
log("#X# DB-DUMP index %d: FREE\n", idx);
|
||||
else
|
||||
log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void checkpoint()
|
||||
{
|
||||
last_created_idx_ptr_ = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (last_created_idx_[i])
|
||||
put_reference(last_created_idx_[i]);
|
||||
last_created_idx_[i] = 0;
|
||||
}
|
||||
#ifdef YOSYS_SORT_ID_FREE_LIST
|
||||
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int get_reference(int idx)
|
||||
{
|
||||
global_refcount_storage_.at(idx)++;
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace) {
|
||||
log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
@ -107,6 +144,11 @@ namespace RTLIL
|
|||
auto it = global_id_index_.find((char*)p);
|
||||
if (it != global_id_index_.end()) {
|
||||
global_refcount_storage_.at(it->second)++;
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace) {
|
||||
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
|
||||
}
|
||||
#endif
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
@ -124,16 +166,22 @@ namespace RTLIL
|
|||
global_refcount_storage_.at(idx)++;
|
||||
|
||||
// Avoid Create->Delete->Create pattern
|
||||
static IdString last_created_id;
|
||||
put_reference(last_created_id.index_);
|
||||
last_created_id.index_ = idx;
|
||||
get_reference(last_created_id.index_);
|
||||
if (last_created_idx_[last_created_idx_ptr_])
|
||||
put_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||
last_created_idx_[last_created_idx_ptr_] = idx;
|
||||
get_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||
last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
|
||||
|
||||
if (yosys_xtrace) {
|
||||
log("#X# New IdString '%s' with index %d.\n", p, idx);
|
||||
log_backtrace("-X- ", yosys_xtrace-1);
|
||||
}
|
||||
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace) {
|
||||
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
@ -144,6 +192,12 @@ namespace RTLIL
|
|||
if (!destruct_guard.ok)
|
||||
return;
|
||||
|
||||
#ifdef YOSYS_XTRACE_GET_PUT
|
||||
if (yosys_xtrace) {
|
||||
log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||
}
|
||||
#endif
|
||||
|
||||
log_assert(global_refcount_storage_.at(idx) > 0);
|
||||
|
||||
if (--global_refcount_storage_.at(idx) != 0)
|
||||
|
@ -493,6 +547,14 @@ struct RTLIL::Const
|
|||
return ret;
|
||||
}
|
||||
|
||||
void extu(int width) {
|
||||
bits.resize(width, RTLIL::State::S0);
|
||||
}
|
||||
|
||||
void exts(int width) {
|
||||
bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back());
|
||||
}
|
||||
|
||||
inline unsigned int hash() const {
|
||||
unsigned int h = mkhash_init;
|
||||
for (auto b : bits)
|
||||
|
@ -914,7 +976,9 @@ public:
|
|||
Module();
|
||||
virtual ~Module();
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false);
|
||||
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail = false);
|
||||
virtual size_t count_id(RTLIL::IdString id);
|
||||
virtual void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces);
|
||||
|
||||
virtual void sort();
|
||||
virtual void check();
|
||||
|
@ -1249,6 +1313,8 @@ struct RTLIL::CaseRule
|
|||
~CaseRule();
|
||||
void optimize();
|
||||
|
||||
bool empty() const;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
RTLIL::CaseRule *clone() const;
|
||||
};
|
||||
|
@ -1260,6 +1326,8 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
|
|||
|
||||
~SwitchRule();
|
||||
|
||||
bool empty() const;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
RTLIL::SwitchRule *clone() const;
|
||||
};
|
||||
|
@ -1301,7 +1369,7 @@ inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
|
|||
return wire ? (offset < other.offset) : (data < other.data);
|
||||
if (wire != nullptr && other.wire != nullptr)
|
||||
return wire->name < other.wire->name;
|
||||
return wire < other.wire;
|
||||
return (wire != nullptr) < (other.wire != nullptr);
|
||||
}
|
||||
|
||||
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
#elif defined(__APPLE__)
|
||||
|
@ -41,13 +41,15 @@
|
|||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <sys/stat.h>
|
||||
# include <glob.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/wait.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB)
|
||||
# include <glob.h>
|
||||
#endif
|
||||
|
||||
|
@ -176,7 +178,7 @@ std::string vstringf(const char *fmt, va_list ap)
|
|||
std::string string;
|
||||
char *str = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32 )|| defined(__CYGWIN__)
|
||||
int sz = 64, rc;
|
||||
while (1) {
|
||||
va_list apc;
|
||||
|
@ -226,12 +228,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings)
|
|||
|
||||
if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
|
||||
string sep_string = sep;
|
||||
for (size_t i = pos_begin+1; i < text.size(); i++)
|
||||
for (size_t i = pos_begin+1; i < text.size(); i++) {
|
||||
if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
|
||||
std::string token = text.substr(pos_begin, i-pos_begin+1);
|
||||
text = text.substr(i+1);
|
||||
return token;
|
||||
}
|
||||
if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) {
|
||||
std::string token = text.substr(pos_begin, i-pos_begin+1);
|
||||
text = text.substr(i+2);
|
||||
return token + ";";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t pos_end = text.find_first_of(sep, pos_begin);
|
||||
|
@ -602,7 +610,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
|
|||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB)
|
||||
results.push_back(filename_pattern);
|
||||
#else
|
||||
glob_t globbuf;
|
||||
|
@ -674,9 +682,10 @@ extern Tcl_Interp *yosys_get_tcl_interp()
|
|||
|
||||
struct TclPass : public Pass {
|
||||
TclPass() : Pass("tcl", "execute a TCL script file") { }
|
||||
virtual void help() {
|
||||
void help() YS_OVERRIDE {
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" tcl <filename>\n");
|
||||
log(" tcl <filename> [args]\n");
|
||||
log("\n");
|
||||
log("This command executes the tcl commands in the specified file.\n");
|
||||
log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
|
||||
|
@ -686,14 +695,24 @@ struct TclPass : public Pass {
|
|||
log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n");
|
||||
log("in order to avoid a name collision with the built in commands.\n");
|
||||
log("\n");
|
||||
log("If any arguments are specified, these arguments are provided to the script via\n");
|
||||
log("the standard $argc and $argv variables.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *) YS_OVERRIDE {
|
||||
if (args.size() < 2)
|
||||
log_cmd_error("Missing script file.\n");
|
||||
if (args.size() > 2)
|
||||
extra_args(args, 1, design, false);
|
||||
if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
|
||||
log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
|
||||
|
||||
std::vector<Tcl_Obj*> script_args;
|
||||
for (auto it = args.begin() + 2; it != args.end(); ++it)
|
||||
script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size()));
|
||||
|
||||
Tcl_Interp *interp = yosys_get_tcl_interp();
|
||||
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0);
|
||||
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0);
|
||||
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0);
|
||||
if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK)
|
||||
log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp));
|
||||
}
|
||||
} TclPass;
|
||||
#endif
|
||||
|
@ -771,7 +790,7 @@ std::string proc_self_dirname()
|
|||
return "/";
|
||||
}
|
||||
#else
|
||||
#error Dont know how to determine process executable base path!
|
||||
#error "Don't know how to determine process executable base path!"
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
|
@ -837,7 +856,7 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
|
|||
while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
|
||||
label += command[pos++];
|
||||
|
||||
if (label.back() == ':' && GetSize(label) > 1)
|
||||
if (GetSize(label) > 1 && label.back() == ':')
|
||||
{
|
||||
label = label.substr(0, GetSize(label)-1);
|
||||
command = command.substr(pos);
|
||||
|
@ -859,17 +878,19 @@ void run_frontend(std::string filename, std::string command, std::string *backen
|
|||
command = "verilog";
|
||||
else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
|
||||
command = "verilog -sv";
|
||||
else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd")
|
||||
else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".vhd")
|
||||
command = "vhdl";
|
||||
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
|
||||
command = "blif";
|
||||
else if (filename.size() > 5 && filename.substr(filename.size()-6) == ".eblif")
|
||||
command = "blif";
|
||||
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json")
|
||||
command = "json";
|
||||
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
|
||||
command = "ilang";
|
||||
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
|
||||
command = "script";
|
||||
else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".tcl")
|
||||
else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".tcl")
|
||||
command = "tcl";
|
||||
else if (filename == "-")
|
||||
command = "script";
|
||||
|
@ -1149,7 +1170,7 @@ void shell(RTLIL::Design *design)
|
|||
|
||||
struct ShellPass : public Pass {
|
||||
ShellPass() : Pass("shell", "enter interactive command mode") { }
|
||||
virtual void help() {
|
||||
void help() YS_OVERRIDE {
|
||||
log("\n");
|
||||
log(" shell\n");
|
||||
log("\n");
|
||||
|
@ -1181,7 +1202,7 @@ struct ShellPass : public Pass {
|
|||
log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
|
||||
extra_args(args, 1, design, false);
|
||||
shell(design);
|
||||
}
|
||||
|
@ -1190,7 +1211,7 @@ struct ShellPass : public Pass {
|
|||
#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
|
||||
struct HistoryPass : public Pass {
|
||||
HistoryPass() : Pass("history", "show last interactive commands") { }
|
||||
virtual void help() {
|
||||
void help() YS_OVERRIDE {
|
||||
log("\n");
|
||||
log(" history\n");
|
||||
log("\n");
|
||||
|
@ -1199,7 +1220,7 @@ struct HistoryPass : public Pass {
|
|||
log("from executed scripts.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
|
||||
extra_args(args, 1, design, false);
|
||||
#ifdef YOSYS_ENABLE_READLINE
|
||||
for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
|
||||
|
@ -1214,7 +1235,7 @@ struct HistoryPass : public Pass {
|
|||
|
||||
struct ScriptCmdPass : public Pass {
|
||||
ScriptCmdPass() : Pass("script", "execute commands from script file") { }
|
||||
virtual void help() {
|
||||
void help() YS_OVERRIDE {
|
||||
log("\n");
|
||||
log(" script <filename> [<from_label>:<to_label>]\n");
|
||||
log("\n");
|
||||
|
@ -1229,7 +1250,7 @@ struct ScriptCmdPass : public Pass {
|
|||
log("marked with that label (until the next label) is executed.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE {
|
||||
if (args.size() < 2)
|
||||
log_cmd_error("Missing script file.\n");
|
||||
else if (args.size() == 2)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/* -*- c++ -*-
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <time.h>
|
||||
|
||||
// minisat is using limit macros and format macros in their headers that
|
||||
// can be the source of some troubles when used from c++11. thefore we
|
||||
// can be the source of some troubles when used from c++11. therefore we
|
||||
// don't force ezSAT users to use minisat headers..
|
||||
namespace Minisat {
|
||||
class Solver;
|
||||
|
|
|
@ -109,7 +109,7 @@ look at the demo.cc example program in this directory.
|
|||
Setting up graphs
|
||||
-----------------
|
||||
|
||||
Instanciate the SubCircuit::Graph class and use the methods of this class to
|
||||
Instantiate the SubCircuit::Graph class and use the methods of this class to
|
||||
set up the circuit.
|
||||
|
||||
SubCircuit::Graph myGraph;
|
||||
|
@ -152,7 +152,7 @@ rotate shift,
|
|||
|
||||
The method createConstant() can be used to add a constant driver to a signal.
|
||||
The signal value is encoded as one char by bit, allowing for multi-valued
|
||||
logic matching. The follwoing command sets the lowest bit of cell6.A to a
|
||||
logic matching. The following command sets the lowest bit of cell6.A to a
|
||||
logic 1:
|
||||
|
||||
myGraph.createConnection("cell6", "A", 0, '1');
|
||||
|
@ -314,7 +314,7 @@ bool userCompareEdge(needleGraphId, needleFromNodeId, needleFromUserData, needle
|
|||
|
||||
Perform additional checks on a pair of a pair of adjacent nodes (one
|
||||
adjacent pair from the needle and one adjacent pair from the haystack)
|
||||
to determine wheter this edge from the needle is compatible with
|
||||
to determine whether this edge from the needle is compatible with
|
||||
that edge from the haystack. The default implementation always
|
||||
returns true.
|
||||
|
||||
|
|
|
@ -119,6 +119,12 @@ than one bit from \B{S} is set the output is undefined. Cells of this type are u
|
|||
``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by
|
||||
an optimization).
|
||||
|
||||
The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH}
|
||||
parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are
|
||||
\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y}
|
||||
is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore,
|
||||
the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;.
|
||||
|
||||
Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements
|
||||
usually results in trees of multiplexer cells. Many passes (from various
|
||||
optimizations to FSM extraction) heavily depend on these multiplexer trees to
|
||||
|
@ -211,14 +217,15 @@ Add information about {\tt \$sr} cells (set-reset flip-flops) and d-type latches
|
|||
\subsection{Memories}
|
||||
\label{sec:memcells}
|
||||
|
||||
Memories are either represented using RTLIL::Memory objects and {\tt \$memrd} and {\tt \$memwr} cells
|
||||
or simply by using {\tt \$mem} cells.
|
||||
Memories are either represented using RTLIL::Memory objects, {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit}
|
||||
cells, or by {\tt \$mem} cells alone.
|
||||
|
||||
In the first alternative the RTLIL::Memory objects hold the general metadata for the memory (bit width,
|
||||
size in number of words, etc.) and for each port a {\tt \$memrd} (read port) or {\tt \$memwr} (write port)
|
||||
cell is created. Having individual cells for read and write ports has the advantage that they can be
|
||||
consolidated using resource sharing passes. In some cases this drastically reduces the number of required
|
||||
ports on the memory cell.
|
||||
ports on the memory cell. In this alternative, memory initialization data is represented by {\tt \$meminit} cells,
|
||||
which allow delaying constant folding for initialization addresses and data until after the frontend finishes.
|
||||
|
||||
The {\tt \$memrd} cells have a clock input \B{CLK}, an enable input \B{EN}, an
|
||||
address input \B{ADDR}, and a data output \B{DATA}. They also have the
|
||||
|
@ -253,7 +260,7 @@ enable bit for each data bit), an address input \B{ADDR} and a data input
|
|||
|
||||
\begin{itemize}
|
||||
\item \B{MEMID} \\
|
||||
The name of the RTLIL::Memory object that is associated with this read port.
|
||||
The name of the RTLIL::Memory object that is associated with this write port.
|
||||
|
||||
\item \B{ABITS} \\
|
||||
The number of address bits (width of the \B{ADDR} input port).
|
||||
|
@ -262,7 +269,7 @@ The number of address bits (width of the \B{ADDR} input port).
|
|||
The number of data bits (width of the \B{DATA} output port).
|
||||
|
||||
\item \B{CLK\_ENABLE} \\
|
||||
When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and
|
||||
When this parameter is non-zero, the clock is used. Otherwise this write port is asynchronous and
|
||||
the \B{CLK} input is not used.
|
||||
|
||||
\item \B{CLK\_POLARITY} \\
|
||||
|
@ -273,6 +280,27 @@ edge if this parameter is {\tt 1'b0}.
|
|||
The cell with the higher integer value in this parameter wins a write conflict.
|
||||
\end{itemize}
|
||||
|
||||
The {\tt \$meminit} cells have an address input \B{ADDR} and a data input \B{DATA}, with the width
|
||||
of the \B{DATA} port equal to \B{WIDTH} parameter times \B{WORDS} parameter. Both of the inputs
|
||||
must resolve to a constant for synthesis to succeed.
|
||||
|
||||
\begin{itemize}
|
||||
\item \B{MEMID} \\
|
||||
The name of the RTLIL::Memory object that is associated with this initialization cell.
|
||||
|
||||
\item \B{ABITS} \\
|
||||
The number of address bits (width of the \B{ADDR} input port).
|
||||
|
||||
\item \B{WIDTH} \\
|
||||
The number of data bits per memory location.
|
||||
|
||||
\item \B{WORDS} \\
|
||||
The number of consecutive memory locations initialized by this cell.
|
||||
|
||||
\item \B{PRIORITY} \\
|
||||
The cell with the higher integer value in this parameter wins an initialization conflict.
|
||||
\end{itemize}
|
||||
|
||||
The HDL frontend models a memory using RTLIL::Memory objects and asynchronous
|
||||
{\tt \$memrd} and {\tt \$memwr} cells. The {\tt memory} pass (i.e.~its various sub-passes) migrates
|
||||
{\tt \$dff} cells into the {\tt \$memrd} and {\tt \$memwr} cells making them synchronous, then
|
||||
|
@ -295,6 +323,9 @@ The number of address bits.
|
|||
\item \B{WIDTH} \\
|
||||
The number of data bits per word.
|
||||
|
||||
\item \B{INIT} \\
|
||||
The initial memory contents.
|
||||
|
||||
\item \B{RD\_PORTS} \\
|
||||
The number of read ports on this memory cell.
|
||||
|
||||
|
@ -345,9 +376,11 @@ This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals
|
|||
This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all data signals for the write ports.
|
||||
\end{itemize}
|
||||
|
||||
The {\tt techmap} pass can be used to manually map {\tt \$mem} cells to
|
||||
specialized memory cells on the target architecture, such as block ram resources
|
||||
on an FPGA.
|
||||
The {\tt memory\_collect} pass can be used to convert discrete {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} cells
|
||||
belonging to the same memory to a single {\tt \$mem} cell, whereas the {\tt memory\_unpack} pass performs the inverse operation.
|
||||
The {\tt memory\_dff} pass can combine asynchronous memory ports that are fed by or feeding registers into synchronous memory ports.
|
||||
The {\tt memory\_bram} pass can be used to recognize {\tt \$mem} cells that can be implemented with a block RAM resource on an FPGA.
|
||||
The {\tt memory\_map} pass can be used to implement {\tt \$mem} cells as basic logic: word-wide DFFs and address decoders.
|
||||
|
||||
\subsection{Finite State Machines}
|
||||
|
||||
|
@ -371,9 +404,15 @@ Verilog & Cell Type \\
|
|||
\hline
|
||||
\lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\
|
||||
\lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\
|
||||
\lstinline[language=Verilog]; Y = ~(A & B); & {\tt \$\_NAND\_} \\
|
||||
\lstinline[language=Verilog]; Y = A & ~B; & {\tt \$\_ANDNOT\_} \\
|
||||
\lstinline[language=Verilog]; Y = A | B; & {\tt \$\_OR\_} \\
|
||||
\lstinline[language=Verilog]; Y = ~(A | B); & {\tt \$\_NOR\_} \\
|
||||
\lstinline[language=Verilog]; Y = A | ~B; & {\tt \$\_ORNOT\_} \\
|
||||
\lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\
|
||||
\lstinline[language=Verilog]; Y = ~(A ^ B); & {\tt \$\_XNOR\_} \\
|
||||
\lstinline[language=Verilog]; Y = S ? B : A; & {\tt \$\_MUX\_} \\
|
||||
\lstinline[language=Verilog]; Y = EN ? A : 'bz; & {\tt \$\_TBUF\_} \\
|
||||
\hline
|
||||
\lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\
|
||||
\lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\
|
||||
|
@ -396,9 +435,10 @@ $ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\
|
|||
\end{table}
|
||||
|
||||
Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. The cell types
|
||||
{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_OR\_}, {\tt \$\_XOR\_} and {\tt \$\_MUX\_}
|
||||
are used to model combinatorial logic. The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_}
|
||||
represent d-type flip-flops.
|
||||
{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_},
|
||||
{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic.
|
||||
The cell type {\tt \$\_TBUF\_} is used to model tristate logic.
|
||||
The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops.
|
||||
|
||||
The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_},
|
||||
{\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement
|
||||
|
@ -410,7 +450,7 @@ otherwise.
|
|||
\begin{lstlisting}[mathescape,language=Verilog]
|
||||
always @($ClkEdge$ C, $RstEdge$ R)
|
||||
if (R == $RstLvl$)
|
||||
Q <= $RstVa$l;
|
||||
Q <= $RstVal$;
|
||||
else
|
||||
Q <= D;
|
||||
\end{lstlisting}
|
||||
|
@ -450,7 +490,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
|
|||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_ORNOT\_},
|
||||
{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
|
||||
Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
|
||||
\end{fixme}
|
||||
|
||||
|
|
|
@ -428,8 +428,8 @@ memory object has the following properties:
|
|||
|
||||
All read accesses to the memory are transformed to {\tt \$memrd} cells and all write accesses to
|
||||
{\tt \$memwr} cells by the language frontend. These cells consist of independent read- and write-ports
|
||||
to the memory. The \B{MEMID} parameter on these cells is used to link them together and to the
|
||||
RTLIL::Memory object they belong to.
|
||||
to the memory. Memory initialization is transformed to {\tt \$meminit} cells by the language frontend.
|
||||
The \B{MEMID} parameter on these cells is used to link them together and to the RTLIL::Memory object they belong to.
|
||||
|
||||
The rationale behind using separate cells for the individual ports versus
|
||||
creating a large multiport memory cell right in the language frontend is that
|
||||
|
|
|
@ -98,7 +98,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
|
|||
// each pass contains a singleton object that is derived from Pass
|
||||
struct StubnetsPass : public Pass {
|
||||
StubnetsPass() : Pass("stubnets") { }
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
// variables to mirror information from passed options
|
||||
bool report_bits = 0;
|
||||
|
|
|
@ -6,7 +6,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct MyPass : public Pass {
|
||||
MyPass() : Pass("my_cmd", "just a simple test") { }
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
log("Arguments to my_cmd:\n");
|
||||
for (auto &arg : args)
|
||||
|
@ -22,7 +22,7 @@ struct MyPass : public Pass {
|
|||
|
||||
struct Test1Pass : public Pass {
|
||||
Test1Pass() : Pass("test1", "creating the absval module") { }
|
||||
virtual void execute(std::vector<std::string>, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
if (design->has("\\absval") != 0)
|
||||
log_error("A module with the name absval already exists!\n");
|
||||
|
@ -49,7 +49,7 @@ struct Test1Pass : public Pass {
|
|||
|
||||
struct Test2Pass : public Pass {
|
||||
Test2Pass() : Pass("test2", "demonstrating sigmap on test module") { }
|
||||
virtual void execute(std::vector<std::string>, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
if (design->selection_stack.back().empty())
|
||||
log_cmd_error("This command can't operator on an empty selection!\n");
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,11 +5,11 @@ vcxsrc="$1-$2"
|
|||
yosysver="$2"
|
||||
gitsha="$3"
|
||||
|
||||
rm -rf YosysVS-Tpl-v1.zip YosysVS
|
||||
wget http://www.clifford.at/yosys/nogit/YosysVS-Tpl-v1.zip
|
||||
rm -rf YosysVS-Tpl-v2.zip YosysVS
|
||||
wget http://www.clifford.at/yosys/nogit/YosysVS-Tpl-v2.zip
|
||||
|
||||
unzip YosysVS-Tpl-v1.zip
|
||||
rm -f YosysVS-Tpl-v1.zip
|
||||
unzip YosysVS-Tpl-v2.zip
|
||||
rm -f YosysVS-Tpl-v2.zip
|
||||
mv YosysVS "$vcxsrc"
|
||||
|
||||
{
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
/* This file comes from the PyPA Setuptools repository, commit 16e452a:
|
||||
https://github.com/pypa/setuptools
|
||||
Modifications include this comment and inline inclusion of the LICENSE text. */
|
||||
|
||||
/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. */
|
||||
|
||||
/* Setuptools Script Launcher for Windows
|
||||
|
||||
This is a stub executable for Windows that functions somewhat like
|
||||
Effbot's "exemaker", in that it runs a script with the same name but
|
||||
a .py extension, using information from a #! line. It differs in that
|
||||
it spawns the actual Python executable, rather than attempting to
|
||||
hook into the Python DLL. This means that the script will run with
|
||||
sys.executable set to the Python executable, where exemaker ends up with
|
||||
sys.executable pointing to itself. (Which means it won't work if you try
|
||||
to run another Python process using sys.executable.)
|
||||
|
||||
To build/rebuild with mingw32, do this in the setuptools project directory:
|
||||
|
||||
gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
|
||||
gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
|
||||
|
||||
To build for Windows RT, install both Visual Studio Express for Windows 8
|
||||
and for Windows Desktop (both freeware), create "win32" application using
|
||||
"Windows Desktop" version, create new "ARM" target via
|
||||
"Configuration Manager" menu and modify ".vcxproj" file by adding
|
||||
"<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
|
||||
as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
|
||||
properties.
|
||||
|
||||
It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
|
||||
actually run Python in the same process. Note that using 'exec' instead
|
||||
of 'spawn' doesn't work, because on Windows this leads to the Python
|
||||
executable running in the *background*, attached to the same console
|
||||
window, meaning you get a command prompt back *before* Python even finishes
|
||||
starting. So, we have to use spawnv() and wait for Python to exit before
|
||||
continuing. :(
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int child_pid=0;
|
||||
|
||||
int fail(char *format, char *data) {
|
||||
/* Print error message to stderr and return 2 */
|
||||
fprintf(stderr, format, data);
|
||||
return 2;
|
||||
}
|
||||
|
||||
char *quoted(char *data) {
|
||||
int i, ln = strlen(data), nb;
|
||||
|
||||
/* We allocate twice as much space as needed to deal with worse-case
|
||||
of having to escape everything. */
|
||||
char *result = calloc(ln*2+3, sizeof(char));
|
||||
char *presult = result;
|
||||
|
||||
*presult++ = '"';
|
||||
for (nb=0, i=0; i < ln; i++)
|
||||
{
|
||||
if (data[i] == '\\')
|
||||
nb += 1;
|
||||
else if (data[i] == '"')
|
||||
{
|
||||
for (; nb > 0; nb--)
|
||||
*presult++ = '\\';
|
||||
*presult++ = '\\';
|
||||
}
|
||||
else
|
||||
nb = 0;
|
||||
*presult++ = data[i];
|
||||
}
|
||||
|
||||
for (; nb > 0; nb--) /* Deal w trailing slashes */
|
||||
*presult++ = '\\';
|
||||
|
||||
*presult++ = '"';
|
||||
*presult++ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
char *loadable_exe(char *exename) {
|
||||
/* HINSTANCE hPython; DLL handle for python executable */
|
||||
char *result;
|
||||
|
||||
/* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
if (!hPython) return NULL; */
|
||||
|
||||
/* Return the absolute filename for spawnv */
|
||||
result = calloc(MAX_PATH, sizeof(char));
|
||||
strncpy(result, exename, MAX_PATH);
|
||||
/*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
|
||||
|
||||
FreeLibrary(hPython); */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
char *find_exe(char *exename, char *script) {
|
||||
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
|
||||
char path[_MAX_PATH], c, *result;
|
||||
|
||||
/* convert slashes to backslashes for uniform search below */
|
||||
result = exename;
|
||||
while (c = *result++) if (c=='/') result[-1] = '\\';
|
||||
|
||||
_splitpath(exename, drive, dir, fname, ext);
|
||||
if (drive[0] || dir[0]=='\\') {
|
||||
return loadable_exe(exename); /* absolute path, use directly */
|
||||
}
|
||||
/* Use the script's parent directory, which should be the Python home
|
||||
(This should only be used for bdist_wininst-installed scripts, because
|
||||
easy_install-ed scripts use the absolute path to python[w].exe
|
||||
*/
|
||||
_splitpath(script, drive, dir, fname, ext);
|
||||
result = dir + strlen(dir) -1;
|
||||
if (*result == '\\') result--;
|
||||
while (*result != '\\' && result>=dir) *result-- = 0;
|
||||
_makepath(path, drive, dir, exename, NULL);
|
||||
return loadable_exe(path);
|
||||
}
|
||||
|
||||
|
||||
char **parse_argv(char *cmdline, int *argc)
|
||||
{
|
||||
/* Parse a command line in-place using MS C rules */
|
||||
|
||||
char **result = calloc(strlen(cmdline), sizeof(char *));
|
||||
char *output = cmdline;
|
||||
char c;
|
||||
int nb = 0;
|
||||
int iq = 0;
|
||||
*argc = 0;
|
||||
|
||||
result[0] = output;
|
||||
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
|
||||
|
||||
do {
|
||||
c = *cmdline++;
|
||||
if (!c || (isspace(c) && !iq)) {
|
||||
while (nb) {*output++ = '\\'; nb--; }
|
||||
*output++ = 0;
|
||||
result[++*argc] = output;
|
||||
if (!c) return result;
|
||||
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
|
||||
if (!*cmdline) return result; /* avoid empty arg if trailing ws */
|
||||
continue;
|
||||
}
|
||||
if (c == '\\')
|
||||
++nb; /* count \'s */
|
||||
else {
|
||||
if (c == '"') {
|
||||
if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */
|
||||
nb = nb >> 1; /* cut \'s in half */
|
||||
}
|
||||
while (nb) {*output++ = '\\'; nb--; }
|
||||
if (c) *output++ = c;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void pass_control_to_child(DWORD control_type) {
|
||||
/*
|
||||
* distribute-issue207
|
||||
* passes the control event to child process (Python)
|
||||
*/
|
||||
if (!child_pid) {
|
||||
return;
|
||||
}
|
||||
GenerateConsoleCtrlEvent(child_pid,0);
|
||||
}
|
||||
|
||||
BOOL control_handler(DWORD control_type) {
|
||||
/*
|
||||
* distribute-issue207
|
||||
* control event handler callback function
|
||||
*/
|
||||
switch (control_type) {
|
||||
case CTRL_C_EVENT:
|
||||
pass_control_to_child(0);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int create_and_wait_for_subprocess(char* command) {
|
||||
/*
|
||||
* distribute-issue207
|
||||
* launches child process (Python)
|
||||
*/
|
||||
DWORD return_value = 0;
|
||||
LPSTR commandline = command;
|
||||
STARTUPINFOA s_info;
|
||||
PROCESS_INFORMATION p_info;
|
||||
ZeroMemory(&p_info, sizeof(p_info));
|
||||
ZeroMemory(&s_info, sizeof(s_info));
|
||||
s_info.cb = sizeof(STARTUPINFO);
|
||||
// set-up control handler callback funciotn
|
||||
SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
|
||||
if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
|
||||
fprintf(stderr, "failed to create process.\n");
|
||||
return 0;
|
||||
}
|
||||
child_pid = p_info.dwProcessId;
|
||||
// wait for Python to exit
|
||||
WaitForSingleObject(p_info.hProcess, INFINITE);
|
||||
if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
|
||||
fprintf(stderr, "failed to get exit code from process.\n");
|
||||
return 0;
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
char* join_executable_and_args(char *executable, char **args, int argc)
|
||||
{
|
||||
/*
|
||||
* distribute-issue207
|
||||
* CreateProcess needs a long string of the executable and command-line arguments,
|
||||
* so we need to convert it from the args that was built
|
||||
*/
|
||||
int len,counter;
|
||||
char* cmdline;
|
||||
|
||||
len=strlen(executable)+2;
|
||||
for (counter=1; counter<argc; counter++) {
|
||||
len+=strlen(args[counter])+1;
|
||||
}
|
||||
|
||||
cmdline = (char*)calloc(len, sizeof(char));
|
||||
sprintf(cmdline, "%s", executable);
|
||||
len=strlen(executable);
|
||||
for (counter=1; counter<argc; counter++) {
|
||||
sprintf(cmdline+len, " %s", args[counter]);
|
||||
len+=strlen(args[counter])+1;
|
||||
}
|
||||
return cmdline;
|
||||
}
|
||||
|
||||
int run(int argc, char **argv, int is_gui) {
|
||||
|
||||
char python[256]; /* python executable's filename*/
|
||||
char *pyopt; /* Python option */
|
||||
char script[256]; /* the script's filename */
|
||||
|
||||
int scriptf; /* file descriptor for script file */
|
||||
|
||||
char **newargs, **newargsp, **parsedargs; /* argument array for exec */
|
||||
char *ptr, *end; /* working pointers for string manipulation */
|
||||
char *cmdline;
|
||||
int i, parsedargc; /* loop counter */
|
||||
|
||||
/* compute script name from our .exe name*/
|
||||
GetModuleFileNameA(NULL, script, sizeof(script));
|
||||
end = script + strlen(script);
|
||||
while( end>script && *end != '.')
|
||||
*end-- = '\0';
|
||||
*end-- = '\0';
|
||||
strcat(script, (GUI ? "-script.pyw" : "-script.py"));
|
||||
|
||||
/* figure out the target python executable */
|
||||
|
||||
scriptf = open(script, O_RDONLY);
|
||||
if (scriptf == -1) {
|
||||
return fail("Cannot open %s\n", script);
|
||||
}
|
||||
end = python + read(scriptf, python, sizeof(python));
|
||||
close(scriptf);
|
||||
|
||||
ptr = python-1;
|
||||
while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
|
||||
|
||||
*ptr-- = '\0';
|
||||
|
||||
if (strncmp(python, "#!", 2)) {
|
||||
/* default to python.exe if no #! header */
|
||||
strcpy(python, "#!python.exe");
|
||||
}
|
||||
|
||||
parsedargs = parse_argv(python+2, &parsedargc);
|
||||
|
||||
/* Using spawnv() can fail strangely if you e.g. find the Cygwin
|
||||
Python, so we'll make sure Windows can find and load it */
|
||||
|
||||
ptr = find_exe(parsedargs[0], script);
|
||||
if (!ptr) {
|
||||
return fail("Cannot find Python executable %s\n", parsedargs[0]);
|
||||
}
|
||||
|
||||
/* printf("Python executable: %s\n", ptr); */
|
||||
|
||||
/* Argument array needs to be
|
||||
parsedargc + argc, plus 1 for null sentinel */
|
||||
|
||||
newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
|
||||
newargsp = newargs;
|
||||
|
||||
*newargsp++ = quoted(ptr);
|
||||
for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
|
||||
|
||||
*newargsp++ = quoted(script);
|
||||
for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]);
|
||||
|
||||
*newargsp++ = NULL;
|
||||
|
||||
/* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
|
||||
|
||||
if (is_gui) {
|
||||
/* Use exec, we don't need to wait for the GUI to finish */
|
||||
execv(ptr, (const char * const *)(newargs));
|
||||
return fail("Could not exec %s", ptr); /* shouldn't get here! */
|
||||
}
|
||||
|
||||
/*
|
||||
* distribute-issue207: using CreateProcessA instead of spawnv
|
||||
*/
|
||||
cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
|
||||
return create_and_wait_for_subprocess(cmdline);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
|
||||
return run(__argc, __argv, GUI);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return run(argc, argv, GUI);
|
||||
}
|
|
@ -29,4 +29,4 @@ OBJS += passes/cmds/chformal.o
|
|||
OBJS += passes/cmds/chtype.o
|
||||
OBJS += passes/cmds/blackbox.o
|
||||
OBJS += passes/cmds/ltp.o
|
||||
|
||||
OBJS += passes/cmds/bugpoint.o
|
||||
|
|
|
@ -83,7 +83,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
|
|||
|
||||
struct AddPass : public Pass {
|
||||
AddPass() : Pass("add", "add objects to the design") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -106,7 +106,7 @@ struct AddPass : public Pass {
|
|||
log("selected modules.\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
std::string command;
|
||||
std::string arg_name;
|
||||
|
|
|
@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct BlackboxPass : public Pass {
|
||||
BlackboxPass() : Pass("blackbox", "change type of cells in the design") { }
|
||||
virtual void help()
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
|
@ -34,7 +34,7 @@ struct BlackboxPass : public Pass {
|
|||
log("module attribute).\n");
|
||||
log("\n");
|
||||
}
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue