Merge remote-tracking branch 'origin/master' into feature/python_bindings

This commit is contained in:
Benedikt Tutzer 2019-03-28 12:16:39 +01:00
commit 03d1606b42
428 changed files with 23388 additions and 2479 deletions

7
.editorconfig Normal file
View File

@ -0,0 +1,7 @@
root = true
[*]
indent_style = tab
indent_size = tab
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -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.

7
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -36,6 +36,8 @@ echo
##########################################################################
./yosys tests/simple/fiedler-cooley.v
echo
echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r'
echo

View File

@ -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

View File

@ -3,7 +3,6 @@ brew "flex"
brew "gawk"
brew "libffi"
brew "git"
brew "mercurial"
brew "graphviz"
brew "pkg-config"
brew "python3"

125
CHANGELOG
View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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`.

View File

@ -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()) {

View File

@ -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;

View File

@ -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;

View File

@ -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");
}

View File

@ -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,27 +321,33 @@ struct FirrtlWorker
a_expr = "asSInt(" + a_expr + ")";
}
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
// 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;
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") {
primop = "neq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
}
else if (cell->type == "$reduce_bool") {
primop = "neq";
// 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());
@ -202,85 +360,112 @@ struct FirrtlWorker
continue;
}
if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
"$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
"$logic_and", "$logic_or"))
"$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
"$logic_and", "$logic_or"))
{
string y_id = make_id(cell->name);
bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B"));
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")) {
b_expr = "asSInt(" + b_expr + ")";
// 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 + ")";
}
if (b_padded_width < y_width) {
auto b_sig = cell->getPort("\\B");
b_padded_width = y_width;
}
}
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);
}
auto a_sig = cell->getPort("\\A");
if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) {
a_expr = "asUInt(" + a_expr + ")";
}
string primop;
bool always_uint = false;
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();
}

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -48,7 +48,7 @@ struct ProtobufDesignSerializer
ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
aig_mode_(aig_mode), use_selection_(use_selection) { }
string get_name(IdString name)
{
return RTLIL::unescape_id(name);
@ -60,7 +60,7 @@ struct ProtobufDesignSerializer
{
for (auto &param : parameters) {
std::string key = get_name(param.first);
yosys::pb::Parameter pb_param;
@ -207,7 +207,7 @@ struct ProtobufDesignSerializer
(*models)[aig.name] = pb_model;
}
}
void serialize_design(yosys::pb::Design *pb, Design *design)
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
@ -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;

View File

@ -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();

View File

@ -3,12 +3,12 @@ module test(input [31:0] a, b, c, output [31:0] x, y, z, w);
unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y));
assign z = a ^ b ^ c, w = z;
endmodule
module unit_x(input [31:0] a, b, c, output [31:0] x);
assign x = (a & b) | c;
endmodule
module unit_y(input [31:0] a, b, c, output [31:0] y);
assign y = a & (b | c);
endmodule

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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:
sys.setrecursionlimit(smtio_reclimit)
if resource.getrlimit(resource.RLIMIT_STACK)[0] < smtio_stacksize:
resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, -1))
if os.name == "posix":
smtio_reclimit = 64 * 1024
if sys.getrecursionlimit() < smtio_reclimit:
sys.setrecursionlimit(smtio_reclimit)
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,19 +166,28 @@ class SmtIo:
self.unroll = False
if self.solver == "yices":
self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts
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":
self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts
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":
self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
if self.noincr:
self.popen_vargs = ['boolector', '--smt2'] + self.solver_opts
else:
self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts
self.unroll = True
if self.solver == "abc":
@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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";
}

View File

@ -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(" << - ");
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("[");
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,43 +1065,46 @@ 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);
clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
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)
{
// for clocked read ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
// if (rd_en) temp_id <= array_reg[r_addr];
// assign r_data = temp_id;
std::string temp_id = next_auto_id();
lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
std::ostringstream os;
if (sig_rd_en != RTLIL::SigBit(true))
dump_sigspec(os, sig_rd_clk);
clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
if( clk_to_lof_body.count(clk_domain_str) == 0 )
clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
}
if (!rd_transparent)
{
// for clocked read ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
// if (rd_en) temp_id <= array_reg[r_addr];
// assign r_data = temp_id;
std::string temp_id = next_auto_id();
lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
os << stringf("if (");
dump_sigspec(os, sig_rd_en);
os << stringf(") ");
std::ostringstream os;
if (sig_rd_en != RTLIL::SigBit(true))
{
os << stringf("if (");
dump_sigspec(os, sig_rd_en);
os << stringf(") ");
}
os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
dump_sigspec(os, sig_rd_addr);
os << stringf("];\n");
clk_to_lof_body[clk_domain_str].push_back(os.str());
}
{
std::ostringstream os;
dump_sigspec(os, sig_rd_data);
std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
clk_to_lof_body[""].push_back(line);
}
os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
dump_sigspec(os, sig_rd_addr);
os << stringf("];\n");
clk_to_lof_body[clk_domain_str].push_back(os.str());
}
else
{
std::ostringstream os;
dump_sigspec(os, sig_rd_data);
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) {
// for rd-transparent read-ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
@ -1036,15 +1124,15 @@ 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];
std::ostringstream os, os2;
dump_sigspec(os, sig_rd_data);
dump_sigspec(os2, sig_rd_addr);
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().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];
std::ostringstream os, os2;
dump_sigspec(os, sig_rd_data);
dump_sigspec(os2, sig_rd_addr);
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
clk_to_lof_body[""].push_back(line);
}
}
@ -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;

7
examples/anlogic/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
demo.bit
demo_phy.area
full.v
*.log
*.h
*.tde
*.svf

12
examples/anlogic/README Normal file
View File

@ -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.

4
examples/anlogic/build.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -ex
yosys demo.ys
$TD_HOME/bin/td build.tcl

View File

@ -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

View File

@ -0,0 +1,2 @@
set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED

18
examples/anlogic/demo.v Normal file
View File

@ -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

3
examples/anlogic/demo.ys Normal file
View File

@ -0,0 +1,3 @@
read_verilog demo.v
synth_anlogic -top demo
write_verilog full.v

View File

@ -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]

View File

@ -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]

View File

@ -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();

4
examples/igloo2/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/netlist.edn
/netlist.vm
/example.stp
/proj

View File

@ -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

View File

@ -0,0 +1,2 @@
# Add timing constraints here
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]

64
examples/igloo2/example.v Normal file
View File

@ -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

View File

@ -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

6
examples/igloo2/runme.sh Normal file
View File

@ -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 .

View File

@ -0,0 +1,3 @@
OBJS += frontends/aiger/aigerparse.o

View File

@ -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

View File

@ -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

View File

@ -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 (id2ast)
fprintf(f, " [%p -> %p]", this, id2ast);
else
fprintf(f, " [%p]", this);
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)
fprintf(f, "[%d:%d]", range_left, range_right);
else {
if (range_valid) {
if (range_swapped)
fprintf(f, "[%d:%d]", range_right, range_left);
else
fprintf(f, "[%d:%d]", range_left, range_right);
} 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

View File

@ -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;

View File

@ -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);
std::stringstream sstr;
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
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

View File

@ -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;

View File

@ -1,4 +1,4 @@
ilang_lexer.cc
ilang_parser.output
ilang_parser.tab.cc
ilang_parser.tab.h
ilang_parser.tab.hh

View File

@ -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 $@)

View File

@ -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;

View File

@ -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

View File

@ -30,7 +30,7 @@
#endif
#include "frontends/ilang/ilang_frontend.h"
#include "ilang_parser.tab.h"
#include "ilang_parser.tab.hh"
USING_YOSYS_NAMESPACE

View File

@ -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,18 +95,36 @@ design:
module:
TOK_MODULE TOK_ID EOL {
if (current_design->has($2))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
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;
current_design->add(current_module);
if (!delete_current_module)
current_design->add(current_module);
attrbuf.clear();
free($2);
} module_body TOK_END {
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;

View File

@ -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");

View File

@ -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 {
}
}
for (auto node : cell->children)
if (!flag_lib)
{
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 (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");

View File

@ -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

View File

@ -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

View File

@ -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);
} else {
parse_property(clocking.body_net, &accept_bit, nullptr);
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 {
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);
}
}
}

View File

@ -1,4 +1,4 @@
verilog_lexer.cc
verilog_parser.output
verilog_parser.tab.cc
verilog_parser.tab.h
verilog_parser.tab.hh

View File

@ -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 $@)

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
};

View File

@ -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;

View File

@ -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);

View File

@ -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(); }
};

View File

@ -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

View File

@ -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
}

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -1,4 +1,4 @@
/*
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>

View File

@ -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)

View File

@ -1,4 +1,4 @@
/*
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>

View File

@ -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;

View File

@ -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.

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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"
{

358
misc/launcher.c Normal file
View File

@ -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);
}

View File

@ -1,12 +1,12 @@
//
// yosys -- Yosys Open SYnthesis Suite
//
//
// Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.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
@ -73,7 +73,7 @@ message Module {
BitVector bits = 2;
}
map<string, Port> port = 2;
// Named cells in this module.
message Cell {
// Set to true when the name of this cell is automatically created and
@ -129,7 +129,7 @@ message Model {
TYPE_FALSE = 6;
};
Type type = 1;
message Port {
// Name of port.
string portname = 1;
@ -148,7 +148,7 @@ message Model {
// Set for AND, NAND.
Gate gate = 3;
}
// Set when the node drives given output port(s).
message OutPort {
// Name of port.

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More